×

ESP32------通用定时器的使用

zxjy辉 zxjy辉 发表于2023-07-07 15:14:37 浏览1965 评论1

1人参与发表评论

唯美大海海岸星空.jpg

esp32定时器的使用和stm32还是有一些区别的,esp32是通过一个定时器句柄来操作,不需要关心那个定时器组,哪个定时器,而stm32则是需要自己选择哪一个定时器,大致上也是差不多一个过程


  1. 大致流程

    1. 需要一个全局的 gptimer_handle_t  类型的变量:围绕这个变量进行 定时器参数的初始化还有警报初始化(即到达一个值触发一个回调),相当于,这个句柄就是一个定时器

    2. 定时器的初始化:通过一个结构体 gptimer_config_t 来操作的。由4个成员,确定定时器的参数

      1. clk_src :定时器的时钟源

      2. direction:选择定时器 每一个tick 是加1还是减1

      3. resolution_hz:这个决定定时器的频率,也就是一个tick是多少时间,需要注意的是:有范围要求(300KHz~80MHz)

      4. intr_shared:是否要共享中断,因为eps32的中断是有限的(32个),但是中断源是比中断来的多,这也导致了需要中断复用

    3. 定时器警报的初始化:这个稍微复杂点,需要两个结构体

      1. 先通过一个结构体 gptimer_alarm_config_t 来确定一个定时器的警报,由3个成员,确定一个警报器(或则说警报功能)的参数

        1. alarm_count:这个就是警报的触发值,当定时器计数到这个值,将会触发一个警报(回调函数)

        2. reload_count:重载的值

        3. flags.auto_reload_on_alarm:一个标志,是否要重载定时器的值,如果需要重载,那么重载值不能和触发值一样,否则,就立马触发了

      2. 通过一个结构体 gptimer_event_callbacks_t 来确定定时器警报功能的回调函数,这个只是确定了回调函数

        1. on_alarm:对应的回调函数名,也就是警报触发后,调用的函数

    4. 最后,将这几个结构体,通过对应的函数,和定时器的句柄联系起来

      1. 定时器初始化:通过gptimer_new_timer();将结构体对象和定时器句柄联系

      2. 定时器警报:

        1. 通过gptimer_set_alarm_action();将结构体对象和定时器句柄联系

        2. 通过gptimer_register_event_callbacks();将回调函数对象注册到对应的定时器上

    5. 使能定时器和启动启动定时器
       gptimer_enable(my_timer_handle);
       gptimer_start(my_timer_handle);


  2. 参考代码

    1. 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;
      }


    2. 注意事项

      1. 不要在中断使用打印功能(难道是因为printf是不可重入函数?)

#好好学习!

群贤毕至

访客
admin admin2023-07-07 16:04:45 · 回复 esp32串口打印汉字好像 有问题,sscom无法识别