本篇文章接上一篇关于定时器原理:http://blog.csdn.net/mybelief321/article/details/8916775

实验前的准备 

      既然是关于定时器的实验,肯定要用到系统时钟,所以一定要保证系统时钟设置好,在这里需要的PCLK为50MHz。第二节分析MDK自带的S3C2440.c可以知道,默认的是不初始化系统时钟(是否选择初始化可以通过修改S3C2440.s中的CLOCK_SETUP来选择)。那么在这里首先修改一下S3C2440.s,对时钟进行初始化。

     在这里只需要设置一处即可将 CLOCK_SETUP     EQU     0修改为CLOCK_SETUP     EQU     1,这样系统在启动时就会对咱们的芯片进行初始化,初始化之后的系统时钟值为:FCLK=300MHz,HCLK=100MHz,PCLK=50MHz。

实验1

     实验实现的功能:使用定时器0的定时功能,是LED每秒钟闪烁一次。   

    因为在启动代码阶段,已经对系统时钟进行初始化,PCLK=50MHz,定时器的输入频率由PCLK分频得到,如图1所示展示了从晶振输入频率到定时器工作频率产生的整体过程。

    

      下图是我的定时器工程的文件布局图:

      

    从上图可以看出,这个工程需要咱们自己编写的文件一共有5个:main.c  timer.c   timer.h    led.c   led.h

    实验代码:

    main.c文件内容:

/* *  使用定时器0的定时功能,使LED灯每秒钟闪烁一次 */

#include<s3c2440.h> #include”timer.h” #include”led.h”

