44 RT-Thread Nano移植到stm32F103CBT6 (STD标准库)

本文详细介绍了如何从零开始将 RT-Thread Nano 移植到 STM32F103C8T6 开发板的过程。包括下载源码、修改工程配置、解决编译错误等步骤,并最终实现 LED 闪烁功能。

一、前言

最近在学习rt-thread,然后网上有介绍用RT-Thread Studio和stm32cubex结合进行开发,还有用rt-thread nano提供的pack直接开发,但是这种方式真的不太行,对于新手而言,不能很好的了解整个代码的结构。

为此,就怀着跟前面网友一样的心思,准备要自己拷贝代码,一步一步来对rt-thread进行移植,然后发现还是挺简单的,如果rt-thread已经移植过相应的cpu的话,那简直移植的方便就超级简单了。

本文章把rt-thread nano移植到stm32f103c8t6,然后也是基于STD标准库进行移植的,网上比较多的是基于HAL库进行移植的,写该文章一是为了下次自己回来看的时候能记忆起来;二是也为新手提供一种思路,如果他们要学习的话。

然后再说说,为什么选用rt-thread,第一是因为国产;第二是因为它能有像Linux的控制台;第三我只想要用一个线程调用的核,所以就选用了它!!挺好的加入支持国产的道路。

二、rt-thread移植记录

  1. stm32-led工程准备。

本次移植RT-Thread Nano内核到一个stm32f103cBt6标准库的一个led工程中,所以需要准备一个点灯程序,其目录如下图示。

 

 

移植前的led点灯工程主程序,以及编译后的大小如下图示。移植前程序所占ROM大小为:2216+268=2484字节;所用RAM:3840+48=3888字节;

2.下载RT-Thread Nano内核

首先,到官网上下载RT-Thread Nano源码,如下图示,本次下载的是rt-thread-3.1.3。下载链接:https://www.rt-thread.org/page/download.html

3.拷贝文件到目标led工程

首先,在原有的led工程的目录下,建立一个RT-Thread目录,如下图示。

然后打开rt-thread-3.1.3,拷贝下面三个目录的内容到刚建好的RT-Thread目录中。

拷贝完成后,删除掉libcpu里面没用到的文件,留下有用的。

最后只剩下面这个cortex-m3目录。

然后打开rt-thread-3.1.3目录下的dsp木,把拷贝board.c和rtconfig.h到工程的RT-Thread目录下。

4.添加目录及文件到led的keil工程。

把board.c和rtconfig.h两个文件,添加这两个文件到User目录下。

5.编译工程解决错误

编译的时候肯定会出现这三个问题,打开代码,定位到这三个函数,把led工程原有的这三个函数注释掉,因为RT-Thread已经实现了这三个函数,所以导致重定义。

注释:HardFault_Handler,如下图示:

注释:PendSV_Handler和SysTick_Handler

然后编译,发现编译通过,然后继续移植。

6.更改board.c文件

RT-Thread系统框架下,设备的时钟及硬件初始化都是放在board.c文件中的,我们只需要在rt_hw_board_init函数配置好,系统时钟和滴答定时器。

然后我把自己的main函数的时钟初始化SystemInit函数拷贝到rt_hw_board_init函数中。

主函数改成这样。

int main(void)
{

	LED_Init(); //LED 端口初始化 
	

	while(1)
	{
		
		LED_SetRGBLight(RGBLED_MODE_Y);
        rt_thread_mdelay(1000);
		LED_SetRGBLight(RGBLED_MODE_G);
        rt_thread_mdelay(1000);

	}

	return 0;
}

然后对工程重新编译,给予RT-Thread 内核的led工程编译通过,下载到开发板,led正常一闪一闪。

编译前我把邮箱和信号量的宏注释掉,关闭了线程通信的方式,所以可以看到移植后,代码量ROM:4004+576=4580,RAM:4720+112=4832

7.添加Finish控制

第一步:在rtconfig.h中确定RT_USING_CONSOLE和RT_USING_FINSH已经打开,如图所示。

第二步,串口初始化。

