stm32CubeMX freertos 二值信号量

freerots系统配置参考: http://www.javashuo.com/article/p-tkjzlcdb-na.html

 

 

 

 

 

 

 

 其它保持默认。

代码实现:

//将二值信号量设置为全局变量:
//osSemaphoreId myBinarySem01Handle;
//osStaticSemaphoreDef_t myBinarySem01ControlBlock;
//赋值添加关键字保存在.h文件中
extern osSemaphoreId myBinarySem01Handle;
extern osStaticSemaphoreDef_t myBinarySem01ControlBlock;

用到的信号量函数为:具体查看代码说明

/**  Semaphore Management Functions   **/
osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count);//创建信号量
osStatus osSemaphoreRelease (osSemaphoreId semaphore_id);//释放信号量
int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec);//等待获取信号量
osStatus osSemaphoreDelete (osSemaphoreId semaphore_id);//信号量删除

二值信号量使用:

1. 信号发生

BaseType_t xHigherPriorityTaskWoken = pdFALSE;
...........
if(myBinarySem01Handle != NULL)//正确创建二值信号量后进入判断
{
    osSemaphoreRelease(myBinarySem01Handle);////释放二值信号量
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken );//需要的话进行一次任务切换,不在中断中使用 portYIELD();
}

2.信号接收

void MYTask(void const * argument)
{
/* USER CODE BEGIN StartTask02 */ BaseType_t err = pdFALSE; /* Infinite loop */ for(;;) { if(myBinarySem01Handle != NULL)//正确创建二值信号量后进入判断 { err = osSemaphoreWait(myBinarySem01Handle,osWaitForever); if(err == osOK) { //HAL_UART_Transmit_DMA(&huart1,(uint8_t *)str2,sizeof(str2));
          ..............
} } osDelay(10); } /* USER CODE END StartTask02 */ }

 实现:串口DMA + 二值信号量

usart.h 引用:#include <stdio.h>

printf()重定向:

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
    //HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);//注意把&huart1改为自己的stm32使用的串口号
    
    //HAL_UART_Transmit_IT(&huart1, (uint8_t *)&ch, 1);
    HAL_UART_Transmit_DMA(&huart1, (uint8_t *)&ch,1);    
    int cnt = 10000;//定义超时
    while((HAL_UART_STATE_READY !=huart1.gState)&&(cnt--));
    return ch;
}

stm32f1xx_it.h 添加:

#define BUFFER_SIZE 100 
extern volatile uint8_t rx_len ; //接收一帧数据的长度
extern volatile uint8_t recv_end_flag; //一帧数据接收完成标志
extern uint8_t rx_buffer[BUFFER_SIZE]; //接收数据缓存数组

stm32f1xx_it.c 添加:

volatile uint8_t rx_len ;  //接收一帧数据的长度
volatile uint8_t recv_end_flag; //一帧数据接收完成标志
uint8_t rx_buffer[BUFFER_SIZE];  //接收数据缓存数组

修改串口1中断函数:

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    uint32_t tmp_flag = 0;
    uint32_t temp;
    tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
    if((tmp_flag != RESET))//idle标志被置位
    { 
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
        HAL_UART_DMAStop(&huart1); //
        temp  =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数   
        //temp  = hdma_usart1_rx.Instance->NDTR;//读取NDTR寄存器 获取DMA中未传输的数据个数,
        //这句和上面那句等效
        rx_len =  BUFFER_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
                if(rx_len != 0)
                {
                    recv_end_flag = 1;    // 接受完成标志位置1  
                    if(myBinarySem01Handle != NULL)//正确创建二值信号量后进入判断
                    {
                        osSemaphoreRelease(myBinarySem01Handle);////释放二值信号量
                        portYIELD_FROM_ISR(xHigherPriorityTaskWoken );//需要的话进行一次任务切换,不在中断中使用 portYIELD();
                    }
                }
     }
   /* USER CODE END USART1_IRQn 0 */
   HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
         
  /* USER CODE END USART1_IRQn 1 */
}

