历史上的今天
返回首页

历史上的今天

今天是:2024年12月05日(星期四)

正在发生

2019年12月05日 | AVR开发 Arduino方法(三) 定时/计数器子系统

2019-12-05 来源:elecfans

Arduino UNO R3的主处理器ATMega328P拥有3个定时/计数器,它们分别是Timer0,Timer1和Timer2;它们都通过对来自内部或外部的脉冲信号进行计数的方式完成基本的定时/计数功能以及一些其他的功能。


Timer0和Timer2是8位定时/计时器,Timer1是16位定时/计数器;下面以Timer2为例讨论定时/计数器子系统的典型应用,这些内容同样适用于Timer0和Timer1。

1. 精准延时

在前面的例子中,已经使用了一些与精准延时相关的Arduino库函数:

 

  delay(ms):延迟一段时间

  ms:延迟的时长,单位是毫秒

 

请注意,上面的Arduino库函数使用了Timer0的中断,因此不要在任何中断服务程序中调用它,否则程序可能无法正常工作。


如果需要在延迟的同时,Arduino可以执行其他程序,这需要借助第三方库MsTimer2;你可以在http://playground.arduino.cc/Main/MsTimer2下载到它,把下载到的MsTimer2.zip解压到Arduino IDE安装目录下的libraries文件夹里就可以使用了,它包含了一个示例:


 1 // FlashLed.ino

 2 #include

 3 

 4 void flash() {

 5   static boolean output = HIGH;

 6   

 7   digitalWrite(13, output);

 8   output = !output;

 9 }

10 

11 void setup() {

12   pinMode(13, OUTPUT);

13 

14   MsTimer2::set(500, flash);

15   MsTimer2::start();

16 }

17 

18 void loop() {

19 }


这个示例的效果与Blink示例基本相同,MsTimer2库提供了3个库函数:

 

  MsTimer2::set(interval, function):每隔一段时间执行指定函数

  interval:间隔时长,单位是毫秒

  function:指定执行函数的名称

  MsTimer2::start():开始每隔一段时间执行指定函数

  MsTimer2::stop():结束每隔一段时间执行指定函数

 

Timer2有2个控制寄存器:TCCR2A和TCCR2B,它们的结构如下图所示:

COM2A1

COM2A0

COM2B1

COM2B0



WGM21

WGM20

 

FOC2A

FOC2B



WGM22

CS22

CS21

CS20

其中WGM2[2:0]位用于设置模式,CS2[2:0]位用于设置时钟源,如下表所示:

WGM2[2:0]

模式

计数上限


CS2[2:0]

时钟源

000

正常

0xFF


000

001

相位校正脉宽调制

0xFF


001

系统时钟

010

比较匹配时清零

OCR2A


010

系统时钟8分频

011

快速脉宽调制

0xFF


011

系统时钟32分频

100

(保留)



100

系统时钟64分频

101

相位校正脉宽调制

OCR2A


101

系统时钟128分频

110

(保留)



110

系统时钟256分频

111

快速脉宽调制

OCR2A


111

系统时钟1024分频

其余位暂且设置为0。


精准延时可以采用正常模式。正常模式下,Timer2不断从0x00计数到0xFF;当定时计数器寄存器TCNT2每一次返回0x00时,若Timer2的中断屏蔽寄存器TIMSK2的溢出中断使能位TOIE2为1,则产生中断,它的结构如下图所示:






OCIE0B

OCIE0A

TOIE0

通过直接访问寄存器改写以上程序为:


 1 // FlashLed_reg.ino

 2 void flash() {

 3   PORTB ^= (1 << PB5);

 4 }

 5 void setup() {

 6   DDRB |= (1 << PB5);

 7 

 8   // 正常模式,系统时钟256分频,计数初值为6

 9   TCCR2A = 0x00;

10   TCCR2B = 0x06;

11   TCNT2 = 0x06;

12   

13   TIMSK2 |= (1 << TOIE2);

14   sei();

15 }