int main() {          int flag=0;      Led_Init();   //对LED初始化为全灭     Timer0_Init();  //定时器0初始化,打开定时器0,定时器0开始进行减1计数。      while(1)     {         if(SRCPND&(1<<10))     //当TCNT0中的计数值减为0时,定时器0中断标志会置位         {                                     //因此,在程序中可以通过不断的检测该位是否置位来判断1s定时              flag=!flag;                     //是否到达。定时器0中断标志位位于SRCPND寄存器的第10位              SRCPND|=(1<<10);     //清除定时器0中断标志位          }          if(1==flag)                      //判断falg是否为1,这里使用一个小技巧,使用if(1==flag)。也可以

                                              //使用if(flag==1)。         {             Led1_On();         }           else        {            Led1_Off();         }        } }

 

    timer.c文件内容

 

            #include<s3c2440.h>   //s3c2440.h对S3C2440芯片的一些地址的宏定义             #include”timer.h”

 /*************************************************************** * 函数名称:void Timer0_Init(void) * 参数说明:无 * 全局变量:无 * 返 回 值:无 * 功    能:对于50MHz的PCLK,经过分频获得62.5KHz的定时器0 *     的输入时钟。 ***************************************************************/ void Timer0_Init(void) {  TCFG0&=~(0xff);          //设置第1级分频系数,分频系数为99  TCFG0|=99;

 TCFG1&=~(0xf);            //设置第2级分频系数,分频系数为8  TCFG1|=0x02;               //62.5KHz=50MHz/(99+1)/8

 TCNTB0=62500;            //1s中断一次。经过上述分频器得到定时器0的输入时钟频率为62.5kHz,即定时                                        //器每秒钟计数62500次。因此,初始化时,定时器0计数值初始值为62500,在这                                        //里我们可以看出TCMPBn没有设置,因为咱们用它的默认值0,所以就不需要设置

 TCON|=(1<<1);             //开启手动更新位,即当定时器开启后,TCMPB0和TCNTB0中的值会加载到寄存

                                      //器TCMP0和TCNT0中  TCON=0x09;                //关闭手动更新位,设置自动加载位,同时开启定时器,这样,TCNT0进行减1计

                                     //数,当TCNT0中的计数值减到0时,TCNTB0、TCMPB0中的数据分别会                                      //自动加载到TCNT0、TCMP0中并进行新一轮的减1计数 }

   timer.h文件内容:

      

#ifndef __TIMER_H__ #define __TIMER_H__

/*************************************************************** * 函数名称:void Timer0_Init(void) * 参数说明:无 * 全局变量:无 * 返 回 值:无 * 功    能:对于50MHz的PCLK,经过分频获得62.5KHz的定时器0 *     的输入时钟。 ***************************************************************/ void Timer0_Init(void);

#endif

   led.c文件内容:

/* *  在我的mini2440开发板上,4个led灯对应的GPIO引脚如下 *   LED1—-GPB5 *   LED2—-GPB6 * LED3—-GPB7 *   LED4—-GPB8 *   当GPIO引脚输出低电平时,对应的led灯亮,输出高电平时,对应的led灯灭。 */

#include<s3c2440.h>   #include”led.h”

/*************************************************************** * 函数名称:void Led_Init(void) * 参数说明:无 * 全局变量:无 * 返 回 值:无 * 功    能:led初始化函数,使4个led初始化为灭 *     的输入时钟。 ***************************************************************/ void Led_Init(void) {  GPBCON&=~((3<<10)|(3<<12)|(3<<14)|(3<<16));  //注意这里设置寄存器的方式,采用先与后或的方式  GPBCON|=((1<<10)|(1<<12)|(1<<14)|(1<<16));    //设置GPB5、6、7、8为输出功能

 GPBUP&=~((1<<5)|(1<<6)|(1<<7)|(1<<8));      //上拉电阻使能。上拉电阻的作用是:当GPIO引脚处于

                                                                          //第三态(既不是输出高电平,也不是输出低电平,而是呈

                                                                         //高阻态,即相当于没接芯片)时,它的电平状态由上拉                                                                            //电阻、下拉电阻确定

 GPBDAT|=((1<<5)|(1<<6)|(1<<7)|(1<<8));      //初始化这4个引脚输出高电平,即4个led灯全灭。 }

    led.h文件内容:

#ifndef __LED_H__ #define __LED_H__

#define Led1_On() {GPBDAT&=(~(1<<5));}       //在程序调用函数时,调用函数需要保存函数的返回地址, #define Led1_Off() {GPBDAT|=(1<<5);}           //然后从函数返回是需要将返回地址赋值给PC,这些都会 #define Led2_On() {GPBDAT&=(~(1<<6));}    //使程序执行速度变慢。为了改善这种情况,对于这种 #define Led2_Off() {GPBDAT|=(1<<6);}         //代码量很小的程序段,可以使用宏的形式实现。 #define Led3_On() {GPBDAT&=(~(1<<7));} #define Led3_Off() {GPBDAT|=(1<<7);} #define Led4_On() {GPBDAT&=(~(1<<8));} #define Led4_Off() {GPBDAT|=(1<<8);} /*************************************************************** * 函数名称:void Led_Init(void) * 参数说明:无 * 全局变量:无 * 返 回 值:无 * 功    能:led初始化函数,使4个led初始化为灭 *     的输入时钟。 ***************************************************************/ void Led_Init(void);

#endif

 

      以上实验1的代码我已经上传到csdn,如有需要可自行下载:http://download.csdn.net/detail/mybelief321/5371577,mske编译成功后,就可以仿真看到结果了。

     上述实验1的已经说完了,再强调一下,我没有再编写代码另外设置系统时钟,而是用MDK自带的S3C2440.s来初始化的,只需要修改一处地方,本文章开头所示。

      还有一处需要说明一下,那就是关于main函数里的中断。虽然定时器0中断标志还没有讲,但是我们可以先了解以下三点:

      ①SRCPND寄存器中的每一位代表一种类型的中断标志,当该位置1时,说明相应的中断发生了。

      ②定时器0中断标志位于SRCPND寄存器的第10位,当定时器0中的计数值减到0时,会触发定时器0中断标志,即SRCPND寄存器第10位会置1.

     ③清除定时器0中断标志的方法是:想SRCPND寄存器的第10位写入1即可。

 

实验2

      实验1主要是针对定时器的原理进行的实验,下面的实验是为了展示定时器0的脉冲宽度调制功能。

    从下图可以看出,当TCMP0=TCNT0时,TOUT0引脚电平会发生翻转;当TCNT0中计数值减为0时,TOUT0引脚电平再次发生翻转。因此,可以利用TOUT0引脚电平的两次翻转进行脉冲宽度调制,即PWM。查询S3C2440数据手册可以得到,TOUT0引脚对应的是GPB0引脚。

      

       在实验1的基础上,修改timer.c中定时器0初始化函数。修改后的定时器0初始化函数如下:    

void  Timer0_Init(void) {  GPBCON&=~(3<<0);  GPBCON|=(1<<1);

 TCFG0&=~(0xff);    //设置第1级分频系数,分频系数为99  TCFG0|=99;

 TCFG1&=~(0xf);      //设置第2级分频系数,分频系数为8  TCFG1|=0x02;        //62.5KHz=50MHz/(99+1)/8                                 //此时定时器0的工作频率为62500Hz

 TCNTB0=62;                  //由于此时定时器0的工作频率为62500Hz,即每秒种可以计数62500次,而其初始值为62,所以产生的方波                                        //的频率为62500/62=1008Hz。又因为TCMP0=TCNT0/2,所以产生的方波高电平持续时间和低电平持续时间  TCMPB0=TCNTB0/2;   //各占一半。

 TCON|=(1<<1); //开启手动更新位,即当定时器开启后,TCMPB0和TCNTB0中的值会加载到寄存器TCMP0和TCNT0中  TCON=0x0d;     //关闭手动更新位,设置自动加载位,同时开启定时器,设置当TCMP0=TCNT0时,TOUT0引脚电平发生翻转 }

      程序总体流程:

       ①开启定时器0后,TCNTB0、TCMPB0中的值分别装入TCNT0和TCMP0中,然后,TCNT0从初值62开始减1计数;

       ②当TCNT0=TCMP0=31时,TOUT0引脚电平发生翻转;

       ③TCNT0继续减1计数,当TCNT0减为0时,TOUT0引脚电平再次发生翻转,此时恰好产生一个方波;

       ④TCNTB0、TCMPB0中的值被自动装入TCNT0、TCMP0中,TCNT0继续从初值62开始减1计数。

 

     上述程序,占空比为50%,如果将 TCMPB0=TCNTB0/2 改为 TCMPB0=TCNTB0/4,那么输出方波的占空比发生了变化,变为75%,这就是所谓的PWM功能。

     由于咱们的开发板的GPB0连接着蜂鸣器,所以你可以通过调节占空比来改变蜂鸣器的频率,将上述初始化函数修改后,直接make,仿真就可以了。

posted on
2018-05-10 14:53 
无网不进 
阅读(216
评论(0
编辑 
收藏 
举报

版权声明:本文为hbtmwangjin原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/hbtmwangjin/articles/9019643.html