一、软件定时器:
1.软件定时器:
是用程序模拟出来的定时器,它的特点是不会受到我们硬件资源不足的限制,在你的 CPU 和内存足够的情况下可以设置成百上千个软件定时器,但是它的缺点就是做不到特 别的准确,因为他是软件模拟的,当我们的 CPU
被别的事情抢占,如中断发生 等,会导致定时时间的不稳定性,因此不能使用在我们对时间要求特别严格的场合。
2.要用到的函数:
1.关闭软件定时器:
void os_timer_disarm (os_timer_t *ptimer)
//ptimer 为 os_timer_t 类型结构体,需要我们提前定义
2.注册定时器回调函数:
void os_timer_setfn(os_timer_t *ptimer,os_timer_func_t *pfunction,void *parg)
//os_timer_t *ptimer:定时器结构体
//os_timer_func_t *pfunction:定时回调函数
//void *parg:回调函数的参数
3.使能毫秒定时器:
void os_timer_arm(os_timer_t *ptimer, uint32_t milliseconds, bool repeat_flag)
//os_timer_t *ptimer:定时器结构体
//uint32_t milliseconds:定时时间,单位:ms
//如未调用 system_timer_reinit,可支持范围 5 ~ 0x68D7A3
//如调用了 system_timer_reinit,可支持范围 100 ~ 0x689D0
//bool repeat_flag:定时器是否重复 0:不重复定时器 1:重复定时
4.
当需要使用微秒定时器时需要重新初始化定时器:
void system_timer_reinit(void)
//注意 system_timer_reinit 需要在程序最开始调用, user_init 的第一句。
5.
使能微秒定时器(不建议使用):
void os_timer_arm_us (os_timer_t *ptimer, uint32_t microseconds, bool repeat_flag)
//os_timer_t *ptimer:定时器结构体
//uint32_t microseconds:定时时间,单位 us,最小 0x64,最大 0xFFFFFFF
//bool repeat_flag:是否重复定时,0:不重复定时,1:重复定时
3.程序的编写:
我们程序的功能是:每隔500ms打印"hello"
我们需要自己编写软件定时器的驱动文件os_timer.c和os_timer.h,然后将他们分别添加到app/driver和app/include/driver下,刷新工程。
1.os_timer.h:
#ifndef __OS_TIMER_H
#define __OS_TIMER_H
#include "ets_sys.h"
#include "osapi.h" //系统函数
#include "user_interface.h"
void OS_Timer_1_Cb(void);
void OS_Timer_Init(uint32_t ms,bool repeat_flag);
#endif /* OS_TIMER_H */
2.os_timer.c:
#include "./driver/os_timer.h"
os_timer_t os_timer_1;//定义软件定时器结构体变量
//软件定时器回调函数
void OS_Timer_1_Cb(void)
{
os_printf("hello\n");
}
//软件定时器配置初始化
void OS_Timer_Init(uint32_t ms,bool repeat_flag)
{
os_timer_disarm(&os_timer_1);//关闭软件定时器
os_timer_setfn(&os_timer_1,(os_timer_func_t*)OS_Timer_1_Cb,NULL);//注册软件定时器回调函数
os_timer_arm(&os_timer_1,ms,repeat_flag);//打开软件定时器,设置定时周期,设置是否自动重装
}
3.user_main.c:
#include "ets_sys.h"
#include "user_config.h"//用户配置
#include "eagle_soc.h"//GPIO函数,宏定义
#include "c_types.h" //变量类型
#include "osapi.h" //系统函数
#include "user_interface.h"
#include "./driver/os_timer.h"//软件定时器
/******************************************************************************
* FunctionName : user_rf_cal_sector_set
* Description : SDK just reversed 4 sectors, used for rf init data and paramters.
* We add this function to force users to set rf cal sector, since
* we don't know which sector is free in user's application.
* sector map for last several sectors : ABCCC
* A : rf cal
* B : rf init data
* C : sdk parameters
* Parameters : none
* Returns : rf cal sector
*******************************************************************************/
uint32 ICACHE_FLASH_ATTR
user_rf_cal_sector_set(void)
{
enum flash_size_map size_map = system_get_flash_size_map();
uint32 rf_cal_sec = 0;
switch (size_map) {
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec = 128 - 5;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec = 256 - 5;
break;
case FLASH_SIZE_16M_MAP_512_512:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_32M_MAP_512_512:
rf_cal_sec = 1024 - 5;
break;
case FLASH_SIZE_32M_MAP_1024_1024:
rf_cal_sec = 1024 - 5;
break;
case FLASH_SIZE_64M_MAP_1024_1024:
rf_cal_sec = 2048 - 5;
break;
case FLASH_SIZE_128M_MAP_1024_1024:
rf_cal_sec = 4096 - 5;
break;
default:
rf_cal_sec = 0;
break;
}
return rf_cal_sec;
}
void ICACHE_FLASH_ATTR
user_rf_pre_init(void)
{
}
//毫秒延时函数
void ICACHE_FLASH_ATTR
delay_ms(u32 ms)
{
for(;ms>0;ms--){
os_delay_us(1000);//1ms
}
}
/******************************************************************************
* FunctionName : user_init
* Description : entry of user application, init user function here
* Parameters : none
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
uart_init(9600,9600);
os_printf("\r\nESP8266软件定时器\r\n");
OS_Timer_Init(500,1);//500ms,重装载
}
4.运行结果:
二、硬件定时器 :
1.硬件定时器:
全名为硬件中断定时器,它不像软件定时器由程序模拟实现,而是由我们的 ESP8266
上的硬件模块实现,也是就说在厂家设计
ESP8266
这一款芯片的时候就已经将我们的硬件定时器设计到芯片内部了,同时,我们的硬件定时器由中断触发,保证了定时器的准确性。
2.使用时的注意事项:
1.我们的硬件定时器中断使用的是哪种中断源?如果我们使用的是 NMI
中断源,那么我们的硬件定时器将为最高优先级,可打断其他中断;如果我们使用的是 FRC1 中断源,那么该定时器将无打断其他中断。
2.
如果我们的硬件定时器使用
NMI
中断源,且设置为自动重装载,也就是 重复定时,那么我们在使能硬件定时器的时候设置的定时时间必须大于100(也就是
hw_timer_arm()
函数的参数必须大于
100
)。
3.
我们的硬件定时器不可以和
PWM
驱动同时使用,因为二者使用的是同一个硬件定时器。
4.为 了 保 证 中 断 服 务 函 数 快 速 响 应 , 中 断 服 务 函 数 不 要 ICACHE_FLASH_ATTR 宏修饰。
5.使用硬件定时器时,请勿调用 wifi_set_sleep_type(LIGHT_SLEEP);开启自动睡眠模式,因为在睡眠期间 CPU 会停止运行,将导致不能响应 NMI中断。
3.要用到的函数:
1.初始化硬件定时器:
void hw_timer_init (FRC1_TIMER_SOURCE_TYPE source_type,u8 req)
//FRC1_TIMER_SOURCE_TYPE source_type:中断源设置。
//0:FRC1_SOURCE:使用 FRC1 中断源;
//1:NMI_SOURCE:使用 NMI 中断源。
//u8 req:设置是否重装载。
//0:不自动重装载;
//1:自动重装载。
2.注册定时器中断服务函数:
void hw_timer_set_func(void(* user_hw_timer_cb_set)(void))
//void (* user_hw_timer_cb_set)(void):定时器回调函数(中断服务函数)
3.使能硬件中断定时器:
void hw_timer_arm(uint32 val)
//uint32_t val:定时时间
/*
注意:在自动重装载模式,如果是 NMI 中断源,取值范围:
100-0x199999μs(100us - 1,677,721us)如果是 FRC1中断源,
取值范围:50-0x199999μs(50us-1,677,721us)。在非自动重装载模式,
取值范围:10 - 0x199999μs
*/
4.程序的编写:
程序的功能:每隔500ms打印"hello HWTimer"
将driver_lib/driver中的
hw_timer.c
添加到
app/driver
下,我们需要使用这里的函数创建自己的硬件驱动
hw_timer_driver.c
和
hw_timer_driver.h
,然后将他们分别添加到
app/driver 和
app/include/driver下,刷新工程。
1.hw_timer_driver.h:
#ifndef __HW_TIMER_DRIVER_H
#define __HW_TIMER_DRIVER_H
#include "ets_sys.h"
#include "osapi.h" //系统函数
#include "user_interface.h"
void HW_Timer_Interrupt(void);
void HW_Timer_Init(uint32_t us);
#endif
2.hw_timer_driver.c:
#include "./driver/hw_timer_driver.h"
//硬件定时器中断服务函数
void HW_Timer_Interrupt(void)
{
os_printf("hello HWTimer\n");
}
//硬件定时器初始化配置函数
void HW_Timer_Init(uint32_t us)
{
if(us<100 || us>1677721)
{
os_printf("us<100 || us>1677721\n");
}
hw_timer_init(1,1);//硬件定时器初始化,使用NMI中断源,重复定时
hw_timer_set_func(HW_Timer_Interrupt);//注册硬件定时器中断服务函数
hw_timer_arm(us);//使能中断定时器并设置定时时间
os_printf("HW_Timer OK !\n");
}
3.user_main.c:
#include "ets_sys.h"
#include "user_config.h"//用户配置
#include "eagle_soc.h"//GPIO函数,宏定义
#include "c_types.h" //变量类型
#include "osapi.h" //系统函数
#include "user_interface.h"
#include "./driver/hw_timer_driver.h"
/******************************************************************************
* FunctionName : user_rf_cal_sector_set
* Description : SDK just reversed 4 sectors, used for rf init data and paramters.
* We add this function to force users to set rf cal sector, since
* we don't know which sector is free in user's application.
* sector map for last several sectors : ABCCC
* A : rf cal
* B : rf init data
* C : sdk parameters
* Parameters : none
* Returns : rf cal sector
*******************************************************************************/
uint32 ICACHE_FLASH_ATTR
user_rf_cal_sector_set(void)
{
enum flash_size_map size_map = system_get_flash_size_map();
uint32 rf_cal_sec = 0;
switch (size_map) {
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec = 128 - 5;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec = 256 - 5;
break;
case FLASH_SIZE_16M_MAP_512_512:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_32M_MAP_512_512:
rf_cal_sec = 1024 - 5;
break;
case FLASH_SIZE_32M_MAP_1024_1024:
rf_cal_sec = 1024 - 5;
break;
case FLASH_SIZE_64M_MAP_1024_1024:
rf_cal_sec = 2048 - 5;
break;
case FLASH_SIZE_128M_MAP_1024_1024:
rf_cal_sec = 4096 - 5;
break;
default:
rf_cal_sec = 0;
break;
}
return rf_cal_sec;
}
void ICACHE_FLASH_ATTR
user_rf_pre_init(void)
{
}
//毫秒延时函数
void ICACHE_FLASH_ATTR
delay_ms(u32 ms)
{
for(;ms>0;ms--){
os_delay_us(1000);//1ms
}
}
/******************************************************************************
* FunctionName : user_init
* Description : entry of user application, init user function here
* Parameters : none
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
uart_init(9600,9600);
os_printf("\r\nESP8266硬件定时器\r\n");
HW_Timer_Init(500000);//500ms
}
5.运行结果: