目录
前言
注:个人记录,本人很菜,如果对你有帮助最好,没有的话我很抱歉,本人小菜鸡,欢迎指正,移植部分参考这位大佬的:
RT-thread的STM32f103c8t6移植_stm32f103c8t6 rtthread-优快云博客
非常感谢!!
主要分为两个部分:
第一部分正点原子找的代码原先应用于f103zet6,修改到f103c8t6上;
第二部分进行RTThread的移植。
提示:以下是本篇文章正文内容,下面案例可供参考
一、F103ZET6代码更改配置到F103C8T6
此处使用的是正点原子资料的跑马灯实验代码
1.keil内部设置更改
首先打开工具栏的魔术棒(目标选项),将下方的芯片类型改成STM32F108C8,如果没有F103这个选项说明没有安装对应的芯片包,去官网下载安装即可。
其次点开C/C++选项卡,将Define中的STM32F10X_HD,USE_STDPERIPH_DRIVER改为STM32F10X_MD,USE_STDPERIPH_DRIVER;这是因为C8T6的芯片资源比ZET6小,不是同一种类型的芯片。
接着修改调试选项卡,将框起来的部分全部修改成图二所示的内容,不然调试起来会卡在系统函数里走不出来。
2.项目文件修改
此处的启动文件也是zet6用的,也需要修改成_md.s文件,如图一所示。
但是正点原子给的例程这边只给了一个.s文件,如图二所示,所以需要外部找一下。
完整的文件应该有这么多,我们这边用的是_md.s文件,如图所示。
最后再回到keil里将原来的_hd文件移除,换成_md.s文件。到此就换成了C8T6的代码
二、RTTHREAD手动移植
此处参考的另外一篇博客的内容,原内容地址:RT-thread的STM32f103c8t6移植_stm32f103c8t6 rtthread-优快云博客
网上找了不少的资料,大部分是用cube去进行移植的,我没有用过cube,所以好不容易找到了这一片在kuil上移植的。此外好像env工具可以便捷的进行移植,我这边还没有接触到。
1.安装rtthread的pack包
rtthread的pack包直接去官网下载即可,此处给出链接:
https://www.rt-thread.org/download/mdk/RealThread.RT-Thread.3.1.5.pack
下载完之后直接打开即可安装。备注:在keil5软件里也可以安装,但我没有尝试。
下载后依次打开图中对应红框,其中shell是相关的组件,kenel是系统的内核,device是相关的设备。此处可以先勾选kenel。然后点ok就完成内核的下载了。
2.相关配置文件修改
因为rtthread内核里的一些函数和我们自己的一些函数会有重定义,所以需要修改一些函数。
移植主要包括全局中断、上下文切换相关的API以及时钟节拍的移植。
1.首先要屏蔽掉原有的异常处理函数void SysTick_Handler(void)和悬挂处理函数void PendSV_Handler(void),这两个函数分别是cortex-M3自己的时钟节拍以及上下文切换函数,我们需要屏蔽掉以防重复定义。
2.在board.c文件的void rt_hw_board_init(void)函数当中注释蓝色的框内的代码,并且添加
SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
这个代码的意思是配置RTTHREAD每一个tick的时长。
接着在此文档中额外添加一个函数,然后在board.c文件中添加#include “stm32f103x.h”:
void SysTick_Handler()
{
rt_interrupt_enter();
rt_tick_increase();
rt_interrupt_leave();
}
至此内核就全部移植完成,可以自己调试试一下,如果有重复定义的错误,进入文件中将对应的函数注释掉就行。
3.FINSH组件添加
finsh组件很好用,可以脱离板子进行调试,非常便捷。
首先可以添加FINSH组件的源码,如上文添加内核一样,将shell选上。
接着需要实现串口初始化的函数,一般模板都会自带,但是为了防止冲突我还是直接复制了大佬写的代码。如下:
#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;
}
usart.h文件
#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
其次修改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_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 */
最后更改一下配置文件中的宏定义,将rtconfig.h中的RT_USING_CONSOLE宏定义打开,以及包含#include “finsh_config.h”
修改完就可以正常运行了。调试就可以出现串口,具体使用方法此处不赘述。
总结
个人的一次学习的总结,仅供参考,本人很菜,如果有问题很抱歉。移植部分主要参考了上文链接中的大佬的步骤。很感谢大佬!
其次这个方法移植的话只能在keil中运行,因为他的RTTHREAD对应的系统文件不在我们自己的项目文件里,实际上在keil的路径那边,所以如果移到别的编译器里面就没法识别到RTTHREAD的相关文件了。我个人觉得还是项目文件中有对应的系统代码会好一点,目前正在琢磨。