main.c 在int main() 中串口初始化后添加:

HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx_buffer,BUFFER_SIZE);//打开DMA接收

main.c 添加函数:

void DMA_Usart_Send(uint8_t *buf,uint8_t len)//串口发送封装
{
    //HAL_UART_Transmit_DMA(&huart1, buf,len);
    if(len != 0)
    {
         if(HAL_UART_Transmit_DMA(&huart1, buf,len)!= HAL_OK) //判断是否发送正常,如果出现异常则进入异常中断函数
        {
            do{
                if(huart1.gState != HAL_UART_STATE_READY)
                {
                    continue;
                }            
            }while(huart1.gState == HAL_UART_STATE_READY) ;
         //Error_Handler();
        }
    }
}

void send_str(char *str)//字符串发送
{
    uint16_t temp = strlen(str);
    if(temp != 0)
    {
        DMA_Usart_Send((uint8_t *)str,temp);
    }
}

main.h 添加:

引用:

  #include <stdio.h>
  #include <stdlib.h>

void DMA_Usart_Send(uint8_t *buf,uint8_t len);//串口发送封装
void send_str(char *str);//字符串发送

FreeRTOS.c :引用:

#include <stdlib.h>
#include "stm32f1xx_it.h"
#include "stm32f1xx_hal_uart.h"
#include "stdint.h"
#include "usart.h"

添加:

uint8_t Recive_buff[BUFFER_SIZE]={0};//转存缓冲区数据,避免DMA引用的数组被其他地方操作而发生错误
static int count_task1 =0;
static int count_task2 =0;
static int count_task3 =0;

修改任务函数:

void Start_Task1(void const * argument)
{
  /* USER CODE BEGIN Start_Task1 */
    BaseType_t err = pdFALSE;
    char temp1[15] = {"TASK1!_"};
    //char itg_to_as1[5] = {"\0"};
  /* Infinite loop */
  for(;;)
  {
        if(myBinarySem01Handle != NULL)//正确创建二值信号量后进入判断
        {
                err = osSemaphoreWait(myBinarySem01Handle,osWaitForever);
                if(err == osOK)
                {
                    //send_str("TASK1!______ \r\n");
                    memcpy(Recive_buff,rx_buffer,rx_len);
                    //DMA_Usart_Send(Recive_buff,rx_len);
                    printf("%s",Recive_buff);
                    memset(rx_buffer,0,rx_len);            
                    rx_len = 0;//清除计数
                    recv_end_flag = 0;//清除接收结束标志位
                    HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx_buffer,BUFFER_SIZE);//重新打开DMA接收
                    
                    
                    count_task1++;
                    printf("TASK1!____ %d\r\n",count_task1);
                }
        }        
        //send_str("TASK1!____");
    osDelay(100);
  }
  /* USER CODE END Start_Task1 */
}
void Start_Task2(void const * argument)
{
  /* USER CODE BEGIN Start_Task2 */
    char temp2[15] = {"TASK2!_"};
    //char itg_to_as2[5] = {"\0"};
  /* Infinite loop */
  for(;;)
  {
        count_task2++;
        //send_str("TASK2!    \r\n");
        printf("TASK2!__ %d\r\n",count_task2);
    osDelay(5000);
  }
  /* USER CODE END Start_Task2 */
}
void Start_Task03(void const * argument)
{
  /* USER CODE BEGIN Start_Task03 */
    char temp3[15] = {"TASK3!_"};
    //char itg_to_as3[5] = {"\0"};
  /* Infinite loop */
  for(;;)
  {
        count_task3++;
        //send_str("TASK3!    \r\n");
        printf("TASK3! %d\r\n",count_task3);
    osDelay(2000);
  }
  /* USER CODE END Start_Task03 */
}

 注: 1. 经测试,将串口响应任务设置为较高优先级,使用二值信号量进行控制,且任务阻塞时间osDelay()设置小点,可以提高串口任务的响应灵敏度。

 

 

 

 

 

posted @ 2022-06-02 21:39  百叶集  阅读(586)  评论(0编辑  收藏  举报