重映射串口到 rt_kprintf 函数(学习笔记)

本文参考自[野火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()的内容,测试成功。

在这里插入图片描述

实验效果

下面是真实的实验效果:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43772810/article/details/123652008
今日推荐