首页 > 编程知识 正文

arduino添加esp8266,esp8266能做什么

时间:2023-05-04 09:39:35 阅读:112191 作者:1427

本文的目的是说明如何使用Arduino内核在ESP32上配置计时器中断。

测试在DFRobot的ESP-WROOM-32设备上进行,该设备集成在ESP32 FireBeetle板上。

引言

本文介绍了主要使用Arduino内核的ESP32

本教程介绍如何设置计时器以使其定期发生中断,以及如何处理中断。

外部中断教程: ESP32 Arduino教程:在外部中断中已经看到了使用这种计数器。 ISR必须尽快运行,因此不要执行太长的操作,例如向串行端口写入数据。 因此,在实现中断处理代码时,最好只让ISR响应中断,而实际处理(可能包括耗时的操作)则交给主循环。

[mw_shl_code=applescript,true ] (port mux _ typetimermux=port mux _ initializer _ unlocked; [/mw_shl_code]

设定函数

在函数设置中,必须首先打开串行连接,然后将程序结果输出到Arduino IDE串行监视器。

[mw_shl_code=applescript,true]

Serial.Begin(115200; [/mw_shl_code]

然后,调用timerBegin函数初始化计时器。 此函数返回指向hw_timer_t结构类型的指针,该结构类型是上一节中声明的计时器全局变量之一。

这个函数有三个输入参数。 分别是指示要使用的计时器编号(0到3,支持所有四个硬件计时器)、预缩放器值和计数器向上(真)或向下(down )计数的标志。

此示例使用第一个计时器并将最后一个参数设置为真。 这表示计数器将递增计数。

关于预分频器,如引言部分所述,ESP32计数器使用的基频信号通常为80 MHz。 此数量为80,000,000 Hz,这意味着基频信号将使计时器计数器每秒递增80,000,000次。

可以根据该值进行计算,设定计数器值来产生中断,但使用预分频器来简化设定。 将该数值除以80,即使用80作为预分频器的数值,可以得到1 MHz的频率。 也就是说,计时器计数器每秒钟增加1,000,000次。

如果将上述数字取反,则可以看到计数器每微秒递增一次。 因此,如果预分频器的值为80,则在调用函数并设置计数器值以产生中断时,指定的值以微秒为单位。

[mw_shl_code=applescript,true ] timer=timer begin (0,80,true ); [/mw_shl_code]

但是,在启用计时器之前,必须绑定到处理函数以响应出现的中断。 可以通过调用timerAttachInterrupt函数来执行此操作。

调用函数时,将计时器全局变量作为第一个输入参数,将名为onTimer的函数(如下所述)地址作为第二个参数,将第三个参数赋值为真),表示中断是边缘触发类型。

[mw_shl_code=applescript,true ] timerattachinterrupt (timer,onTimer,true ); [/mw_shl_code]

然后,使用timerAlarmWrite函数指定触发计时器中断的计数器值。 此函数的第一个参数是计时器指针,第二个参数是触发中断的计数器值,第三个参数是指示发生中断时计时器是否重新加载的标志。

因此,调用函数时,也会将计时器全局变量设置为第一个输入参数,将第三个参数设置为真,以指示计数器将自动重载。 这样会周期性地发生中断。

对于第二个参数,请不要忘记设置预分频器。 中断必须在几微秒后发生。 因此,在本例中,如果希望每秒发生一个中断,其值为1,000,000微秒(等于1秒)。

重要信息:请注意,只有将预分频器值设置为80时,此处指定的时间单位才为微秒。 如果使用其他预缩放器值,则必须重新计算计数值。

[mw_shl_code=applescript,true]timeralarmwrite(timer,1000000,true ); [/mw_shl_code]

在设置函数的最后,可以通过调用timerAlarmEnable函数来启用计时器。 调用函数时的输入参数是计时器变量。

[mw_shl_code=applescript,true]timeralarmenable(timer ); [/mw_shl_code]

设定函数的最终代码如下。

[mw_shl_code=applescript,true]void setup

Serial.Begin(115200;

时间=时间begin (0,80,true );

timerattachinterrupt(timer,onTimer,true );

timerAlarmWrite(timer, 1000000, true);

timerAlarmEnable(timer);

}[/mw_shl_code]

主循环

如前文所述,在ISR对中断做出响应之后,真正的定时器中断处理操作其实是在主循环中。为简单起见,我们仅通过轮询对中断计数器的数值进行检验。但是更有效的处理方式是,使用一个信号量将主循环锁定,然后在ISR中将其解锁。这也是原始示例中所使用的方法:https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/examples/Timer/RepeatTimer/RepeatTimer.ino 。

首先,我们会检查interruptCounter变量是不是大于零,如果大于零,那么就进入中断处理代码。在中断处理代码中,首先会递减计数器的数值,表示已经对中断进行了响应和处理。

由于该变量由主循环和ISR所共享,所以必须在portENTER_CRITICAL和portEXIT_CRITICAL宏指定的关键代码段内处理。两次函数调用所使用的输入参数都是portMUX_TYPE全局变量的地址。

[mw_shl_code=applescript,true]if (interruptCounter > 0) {

portENTER_CRITICAL(&timerMux);

interruptCounter--;

portEXIT_CRITICAL(&timerMux);

// Interrupt handling code

}[/mw_shl_code]

实际的中断处理操作只是对计数器(计数器数值表示自程序运行以来所发生的中断总数)进行递减,并将计数器值输出到串口。完整的主循环代码如下所示,其中已经包含了该函数调用。

[mw_shl_code=applescript,true]void loop() {

if (interruptCounter > 0) {

portENTER_CRITICAL(&timerMux);

interruptCounter--;

portEXIT_CRITICAL(&timerMux);

totalInterruptCounter++;

Serial.print("An interrupt as occurred. Total number: ");

Serial.println(totalInterruptCounter);

}

}[/mw_shl_code]

ISR代码

中断服务程序必须是一个返回void(空)且没有输入参数的函数。

本例中,中断服务程序非常简单,仅对中断计数器进行递增,以告知主循环发生了一次中断。代码位于portENTER_CRITICAL和portEXIT_CRITICAL宏指定的关键代码段内。两次函数调用所使用的输入参数都是先前声明的portMUX_TYPE全局变量的地址。

更新:为使编译器将代码分配到IRAM内,中断处理程序应该具有 IRAM_ATTR属性。而且,根据IDF文档的说明(参见此处),中断处理程序只能调用同样位于IRAM内的函数。感谢Manuato指出这一点。

该函数的完整代码如下所示。

[mw_shl_code=applescript,true]void IRAM_ATTR onTimer() {

portENTER_CRITICAL_ISR(&timerMux);

interruptCounter++;

portEXIT_CRITICAL_ISR(&timerMux);

}[/mw_shl_code]

最终代码

周期计数器中断程序的最终源代码如下所示。

[mw_shl_code=applescript,true]volatile int interruptCounter;

int totalInterruptCounter;

hw_timer_t * timer = NULL;

portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR onTimer() {

portENTER_CRITICAL_ISR(&timerMux);

interruptCounter++;

portEXIT_CRITICAL_ISR(&timerMux);

}

void setup() {

Serial.begin(115200);

timer = timerBegin(0, 80, true);

timerAttachInterrupt(timer, &onTimer, true);

timerAlarmWrite(timer, 1000000, true);

timerAlarmEnable(timer);

}

void loop() {

if (interruptCounter > 0) {

portENTER_CRITICAL(&timerMux);

interruptCounter--;

portEXIT_CRITICAL(&timerMux);

totalInterruptCounter++;

Serial.print("An interrupt as occurred. Total number: ");

Serial.println(totalInterruptCounter);

}

}[/mw_shl_code]

测试代码

将程序上传到您的ESP32开发板并打开Arduino IDE串口监测器,即可对代码进行测试。输出结果如图1所示,相关消息会周期性地显示出来(每秒显示一条消息)。

esp32-arduino-timer-interrupt.png (240.4 KB, 下载次数: 0)

2019-5-30 23:40 上传

图1 - 定时器中断程序的输出。

注:本文作者是Nuno Santos,他是一位和蔼可亲的电子和计算机工程师,住在葡萄牙里斯本 (Lisbon)。

他写了200多篇有关ESP32、ESP8266的有用的教程和项目。

查看更多ESP32/ESP8266教程和项目,请点击 : ESP32教程汇总贴

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。