Waveshare
直播中

南惜北

10年用户 89经验值
擅长:可编程逻辑 处理器/DSP
私信 关注
[经验]

【XNUCLEO-F030R8试用体验】之六:mbed开发之定时器

本帖最后由 南惜北 于 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芯片内定时器的构成。
1.png
      事实上,Cortex M0内核还有一个systick定时器,在使用操作系统的时候可以作为系统时钟节拍,系统上电后,只要不清除其使能位,计时就不会停息。Systick定时器包含三个寄存器,分别是CTRL、LOAD、VAL寄存器,下图是寄存器的具体信息。
2.png
(图片摘自正点原子《STM32开发指南》)
       在mbed 里面提供了三个对象用来完成和时间相关的功能,分别是 Timeout,用来在给定的时间执行特定函数;Ticker,用来定时执行特定函数;Timer,用来给系统计时。下面是系统提供的一些方法。
3.png
      下面通过一个简单的例子来学习一下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是比较合适的时间。
4.png
      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的用途可以说相当广泛,比如在电能变换、电机调速等场合。
5.png
      可以看到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输出功能,可能是板子标注有误。
6.png
7.png
好啦,这部分就讲到这里,下节带来SPI的相关知识。
ticker.zip (1.14 MB)
(下载次数: 3, 2016-6-13 12:24 上传)

PWM.zip (1.14 MB)
(下载次数: 1, 2016-6-13 12:25 上传)




更多回帖

发帖
×
20
完善资料,
赚取积分