Arduino定时计数器 0、1、2的灵活使用
来源:互联网 发布:b1ued同志交友软件 编辑:程序博客网 时间:2024/06/16 05:40
Arduino定时计数器 0、1、2的灵活使用
本人刚接触Arduino不久,由于ArduinoIDE封装太多,相信不少初学者对Arduino定时计数器的概念和使用比较模糊,比如定时器0的用法。下面我就结合AVR GCC介绍一下如何在Arduino中灵活使用这三个定时计数器。
就最经典的UNO板而言,它的控制芯片是atmega328,它有0、1、2三个定时计数器,除了定时中断,它们还可以控制引脚pwm输出,通过查询芯片手册和引脚分布可知这三个定时器分别控制的引脚。
T/C0: Pin6(OC0A)和Pin5(OC0B)
T/C1: Pin9(OC1A)和Pin10(OC1B)
T/C3: Pin11(OC2A)和Pin3(OC2B)
但是实际上Arduino已经将T/C0的溢出中断运用到了delay()、delayMicroseconds、millis()、micros()中,这些函数都写在了Arduino核心代码wiring.c文件中,请参考:http://wiki.geek-workshop.com/doku.php?id=arduino:cores:wiring.c,或者直接在arduino-1.0.5-r2\hardware\arduino\cores\arduino文件夹中找到这个C文件。
假如有个问题摆在你面前:你的项目需要用一个UNO控制4个直流电机始终运转,但同时又要定时接收外来信号,那么必然需要全部用上这三个定时器,其中两个用来输出4路PWM波,另一个定时器用来定时中断。那问题来了,T/C0已经用在了像delay()这些可恶的不可与程序并行的函数中,并且wiring.c中已经声明了T/C0的溢出中断函数ISR(TIMER0_OVF_vect),也就是说我们在主程序中将不能再写一个ISR(TIMER0_OVF_vect)用来写定时接受外来信号的中断程序,那怎么办呢?
最大胆的方法就是直接改那些老外写的库函数,没错,直接修改wiring.c。这个时候你就需要仔细阅读一下wiring.c的代码了,其实也不难,里面有一个T0的溢出中断函数,然后是delay()、millis()之类的函数,这些函数都利用了T0的溢出中断,然后就是init()函数,这个函数是Arduino编译器首先编译的程序,在setup()之前首先编译的就是它,里面写的大多都是timer0、1、2或者3、4、5寄存器的初始化,学过AVR GCC的伙伴们应该可以看懂吧,实际上就是配置预分频和工作模式,比如快速PWM啦,相位修正PWM啦,(其实我也不怎么懂定时器工作原理啥的,才接触Arduino三周)。
好吧,为了达到我们使用T0去定时中断的目的,我们开始修改吧!为了可以调用T0的溢出中断,直接把ISR(TIM0_OVF_vect)那段程序注释掉,后面的millis()等函数可以不用注释掉,但是这些函数已经没有用了,你一定会觉得可惜,但是我觉得一点也不可惜,你可以有别的简单方法创造它们。
当我做完上述这些后,我写了一个T/C0的定时1秒溢出中断,结合AVR GCC的编程语法编写的测试程序,成功!串口调试助手每隔1秒输出1,程序代码如下:
// timer0_ov_interrupt.ino
//用Timer0定时中断,每隔1s输出1。
int count = 0;
void setup()
{
Serial.begin(9600);
init_time();
}
void loop( void )
{
while(1);
}
void init_time() //配置寄存器,普通模式,64分频,定时器初值为6
{
TCCR0A=0;
TCCR0B=_BV(CS01)|_BV(CS00);
TIMSK0=_BV(TOIE0);
TCNT0=6;
sei();
}
ISR(TIMER0_OVF_vect) //T0溢出中断函数
{
TCNT0=6;
++count;
if(count == 1000 )
{
Serial.write(1);
count=0;
}
}
但是尼玛当我用同样的语法测试了一下T/C2,发现始终不输出1,我也始终没有找到原因,一怒之下,我把init()函数中#if defined(ADCSRA)(这个有关ADC,不敢注释!)语句之前的所有关于定时器寄存器配置的语句都注释了。再次测试了一下T/C2,成功了!T/C1测试也同样成功了!当然测试成功还取决于我在主程序中寄存器的准确配置,这个就得多看看芯片手册了。
如此一来,三个定时器都解放了,我可以任意操作他们,我可以改变pwm的频率,而不是是使用analogwrite()函数输出一个品质很差的pwm波了。
有人会问那些delay()、delayMicroseconds函数不能用了怎么办?我之所以讨厌这写函数是因为它们不但不能与程序并行,而且还浪费了T0这个定时器,所以直接采用软件延时来代替上面的delay()函数,学过单片机的孩纸都懂的。可以参考我的另一个帖子:http://www.arduino.cn/thread-16784-1-1.html
- Arduino定时计数器 0、1、2的灵活使用
- 【51单片机学习过程记录】9 中断之定时计数器0的使用2
- 三菱PlC计数器与定时的使用
- 80C52、AT89C52的定时/计数器2
- 单片机的定时/计数器
- arduino的定时中断
- STM8 定时计数器2
- Arduino 中使用定时中断
- Arduino 中使用定时中断
- Arduino 中使用定时中断
- 【51单片机学习过程记录】8 中断 之定时计数器0的使用
- MSP430定时/计数器TimerA的使用详解(一)
- 51单片机的定时/计数器
- MCS-51的定时/计数器
- 定时/计数器的verilog代码
- 52单片机中定时/计数器2的研究
- 52单片机中定时/计数器2的研究 .
- 定时器/计数器的定时或计数范围
- Scala开发环境的搭建和HelloWorld
- Android WebView中软键盘会遮挡输入框相关问题
- 基本数据类型与字符串的转换
- Zookeeper注册中心解析
- java中的单例设计模式简谈
- Arduino定时计数器 0、1、2的灵活使用
- 浅析为什么 char 类型的范围是 : -128~+127
- [Leetcode 154, Hard] Find Minimum in Rotated Sorted Array II
- best fit line
- 重写= 覆盖 = override
- 字符串重组,字符串的插入,替换,删除,拼接
- HDU 2298 Toxophily(公式/三分+二分)
- 关于PCAP包的一点小结
- ARC机制之__weak,__autorelease详解