目录
一、将STM32F103ZET6代码变更成STM32F103C8T6
二、 将FreeRTOS码源添加到文件
三、代码更改适配
四、测试
一、将STM32F103ZET6代码变更成STM32F103C8T6
点击魔法棒,点击Device,选择芯片为STM32F103C8T6
进行编译,无报错无警告:
二、 将FreeRTOS码源添加到文件
先进入官网获取FreeRTOS码源:https://www.freertos.org/a00110.html
将获取到的源码中的FreeRTOS/Source文件夹移植到工程文件中的Middlewares下
点击文件拓展工具,添加Middlewares/FreeRTOS_CODE与Middlewares/FreeRTOS_PORT两个组
将相关代码添加到这两个新建组中
引入相关头文件地址
将 FreeRTOSConfig.h添加到User中
三、代码更改适配
sys.h文件
将宏SYS_SUPPORT_OS定义为1
#define SYS_SUPPORT_OS 1
usart.c文件
USART_UX_IRQHandler适配更改:
void USART_UX_IRQHandler(void)
{
HAL_UART_IRQHandler(&g_uart1_handle); /* 调用HAL库中断处理公用函数 */
while (HAL_UART_Receive_IT( &g_uart1_handle,
(uint8_t *)g_rx_buffer,
RXBUFFERSIZE) != HAL_OK)/* 重新开启中断并接收数据 */
{
/* 如果出错会卡死在这里 */
}
}
删除无关头文件
/* 如果使用os,则包括下面的头文件即可. */
#if SYS_SUPPORT_OS
#include "includes.h" /* os 使用 */
#endif
delay.c文件
将如下代码删除
static uint16_t g_fac_ms = 0;
#ifdef OS_CRITICAL_METHOD
#define delay_osrunning OSRunning /* OS是否运行标记,0,不运行;1,在运行 */
#define delay_ostickspersec OS_TICKS_PER_SEC /* OS时钟节拍,即每秒调度次数 */
#define delay_osintnesting OSIntNesting /* 中断嵌套级别,即中断嵌套次数 */
#endif
#ifdef CPU_CFG_CRITICAL_METHOD
#define delay_osrunning OSRunning /* OS是否运行标记,0,不运行;1,在运行 */
#define delay_ostickspersec OSCfg_TickRate_Hz /* OS时钟节拍,即每秒调度次数 */
#define delay_osintnesting OSIntNestingCtr /* 中断嵌套级别,即中断嵌套次数 */
#endif
static void delay_osschedlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD /* 使用UCOSIII */
OS_ERR err;
OSSchedLock(&err); /* UCOSIII的方式,禁止调度,防止打断us延时 */
#else /* 否则UCOSII */
OSSchedLock(); /* UCOSII的方式,禁止调度,防止打断us延时 */
#endif
}
static void delay_osschedunlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD /* 使用UCOSIII */
OS_ERR err;
OSSchedUnlock(&err); /* UCOSIII的方式,恢复调度 */
#else /* 否则UCOSII */
OSSchedUnlock(); /* UCOSII的方式,恢复调度 */
#endif
}
static void delay_ostimedly(uint32_t ticks)
{
#ifdef CPU_CFG_CRITICAL_METHOD
OS_ERR err;
OSTimeDly(ticks, OS_OPT_TIME_PERIODIC, &err); /* UCOSIII延时采用周期模式 */
#else
OSTimeDly(ticks); /* UCOSII延时 */
#endif
}
将代码添加到 SysTick中断服务函数之前
extern void xPortSysTickHandler(void);
修改SysTick_Handler()
void SysTick_Handler(void)
{
HAL_IncTick();
/* OS开始跑了,才执行正常的调度处理 */
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
xPortSysTickHandler();
}
}
xPortSysTickHandler()
void SysTick_Handler(void)
{
HAL_IncTick();
/* OS开始跑了,才执行正常的调度处理 */
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
xPortSysTickHandler();
}
}
SysTick_Handler 函数
delay_init()
void delay_init(uint16_t sysclk)
{
#if SYS_SUPPORT_OS
uint32_t reload;
#endif
SysTick->CTRL = 0;
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);
g_fac_us = sysclk / 8;
#if SYS_SUPPORT_OS
reload = sysclk / 8;
/* 使用configTICK_RATE_HZ计算重装载值
* configTICK_RATE_HZ在FreeRTOSConfig.h中定义
*/
reload *= 1000000 / configTICK_RATE_HZ;
/* 删除不用的g_fac_ms相关代码 */
SysTick->CTRL |= 1 << 1;
SysTick->LOAD = reload;
SysTick->CTRL |= 1 << 0;
#endif
}
delay_us()
void delay_us(uint32_t nus)
{
uint32_t ticks;
uint32_t told, tnow, tcnt = 0;
uint32_t reload = SysTick->LOAD;
/* 删除适用于µC/OS用于锁定任务调度器的自定义函数 */
ticks = nus * g_fac_us;
told = SysTick->VAL;
while (1)
{
tnow = SysTick->VAL;
if (tnow != told)
{
if (tnow < told)
{
tcnt += told - tnow;
}
else
{
tcnt += reload - tnow + told;
}
told = tnow;
if (tcnt >= ticks)
{
break;
}
}
}
/* 删除适用于µC/OS用于解锁任务调度器的自定义函数 */
}
delay_ms()
void delay_ms(uint16_t nms)
{
uint32_t i;
for (i=0; i<nms; i++)
{
delay_us(1000);
}
}
将#include "includes.h" 修改成
/* 添加公共头文件 (FreeRTOS 需要用到) */
#include "FreeRTOS.h"
#include "task.h"
完整delay.c文件:
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
static uint32_t g_fac_us = 0; /* us延时倍乘数 */
/* 如果SYS_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS) */
#if SYS_SUPPORT_OS
/* 添加公共头文件 (FreeRTOS 需要用到) */
#include "FreeRTOS.h"
#include "task.h"
extern void xPortSysTickHandler(void);
/**
* @brief systick中断服务函数,使用OS时用到
* @param ticks : 延时的节拍数
* @retval 无
*/
void SysTick_Handler(void)
{
HAL_IncTick();
/* OS 开始跑了,才执行正常的调度处理 */
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
xPortSysTickHandler();
}
}
#endif
/**
* @brief 初始化延迟函数
* @param sysclk: 系统时钟频率, 即CPU频率(rcc_c_ck), 180MHz
* @retval 无
*/
void delay_init(uint16_t sysclk)
{
#if SYS_SUPPORT_OS /* 如果需要支持OS */
uint32_t reload;
#endif
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);/* SYSTICK使用外部时钟源,频率为HCLK */
g_fac_us = sysclk; /* 不论是否使用OS,g_fac_us都需要使用 */
#if SYS_SUPPORT_OS /* 如果需要支持OS. */
reload = sysclk; /* 每秒钟的计数次数 单位为M */
reload *= 1000000 / configTICK_RATE_HZ; /* 根据delay_ostickspersec设定溢出时间,reload为24位
* 寄存器,最大值:16777216,在180M下,约合0.0932s左右
*/
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; /* 开启SYSTICK中断 */
SysTick->LOAD = reload; /* 每1/delay_ostickspersec秒中断一次 */
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; /* 开启SYSTICK */
#endif
}
#if SYS_SUPPORT_OS /* 如果需要支持OS, 用以下代码 */
/**
* @brief 延时nus
* @param nus: 要延时的us数
* @note 注意: nus的值,不要大于93206us(最大值即2^24 / g_fac_us @g_fac_us = 180)
* @retval 无
*/
void delay_us(uint32_t nus)
{
uint32_t ticks;
uint32_t told, tnow, tcnt = 0;
uint32_t reload = SysTick->LOAD; /* LOAD的值 */
ticks = nus * g_fac_us; /* 需要的节拍数 */
told = SysTick->VAL; /* 刚进入时的计数器值 */
while (1)
{
tnow = SysTick->VAL;
if (tnow != told)
{
if (tnow < told)
{
tcnt += told - tnow; /* 这里注意一下SYSTICK是一个递减的计数器就可以了 */
}
else
{
tcnt += reload - tnow + told;
}
told = tnow;
if (tcnt >= ticks)
{
break; /* 时间超过/等于要延迟的时间,则退出 */
}
}
}
}
/**
* @brief 延时nms
* @param nms: 要延时的ms数 (0< nms <= 65535)
* @retval 无
*/
void delay_ms(uint16_t nms)
{
uint32_t i;
for (i=0; i<nms; i++)
{
delay_us(1000);
}
}
#else /* 不使用OS时, 用以下代码 */
/**
* @brief 延时nus
* @param nus: 要延时的us数.
* @note 注意: nus的值,不要大于93206us(最大值即2^24 / g_fac_us @g_fac_us = 180)
* @retval 无
*/
void delay_us(uint32_t nus)
{
uint32_t ticks;
uint32_t told, tnow, tcnt = 0;
uint32_t reload = SysTick->LOAD; /* LOAD的值 */
ticks = nus * g_fac_us; /* 需要的节拍数 */
told = SysTick->VAL; /* 刚进入时的计数器值 */
while (1)
{
tnow = SysTick->VAL;
if (tnow != told)
{
if (tnow < told)
{
tcnt += told - tnow; /* 这里注意一下SYSTICK是一个递减的计数器就可以了 */
}
else
{
tcnt += reload - tnow + told;
}
told = tnow;
if (tcnt >= ticks)
{
break; /* 时间超过/等于要延迟的时间,则退出 */
}
}
}
}
/**
* @brief 延时nms
* @param nms: 要延时的ms数 (0< nms <= 65535)
* @retval 无
*/
void delay_ms(uint16_t nms)
{
uint32_t repeat = nms / 65; /* 这里用60,是考虑到可能有超频应用,比如180M的时候,delay_us最大只能延时93206us左右了 */
uint32_t remain = nms % 65;
while (repeat)
{
delay_us(65 * 1000); /* 利用delay_us 实现 65ms 延时 */
repeat--;
}
if (remain)
{
delay_us(remain * 1000); /* 利用delay_us, 把尾数延时(remain ms)给做了 */
}
}
/**
* @brief HAL库内部函数用到的延时
* @note HAL库的延时默认用Systick,如果我们没有开Systick的中断会导致调用这个延时后无法退出
* @param Delay : 要延时的毫秒数
* @retval None
*/
void HAL_Delay(uint32_t Delay)
{
delay_ms(Delay);
}
#endif
stm32f1xx_it.c
/* 加入宏开关 */
#if (!SYS_SUPPORT_OS)
void SVC_Handler(void)
{
}
#endif
/**
* @brief This function handles PendSVC exception.
* @param None
* @retval None
*/
/* 加入宏开关 */
#if (!SYS_SUPPORT_OS)
void PendSV_Handler(void)
{
}
#endif
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
/* 加入宏开关 */
#if (!SYS_SUPPORT_OS)
void SysTick_Handler(void)
{
HAL_IncTick();
}
#endif
FreeRTOSConfig.h
#define configPRIO_BITS __NVIC_PRIO_BITS
//#define __NVIC_PRIO_BITS 4U
#define __NVIC_PRIO_BITS 4
编译:无报错无警告
四、测试
编写主函数:
#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./SYSTEM/usart/usart.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1 /* 任务优先级 */
#define START_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t StartTask_Handler; /* 任务句柄 */
void start_task(void *pvParameters); /* 任务函数 */
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2 /* 任务优先级 */
#define TASK1_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task1Task_Handler; /* 任务句柄 */
void task1(void *pvParameters); /* 任务函数 */
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3 /* 任务优先级 */
#define TASK2_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task2Task_Handler; /* 任务句柄 */
void task2(void *pvParameters); /* 任务函数 */
/******************************************************************************************************/
void led_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
__HAL_RCC_GPIOC_CLK_ENABLE();
gpio_initstruct.Pin = GPIO_PIN_13; /* LED0引脚 */
gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */
gpio_initstruct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(GPIOC, &gpio_initstruct); /* 初始化LED0引脚 */
// gpio_initstruct.Pin = GPIO_PIN_5; /* LED1引脚 */
// HAL_GPIO_Init(GPIOE, &gpio_initstruct); /* 初始化LED1引脚 */
}
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
xTaskCreate((TaskFunction_t )start_task, /* 任务函数 */
(const char* )"start_task", /* 任务名称 */
(uint16_t )START_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )START_TASK_PRIO, /* 任务优先级 */
(TaskHandle_t* )&StartTask_Handler); /* 任务句柄 */
vTaskStartScheduler();
}
/**
* @brief start_task
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); /* 进入临界区 */
/* 创建任务1 */
xTaskCreate((TaskFunction_t )task1,
(const char* )"task1",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
/* 创建任务2 */
xTaskCreate((TaskFunction_t )task2,
(const char* )"task2",
(uint16_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_PRIO,
(TaskHandle_t* )&Task2Task_Handler);
vTaskDelete(StartTask_Handler); /* 删除开始任务 */
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/**
* @brief task1
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void task1(void *pvParameters)
{
while(1)
{
printf("task1\r\n");delay_ms(500);
}
}
/**
* @brief task2
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void task2(void *pvParameters)
{
led_init(); /* LED初始化 */
while(1)
{
printf("task2\r\n");delay_ms(500);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET); /* PB5置1 */
delay_ms(500);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET); /* PB5置0 */
delay_ms(500);
}
}
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
usart_init(115200);
printf("start\r\n");
freertos_demo();
// while(1)
// {
// }
}
编译烧入:
参考:第7讲 FreeRTOS移植_哔哩哔哩_bilibili