ESP8266学习三
软件定时器
软件定时器不一定看可以成功得执行 在CPU长期占用得情况下软件定时器不会执行;
毫秒级别定时
os_timer_t OS_TIMER_1; //定义定时器结构 必须要全局变量
//不要写成os_timer_t *OS_TIMER_1;
// 定时器中断回调函数
void Timer_INTERRUPT()
{
flag = !flag;
GPIO_OUTPUT_SET(GPIO_ID_PIN(4),flag);
}
/* 初始化软件定时器
*delay_ms 为延长多长时间
*repeat_flag 为是否需要重复定时中断 1 需要 0只执行一次
*/
void ICACHE_FLASH_ATTR
OS_TIMER_Init(uint32_t delay_ms,bool repeat_flag)
{
//取消定时器定时
os_timer_disarm (&OS_TIMER_1);
//设置定时器回调函数
os_timer_setfn(&OS_TIMER_1,(os_timer_func_t *)Timer_INTERRUPT,NULL);
//启动定时器
os_timer_arm(&OS_TIMER_1,delay_ms,repeat_flag);
//- 如未调⽤ system_timer_reinit,可⽀持范围 5 ~ 0x68D7A3
//- 如调⽤了 system_timer_reinit,可⽀持范围 100 ~ 0x689D0
}
void ICACHE_FLASH_ATTR
user_init(void)
{
uart_init(9600,115200);
os_printf("------------------------------------\r\n");
uart0_sendStr("串口开始打印13\r\n");
uart0_sendStr("------------------------------------\r\n");
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4); // 选择引脚4
GPIO_OUTPUT_SET(GPIO_ID_PIN(4),0); //IO4 = 0
OS_TIMER_Init(500,1);
}
注意
如果要使用system_timer_reinit()函数 必须要先定义USE_US_TIMER
(#define USE_US_TIMER) 而system_timer_reinit()函数 必须在程序最开始调⽤,user_init 的第⼀句。
硬件定时
需要提前将hw_timer.c得文件提前包含到app/driver中
注意:
- • 如果使⽤ NMI 中断源,且为⾃动填装的定时器,调⽤ hw_timer_arm 时参数 val 必须⼤于 100。
- • 如果使⽤ NMI 中断源,那么该定时器将为最⾼优先级,可打断其他 ISR。
- • 如果使⽤ FRC1 中断源,那么该定时器⽆法打断其他 ISR。
- • hw_timer.c 的接⼝不能跟 PWM 驱动接⼝函数同时使⽤,因为⼆者共⽤了同⼀个硬件定时器。
- • 硬件中断定时器的回调函数定义,请勿添加 ICACHE_FLASH_ATTR 宏。
- • 使⽤ hw_timer.c 的接⼝,请勿调⽤ wifi_set_sleep_type(LIGHT_SLEEP);
将⾃动睡眠模式设置为 Light-sleep。因为 Light-sleep 在睡眠期间会停 CPU,停 CPU 期间不能响应 NMI
中断。
// 定时器中断回调函数 不需要写 ICACHE_FLASH_ATTR
void HWTimer_INTERRUPT()
{
flag = !flag;
GPIO_OUTPUT_SET(GPIO_ID_PIN(4),flag);
}
//初始化硬件定时器
void ICACHE_FLASH_ATTR
HW_Timer_Init(uint32_t delay_ms,bool repeat_flag)
{
//初始化硬件定时器
hw_timer_init(0,repeat_flag);//使⽤ FRC1 中断源 repeat_flag是否自动重装
//hw_timer_init(1,repeat_flag);//使⽤ NMI 中断源 repeat_flag是否自动重装
hw_timer_set_func(HWTimer_INTERRUPT); //设置定时器回调函数
hw_timer_arm(delay_ms); //使能硬件中断定时器
}
void ICACHE_FLASH_ATTR
user_init(void)
{
uart_init(9600,115200);
os_printf("------------------------------------\r\n");
uart0_sendStr("串口开始打印14\r\n");
uart0_sendStr("------------------------------------\r\n");
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4); // 选择引脚4
GPIO_OUTPUT_SET(GPIO_ID_PIN(4),0); //IO4 = 0
HW_Timer_Init(50000,1);
}
hw_timer.c 文件
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "ets_sys.h"
#include "os_type.h"
#include "osapi.h"
#define US_TO_RTC_TIMER_TICKS(t) \
((t) ? \
(((t) > 0x35A) ? \
(((t)>>2) * ((APB_CLK_FREQ>>4)/250000) + ((t)&0x3) * ((APB_CLK_FREQ>>4)/1000000)) : \
(((t) *(APB_CLK_FREQ>>4)) / 1000000)) : \
0)
#define FRC1_ENABLE_TIMER BIT7
#define FRC1_AUTO_LOAD BIT6
//TIMER PREDIVED MODE
typedef enum {
DIVDED_BY_1 = 0, //timer clock
DIVDED_BY_16 = 4, //divided by 16
DIVDED_BY_256 = 8, //divided by 256
} TIMER_PREDIVED_MODE;
typedef enum { //timer interrupt mode
TM_LEVEL_INT = 1, // level interrupt
TM_EDGE_INT = 0, //edge interrupt
} TIMER_INT_MODE;
typedef enum {
FRC1_SOURCE = 0,
NMI_SOURCE = 1,
} FRC1_TIMER_SOURCE_TYPE;
/******************************************************************************
* FunctionName : hw_timer_arm
* Description : set a trigger timer delay for this timer.
* Parameters : uint32 val :
in autoload mode
50 ~ 0x7fffff; for FRC1 source.
100 ~ 0x7fffff; for NMI source.
in non autoload mode:
10 ~ 0x7fffff;
* Returns : NONE
*******************************************************************************/
void hw_timer_arm(u32 val)
{
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, US_TO_RTC_TIMER_TICKS(val));
}
static void (* user_hw_timer_cb)(void) = NULL;
/******************************************************************************
* FunctionName : hw_timer_set_func
* Description : set the func, when trigger timer is up.
* Parameters : void (* user_hw_timer_cb_set)(void):
timer callback function,
* Returns : NONE
*******************************************************************************/
void hw_timer_set_func(void (* user_hw_timer_cb_set)(void))
{
user_hw_timer_cb = user_hw_timer_cb_set;
}
static void hw_timer_isr_cb(void *arg)
{
if (user_hw_timer_cb != NULL) {
(*(user_hw_timer_cb))();
}
}
static void hw_timer_nmi_cb(void)
{
if (user_hw_timer_cb != NULL) {
(*(user_hw_timer_cb))();
}
}
/******************************************************************************
* FunctionName : hw_timer_init
* Description : initilize the hardware isr timer
* Parameters :
FRC1_TIMER_SOURCE_TYPE source_type:
FRC1_SOURCE, timer use frc1 isr as isr source.
NMI_SOURCE, timer use nmi isr as isr source.
u8 req:
0, not autoload,
1, autoload mode,
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR hw_timer_init(FRC1_TIMER_SOURCE_TYPE source_type, u8 req)
{
if (req == 1) {
RTC_REG_WRITE(FRC1_CTRL_ADDRESS,
FRC1_AUTO_LOAD | DIVDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT);
} else {
RTC_REG_WRITE(FRC1_CTRL_ADDRESS,
DIVDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT);
}
if (source_type == NMI_SOURCE) {
ETS_FRC_TIMER1_NMI_INTR_ATTACH(hw_timer_nmi_cb);
} else {
ETS_FRC_TIMER1_INTR_ATTACH(hw_timer_isr_cb, NULL);
}
TM1_EDGE_INT_ENABLE();
ETS_FRC1_INTR_ENABLE();
}
//-------------------------------Test Code Below--------------------------------------
#if 0
void hw_test_timer_cb(void)
{
static uint16 j = 0;
j++;
if ((WDEV_NOW() - tick_now2) >= 1000000) {
static u32 idx = 1;
tick_now2 = WDEV_NOW();
os_printf("b%u:%d\n", idx++, j);
j = 0;
}
//hw_timer_arm(50);
}
void ICACHE_FLASH_ATTR user_init(void)
{
hw_timer_init(FRC1_SOURCE, 1);
hw_timer_set_func(hw_test_timer_cb);
hw_timer_arm(100);
}
#endif
/*
NOTE:
1 if use nmi source, for autoload timer , the timer setting val can't be less than 100.
2 if use nmi source, this timer has highest priority, can interrupt other isr.
3 if use frc1 source, this timer can't interrupt other isr.
*/