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()设置小点,可以提高串口任务的响应灵敏度。