
esp32定时器的使用和stm32还是有一些区别的,esp32是通过一个定时器句柄来操作,不需要关心那个定时器组,哪个定时器,而stm32则是需要自己选择哪一个定时器,大致上也是差不多一个过程
大致流程
需要一个全局的 gptimer_handle_t 类型的变量:围绕这个变量进行 定时器参数的初始化还有警报初始化(即到达一个值触发一个回调),相当于,这个句柄就是一个定时器
定时器的初始化:通过一个结构体 gptimer_config_t 来操作的。由4个成员,确定定时器的参数
clk_src :定时器的时钟源
direction:选择定时器 每一个tick 是加1还是减1
resolution_hz:这个决定定时器的频率,也就是一个tick是多少时间,需要注意的是:有范围要求(300KHz~80MHz)
intr_shared:是否要共享中断,因为eps32的中断是有限的(32个),但是中断源是比中断来的多,这也导致了需要中断复用
定时器警报的初始化:这个稍微复杂点,需要两个结构体
先通过一个结构体 gptimer_alarm_config_t 来确定一个定时器的警报,由3个成员,确定一个警报器(或则说警报功能)的参数
alarm_count:这个就是警报的触发值,当定时器计数到这个值,将会触发一个警报(回调函数)
reload_count:重载的值
flags.auto_reload_on_alarm:一个标志,是否要重载定时器的值,如果需要重载,那么重载值不能和触发值一样,否则,就立马触发了
通过一个结构体 gptimer_event_callbacks_t 来确定定时器警报功能的回调函数,这个只是确定了回调函数
on_alarm:对应的回调函数名,也就是警报触发后,调用的函数
最后,将这几个结构体,通过对应的函数,和定时器的句柄联系起来
定时器初始化:通过gptimer_new_timer();将结构体对象和定时器句柄联系
定时器警报:
通过gptimer_set_alarm_action();将结构体对象和定时器句柄联系
通过gptimer_register_event_callbacks();将回调函数对象注册到对应的定时器上
使能定时器和启动启动定时器 gptimer_enable(my_timer_handle); gptimer_start(my_timer_handle);
参考代码
gptimer_handle_t my_timer_handle; //为了省去考虑硬件所属的定时器以及定时器组,引入了资源池,通过句柄来控制分配到的定时器 //很像说是,你创建好一个理想中的定时器模板,然后,去资源池中,找一个定时器,然后把这个模板套上去 static const char* TAG = "MyModule"; QueueHandle_t queue; //消息队列 /// @brief 通用定时器初始化 /// @param 无 void Timer_Init( void ) { gptimer_config_t my_timer = { .clk_src = GPTIMER_CLK_SRC_DEFAULT, //设定时钟源选择APB时钟源 .direction = GPTIMER_COUNT_UP, //设置为向上计数 .resolution_hz = 1*1000*1000, //设定定时器的分辨率为1000hz,也就是1ms计数一次,这个有一个范围,大致是 300KHz ~80MHz之间,不能太大,也不能太小,设置错误,将导致不断重启 // .intr_shared = false, //不共享中断 }; //创建一个定时器 ESP_ERROR_CHECK(gptimer_new_timer(&my_timer,&my_timer_handle)); } /// @brief 通用定时器的警报 /// @param 无 void Timer_Alarm_Init( void ) { ///给定时器添加警报功能 gptimer_alarm_config_t my_timer_alarm={ .alarm_count = 1000*1000, //警报计数值 .reload_count = 0, //警报发生时,重载的值 .flags.auto_reload_on_alarm = true, //使能警报时重载 }; gptimer_set_alarm_action(my_timer_handle,&my_timer_alarm); } void Gptimer_Test_Task( void *param ) { BaseType_t xReturn; int buf; while (1) { xReturn = xQueueReceive(queue,&buf,portMAX_DELAY); if (xReturn == pdTRUE) { ESP_LOGI(TAG, "哈哈哈"); printf("接收到数据:%d",buf); } vTaskDelay(10); } } /// @brief 定时器学习全部初始化 void Timer_Study_Init( void ) { //定时器的参数设置,最终都是围绕一个 定时器句柄 来操作的 Timer_Init(); //初始化一个定时器 Timer_Alarm_Init(); //给定时添加一个报警功能 // ///给这个警报功能添加回调函数 gptimer_event_callbacks_t my_timer_event = { .on_alarm = Timer_Alarm_CB, }; // ///将对应的回调函数结构体注册到对应的定时器 gptimer_register_event_callbacks(my_timer_handle,&my_timer_event,NULL); gptimer_enable(my_timer_handle); gptimer_start(my_timer_handle); //初始化一个消息队列 queue = xQueueCreate(10,sizeof(uint32_t)); xTaskCreate(Gptimer_Test_Task,"Gptimer_Test_Task",2048,NULL,2,NULL); // esp_rom_gpio_pad_select_gpio(10); //选择gpIO口 // gpio_set_direction(10, GPIO_MODE_OUTPUT); //设置GPIO口的输出方向:输入、输出 } int flag =0; //用于翻转电平 /// @brief 定时器的回调函数 bool Timer_Alarm_CB(gptimer_handle_t gpHandle,const gptimer_alarm_event_data_t *edata, void *Udata) { // ESP_LOGI(TAG, "Total APs scanned"); //打印函数导致系统一直复位? // ets_printf("中断了"); //貌似在中断中不能够使用串口答应 flag=~flag; if(flag==0) { gpio_set_level(19,0); }else{ gpio_set_level(19,1); xQueueSendFromISR(queue,&flag,pdFALSE); } // return true; }注意事项
不要在中断使用打印功能(难道是因为printf是不可重入函数?)