05_ESP8266 NONOS_SDK Timer
今天学习三点内容:
一是延时函数,
二是软件定时器,
三是硬件定时器。
软件定时器就是靠里面的任务延时实现的,这样的定时器其实延时不准确。
硬件定时器 就是硬件中断定时器,就像单片机,中断的准确。
一、使用os_delay_us 函数
1、os_delay_us函数分析:
功能: 延时函数。最大值 65535 μs
函数定义: void os_delay_us(uint16 us)
参数: uint16 us:延时时间
返回: 无
写一个毫秒延时函数(不能延时太久) // 这种延时不太精确
void ICACHE_FLASH_ATTR delay_ms(u32 ms_time) { for(;ms_time>0; ms_time--) { os_delay_us(10000); } }
主函数每隔1s打印一次
编译,下载固件,打开串口调试助手,看现象,每隔1s打印一次。
二、软件定时器
软件定时器由软件实现,定时器的函数在任务中被执行。因为任务可能被中断,或者被其他高优先级的任务延迟,因此软件定时器并不能保证定时器精确执行,如果需要精确的定时,建议用硬件定时器。
先看几个和软件定时器相关的函数:
步骤:
1、先添加头文件
2、定义全局变量
os_timer_t OS_Timer; //定义软件定时器(os_timer_t型结构体) u8 Led_Flag = 0; //LED的状态标志位
3、定义软件定时的回调函数
我们在回调函数中实现LED灯的闪烁,输出LED的状态和进入回调函数的提示。
void ICACHE_FLASH_ATTR OS_Timer_cb(void) { Led_Flag = !Led_Flag; //LED状态翻转
//设置gpio4的输出值,即LED的值 GPIO_OUTPUT_SET(GPIO_ID_PIN(4),Led_Flag);
os_printf("\r\nLED的状态为:%d\r\n",Led_Flag); os_printf("\r\n-------------进入回调函数-------------\r\n"); }
4、封装软件定时器初始化函数(ms毫秒)
我们将函数进行封装,以便在初始化的时候直接调用。
(1)首先要关闭定时器,参数是要关闭的定时器
(2)接着设置定时器:
第一个参数是:需要设置的定时器,
第二个参数是:回调函数(需要要类型转换)
第三个参数是:回调函数的参数
注意:os_timer_setfn必须在软件定时器未使能的情况下调用
(3)使能毫秒定时器:
第一个参数是:要使能的定时器,
第二个参数是:定时时间(单位:ms)
第三个参数是:定时器是否重复。1=重复/0=只一次
void ICACHE_FLASH_ATTR OS_Timer_Init(u32 time_ms,bool repeat_flag) { //关闭定时器 os_timer_disarm(&OS_Timer); //设置定时器回调函数 os_timer_setfn(&OS_Timer, (os_timer_func_t *)OS_Timer_cb,NULL); //os_timer_setfn(&OS_Timer, (ETSTimerFunc *)OS_Timer_cb,NULL); //使能毫秒级定时器: //OS_Timer:要使能的定时器; //time_ms:定时时间(单位:ms); //repeat_flag:1=重复/0=只一次 os_timer_arm(&OS_Timer, time_ms, repeat_flag); //设置定时器参数并使能定时器 //【如未调用system_timer_reinit,可支持范围:[5ms ~ 6,870,947ms]】 //【如果调用system_timer_reinit,可支持范围:[100ms ~ 428,496 ms]】 }
5、GPIO初始化函数
void ICACHE_FLASH_ATTR gpio_Init(void) { //将GPIO4设置为IO口 PIN_FUNC_SELECT( PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4); //将管脚设为输出模式,并输出高电平 GPIO_OUTPUT_SET(GPIO_ID_PIN(4),1); }
6、主函数
void ICACHE_FLASH_ATTR user_init(void) { uart_init(9600,9600); //初始化串口波特率 os_delay_us(10000);//等待串口稳定 gpio_Init(); os_printf("\r\n----------------------------------------\r\n");
//定时1秒,重复 OS_Timer_Init(1000,1); //隔一秒进入回调函数 //OS_Timer_Init(1000,TRUE);
os_printf("\t SDK version:\t%s", system_get_sdk_version()); os_printf("\r\n----------------------------------------\r\n"); }
效果如下:
扩展:
上面说的是回调函数不带参数的,那么在设置回调函数的时候,需要(os_timer_func_t *)(回调函数名),进行强制转换。
那如果带参数呢?就需要在定义回调函数的时候,带一个参数xxx。如下:
//1.定义定时器用的回调函数(有参数) void os_timer_parg(void *parg) { os_printf("parg:%s\n", parg);//打印传过来的参数
Led_Flag = !Led_Flag; //LED状态翻转
// 设置gpio4的输出值,即LED的值 GPIO_OUTPUT_SET(GPIO_ID_PIN(4),Led_Flag); }
注意:void *XXX 意思是可以接收任意的指针变量
// 2.设置定时器回调函数(带参数Frank1995) os_timer_setfn(&OS_Timer,os_timer_parg,"Frank1995");
效果如下:
三、硬件定时器
看相关的三个函数:
步骤:
1、添加文件:
需要添加hw_timer.c 文件到app/driver 目录下
2、硬件定时器回调函数
//硬件定时器回调函数
//1.回调函数前不能添加 ICACHE_FLASH_ATTR 宏定义,中断响应不能存放在 Flash 中。
void HwTimer_cb(void) { Led_Flag = !Led_Flag; //LED状态翻转 //设置gpio4的输出值,即LED的值 GPIO_OUTPUT_SET(GPIO_ID_PIN(4),Led_Flag);
os_printf("\r\nLED的状态为:%d\r\n",Led_Flag); os_printf("\r\n--------进入硬件回调函数-----------\r\n"); }
3、封装硬件定时器初始化函数
void ICACHE_FLASH_ATTR Hw_Timer_Init(void) { /* 2.初始化硬件定时器 * 【参数1:中断源】 NMI_SOURCE=1 FRC1_SOURCE = 0 * 【参数2:是否重复】 1 自动填装 0 不自动填装 */
hw_timer_init(0, 1); //3.注册硬件定时器中断回调函数 hw_timer_set_func(HwTimer_cb); //4.使能硬件中断定时器 (单位us,参数必须<=1,677,721) hw_timer_arm(1000000); //由于使用的是FRC1 中断源 FRC1_SOURCE,取值范围: 50 ~ 0x199999 μs; }
4、主函数中调用
效果如下: