本帖最后由 南惜北 于 2016-6-13 12:25 编辑
【XNUCLEO-F030R8试用体验】之六:mbed开发之定时器 在开发过程中,许多场合都和时间有关,前面代码中多次出现的 wait 函数就是最常
用的延时函数。显然,如果通过软件延时,不仅延时精度不高,而且大量占用CPU资源,在微处理器中采用定时/计数器来完成与时间计算有关的工作。 定时/计数器的工作原理非常简单,就是每当它接收到一个脉冲时,它的计数值加1(有些为减1计数),一旦它的计数值达到用户设定的阈值,计数器就会产生溢出信号和一些标志位,并重新从 0 开始计数。如果我们使能了相应的中断,当计数溢出时会产生中断。根据计数器可设定阈值的大小,我们可以把计数器分成8 位计数器, 16 位计数器等。8 位计数器可设定的最大阈值为 2^8-1 即 255, 16 位则为 65535。如果我们给定的计数时钟为1M,而给定的计数器阈值为 0,设置为减计数模式,那么计数器就会每1us 就会计满一次,系统通过多次调用延时函数达到延时1s、10s以致更长的时间。F030R8有7个定时器,均为16位, tiM6为基本定时器,TIM3、14、15、16、17为通用定时器,TIM1为高级定时器,下面的图片描述了F030R8芯片内定时器的构成。
事实上,Cortex M0内核还有一个systick定时器,在使用操作系统的时候可以作为系统时钟节拍,系统上电后,只要不清除其使能位,计时就不会停息。Systick定时器包含三个寄存器,分别是CTRL、LOAD、VAL寄存器,下图是寄存器的具体信息。
在mbed 里面提供了三个对象用来完成和时间相关的功能,分别是 Timeout,用来在给定的时间执行特定函数;Ticker,用来定时执行特定函数;Timer,用来给系统计时。下面是系统提供的一些方法。
下面通过一个简单的例子来学习一下Timer对象及其方法。这个例子使用Timer对象提供的方法计算用户按下按键的时间,发送到串口,在屏幕上显示。相关代码如下: #include "mbed.h" Serial pc(USBTX,USBRX); InterruptIn btn(PC_13); Timer mytimer; int falltime; int risetime; void fall() { falltime=mytimer.read_us(); } void rise() { risetime=mytimer.read_us(); pc.printf("You pres***utton for %d us n",risetime-falltime); } int main() { mytimer.start(); btn.fall(&fall); btn.rise(&rise); while (1); } 程序的思路很简单,按下按键时执行下降沿中断函数,读取当前定时器的值,松开按键时执行上升沿中断函数,读取当前定时器的值,两项相减即为按下按键的时间。下图是串口收到的数据,可以看到,按下按键最快时间也要7ms左右,正常时间在15ms,因此在按键消抖时延时8~10ms是比较合适的时间。
Ticker对象用来周期性执行某个特定函数,初始化完成后,函数会反复执行。下面通过一个例子来学习一下,例子中四个LED以不同的频率闪烁。按键每按下一次,LED1的闪烁频率加快一倍。代码如下: #include "mbed.h" DigitalOut led1(LED1); DigitalOut led2(PC_9); DigitalOut led3(PC_8); DigitalOut led4(PC_5); InterruptIn btn(PC_13); Ticker timer_led1; Ticker timer_led2; Ticker timer_led3; Ticker timer_led4; float m; void led1func() { led1=!led1; } void led2func() { led2=!led2; } void led3func() { led3=!led3; } void led4func() { led4=!led4; } void btn_fall(void) { m=m/2; timer_led1.attach(&led1func,m); } int main() { m=2; timer_led2.attach(&led2func,2); timer_led3.attach(&led3func,4); timer_led4.attach(&led4func,8); btn.fall(&btn_fall); while (1) ; } 相比于Ticker对象,TimeOut对象主要用来在给定的时间后执行给定的函数,如果我们将上面的代码中Ticker换成TimeOut,运行后你会发现四个 led 分别点亮,但由于 timeout 只会被执行一次,所以点亮后会保持不变。 讲到这里,似乎关于时间的部分已经差不多了,事实上PWM这个非常常用的对象我们还没有涉及到,PWM本质上也是利用定时器实现的,PWM的用途可以说相当广泛,比如在电能变换、电机调速等场合。
可以看到mbed提供的方法相当丰富,可以设置PWM周期、占空比、输出值等。下面用一个例子来学习一下,通过改变PWM输出波形的占空比,改变LED灯的亮度。 #include "mbed.h" PwmOut PWM1(D9); //PwmOut PWM2(D6); PwmOut PWM3(D10); PwmOut PWM4(D11); float pv=0; int main() { PWM1.period_us(100); //PWM2.period_us(100); PWM3.period_us(100); PWM4.period_us(100); PWM1=0;//设定占空比 // PWM2=0.75; PWM3=0.90; PWM4=0.60;//PWM4.pulsewidth_us(60)效果相同 while (1) { PWM1=pv; pv=pv+0.01; wait(0.05); if (pv>1) pv=0; } } 实验中发现,当D6作为PWM输出时,D9,D10,D11不能输出PWM信号,查资料后发现D6对应引脚为PB10,并没有PWM输出功能,可能是板子标注有误。
好啦,这部分就讲到这里,下节带来SPI的相关知识。
|