16 

17 void loop() {

18 }

19 

20 ISR(TIMER2_OVF_vect) {

21   static volatile int iTimes = 0;

22 

23   // 中断125次为500毫秒

24   if (++iTimes == 125) {

25     flash();

26     iTimes = 0;

27   }

28   // 重新赋初值6

29   TCNT2 = 0x06;

30 }


程序中的“中断125次为500毫秒”是这样计算出来的:Arduino UNO R3开发板使用16MHz的系统时钟,Timer2使用系统时钟256分频,每记256-6=250个脉冲溢出一次,则每秒溢出16000000÷256÷250=250次,因此每溢出125次为500毫秒。

2.脉宽调制

脉宽调制的一个典型应用是控制直流电机速度。将直流电机两极分别连接到直流电源的正负两极上,电机会以最快速度运行;要调整电机速度,一个很容易想到的方法是调整直流电源的功率,但在数字系统中还有一个更简单的方式:使用高低电平宽度不一样的脉冲信号快速开关直流电机;因为惯性的作用,电机不会以最快的速度运行。一般来说,高电平在一个脉冲周期中所占宽度更宽时,直流电机速度越快;我们把高电平所占一个脉冲周期的宽度称为占空比。


如图所示连接电路,11(PB3/OC2A)引脚通过三极管间接控制直流电机:

用Arduino库函数输出一个脉宽调制信号十分简单,下面的示例使得直流电机由慢到快,又由快到慢反复运行:


 1 // FadingMotor.ino

 2 int motor = 11;

 3 int speed = 0;

 4 int fadeAmount = 5;

 5 

 6 void setup() {

 7   pinMode(motor, OUTPUT);

 8 }

 9 

10 void loop() {

11   analogWrite(motor, speed);

12 

13   speed = speed + fadeAmount;

14   if (speed <= 0 || speed >= 255) {

15     fadeAmount = -fadeAmount;

16   }

17 

18   delay(30);

19 }


与脉宽调制相关的Arduino库函数有:

 

  analogWrite(pin, value):在指定引脚上输出一个指定占空比脉宽调制信号

  pin:指定引脚

  value:脉宽调制信号的占空比;0为0%,255为100%

 

Timer2拥有2个输出比较寄存器OCR2A和OCR2B,它们通过与TCNT2寄存器发生比较匹配时对引脚置位、清零或取反来完成脉宽调制信号的输出。TCCR2A寄存器中的COM2A[1:0]位用于设置OCR2A寄存器发生比较匹配时的行为,如下表所示:

COM2A[1:0]

行为

00

正常的端口操作,OC2A未连接

01

WGM22=0,正常的端口操作,OC2A未连接

WGM22=1,发生比较匹配时OC2A取反

10

发生比较匹配时OC2A清零,计数到下限时OC2A置位

11

发生比较匹配时OC2A置位,计数到下限时OC2A清零

通过直接访问寄存器改写以上程序为:


 1 // FadingMotor_reg.ino

 2 int speed = 0;

 3 int fadeAmount = 5;

 4 

 5 void setup() {

 6   DDRB |= (1 << PB3);

 7 

 8   // 快速脉宽调制,OC2A比较匹配置位,下限清零,系统时钟

 9   TCCR2A = 0x83;

10   TCCR2B = 0x01;

11 }

12 

13 void loop() {

14   OCR2A = speed;

15 

16   speed = speed + fadeAmount;

17   if (speed <= 0 || speed >= 255) {

18     fadeAmount = -fadeAmount;

19   }

20 

21   delay(30);

22 }


3. 输入捕获*

  输入捕获用来计算外部输入信号的周期,它是Timer1的特有功能,Arduino官网提供了一个输入捕获的示例:


 1 // PulseIn.ino

 2 const int pin = 8;

 3 unsigned long duration;

 4 

 5 void setup() {

 6   pinMode(pin, INPUT);

 7 }

 8 

 9 void loop() {

10   duration = pulseIn(pin, HIGH);

11 }


