最近终于在裸机工程中移植了RTThread这个实时操作系统,这是迈向嵌入式的第一步,在这里要感谢野火的《RT-Thread 内核实现与应用开发实战指南》,这本书简单细致的向我们介绍了RTThread的内核,以及对裸机程序如何移植到rtthread的操作环境中。在大型一点的项目中,RTOS给了我们希望,让我们不必再让阻塞延时来降低我们的工作效率,同时模块化任务的管理,信号量,互斥量的处理可以让我们减少bug。消息队列,邮箱,双向链表是我们对数据处理的有效手段,内存管理解决了RAM空间不足,可能产生碎片等问题。中断管理解决了中断对线程上下文所产生的影响。
方法有两种:
用户在使用 RT-Thread 的时候,用户只需要修改 board.c 和 rtconfig.h 这两个文件的内容即可,其它
文件我们不需要改动。 如果为了减小工程的大小, bsp 文件夹下面除了 board.c 和 rtconfig.h
这两个文件要保留外,其它的统统可以删除。
/* RT-Thread config file */
#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__
#define RT_THREAD_PRIORITY_MAX 32 //RT_THREAD_PRIORITY_MAX 这个宏表示 RT-Thread 支持多少个优先级,取值范围为 8~256,默认为 32。
#define RT_TICK_PER_SECOND 1000 //RT_TICK_PER_SECOND 表示操作系统每秒钟有多少个 tick,tick 即是操作系统的时钟周期,默认为 1000,即操作系统的时钟周期 tick 等于 1ms。
#define RT_ALIGN_SIZE 4 //RT_ALIGN_SIZE 这个宏表示 CPU 处理的数据需要多少个字节对齐,默认为 4 个字节。
#define RT_NAME_MAX 10 //RT_NAME_MAX 这个宏表示内核对象名字的最大长度, 取值范围为 2~16, 默认为 8。
#define RT_USING_COMPONENTS_INIT //使用 RT-Thread 组件初始化,默认使能。
#define RT_USING_USER_MAIN //使用用户 main 函数,默认打开。
#define RT_MAIN_THREAD_STACK_SIZE 512 //main 线程栈大小,取值范围为 1~4086,单位为字节,默认为512。
#define RT_DEBUG_INIT 0 //调试配置。包括了内核调试配置,组件调试配置和线程栈溢出检测,目前全部关闭。
#define RT_USING_TIMER_SOFT 0 //软件定时器配置,目前关闭,不使用软件定时器。
#if RT_USING_TIMER_SOFT == 0
#undef RT_USING_TIMER_SOFT
#endif
#define RT_TIMER_THREAD_PRIO 4
#define RT_TIMER_THREAD_STACK_SIZE 512
#define RT_TIMER_TICK_PER_SECOND 100
#define RT_USING_SEMAPHORE //信号量使能
#define RT_USING_MAILBOX //邮箱使能
#define RT_USING_HEAP //堆使能
#define RT_USING_SMALL_MEM //小内存使能
#define RT_USING_CONSOLE //控制台配置,重映射串口使能
#define RT_CONSOLEBUF_SIZE 128 //重映射串口内存大小
#define RT_CONSOLE_DEVICE_NAME "uart2" //重映射串口号
#if defined(RTE_FINSH_USING_MSH)//FINSH 配置。
#define RT_USING_FINSH
#define FINSH_USING_MSH
#define FINSH_USING_MSH_ONLY
#define __FINSH_THREAD_PRIORITY 5
#define FINSH_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 8 * __FINSH_THREAD_PRIORITY + 1)
#define FINSH_THREAD_STACK_SIZE 512
#define FINSH_HISTORY_LINES 1
#define FINSH_USING_SYMTAB
#endif
#if defined(RTE_USING_DEVICE) //设备配置。
#define RT_USING_DEVICE
#endif
#endif
rtconfig.h 头文件对比默认功能的内容修改的不多,具体是: 注释掉头文件 RTE_Components.h、 修
改 了 RT_THREAD_PRIORITY_MAX 、 RT_TICK_PER_SECOND 和
RT_MAIN_THREAD_STACK_SIZE 这三个宏的大小。
/*
* File : board.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2017-07-24 Tanek the first version
*/
/*初始化硬件相关头文件*/
#include "board.h"
/*初始化rtthread相关头文件*/
#include
#include
#if 0
/*========================================================*/
#define _SCB_BASE (0xE000E010UL)
#define _SYSTICK_CTRL (*(rt_uint32_t *)(_SCB_BASE + 0x0))
#define _SYSTICK_LOAD (*(rt_uint32_t *)(_SCB_BASE + 0x4))
#define _SYSTICK_VAL (*(rt_uint32_t *)(_SCB_BASE + 0x8))
#define _SYSTICK_CALIB (*(rt_uint32_t *)(_SCB_BASE + 0xC))
#define _SYSTICK_PRI (*(rt_uint8_t *)(0xE000ED23UL))
// Updates the variable SystemCoreClock and must be called
// whenever the core clock is changed during program execution.
extern void SystemCoreClockUpdate(void);
// Holds the system core clock, which is the system clock
// frequency supplied to the SysTick timer and the processor
// core clock.
extern uint32_t SystemCoreClock;
static uint32_t _SysTick_Config(rt_uint32_t ticks)
{
if ((ticks - 1) > 0xFFFFFF)
{
return 1;
}
_SYSTICK_LOAD = ticks - 1;
_SYSTICK_PRI = 0xFF;
_SYSTICK_VAL = 0;
_SYSTICK_CTRL = 0x07;
return 0;
}
/*==========================================================*/
#endif
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#define RT_HEAP_SIZE 1024
static uint32_t rt_heap[RT_HEAP_SIZE]; // heap default size: 4K(1024 * 4)
RT_WEAK void *rt_heap_begin_get(void)
{
return rt_heap;
}
RT_WEAK void *rt_heap_end_get(void)
{
return rt_heap + RT_HEAP_SIZE;
}
#endif
/**
* This function will initial your board.
*/
/**
* @brief 重映射串口 DEBUG_USARTx 到 rt_kprintf()函数
* Note: DEBUG_USARTx 是在 bsp_usart.h 中定义的宏,默认使用串口 1
* @param str:要输出到串口的字符串
* @retval 无
*
* @attention
*
*/
void rt_hw_console_output(const char *str)
{
/* 进入临界段 */
rt_enter_critical();
/* 直到字符串结束 */
while (*str!='\0')
{
/* 换行 */
if (*str=='\n')
{
USART_SendData(DEBUG_USARTx, '\r');
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
}
USART_SendData(DEBUG_USARTx, *str++);
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
}
/* 退出临界段 */
rt_exit_critical();
}
/**
* @brief PVD电压监测配置函数
* Note: None
* @param None
* @retval 无
*
* @attention
*
*/
void PVD_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
/*使能 PWR 时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
/* 使能 PVD 中断 */
NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 配置 EXTI16 线(PVD 输出) 来产生上升下降沿中断*/
EXTI_ClearITPendingBit(EXTI_Line16);
EXTI_InitStructure.EXTI_Line = EXTI_Line16;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
//配置 PVD 级别 PWR_PVDLevel_2V6
PWR_PVDLevelConfig(PWR_PVDLevel_2V6);
/* 使能 PVD 输出 */
PWR_PVDCmd(ENABLE);
}
//硬件初始化
static void HardWareInit(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
ADC_DMA_ConfigInit();
OLED_ConfigInit();
USB_USART_Config();
TIMx_NVIC_Configuration();
Timer_out_ConfigInit();
Digital_GPIO_Config();
CANPro_Init();
PVD_Config();
IWDG_Config(IWDG_Prescaler_64 ,625);//看门狗溢出时间(1s)
}
void rt_hw_board_init()
{
#if 0
/* System Clock Update */
SystemCoreClockUpdate();
/* System Tick Configuration */
_SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
#endif
/*初始化Systick*/
SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
/* 硬件 BSP 初始化统统放在这里,比如 LED,串口, LCD 等 */
HardWareInit();
/* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}
void SysTick_Handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
rt_tick_increase();
/* leave interrupt */
rt_interrupt_leave();
}
修改一: 在 user 目录下新建一个 board.h 头文件,用来包含固件库和
BSP 相关的头文件和存放 board.c 里面的函数声明.
修改二:SysTick 相关的寄存器和初始化函数统统屏蔽掉,将由固件库
文件 core_cm3/4/7 里面的替代。
修改三:SysTick 初始化函数由固件库文件 core_cm3/4/7 里面的
SysTick_Config()函数替代。
如果使用的是 HAL 库 ,则必须添加系统时钟初始化函数,这个函数在我们利用 STM32CubeMX 代码生成工具配置工程时会自动给我们生成,我们只需添加到 rt_hw_board_init()函数进行初始化即可。同时只有在使用 HAL 库时才需要添加 core_delay.c 和 core_delay.h 文件。