整体介绍:
使用的单片机型号为stm32f103c8t6,之所以选择这款芯片还是因为其小巧玲珑,之后做一些小的项目时,使用比较方便,另外这款芯片也是大部分人入门学习的一款。
编译器使用的是keil5。
RT-thread 官方网站:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-nano/an0038-nano-introduction
移植前准备工作:
① 首先得有一份stm32f103c8t6的裸机程序,最简单的即可,如点灯。。。
② 在keil5编译环境下需要下载RT-thread 的nano pack包,可以直接在keil5软件内进行安装也可以离线下载后直接进行安装。这里推荐第二种,在keil5里面进行安装时下载速度一般都比较慢。
Nano pack包文末附的资源里面有。也可以自行下载:https://www.rt-thread.org/download/mdk/RealThread.RT-Thread.3.1.5.pack。

下载完成直接双击打开,全部保持默认一步一步往下走即可。
移植步骤:
① 首先打开准备好的裸机程序,添加nano pack软件包。


勾选之后点击“OK”就完成了nano pack包的添加。这样RT-thread的文件就添加到我们的工程当中了。
② 更改时钟与中断初始化
RT-thread操作系统会接管裸机程序当中原有的系统时钟与中断的初始化,所以我们要将裸机程序原有的系统时钟与中断的初始化屏蔽掉,然后在RT-thread的配置初始化文件当中去添加新的初始化函数。
首先要屏蔽掉原有的异常处理函数void SysTick_Handler(void)和悬挂处理函数void PendSV_Handler(void)

2、在board.c文件的void rt_hw_board_init(void)函数当中注释掉如下代码,并且添加
SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
如下图所示:

删除完成之后添加如下函数:
void SysTick_Handler()
{
rt_interrupt_enter();
rt_tick_increase();
rt_interrupt_leave();
}
并且在board.c文件顶部添加
#include “stm32f10x.h”
至此RT-thread核心的文件就全部移植完成。
此时如果编译有警告,请忽略,添加完后面的代码这个警告就自己消失了。
在主函数当中写一个线程实现led灯的闪烁。
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include <rtthread.h>
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void thread01_entry(void *param);
static rt_thread_t thread01 = RT_NULL;
int main()
{
LED_Init();
thread01 = rt_thread_create("thrad01", thread01_entry, RT_NULL, 512, 3, 20);
rt_thread_startup(thread01);
}
void thread01_entry(void *param)
{
while(1)
{
LED1 = 0;
rt_kprintf("hello \n");
rt_thread_mdelay(500);
LED1 = 1;
rt_thread_mdelay(500);
}
}
③ 添加Finsh组件,实现串口打印以及命令输入。
本人觉得RT-thread的Finsh是非常便捷的一种串口调试方式,在后期调式代码时可以提供非常便捷的方式。
实现串口初始化,下面是基于标准库的串口初始函数:
#include "usart.h"
#include <rtthread.h>
//int fputc(int ch,FILE *p) //函数默认的,在使用printf函数时自动调用
//{
// USART_SendData(USART1,(u8)ch);
// while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
// return ch;
//}
////串口1中断服务程序
////注意,读取USARTx->SR能避免莫名其妙的错误
//u8 USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
////接收状态
////bit15, 接收完成标志
////bit14, 接收到0x0d
////bit13~0, 接收到的有效字节数目
//u16 USART1_RX_STA=0; //接收状态标记
/*******************************************************************************
* 函 数 名 : USART1_Init
* 函数功能 : USART1初始化函数
* 输 入 : bound:波特率
* 输 出 : 无
*******************************************************************************/
int USART1_Init(void)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
//NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
/* 配置GPIO的模式和IO口 */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX //串口输出PA9
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入IO */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX //串口输入PA10
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */
//USART1 初始化设置
USART_InitStructure.USART_BaudRate = 115200;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_Cmd(USART1, ENABLE); //使能串口1
USART_ClearFlag(USART1, USART_FLAG_TC);
// USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
// //Usart1 NVIC 配置
// NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
// NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
// NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
return 0;
}
///*******************************************************************************
//* 函 数 名 : USART1_IRQHandler
//* 函数功能 : USART1中断函数
//* 输 入 : 无
//* 输 出 : 无
//*******************************************************************************/
//void USART1_IRQHandler(void) //串口1中断服务程序
//{
// u8 r;
// if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
// {
// r =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
// if((USART1_RX_STA&0x8000)==0)//接收未完成
// {
// if(USART1_RX_STA&0x4000)//接收到了0x0d
// {
// if(r!=0x0a)USART1_RX_STA=0;//接收错误,重新开始
// else USART1_RX_STA|=0x8000; //接收完成了
// }
// else //还没收到0X0D
// {
// if(r==0x0d)USART1_RX_STA|=0x4000;
// else
// {
// USART1_RX_BUF[USART1_RX_STA&0X3FFF]=r;
// USART1_RX_STA++;
// if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//接收数据错误,重新开始接收
// }
// }
// }
// }
//}
#ifndef _usart_H
#define _usart_H
#include "system.h"
#include "stdio.h"
//#define USART1_REC_LEN 200 //定义最大接收字节数 200
//extern u8 USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
//extern u16 USART1_RX_STA; //接收状态标记
int USART1_Init(void);
#endif
打开rtconfig.h文件当中的这个宏定义,并且删除board.c文件当中的这个两个报错。

修改board.c当中的串口初始化代码如下:
static int uart_init(void)
{
USART1_Init();
return 0;
}
INIT_BOARD_EXPORT(uart_init);
void rt_hw_console_output(const char *str)
{
rt_enter_critical();
/* 直到字符串结束 */
while ( *str != '\0' )
{
/* 换行 */
//RT-Thread 系统中已有的打印均以 \n 结尾,而并非 \r\n,所以在字符输出时,需要在输出 \n 之前输出 \r,完成回车与换行,否则系统打印出来的信息将只有换行
if ( *str == '\n' )
{
USART_SendData(USART1, '\r' );
while ( USART_GetFlagStatus( USART1, USART_FLAG_TXE ) == RESET );
}
USART_SendData( USART1, *str++ );
while ( USART_GetFlagStatus( USART1, USART_FLAG_TXE ) == RESET );
}
/* 退出临界段 */
rt_exit_critical();
}
添加Finsh源码:
编辑
编辑
这是编译有错误,点击错误进入文件,或者直接打开文件finsh_port.c并且替换文件的代码如下:
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include <rthw.h>
#include <rtconfig.h>
#include "system.h"
#ifndef RT_USING_FINSH
#error Please uncomment the line <#include "finsh_config.h"> in the rtconfig.h
#endif
#ifdef RT_USING_FINSH
RT_WEAK char rt_hw_console_getchar(void)
{
/* Note: the initial value of ch must < 0 */
int ch = -1;
//查询方式实现,记得将Usart1初始化中的中断接收配置相关代码注释掉
/*等待串口1输入数据*/
if( USART_GetFlagStatus(USART1, USART_FLAG_RXNE ) != RESET )
{
ch = ( int )USART_ReceiveData( USART1 );
USART_ClearFlag( USART1, USART_FLAG_RXNE );
}
else
{
if( USART_GetFlagStatus( USART1, USART_FLAG_ORE ) != RESET )
{
USART_ClearFlag( USART1, USART_FLAG_ORE );
}
rt_thread_mdelay( 10 );
}
return ch;
}
#endif /* RT_USING_FINSH */
至此就全部移植完成。
烧录后串口打印信息如下:
编辑
全部评论