与输入捕获相关的Arduino库函数有:

 

  pulseIn(pin, value):计算指定引脚输入外部信号的周期

  pin:指定引脚

  value:捕获脉冲的类型,LOW(低电平,0V)或HIGH(高电平,5V)

  函数返回外部输入信号的周期,是一个unsigned long类型的整数,单位为微秒

 

Timer1的控制寄存器与Timer2的不尽相同,请参阅ATMega328P芯片手册16-bit Timer/Counter1 with PWM章的Register Description小节进行设置。通过直接访问寄存器改写以上程序为:


 1 // PulseIn_reg.ino

 2 unsigned long duration;

 3 unsigned long timer1_pulse_in();

 4 

 5 void setup() {

 6   DDRB &= ~(1 << PB0);

 7   PORTB &= ~(1 << PB0);

 8 

 9   // 正常模式,系统时钟8分频

10   // 噪声抑制关闭,下降沿触发输入捕获

11   TCCR1A = 0x00;

12   TCCR1B = 0x42;

13   TCCR1C = 0x00;

14   TIMSK1 |= (1 << ICIE1) | (1 << TOIE1);

15   sei();

16 }

17 

18 void loop() {

19   duration = timer1_pulse_in();

20 }

21 

22 volatile int iOvf = 0;

23 volatile bool isCap = false;

24 volatile uint16_t iCap = 0;

25 volatile uint16_t iLastCap = 0;

26 

27 unsigned long timer1_pulse_in() {

28   unsigned long duration;

29 

30   while (!isCap);

31   duration = 0xffff - iCap 

32       + 0xffff * (iOvf - 1) 

33       + iLastCap;

34 

35   isCap = false;

36   return duration;

37 }

38 

39 ISR(TIMER1_CAP_vect) {

40   iCap = iLastCap;

41   iLastCap = (ICR1H << 8) | ICR1L;

42   

43   isCap = true;

44 }

45 

46 ISR(TIMER1_OVF_vect) {

47   iOvf += 1;

48 }


事实上,本章仅仅讨论了定时/计数器子系统的典型应用,这仅仅是定时/计数器子系统强大功能的冰山一角,由于篇幅关系没有提及的部分,另请参阅ATMega328P芯片手册。 

推荐阅读

史海拾趣

Dexter Research Center Inc公司的发展小趣事

作为一家有社会责任感的企业,Dexter始终关注环境保护和可持续发展问题。公司积极采用环保材料和工艺,减少生产过程中的废弃物和污染物排放。同时,Dexter还积极参与社会公益事业,为当地社区和弱势群体提供帮助和支持。这些举措不仅有助于保护环境、推动社会进步,还提升了Dexter的企业形象和品牌价值。

Endicott Research Group Inc (ERG)公司的发展小趣事

面对日益激烈的市场竞争,ERG始终坚持技术研发和创新。他们与多所知名大学和科研机构建立合作关系,共同研发新型电源技术和照明解决方案。这些合作不仅为ERG带来了先进的技术和研发资源,还使其在行业中保持了技术领先地位。通过与科研机构的紧密合作,ERG不断推出更具创新性和竞争力的产品。

百蓉(ECE)公司的发展小趣事

随着全球对可持续发展的日益重视,百蓉公司也开始在这一领域进行探索。他们研发出了一系列节能环保的电子产品,如低功耗显示器、高效能电源管理器等。同时,公司还积极参与废旧电子产品的回收和再利用工作,致力于减少电子废物对环境的污染。这些举措不仅提升了百蓉公司的品牌形象,也为其赢得了更多的市场份额。

上述五个故事,客观描述了百蓉公司在电子行业的发展历程,展现了其在技术创新、市场拓展、智能制造和可持续发展等方面的努力和成果。

C&K Components公司的发展小趣事

