原创 STM32学习笔记(7)-定时器初步

2010-7-15 10:54 6069 7 8 分类: MCU/ 嵌入式
 接下来研究定时器。为什么开始研究定时器了呢?那个I/O还是刚刚开了头啊,还有很多很多知识没有掌握!不怕,方法论告诉我们:对事物的认识是螺旋式上升的,所以不要一杆子打到底,想着把I/O口的所有情况都掌握了再学下面的,那会是很困难的

       STM32的定时器是什么样子的,心里一点底也没有,还是找个现成的例子来吧。在ST提供的库里,有很多的例子



第一个就是它了。


7784c0a2-a9bc-456d-bc8a-644beb2a1322.jpg

       把整个文件夹复制一份到自己的实验文件夹中

29cbc50f-4567-4aff-ab1c-cd7ac0e4fccb.jpg

       在Source文件夹中再建立名为APP的文件夹,将上图中所有源程序文件全部复制到APP文件夹中。然后将库所提供的CMSIS文件夹和STM32F10x_StdPeriph_Driver文件夹复制到Source文件夹中。然后按照前面的方法建立项目。


32d34589-2fd6-49f1-ac94-a8c7895a48a2.jpg

这是建好的项目的结构。



b97c555e-95d0-4677-a2da-71606548f32a.jpg

       下面开始研究,首先看附带的readme.txt文件,了解到该例子的大体用途是验证Tim2的Output Compare Timing mode的。于是打开PDF文件,直接翻到下面的位置:

-----------------------------------------------------------------------------------------

 13.3.8  输出比较模式


此项功能是用来控制一个输出波形或者指示何时一段给定的的时间已经到时。


当计数器与捕获/比较寄存器的内容相同时,输出比较功能做如下操作:


●  将输出比较模式(TIMx_CCMRx寄存器中的OCxM位)和输出极性(TIMx_CCER寄存器中的CCxP位)定义的值输出到对应的管脚上。在比较匹配时,输出管脚可以保持它的电平


(OCxM=000)、被设置成有效电平(OCxM=001)、被设置成无有效电平(OCxM=010)或进行翻转(OCxM=011)。


●  设置中断状态寄存器中的标志位(TIMx_SR寄存器中的CCxIF位)。


●  若设置了相应的中断屏蔽(TIMx_DIER寄存器中的CCXIE位),则产生一个中断。


●  若设置了相应的使能位(TIMx_DIER寄存器中的CCxDE位,TIMx_CR2寄存器中的CCDS位选择DMA请求功能),则产生一个DMA请求。


TIMx_CCMRx中的OCxPE位选择TIMx_CCRx寄存器是否需要使用预装载寄存器。


在输出比较模式下,更新事件UEV对OCxREF和OCx输出没有影响。


同步的精度可以达到计数器的一个计数周期。输出比较模式(在单脉冲模式下)也能用来输出一个单脉冲。


输出比较模式的配置步骤:


1.  选择计数器时钟(内部,外部,预分频器)


2.  将相应的数据写入TIMx_ARR和TIMx_CCRx寄存器中


3.  如果要产生一个中断请求和/或一个DMA请求,设置CCxIE位和/或CCxDE位。


4.  选择输出模式,例如:必须设置OCxM=’011’、OCxPE=’0’、CCxP=’0’和CCxE=’1’,当计数器CNT与CCRx匹配时翻转OCx的输出管脚,CCRx预装载未用,开启OCx输出且高电平有效。



5.  设置TIMx_CR1寄存器的CEN位启动计数器--------------------------------------------------------------------------------

说得并不复杂,但是要弄清楚也绝非易事,况且main.c中一系列的符号究竟是什么意思也不是那么容易搞清楚的。这些东西搞不清,将来自己编程时,就算想要依葫芦画瓢都难。怎么办呢?可能并没有多少偷巧的办法,只能是一步一步地摸索吧。

       进入调试,打开Peripherals->Timers->Tim2,出现下面的窗口。



f3858385-96b8-485f-9110-576c3237f71c.jpg

       然后单步执行程序,并观察界面的变化,并将这些符号作为线索,在PDF文件,stmf10x_tim.c等文件中搜索,了解相关符号的含义。


       如下图是执行到:while(1)前,也就是所有设置完成后的图。


 b40579e4-5a7d-464c-bd84-35b58db733f2.jpg

沿着这些线索一路追踪,边看源程序,边找数据手册,边找相关的头文件,其他源程序,总算大体有了个明白,下面将main.c中的部分代码作为注释,也算是做点记录。


 /* Includes ------------------------------------------------------------------*/


#include "stm32f10x.h"


//这个头文件需要根据所选择的芯片进行更改




/* Private variables ---------------------------------------------------------*/


TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;    


TIM_OCInitTypeDef  TIM_OCInitStructure;     //定义两个结构型变量


__IO uint16_t CCR1_Val = 49152;


__IO uint16_t CCR2_Val = 32768;


__IO uint16_t CCR3_Val = 16384;


__IO uint16_t CCR4_Val = 8192;  //


ErrorStatus HSEStartUpStatus;

/* Private function prototypes -----------------------------------------------*/

void RCC_Configuration(void);


void GPIO_Configuration(void);


void NVIC_Configuration(void);

int main(void)

{


  /* System Clocks Configuration */


  RCC_Configuration();


 


  /* NVIC Configuration */


  NVIC_Configuration();


 


  /* GPIO Configuration */


  GPIO_Configuration();


   /* ---------------------------------------------------------------


    TIM2 Configuration: Output Compare Timing Mode:


    TIM2CLK = 36 MHz, Prescaler = 4, TIM2 counter clock = 7.2 MHz


    CC1 update rate = TIM2 counter clock / CCR1_Val = 146.48 Hz


    CC2 update rate = TIM2 counter clock / CCR2_Val = 219.7 Hz


    CC3 update rate = TIM2 counter clock / CCR3_Val = 439.4 Hz


    CC4 update rate = TIM2 counter clock / CCR4_Val =  878.9 Hz


  --------------------------------------------------------------- */


 


  /* Time base configuration */


  TIM_TimeBaseStructure.TIM_Period = 65535;      //它对应TIM2_ARR


  TIM_TimeBaseStructure.TIM_Prescaler = 0; 


  /* 它对应TIM2_PSC,相关代码如下(stm32f10x_tim.c中):


  TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;


但很奇怪,这里令其为0,然后再在下面设置为4??为何??


  */


  TIM_TimeBaseStructure.TIM_ClockDivision = 0x0200;


  //ClockDivision是对CKD位进行设置的,但是这个必须要自己给其赋正确的值


  /*在stm32f10_tim.c文件中是这样操作的


   TIMx->CR1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision |


                TIM_TimeBaseInitStruct->TIM_CounterMode;


  */


  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;


  /*计数模式,st32f10x_tim.h中定义,其他可用的符号还有:


 TIM_CounterMode_Up,TIM_CounterMode_Down,TIM_CounterMode_CenterAligned1


 TIM_CounterMode_CenterAligned2,TIM_CounterMode_CenterAligned3


  */


  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);


  /* Prescaler configuration */


  TIM_PrescalerConfig(TIM2, 4, TIM_PSCReloadMode_Immediate);


/*stm32f10x_tim.c中相关代码:


  TIMx->PSC = Prescaler;


*/


  /* Output Compare Timing Mode configuration: Channel1 *///输出比较模式


  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;  


  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;


  TIM_OCInitStructure.TIM_Pulse = CCR1_Val;                            //预置值


  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;     //对CCER中CCxP的操作


   TIM_OC1Init(TIM2, &TIM_OCInitStructure);


 /*对捕获/比较使能寄存器(TIMx_CCER)进行操作,置CC1E为1 */


  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);


   /* Output Compare Timing Mode configuration: Channel2 */


  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;


  TIM_OCInitStructure.TIM_Pulse = CCR2_Val;


  //这个是将CCR2_Val的值送到TMI2_CCR2中


  TIM_OC2Init(TIM2, &TIM_OCInitStructure);


   TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);


  /* Output Compare Timing Mode configuration: Channel3 */


  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;


  TIM_OCInitStructure.TIM_Pulse = CCR3_Val;


    TIM_OC3Init(TIM2, &TIM_OCInitStructure);


   TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);


/*


*/


  /* Output Compare Timing Mode configuration: Channel4 */


  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;


  TIM_OCInitStructure.TIM_Pulse = CCR4_Val;


   TIM_OC4Init(TIM2, &TIM_OCInitStructure);


   TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);


   /* TIM IT enable */


  TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);


对DIER寄存器操作,中断允许配置,相关代码如下:



3d1c54d0-5e95-4d05-817c-1422198b5ae5.jpg


而DIER寄存器如下:


67a81e80-091e-4529-b4ca-b6033e213fd3.jpg



  /* TIM2 enable counter */


  TIM_Cmd(TIM2, ENABLE);


//开启定时器的运行


  while (1);


}


解读:


(1)       时钟来源 CK_INT,设置的方法是让TIMx_SMCR中的SMS[2:0]=000,最后通过TIM_Cmd(TIM2, ENABLE);函数将TIMx_CR1中的CEN置1,开启定时器的运行;


(2)       接下来设置定时器的基本参数


(3)       然后是设置定时器的各个通道


(4)       最后开启定时器运行


最后,将这个例子稍加修改,令其运行在我的实验板上。


需要修改的仅是将其原来的输出从GPIOC的第6~第9脚变为GPIOD的第8~第11脚。为此,需要改的地方有:


86663153-f8d8-4b51-8350-8b7e0c5473b4.jpg

将蓝色框内的GPIOC改为GPIOD。这个是最先写的,但实际上一开始根本没注意到这个地方,没有改成GPIOD,结果一仿真,不正确,再一细查,原来端口还要配置时钟,改过来就对了。瞧,这不验证了上面的说法“认识事物是螺旋式上升的”学了定时器,对于I/O口和时钟又有了更进一步的理解了。



bf1140e6-6ab1-4e97-af60-2d1dba1deb9e.jpg


将红色框内的GPIO分别改成8,9,10,11,将蓝色框内的GPIOC改为GPIOD。


最后,到stm32f10x_it.c中,修改相应的输出



1eeae997-d0cb-4f50-b02e-5dfec6888ba8.jpg


参考上图红色框内,将GPIOC改为GPIOD,将6脚改为8脚,其他部分类推。


修改好后运行,所有灯亮了,看不出效果,于是又将预分频系数由4改为64,这样一来,LED开始闪烁了。

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户416388 2012-7-4 14:59

你是怎么都学会的呢,我咋就不会,
相关推荐阅读
teach51_109853927 2015-10-25 22:37
带“锁定输出”的数控稳压电源(二)
3.控制程序编写        硬件电路设计完成后,就要编写软件了。软件基本上可以分为键盘驱动,PWM生成,功能实现等部分。 3.1 键盘处理程序        STC单片机的引脚可以...
teach51_109853927 2014-03-02 12:17
带“锁定输出”的数控稳压电源(一)
本文是探索“开源培训”思想的作品。 所谓“开源培训”是指在某个社区,各志愿者提供有一定实用价值和教学价值的作品,同时详细说明制作过程,并提供制作所需的各类资源,帮助入门者快速找到适合自己的项目...
teach51_109853927 2014-02-22 21:15
《单片机项目教程》、《单片机项目教程C语言版》电子课件
《单片机项目教程》电子课件 http://pan.baidu.com/s/1kT2Yb6f 《单片机项目教程C语言版》电子课件 http://pan.baidu.com/s/1gd5O...
teach51_109853927 2014-02-22 21:05
《单片机应用与接口技术》相关资源
单片机应用与接口技术    机械工业出版社出版,江苏省教育厅推荐教材 《单片机应用与接口技术》课件 http://pan.baidu.com/s/1c0kpzUg 《单片机应用与接...
teach51_109853927 2014-02-22 15:25
便携式无线抢答器
本产品专门为开展活动时需要用到抢答器的场合设计,已制作成品,读者可以参考作为练手之用。 如图1所示左边为信号接收装置(主持人用),右边两个为发射装置(比赛选手用)。都只需要使用干电池供电即可。...
teach51_109853927 2014-02-22 15:22
Modbus通讯协议
Modbus协议最初由Modicon公司开发出来,在1979年末该公司成为施耐德自动化(Schneider Automation)部门的一部分,现在Modbus已经是工业领域全球最流行的协议。此协...
EE直播间
更多
我要评论
1
7
关闭 站长推荐上一条 /3 下一条