我们在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。
二、stm32cube的配置
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触发中断,向队列发送一,同时队列接收并通过串口打印出来。