到了90年代,随着电子产品的普及和技术的进步,开关市场的竞争愈发激烈。然而,C&K凭借多年的技术积累和市场经验,已经成为世界领先的开关制造商之一。公司不断推出创新产品,满足市场的多样化需求,同时加强与国际知名企业的合作,进一步巩固了其在行业内的领先地位。

EOS POWER INDIA Pvt公司的发展小趣事

EOS POWER INDIA Pvt公司成立于1991年,由美国加利福尼亚州几位电力电子领域的先驱创立。成立之初,EOS就致力于电力电子技术的研发与应用,特别是在电源解决方案方面。通过引进先进的技术和工艺,EOS在印度市场上逐步建立起自己的品牌形象,并开始为本地客户提供优质的电源产品和服务。

Concurrent Logic公司的发展小趣事

Concurrent Logic公司的创立源于一群工程师对并行计算和逻辑设计的热爱。在公司成立初期,他们面临着巨大的挑战。由于资金有限,他们不得不在狭小的办公室内开始他们的创新之旅。初创团队的成员们夜以继日地工作,开发并优化他们的第一个产品——一款高性能的并行处理芯片。尽管条件艰苦,但他们的努力和热情为公司的未来奠定了坚实的基础。

问答坊 | AI 解惑

被动电子元件

电子 初学者的 基础 基础决定高度…

查看全部问答>

串行接口10位单通道A_D转换TLC1549中文数据资

本帖最后由 paulhyde 于 2014-9-15 04:12 编辑 供大家 参考  …

查看全部问答>

降低噪声与干扰

降低噪声与干扰 1)  能用低速芯片就不用高速的,高速芯片用在关键地方。 (2)  可用串一个电阻的办法,降低控制电路上下沿跳变速率。 (3)  尽量为继电器等提供某种形式的阻尼。 (4)  使用满足系统要求的 ...…

查看全部问答>

如何实现485通信

pc机经232-〉485转换器,后和多台485设备双向通信,我写过232的,对于485不清楚。 请问: (1)这个应该是全双工方式还是半双工方式? (2)如果是半双工如何知道现在有没有485设备占用通信线路? (3)如果发送不成功怎么知道?怎么办?再 ...…

查看全部问答>

iap使用问题

使用str711的iap功能向 flash bank1 写入数据 但是每次 执行写入 或者 清除片内内容时,系统都会重启,请问为何?…

查看全部问答>

iar5.40.7连接stm32f10xx问题

                                 我这有一个stm32f10xx的开发板,但是使用IAR5.40.7的开发软件,可是编译通过了,可无论如很都写不进flash,也无法 ...…

查看全部问答>

我的EK-LM3S811-ND Rev2 无法download 和debug

按照LM3S811 TI Evaluation kit光盘资料中的LM3S811EVALUATION KIT README FIRST安装驱动,安装后和资料里显示是驱动名称不一样. 资料讲的是LM3S811 Virtual COM Port(com6).”而我安装后显示\"stellaris ICDI Debug port(COM15)\",\"\"stellaris IC ...…

查看全部问答>

高价求芯片、电路设计,高手QQ1342451273

高价求芯片、电路设计,高手QQ1342451273…

查看全部问答>

请教一下,在沈阳做电路板制作有市场吗?

  请教一下大家,我想在沈阳开一个制作电路板的小店,主要是针对零散小批量的客户,利用雕刻机做,不知道有没有市场,需求量怎么样?有了解的朋友能不能给点建议。先谢谢大家了!…

查看全部问答>

【跟TI学电源】系列----- TI工程师编写的的WEBENCH设计教程资料,不会的童鞋有福了!

TI工程师编写的的WEBENCH设计教程资料,不会的童鞋有福了! 不知道怎么使用WEBENCH的同学可以下载看看,很详细的中文教程.本文档图文并茂,一步一步带你畅游WEBENCH设计,,, 这些日子,eeworld论坛的【三重礼】活动,正在如火如荼的进行,正确使 ...…

查看全部问答>