首先,在board.c实现rt_hw_console_getchar函数,然后再kservice实现rt_hw_console_output函数,下列使用的是标准库,如下图所示。

char rt_hw_console_getchar(void)
{
	int ch = -1;
	if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
	{
		ch = (int)USART_ReceiveData(USART1);
	}
	else
	{
		if(USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET)
		{
			USART_ClearFlag(USART1,USART_FLAG_TC);
		}
		rt_thread_mdelay(10);
	}
	return ch;	
}
RT_WEAK void rt_hw_console_output(const char *str)
{
    /* empty console output */
	rt_size_t i = 0, size = 0;
	char a = '\r';

	USART_ClearFlag(USART1, USART_FLAG_TC);
	
	size = rt_strlen(str);
	for (i = 0; i < size; i++)
	{
		if (*(str + i) == '\n') 
		{
			USART_SendByte(USART1, a);
		}
		USART_SendByte(USART1, *(str + i));
	}
}

 

然后实现串口初始化,如下图示。但这里有一个坑,因为默认的shell使用的是轮询的方式实现,所以串口初始化这里,不能启动中断接收,否则shell将不正常。



void uart1_init(u32 bound)
{
	//GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);	//使能USART1,GPIOA时钟

	//USART1_TX   GPIOA.9
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9

	//USART1_RX	  GPIOA.10初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

	//Usart1 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器

	//USART 初始化设置
	USART_DeInit(USART1);
	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	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_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
	USART_Cmd(USART1, ENABLE);                    //使能串口1 
	USART_ClearFlag(USART1, USART_FLAG_TC);
}

然后,将初始化放在board.c的rt_hw_board_init函数里面,如下图示。

void rt_hw_board_init()
{
		SystemInit();				//配置系统时钟为72M 

	  /* System Tick Configuration */
    _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);

		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
		uart1_init(115200); 		//调试串口

    /* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}

到此,算是通过拷贝代码的方式将rt-thread搞到自己的开发板上了吧!

over!

 

以下是基于STM32CubeIDE在STM32F103CBT6芯片上实现点灯的教学内容: ### 1. 环境准备 - 安装STM32CubeIDE开发环境。可以从ST官方网站下载并安装。 - 准备好STM32F103CBT6开发板及相应的硬件连接,确保开发板通过USB线连接到电脑。 ### 2. 创建新工程 - 打开STM32CubeIDE,选择`File` -> `New` -> `STM32 Project`。 - 在弹出的窗口中,选择`Board Selector`,在搜索框中输入`STM32F103CBT6`,选择对应的开发板型号,然后点击`Next`。 - 输入工程名称和保存路径,点击`Finish`完成工程创建。 ### 3. 配置引脚 - 打开`STM32CubeMX`图形化配置工具(在工程中双击`.ioc`文件)。 - 在`Pinout & Configuration`界面,找到要控制的LED连接的引脚(例如,假设LED连接到`PC13`),将其模式设置为`GPIO_Output`。 ### 4. 生成代码 - 配置完成后,点击`Project` -> `Generate Code`,在弹出的对话框中点击`Yes`,STM32CubeIDE会自动生成初始化代码。 ### 5. 编写点灯代码 - 打开`main.c`文件,在`main`函数的`while(1)`循环中添加控制LED的代码。示例代码如下: ```c #include "main.h" #include "stm32f1xx_hal.h" void SystemClock_Config(void); static void MX_GPIO_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); while (1) { // 点亮LED HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); HAL_Delay(1000); // 延时1秒 // 熄灭LED HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); HAL_Delay(1000); // 延时1秒 } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); /*Configure GPIO pin : PC13 */ GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); } void Error_Handler(void) { while(1) { } } ``` ### 6. 编译和下载 - 点击工具栏上的编译按钮(锤子图标)编译工程,确保没有编译错误。 - 连接好开发板,点击下载按钮(箭头图标)将程序下载到STM32F103CBT6芯片中。 ### 7. 验证结果 - 下载完成后,开发板上连接到`PC13`引脚的LED应该会以1秒的间隔闪烁。
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值