本文参考自[野火EmbedFire]《RT-Thread内核实现与应用开发实战——基于STM32》,仅作为个人学习笔记。更详细的内容和步骤请查看原文(可到野火资料下载中心下载)
在 RT-Thread 中,有一个打印函数
rt_kprintf()
,它可以输出各种信息,方便我们的调试。如果要想使用 rt_kprintf(),必须将控制台重映射到 rt_kprintf(),这个控制台可以是串口、CAN、USB、以太网等输出设备,用的最多的就是串口,接下来我们讲解下如何将串口重定向到 rt_kprintf()。
硬件初始化
这里要用到的硬件是串口,我直接拷贝了野火的串口底层代码,
修改board.c
文件,添加串口初始化函数
void rt_hw_board_init(void)
{
#if 0
/* TODO: OS Tick Configuration */
_SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
#endif
/* 初始化 SysTick */
SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
/* 硬件 BSP 初始化统统放在这里,比如 LED,串口,LCD 等 */
// LED初始化
LED_GPIO_Config();
// 串口初始化
USART_Config();
/* 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_hw_console_output()
rt_kprintf()
支持两种方式的输出,一种是当使用设备驱动时,将设备将作为控制台;另外一种是当没有使用设备驱动时,系统通过rt_hw_console_output()
函数处理rt_kprintf()
输出的设备。
rt_hw_console_output()
在board.c
中实现,下面的代码参考《RT-Thread内核实现与应用开发实战——基于STM32》,使用的是库函数。
#ifdef RT_USING_CONSOLE
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();
}
上面第一行表示要想使用控制台,还需要对其进行使能,方法:修改rtconfig.h
,开启对应宏定义。
编写测试代码
接下来我们创建线程来测试rt_kprintf()
,用的是动态线程(上一篇文章所用的代码)
#include "board.h"
#include "rtthread.h"
// 定义线程控制块指针
static rt_thread_t led0_thread = RT_NULL;
/******************************************************************************
* @ 函数名 : led0_thread_entry
* @ 功 能 : LED0线程入口函数
* @ 参 数 : parameter 外部传入的参数
* @ 返回值 : 无
******************************************************************************/
static void led0_thread_entry(void *parameter)
{
while(1)
{
LED0(ON);
rt_thread_delay(500); // 500个tick(500ms)
rt_kprintf("kprintf test, LED0_ON\r\n");
LED0(OFF);
rt_thread_delay(500);
rt_kprintf("kprintf test, LED0_OFF\r\n");
}
}
int main(void)
{
// 硬件初始化和RTT的初始化已经在component.c中的rtthread_startup()完成
// 创建一个动态线程
led0_thread = // 线程控制块指针
rt_thread_create("led0", // 线程名字
led0_thread_entry, // 线程入口函数
RT_NULL, // 入口函数参数
255, // 线程栈大小
5, // 线程优先级
10); // 线程时间片
// 开启线程调度
if(led0_thread != RT_NULL)
rt_thread_startup(led0_thread);
else
return -1;
}
使用Keil Debug仿真
如果手头上没有硬件,我们可以使用Keil的Debug功能来测试串口打印,
- 首先将调试修改成软件模拟调试:
- 打开串口调试窗口(此时串口只能读不能写,还没有实现串口发送)
- 但是我第一次运行时出现了如下报错:
- 到网上找了一下解决方法,发现软件调试是需要指定芯片型号的(这的确很合理)
- 将对应的DLL和参数填写到模拟仿真下面的对应编辑框中,
- 再次软件仿真,可以看到
UART #1
串口打印出了线程里rt_kprintf()
的内容,测试成功。
实验效果
下面是真实的实验效果: