准备工作
裸机工程模板
移植之前需要准备一个STM32裸机工程,这个裸机工程要能使用串口发送数据、在串口中断中接收数据。因为后面移植之后主要用串口来验证程序。
这里是我移植完成的工程:ProjectTemplate
RT-Thread 准备
使用的是3.1.5版本。下载地址:RTT官网
下载完成后,我们打开跟我们最相近的工程模板:stm32f103-msh
打开工程后,打开rtconfig.h的文件路径,把rtconfig.h复制到裸机工程中(如下图)。按这个方法,再把board.c复制到裸机工程中。
最后把RT-Thread中,除了bsp文件夹全部拷贝到裸机工程。
RT-Thread添加到工程
接下来要把复制过来的文件添加到工程,需要添加到工程的文件如下:
文件夹 | 作用 |
---|---|
src | 这是RTT内核的源码 |
libcpu\arm\cortex-m3 | 需要把context_rvds.S和cpuport.c添加到工程 |
components\finsh | finsh 控制台相关的文件 |
文件添加完成后,效果如下图
让工程包含头文件路径
文件夹 | 作用 |
---|---|
include | 必需的头文件 |
include\libc | 必需的头文件 |
components\finsh | finsh头文件路径 |
Finsh 函数实现
rt_kprintf
要实现rt_kprintf串口输出,需要重新实现rt_hw_console_output函数
void rt_hw_console_output(const char *str)
{
rt_size_t i = 0, size = 0;
char a = '\r';
size = rt_strlen(str);
for (i = 0; i < size; i++)
{
if (*(str + i) == '\n')
{
USART_SendData(USART1, (uint8_t)a);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
{;}
}
USART_SendData(USART1, str[i]);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
{;}
}
}
Finsh接收
Finsh的接收,我们使用的是中断方式,需要在rt_hw_board_init函数最后先创建一个信号量:
/* 创建一个动态信号量,初始值是0 */
g_finshSem = rt_sem_create("finshSem", 0, RT_IPC_FLAG_FIFO);
在串口中断中释放信号量:
void USART1_IRQHandler(void)
{
// uint8_t recv;
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
// recv = USART_ReceiveData(USART1);
rt_sem_release(g_finshSem); //释放信号量
}
}
finsh获取字符函数:
char rt_hw_console_getchar(void)
{
int ch = -1;
// 获取信号量
rt_sem_take(g_finshSem, RT_WAITING_FOREVER);
ch = USART_ReceiveData(USART1);
return ch;
}
这样一来,一旦串口接收中断收到数据,程序就马上在中断中释放信号量,rt_hw_console_getchar立即获得数据。
RT-Thread配置文件
我使用的配置文件详情
/* RT-Thread config file */
#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__
// <<< Use Configuration Wizard in Context Menu >>>
// <h> 基本配置
// <o> 线程优先级的最大级别 8-256
// <i>Default: 32
#define RT_THREAD_PRIORITY_MAX 32
// <o> 操作系统每秒滴答数
// <i>Default: 1000 (1ms)
#define RT_TICK_PER_SECOND 1000
// <o> CPU架构数据访问的对齐大小
// <i>Default: 4
#define RT_ALIGN_SIZE 4
// <o> 对象名称的最大程度 2-16
// <i>Default: 8
#define RT_NAME_MAX 8
// <c1> 使用RT-Thread组件初始化
// <i>Using RT-Thread components initialization
#define RT_USING_COMPONENTS_INIT
// </c>
#define RT_USING_USER_MAIN
// <o> 主线程的堆栈大小 1-4086
// <i>Default: 512
#define RT_MAIN_THREAD_STACK_SIZE 512
// </h>
// <h> 调试配置
// <c1> 启用内核调试配置
// <i>Default: enable kernel debug configuration
//#define RT_DEBUG
// </c>
// <o> 启用组件初始化调试配置 0-1
// <i>Default: 0
#define RT_DEBUG_INIT 0
// <c1> 线程堆栈溢出检测
// <i> Diable Thread stack over flow detect
//#define RT_USING_OVERFLOW_CHECK
// </c>
// </h>
// <h> 钩子函数(hook)配置
// <c1> 使用钩子函数(hook)
// <i>using hook
//#define RT_USING_HOOK
// </c>
// <c1> 使用空闲钩子函数(idle hook)
// <i>using idle hook
//#define RT_USING_IDLE_HOOK
// </c>
// </h>
// <e> 软件定时器配置
// <i> Enables user timers
#define RT_USING_TIMER_SOFT 1
#if RT_USING_TIMER_SOFT == 0
#undef RT_USING_TIMER_SOFT
#endif
// <o> 定时器线程的优先级 0-31
// <i>Default: 4
#define RT_TIMER_THREAD_PRIO 4
// <o> 定时器线程的堆栈大小 0-8192
// <i>Default: 512
#define RT_TIMER_THREAD_STACK_SIZE 512
// </e>
// <h>IPC(线程间通信)配置
// <c1> 使用信号量 Semaphore
// <i>Using Semaphore
#define RT_USING_SEMAPHORE
// </c>
// <c1> 使用互斥量 Mutex
// <i>Using Mutex
#define RT_USING_MUTEX
// </c>
// <c1> 使用事件 Event
// <i>Using Event
//#define RT_USING_EVENT
// </c>
// <c1> 使用邮箱 MailBox
// <i>Using MailBox
#define RT_USING_MAILBOX
// </c>
// <c1> 使用消息队列 Message Queue
// <i>Using Message Queue
//#define RT_USING_MESSAGEQUEUE
// </c>
// </h>
// <h> 内存管理配置
// <c1> 使用动态内存堆 Dynamic Heap Management
// <i>Please modify RT_HEAP_SIZE if RT_USING_HEAP is enabled
#define RT_USING_HEAP
// </c>
// <c1> 使用小内存 small memory
// <i>using small memory
#define RT_USING_SMALL_MEM
// </c>
// <c1> 使用极小内存 tiny size of memory
// <i>using tiny size of memory
//#define RT_USING_TINY_SIZE
// </c>
// </h>
// <h> 控制台配置 console
// <c1> 使用控制台 console
// <i>Using console
#define RT_USING_CONSOLE
// </c>
// <o> 控制台缓冲区大小 1-1024
// <i>the buffer size of console
// <i>Default: 128 (128Byte)
#define RT_CONSOLEBUF_SIZE 256
// </h>
// <h>FinSH 组件配置
// <c1> 使用Fnish组件
// <i>Select this choice if you using FinSH
#include "finsh_config.h"
// </c>
// </h>
// <h>Device 设备驱动配置
// <c1> 使用 device 设备驱动
// <i>using device framework
//#define RT_USING_DEVICE
// </c>
// </h>
// <<< end of configuration section >>>
#endif