我们在stm32f103c8t6单片机上验证RTOS中断管理,利用stm32cube进行RTOS的配置。裸机的时钟源默认是 SysTick,但是开启 FreeRTOS 后,FreeRTOS会占用 SysTick (用来生成1ms 定时,用于任务调度),所以我们开启TIM2当做裸机的时钟源,为其他总线提供另外的时钟源。
验证的功能比较简单,选择V1 版本的内核完全够用。
1.验证思路
创建 1 个任务:Task。
任务要求如下:
按下KEY1,在中断里调用xQueueSendFromISR()函数,向队列的尾部写入消息;在入口函数StartTask中接收接受消息并显示。
其实很简单,就是相当于在我们在51和32单片机那里一样,特定的条件下触发中断,并在中断里执行一些操作。但是在RTOS里很有意思的是,明明都是向队列发送消息,却还要进行区分,如下表格
xQueueSend() | 往队列的尾部写入消息 |
xQueueSendFromISR() | 在中断中往队列的尾部写入消息 |
如果你在中断中执行操作,就要要执行与中断相关的API函数。
2.需要用到的函数
xQueueSendFromISR(xQueue, pvItemToQueue, pxHigherPriorityTaskWoken)
该队列写入函数有三个参数
xQueue:队列的句柄
pvItemToQueue:写入数据(如果你在该参数下按F12进去,该参数实际是个指针类型的)
pxHigherPriorityTaskWoken:这里我们设置为NULL
BaseType_t xQueueReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait )
该读出队列有3个参数:
xQueue:待读取的队列句柄
pvItemToQueue:数据读取缓冲区
xTicksToWait:阻塞超时时间
返回值: 成功返回 pdTRUE,否则返回 pdFALSE。
SYS
RCC
GPIO
PA0设置为GPIO_EXTI0
NVIC
RTOS
创建任务和队列,所有的参数配置默认即可
usart.c
#include "stdio.h"
int fputc(int ch, FILE *f)
{?????
?????? unsigned char temp[1]={ch};
?????? HAL_UART_Transmit(&huart1,temp,1,0xffff);?
?????? return ch;
}
stm32f1xx_it.c
中断回调函数里向队列发送数据
extern osMessageQId myQueueHandle;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
?????? uint32_t send=1;
?????? xQueueSendFromISR(myQueueHandle,&send,NULL);
}
freertos.c
在StartTask函数里接收数据,并通过串口显示出来
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
/* USER CODE END Variables */
osThreadId TaskHandle;
osMessageQId myQueueHandle;
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
/* USER CODE END FunctionPrototypes */
void StartTask(void const * argument);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );
/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
? *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
? *ppxIdleTaskStackBuffer = &xIdleStack[0];
? *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
? /* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */
/**
? * @brief? FreeRTOS initialization
? * @param? None
? * @retval None
? */
void MX_FREERTOS_Init(void) {
? /* USER CODE BEGIN Init */
? /* USER CODE END Init */
? /* USER CODE BEGIN RTOS_MUTEX */
? /* add mutexes, ... */
? /* USER CODE END RTOS_MUTEX */
? /* USER CODE BEGIN RTOS_SEMAPHORES */
? /* add semaphores, ... */
? /* USER CODE END RTOS_SEMAPHORES */
? /* USER CODE BEGIN RTOS_TIMERS */
? /* start timers, add new ones, ... */
? /* USER CODE END RTOS_TIMERS */
? /* Create the queue(s) */
? /* definition and creation of myQueue */
? osMessageQDef(myQueue, 16, uint16_t);
? myQueueHandle = osMessageCreate(osMessageQ(myQueue), NULL);
? /* USER CODE BEGIN RTOS_QUEUES */
? /* add queues, ... */
? /* USER CODE END RTOS_QUEUES */
? /* Create the thread(s) */
? /* definition and creation of Task */
? osThreadDef(Task, StartTask, osPriorityNormal, 0, 128);
? TaskHandle = osThreadCreate(osThread(Task), NULL);
? /* USER CODE BEGIN RTOS_THREADS */
? /* add threads, ... */
? /* USER CODE END RTOS_THREADS */
}
/* USER CODE BEGIN Header_StartTask */
/**
? * @brief? Function implementing the Task thread.
? * @param? argument: Not used
? * @retval None
? */
/* USER CODE END Header_StartTask */
void StartTask(void const * argument)
{
? /* USER CODE BEGIN StartTask */
? uint32_t rev = 0;
/* Infinite loop */
for(;;)
{
if (xQueueReceive(myQueueHandle, &rev, portMAX_DELAY) == pdTRUE)
printf("rev = %d\r\n", rev);
osDelay(1);
? /* USER CODE END StartTask */
}
}
结果如下图所示,按下KEY1触发中断,向队列发送一,同时队列接收并通过串口打印出来。