• FreeRTOS_软件定时器


     FreeRTOS 软件定时器

    实验

    创建2个任务,start_task、timercontrol_task。

    start_stask:创建timercontrol_task任务;创建周期定时器AutoReloadTimer 和单次定时器OneShotTimer;创建二值信号量BinarySemaphore。

    BinarySemaphore:接收串口命名,在中断中释放信号,在timercontrol_task中等待信号量,解析命名,通过不同的命令控制周期定时器AutoReloadTimer和单次定时器OneShotTimer的开启和关闭。

    AutoReloadTimer 的回调函数会输出运行的次数

    OneShotTimer的回电函数会输出运行的次数

    任务分配:

    //任务优先级
    #define START_TASK_PRIO        1
    //任务堆栈大小    
    #define START_STK_SIZE         128  
    //任务句柄
    TaskHandle_t StartTask_Handler;
    //任务函数
    void start_task(void *pvParameters);
    
    //任务优先级
    #define TIMERCONTROL_TASK_PRIO        2
    //任务堆栈大小    
    #define TIMERCONTROL_STK_SIZE         50  
    //任务句柄
    TaskHandle_t TimerControlTask_Handler;
    //任务函数
    void timercontrol_task(void *pvParameters);
    
    SemaphoreHandle_t BinarySemaphore_Handle;    // 二值信号量句柄
    
    TimerHandle_t AutoReloadTimer_Handle ;    // 周期定时器句柄
    TimerHandle_t OneShotTimer_Handle;        // 单次定时器句柄
    
    
    void AutoReloadTimerCallback(void);        // 周期定时器回调函数
    void OneShotTimerCallback(void);        // 周期定时器回调函数

    main() 函数

    int main(void)
    {
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4     
        delay_init();                        //延时函数初始化      
        uart_init(115200);                    //初始化串口
        LED_Init();                              //初始化LED
         
        //创建开始任务
        xTaskCreate((TaskFunction_t )start_task,            //任务函数
                    (const char*    )"start_task",          //任务名称
                    (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                    (void*          )NULL,                  //传递给任务函数的参数
                    (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                    (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
        vTaskStartScheduler();          //开启任务调度
    }

    命令解析相关函数:

    // 将字符串中的小写字母转换为大写
    // str:要转换的字符串
    // len:字符串长度
    void LowerToCap(u8 *str,u8 len)
    {
        u8 i;
        
        for(i=0;i<len;i++)
        {
            if((96<str[i])&&(str[i]<123))    // 小写字母
                str[i] = str[i]-32;            // 转换为大写
        }
    }
    
    // 命令处理函数,将字符串命令转换成命令值
    // str:命令
    // 返回值:0xFF-命令错误 其他值-命令值
    u8 CommandProcess(u8 *str)
    {
        u8 CommandValue = 0xFF;
        
        if(strcmp((char*)str,"KEY1")==0) CommandValue = 1;
        else if(strcmp((char*)str,"KEY2")==0) CommandValue = 2;
        else if(strcmp((char*)str,"KEY3")==0) CommandValue = 3;
        else if(strcmp((char*)str,"KEY4")==0) CommandValue = 4;
        
        return CommandValue;
    }

    任务函数:

    //开始任务任务函数
    void start_task(void *pvParameters)
    {
        taskENTER_CRITICAL();           //进入临界区
        
        // 创建二值信号量
        BinarySemaphore_Handle =  xSemaphoreCreateBinary();    // 创建二值信号量
        if(BinarySemaphore_Handle ==NULL)
        {
            printf("BinarySemaphore Create Failed!
    ");
        }else{
            xSemaphoreGive(BinarySemaphore_Handle);            // 释放信号量
        }
        
        
        // 创建周期定时器
        AutoReloadTimer_Handle =  xTimerCreate(    (const char *)"AutoReloadTimer",
                                    (TickType_t) 1000,
                                    (UBaseType_t) pdTRUE,
                                    (void *) 1,
                                    (TimerCallbackFunction_t)AutoReloadTimerCallback );
        if(AutoReloadTimer_Handle == NULL)
        {
            printf("AutoReloadTimer Created Failed 
    ");
        }else{
            printf("AutoReloadTimer Created Success 
    ");
        }
        
        // 创建单次定时器                            
        OneShotTimer_Handle =  xTimerCreate(    (const char *)"OneShotTimer",
                                    (TickType_t) 2000,
                                    (UBaseType_t) pdFALSE,
                                    (void *) 2,
                                    (TimerCallbackFunction_t)OneShotTimerCallback );
        if(OneShotTimer_Handle == NULL)
        {
            printf("OneShotTimer Created Failed 
    ");
        }else{
            printf("OneShotTimer Created Success 
    ");
        }
        
        //创建TIMECONTRFOL任务
        xTaskCreate((TaskFunction_t )timercontrol_task,         
                    (const char*    )"timercontrol_task",       
                    (uint16_t       )TIMERCONTROL_STK_SIZE, 
                    (void*          )NULL,                
                    (UBaseType_t    )TIMERCONTROL_TASK_PRIO,    
                    (TaskHandle_t*  )&TimerControlTask_Handler);   
          
        vTaskDelete(StartTask_Handler); //删除开始任务
        taskEXIT_CRITICAL();            //退出临界区
    }
    
    
    
    //TIMERCONTROL任务函数
    void timercontrol_task(void *pvParameters)
    {
        u8 len = 0;
        u8 CommandValue = 0xFF;
        u8 CommandStr[USART_REC_LEN];
        BaseType_t err;
        
        while(1)
        {
            xSemaphoreTake( BinarySemaphore_Handle, portMAX_DELAY );    // 死等
            len = USART_RX_STA&0x3fff;                                // 得到此次接收到的数据长度
            
            sprintf((char *)CommandStr,"%s",USART_RX_BUF);            // 装载数据
            CommandStr[len] = '';                                    // 加上字符串结尾符号
            LowerToCap(CommandStr,len);                                // 将字符串转换为大写
            CommandValue = CommandProcess(CommandStr);                // 命令解析
            
            if(CommandValue != 0xFF)                                // 接收到正确的命令
            {
                switch(CommandValue)
                {
                    case 1:        // 开启周期定时器
                        err =  xTimerStart( AutoReloadTimer_Handle, 0 );
                        if(err == pdFAIL)
                        {
                            printf("AutoReloadTimer Start Failed! 
    ");
                        }else{
                            printf("AutoReloadTimer Start Succeed! 
    ");
                        }
                        break;
                    case 2:        // 关闭周期定时器
                        err =  xTimerStop( AutoReloadTimer_Handle, 0 );
                        if(err == pdFAIL)
                        {
                            printf("AutoReloadTimer Stop Failed! 
    ");
                        }else{
                            printf("AutoReloadTimer Stop Succeed! 
    ");
                        }
                        break;
                    case 3:        // 开启单次定时器
                        err =  xTimerStart( OneShotTimer_Handle, 0 );
                        if(err == pdFAIL)
                        {
                            printf("OneShotTimer Start Failed! 
    ");
                        }else{
                            printf("OneShotTimer Start Succeed! 
    ");
                        }
                        break;
                    case 4:        // 关闭周期定时器
                        err =  xTimerStop( OneShotTimer_Handle, 0 );
                        if(err == pdFAIL)
                        {
                            printf("OneShotTimer Stop Failed! 
    ");
                        }else{
                            printf("OneShotTimer Stop Succeed! 
    ");
                        }
                        break;
                }
            }else{
                printf("Cmd error!
    ");
            }
            USART_RX_STA = 0;
        }
    }

    定时器回调函数:

    // 周期定时器回调函数
    void AutoReloadTimerCallback(void)
    {
        static u8 count = 0;
        
        count ++;
        printf("AutoReloadTimerCallback running %d timers
    ",count);
    }
    
    // 周期定时器回调函数
    void OneShotTimerCallback(void)
    {
        static u8 count = 0;
        
        count ++;
        printf("OneShotTimerCallback running %d timers
    ",count);
    }

    串口中断初始化和中断处理函数

    u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
    //接收状态
    //bit15,    接收完成标志
    //bit14,    接收到0x0d
    //bit13~0,    接收到的有效字节数目
    u16 USART_RX_STA=0;       //接收状态标记      
      
    void uart_init(u32 bound){
        //GPIO端口设置
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
         
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);    //使能USART1,GPIOA时钟
      
        //USART1_TX   GPIOA.9
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
       
        //USART1_RX      GPIOA.10初始化
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  
    
        //Usart1 NVIC 配置
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=8 ;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器
      
        //USART 初始化设置
    
        USART_InitStructure.USART_BaudRate = bound;//串口波特率
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
        USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
        USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //收发模式
    
        USART_Init(USART1, &USART_InitStructure); //初始化串口1
        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
        USART_Cmd(USART1, ENABLE);                    //使能串口1 
    }
    
    extern SemaphoreHandle_t BinarySemaphore_Handle;    // 二值信号量句柄
    void USART1_IRQHandler(void)                    //串口1中断服务程序
    {
        u8 Res;
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
        {
            Res =USART_ReceiveData(USART1);    //读取接收到的数据
            
            if((USART_RX_STA&0x8000)==0)//接收未完成
                {
                if(USART_RX_STA&0x4000)//接收到了0x0d
                    {
                    if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
                    else USART_RX_STA|=0x8000;    //接收完成了 
                    }
                else //还没收到0X0D
                    {    
                    if(Res==0x0d)USART_RX_STA|=0x4000;
                    else
                        {
                        USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
                        USART_RX_STA++;
                        if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收      
                        }         
                    }
                }            
         } 
        
         if((BinarySemaphore_Handle != NULL) && (USART_RX_STA&0x8000))
         {
             xSemaphoreGiveFromISR( BinarySemaphore_Handle, &xHigherPriorityTaskWoken );    // 释放互斥信号量
             portYIELD_FROM_ISR(xHigherPriorityTaskWoken);    // 如果需要进行一次任务切换
         }
         
    }
    #define USART_REC_LEN              20      //定义最大接收字节数 200
    #define EN_USART1_RX             1        //使能(1)/禁止(0)串口1接收
              
    extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 

    注意:串口中断的优先级在FreeRTOS的优先级管理范围内。

    运行结果:

    输入KEY1命令,周期定时器开始运行,周期性调用其回调函数,直到输入KEY2命令,停止周期定时器,其回调函数不再被调用。

    输入KYE3命令,单次定时器开始运行,调用其回调函数,只调用一次,就不再调用。再次输入KEY3命令,还是只调其回调函数一次。

    可以看出,停止单次定时器命令KEY4,可以不存在。

  • 相关阅读:
    Educational Codeforces Round 88 (Rated for Div. 2) D. Yet Another Yet Another Task(枚举/最大连续子序列)
    Educational Codeforces Round 88 (Rated for Div. 2) A. Berland Poker(数学)
    Educational Codeforces Round 88 (Rated for Div. 2) E. Modular Stability(数论)
    Educational Codeforces Round 88 (Rated for Div. 2) C. Mixing Water(数学/二分)
    Codeforces Round #644 (Div. 3)
    Educational Codeforces Round 76 (Rated for Div. 2)
    Educational Codeforces Round 77 (Rated for Div. 2)
    Educational Codeforces Round 87 (Rated for Div. 2)
    AtCoder Beginner Contest 168
    Codeforces Round #643 (Div. 2)
  • 原文地址:https://www.cnblogs.com/doitjust/p/11052175.html
Copyright © 2020-2023  润新知