Arduino开发平台最初于2005年开发,是一种用于艺术设计项目的易于使用的可编程设备。它的目的是帮助非工程师在没有太多编程知识的情况下使用基本的电子设备和微控制器。但是,由于它易于使用的特性,很快就被世界各地的电子初学者和业余爱好者所采用,如今,它甚至更适合原型开发和POC开发。
虽然可以从Arduino开始,但重要的是慢慢进入AVR,ARM,PIC,STM等核心微控制器并使用其本机应用程序对其进行编程。这是因为Arduino编程语言非常易于理解,因为大多数工作都是通过诸如digitalWrite(),AnalogWrite(),Delay()等预建函数完成的,而底层的机器语言则隐藏在它们后面。Arduino程序与其他嵌入式C编码不同,我们在其中处理寄存器位,并根据程序的逻辑将其设置为高或低。
Arduino计时器无延迟:
因此,要了解预构建函数内部发生的情况,我们需要深入了解这些术语。例如,当使用delay()函数时,它将实际设置ATmega微控制器的定时器和计数器寄存器位。
在此arduino计时器教程中,我们将避免使用delay()函数,而是实际处理寄存器本身。好消息是您可以为此使用相同的Arduino IDE。我们将设置定时器寄存器位,并在每次发生中断时使用定时器溢出中断来切换LED。还可以使用按钮来调节定时器位的预加载器值,以控制中断发生的持续时间。
嵌入式电子中的TIMER是什么?
计时器是一种中断。它就像一个简单的时钟,可以测量事件的时间间隔。每个微控制器都有一个时钟(振荡器),例如在Arduino Uno中为16Mhz。这是速度的原因。时钟频率越高,处理速度就越高。计时器使用计数器,该计数器根据时钟频率以一定速度进行计数。在Arduino Uno中,进行一次计数需要1/16000000秒或62nano秒。这意味着Arduino每62纳秒从一条指令移动到另一条指令。
Arduino UNO中的计时器:
在Arduino UNO中,有三个用于不同功能的计时器。
定时器0:
它是一个8位计时器,用于计时器功能(如delay(),millis())。
计时器1:
它是一个16位定时器,在伺服库中使用。
计时器2:
它是一个8位定时器,用于tone()函数。
Arduino定时器寄存器
要更改计时器的配置,请使用计时器寄存器。
1.定时器/计数器控制寄存器(TCCRnA / B):
该寄存器保存定时器的主要控制位,并用于控制定时器的预分频器。它还允许使用WGM位控制定时器的模式。
帧格式:
TCCR1A | 7 | 6 | 5 | 4 | 3 | 2 | 1个 | 0 |
COM1A1 | COM1A0 | COM1B1 | COM1B0 | COM1C1 | COM1C0 | WGM11 | WGM10 |
TCCR1B | 7 | 6 | 5 | 4 | 3 | 2 | 1个 | 0 |
ICNC1 | ICES1 | -- | WGM13 | WGM12 | CS12 | CS11 | CS10 |
预分频器:
TCCR1B中的CS12,CS11,CS10位设置预分频器值。预分频器用于设置计时器的时钟速度。Arduino Uno的预分频器为1,8,64,256,1024。
CS12 | CS11 | CS10 | 采用 |
0 | 0 | 0 | 无时钟定时器停止 |
0 | 0 | 1个 | CLCK i / o / 1无预分频 |
0 | 1个 | 0 | CLK I / O / 8(来自预分频器) |
0 | 1个 | 1个 | CLK I / O / 64(来自预分频器) |
1个 | 0 | 0 | CLK I / O / 256(来自预分频器) |
1个 | 0 | 1个 | CLK I / O / 1024(来自预分频器) |
1个 | 1个 | 0 | T1引脚上的外部时钟源。时钟在下降沿 |
1个 | 1个 | 1个 | T1引脚上的外部时钟源。时钟在上升沿。 |
2.定时器/计数器寄存器(TCNTn)
该寄存器用于控制计数器值和设置预加载器值。
所需时间(以秒为单位)的预加载器值的公式:
TCNTn = 65535 –(16x10 10 xTime以秒为单位/预分频器值)
要为timer1计算2秒的时间的预加载器值:
TCNT1 = 65535 –(16x10 10 x2 / 1024)= 34285
Arduino定时器中断
我们之前了解了Arduino中断,并且已经看到Timer中断是一种软件中断。Arduino中有各种定时器中断,下面将进行解释。定时器溢出中断:
每当计时器达到最大值时,例如(16位-65535),就会发生 计时器溢出中断 。因此,当定时器中断屏蔽寄存器TIMSKx中的TOIEx中的定时器溢出中断位被使能时,将调用ISR中断服务程序。
ISR格式:
ISR(TIMERx_OVF_vect) { }
输出比较寄存器(OCRnA / B):
此处,当发生输出比较匹配中断时,将调用中断服务ISR(TIMERx_COMPy_vect),并且TIFRx寄存器中的OCFxy标志位将被置1。通过设置TIMSKx寄存器中OCIExy中的使能位来使能该ISR。其中TIMSKx是定时器中断屏蔽寄存器。
定时器输入捕捉:
接下来,当发生定时器输入捕捉中断时,将调用中断服务ISR(TIMERx_CAPT_vect),并且还将在TIFRx(定时器中断标志寄存器)中将ICFx标志位置1。通过设置TIMSKx寄存器中ICIEx中的使能位来使能该ISR。
所需组件
- Arduino UNO
- 按钮(2)
- LED(任何颜色)
- 10k电阻器(2),2.2k(1)
- 16x2 LCD显示屏
电路原理图
Arduino UNO和16x2 LCD显示器之间的电路连接:
16x2 LCD |
Arduino UNO |
VSS |
地线 |
VDD |
+5伏 |
V0 |
电位器中心引脚,用于LCD对比度控制 |
RS |
8 |
读写器 |
地线 |
Ë |
9 |
D4 |
10 |
D5 |
11 |
D6 |
12 |
D7 |
13 |
一种 |
+5伏 |
ķ |
地线 |
两个具有10K下拉电阻的按钮与Arduino引脚2和4连接,并且LED通过2.2K电阻与Arduino的PIN 7连接。
设置如下图所示。
编程Arduino UNO计时器
在本教程中,我们将使用“定时器溢出中断”,并使用它通过使用按钮来调整预加载器值(TCNT1),使LED在一定时间内闪烁。最后给出了Arduino Timer的完整代码。这里我们逐行解释代码:
由于项目中使用16x2 LCD来显示预加载器的值,因此使用液晶库。
#包括
与Arduino引脚7连接的LED阳极引脚定义为 ledPin 。
#define ledPin 7
接下来,使用与Arduino UNO连接的LCD引脚(RS,E,D4,D5,D6,D7)声明用于访问液晶类的对象。
液晶液晶(8,9,10,11,12,13);
然后将预加载器值3035设置4秒钟。检查上面的公式以计算预加载器值。
浮点值= 3035;
接下来在 void setup()中, 首先将LCD设置为16x2模式,并显示欢迎消息几秒钟。
lcd.begin(16,2); lcd.setCursor(0,0); lcd.print(“ ARDUINO TIMERS”); delay(2000); lcd.clear();
接下来将LED引脚设置为OUTPUT引脚,将按钮设置为INPUT引脚
pinMode(ledPin,输出); pinMode(2,INPUT); pinMode(4,输入);
接下来禁用所有中断:
noInterrupts();
接下来,初始化Timer1。
TCCR1A = 0; TCCR1B = 0;
设置预加载器计时器值(最初为3035)。
TCNT1 =值;
然后在TCCR1B寄存器中设置预分频器值1024。
TCCR1B-=(1 << CS10)-(1 << CS12);
在定时器中断屏蔽寄存器中使能了定时器溢出中断,因此可以使用ISR。
TIMSK1-=(1 << TOIE1);
最后,所有中断均被启用。
interrupts();
现在编写用于定时器溢出中断的ISR,它负责使用 digitalWrite来 打开和关闭LED 。每当定时器溢出中断发生时,状态都会改变。
ISR(TIMER1_OVF_vect) { TCNT1 =值; digitalWrite(ledPin,digitalRead(ledPin)^ 1); }
在 void loop()中 ,通过使用按钮输入来增加或减少预加载器的值,并且该值也会显示在16x2 LCD上。
if(digitalRead(2)== HIGH) { 值=值+10; //预加载值 } if(digitalRead(4)== HIGH) { value = value-10; //递减预加载值 } lcd.setCursor(0,0); lcd.print(value); }
所以这就是计时器可以用来在Arduino程序中产生延迟的方式。查看下面的视频,其中我们已通过使用按钮增加和减小预载器值来演示了延迟的变化。