FreeRTOS移植到STM32f103(寄存器版)静态创建任务
文章目录
- FreeRTOS移植到STM32f103(寄存器版)静态创建任务
- 前言
- 1.配置启动文件
- 2. 配置FreeRTOSConfig.h:
- 3. 在main.c的最下方写上systick中断服务函数:
- 4. FreeRtos默认的系统CPU_CLOCK是72MHz,TICK_RATE为每秒1000个tick(时间片),即1个tick(时间片)是1ms,但是STM32默认的SYSCLK是内核不精准的8MHz内部晶振,这导致了一个时间片长达9毫秒之久,所以我们要配置时钟为外部精准的72MHz系统时钟,代码如下(sysclk.c):
- 5. systick定时器配置成使用外部晶振,并关闭systick定时器(关闭的目的是防止触发systick中断):
- 6. NVIC优先级分组为第四组(全部设置为抢占优先级):
- 7. 工程代码:
- 总结
前言
基于寄存器的FreeRTOS移植到STM32,没有库函数,本文只是移植过程中代码相关的修改,没有目录结构的创建,参考此文需要先创建好FreeRtos的相关目录。创建目录参考文章:https://blog.csdn.net/qq_61672347/article/details/125529482
关于串口的寄存器配置,请参考我的另一篇文章:STM32寄存器配置USART1串口及USART->BRR值的计算https://blog.csdn.net/qq_47775761/article/details/130231106
1.配置启动文件
- Start文件夹下添加启动文件
2.根据自己的芯片,设置宏定义:我的是64kb的rom,故设置中容量产品的宏定义:STM32F10X_MD
2. 配置FreeRTOSConfig.h:
中断服务相关的配置,手写进去即可:
#define xPortPendSVHandler PendSV_Handler #define vPortSVCHandler SVC_Handler
使用静态内存分配,默认为动态分配:
#define configSUPPORT_STATIC_ALLOCATION 1
其他的默认即可。
3. 在main.c的最下方写上systick中断服务函数:
///**
// * @brief This function handles SysTick Handler.
// * @param None
// * @retval None
// */
extern void xPortSysTickHandler(void);
//systick中断服务函数
void SysTick_Handler(void)
{
#if (INCLUDE_xTaskGetSchedulerState == 1 )
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
#endif /* INCLUDE_xTaskGetSchedulerState */
xPortSysTickHandler();
#if (INCLUDE_xTaskGetSchedulerState == 1 )
}
#endif /* INCLUDE_xTaskGetSchedulerState */
}
4. FreeRtos默认的系统CPU_CLOCK是72MHz,TICK_RATE为每秒1000个tick(时间片),即1个tick(时间片)是1ms,但是STM32默认的SYSCLK是内核不精准的8MHz内部晶振,这导致了一个时间片长达9毫秒之久,所以我们要配置时钟为外部精准的72MHz系统时钟,代码如下(sysclk.c):
#include "stm32f10x.h" // Device header
/*时钟源为外部晶振,9倍频,SYSCLK为72MHz,APB2不分频,APB1二分频*/
void SYSCLK_Init()
{
/*打开HSE*/
RCC->CR |= RCC_CR_HSEON;
/* 等待HSE等待完毕 */
while ((RCC->CR & RCC_CR_HSERDY) == 0)
{
}
/*时钟源选择为 HSE,进行9倍频 SYSCLK = HSE*9 = 8MHz*9 = 72MHz */
RCC->CFGR |= RCC_CFGR_PLLMULL9;
RCC->CFGR |= RCC_CFGR_PLLSRC;
FLASH->ACR |= FLASH_ACR_LATENCY_2; // FLASH缓冲
/* 使能PLL倍频器 */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while ((RCC->CR & RCC_CR_PLLRDY) == 0) // 等待PLL倍频器就绪
{
}
/* SYSCLK预分频系数为1,即不分频 */
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
/* APB2预分频系数为1,即不分频 =SYSCLK */
RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
//
// /* APB1预分频系数为2,即 APB2 = SYSCLK/2 */
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
/* 复位时钟源选择,并将时钟源选择为PLL */
RCC->CFGR &= (~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;
//
/* 等待时钟源选择完成置位 */
while ((RCC->CFGR & RCC_CFGR_SWS) != 0x08)
{
}
}
5. systick定时器配置成使用外部晶振,并关闭systick定时器(关闭的目的是防止触发systick中断):
SysTick->CTRL |= 0x00000004;
6. NVIC优先级分组为第四组(全部设置为抢占优先级):
SCB->AIRCR=0x05fa0000|0x300;//NVIC优先级分组为第四组
7. 工程代码:
-
main.c
#include "stm32f10x.h" #include "FreeRTOS.h" #include "task.h" #include "sysclk.h" static TaskHandle_t LED_Task_handle = NULL; /*空闲任务栈*/ static StackType_t Idle_Task_Stack[configMINIMAL_STACK_SIZE]; /*空闲任务控制块*/ static StaticTask_t Idle_Task_TCB; /*Led任务栈*/ static StackType_t Led_Task_Stack[128]; /*Led任务控制块*/ static StaticTask_t Led_Task_TCB; void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) { *ppxIdleTaskTCBBuffer = &Idle_Task_TCB; *ppxIdleTaskStackBuffer = Idle_Task_Stack; *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; } static void LED_Task_Entry(void *p_arg) { while(1) { GPIOC->ODR &= ~(1 << 13);//关灯 vTaskDelay(1000); GPIOC->ODR |= 1 << 13;//开灯 vTaskDelay(1000); } } void GPIO_Init() { RCC->APB2ENR |= (1 << 4); // 使能APB2上的GPIOC GPIOC->CRH &= 0xff0fffff; // 配置c13口为推挽输出,由于点亮LED GPIOC->CRH |= 0x00300000; } int main(void) { /*SYSCLK初始化*/ SYSCLK_Init(); /*使用外部晶振,并关闭systick定时器*/ SysTick->CTRL |= 0x00000004; //NVIC优先级分组为第四组 SCB->AIRCR=0x05fa0000|0x300; GPIO_Init(); LED_Task_handle=xTaskCreateStatic((TaskFunction_t)LED_Task_Entry,//任务函数入口 (const char*)"LED_Task",//任务名称 (uint32_t) 128, //任务栈大小 (void *)NULL,//传给任务的参数 (UBaseType_t) 4,//优先级 (StackType_t *)Led_Task_Stack,//任务栈的起始地址 (StaticTask_t *)&Led_Task_TCB);//任务控制块 if(LED_Task_handle!=NULL) vTaskStartScheduler(); while(1); } ///** // * @brief This function handles SysTick Handler. // * @param None // * @retval None // */ extern void xPortSysTickHandler(void); //systick中断服务函数 void SysTick_Handler(void) { #if (INCLUDE_xTaskGetSchedulerState == 1 ) if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { #endif /* INCLUDE_xTaskGetSchedulerState */ xPortSysTickHandler(); #if (INCLUDE_xTaskGetSchedulerState == 1 ) } #endif /* INCLUDE_xTaskGetSchedulerState */ }
- sysclk.h
#ifndef __SYSCLK_H_ #define __SYSCLK_H_ void SYSCLK_Init(void); #endif
-
其他头文件为FREERTOS文件,直接用即可
总结
实验内容是一个LED每隔1S亮灭一次。