RTThread 重定义rt_hw_console_output函数
在学习单片机时,我们会经常使用printf函数进行信息输出,方便调试程序,而学习RT-Thread时也会经常使用rt_kprintf函数进行信息输出,所以在移植完RT-Thread时,我们首先需要定义rt_hw_console_output使得rt_kprintf函数能正常运行
一、初始化UART
rt_kprintf函数最终都是通过串口进行日志打印的,所以在使用之前需要对uart外设进行初始化。下面是STM32F10x的初始化程序:
void USART1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* 使能 USART1 时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
/* USART1 使用IO端口配置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA
/* USART1 工作模式配置 */
USART_InitStructure.USART_BaudRate = 115200; //波特率设置:115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位数设置:8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位设置: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); //初始化USART1
USART_Cmd(USART1, ENABLE);// USART1使能
}
注意:需要在board.c文件中的rt_hw_board_init()函数中进行初始化程序的调用,因为在完成RT-Thread的启动后(也就是在main函数运行之前)会打印相应的启动信息,如果放在mian函数中进行串口的初始化,会使程序跑飞。
二、rt_kprintf输出的两种方式
rt_kprintf()支持两种方式的输出,一种是当使用设备驱动时,将设备将作为控制台;另外一种是当没有使用设备驱动时,系统通过rt_hw_console_output()函数处理rt_kprintf()输出的设备。从下面的代码可以看出两种输出方式的使用

注意:想要使用控制台时(或者rt_kprintf()时),需要使能RT_USING_CONSOLE,使能方式是在rtconfig.h文件中添加如下代码
#ifdef RT_USING_CONSOLE
三、自定义 rt_hw_console_output()
rt_hw_console_output()在哪里实现都是可以的,我是在自己编写的drv_usart.c文件中实现的,程序如下所示:
#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();
}
#endif
四、drv_usart.c文件
/***************************************
* 文件名 :usart1.c
* 描述 :配置USART1
* 实验平台:MINI STM32开发板 基于STM32F103C8T6
* 硬件连接:------------------------
* | PA9 - USART1(Tx) |
* | PA10 - USART1(Rx) |
* ------------------------
**********************************************************************************/
#include "drv_usart.h"
#include <stdarg.h>
#include "misc.h"
#include <stdio.h>
#include <rtthread.h>
#define DEBUG_USARTx USART1
void USART1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* 使能 USART1 时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
/* USART1 使用IO端口配置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA
/* USART1 工作模式配置 */
USART_InitStructure.USART_BaudRate = 115200; //波特率设置:115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位数设置:8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位设置: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); //初始化USART1
USART_Cmd(USART1, ENABLE);// USART1使能
}
#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();
}
#endif
五、下载测试

六参考文献
重映射串口到 rt_kprintf 函数(学习笔记):https://blog.csdn.net/weixin_43772810/article/details/123652008
RTThread 重定义rt_hw_console_output函数的更多相关文章
- Qt 自定义model实现文件系统的文件名排序(重定义sort函数即可。忽然开窍了:其实捕捉点击Header事件,内部重排序,全部刷新显示即可)
前段时间,需要做一个功能是要做文件系统的排序的功能.由于是自己写的model, 自己定义的数据结构.最初的想法只有一个自己去实现文件夹跟文件名的排序算法,不过感觉比较费时间.后来想到的是QFileSy ...
- 【转】深入理解C++的动态绑定和静态绑定 & 不要重定义虚函数中的默认参数
为了支持c++的多态性,才用了动态绑定和静态绑定.理解他们的区别有助于更好的理解多态性,以及在编程的过程中避免犯错误.需要理解四个名词:1.对象的静态类型:对象在声明时采用的类型.是在编译期确定的.2 ...
- 《STM32CubeMX配置STM32H743XI工程》第一讲《初始化UART,重定义printf函数,点亮一个LED灯》
1.打开STM32CubeMX软件->新建一个工程(软件自行到ST官网下载安装) 2.输入对应的芯片型号(本次基于野火STM32H743XI Pro 开发板)点击Start Project生成项 ...
- C++函数重载,重写,重定义
目录 1 重载 2 重写 3 重定义 4 函数重载二义性 笔者原创,转载请注明出处 C++中经常会提到重载,除了重载,还有重写,重定义,下面对这三个概念逐一进行区分 1 重载 函数重载是同 ...
- C++ 类的多态二(函数重载--函数重写--函数重定义)
//函数重载--函数重写--函数重定义 #include<iostream> using namespace std; /* 函数重载: 必须在一个类中进行(子类无法重载父类中的函数) 子 ...
- 事件Qevent的接受和忽略 和重定义 事件过滤器(转)
转载来源:http://blog.csdn.net/seanyxie/article/details/5821970 事件处理流程:某个事件发生------>exec()循环会接收到这个事件-- ...
- C++ 虚函数及重载、重定义、重写
#include<iostream> usingnamespace std; class BASE { public: BASE()=default; BASE(int publicVal ...
- C++纯虚函数、虚函数、实函数、抽象类,重载、重写、重定义
首先,面向对象程序设计(object-oriented programming)的核心思想是数据抽象.继承.动态绑定.通过数据抽象,可以使类的接口与实现分离,使用继承,可以更容易地定义与其他类相似但不 ...
- C++编译错误 --- 成员函数定义在 .h 文件中出现重定义错误(Error LNK 2005)
今天写了一个简单的类,定义在 .h 文件中, 类很简单就将其成员函数定义在了一起(class类后面).运行的时候出现了如下图所示的编译错误(error LNK2005) 查资料,大部分都是说需要加上 ...
- c++中的函数重载、函数重写、函数重定义
目录 一.函数重载 二.函数重写 三.函数重定义 为了更加深刻的理解 函数重载.重写.重定义,我们可以带着如下这两个问题去思考: 1.子类中是否可以定义父类中的同名成员?为什么? 可以,因为子类与父类 ...
随机推荐
- .NET分布式Orleans - 5 - 持久化
在分布式系统中,数据的持久化是至关重要的一环. Orleans 7 引入了强大的持久化功能,使得在分布式环境下管理数据变得更加轻松和可靠. 本文将介绍什么是 Orleans 7 的持久化,如何设置它以 ...
- Minlexes题解
\(\texttt{Problem Link}\) 简要题意 在一个字符串 \(s\) 中,对于每个后缀,任意删掉一些相邻的相同的字符,使得字符串字典序最小. 注意:删掉之后拼起来再出现的相邻相同字符 ...
- 实例演示如何使用CCE XGPU虚拟化
本文分享自华为云社区<CCE XGPU虚拟化的使用>,作者: 可以交个朋友. 一 背景 在互联网场景中,用户的AI训练和推理任务对GPU虚拟化有着强烈的诉求.GPU卡作为重要的计算资源不管 ...
- ASCII编码的全面介绍
1. ASCII编码的定义和历史 ASCII(American Standard Code for Information Interchange)是一种用于将文本字符转换为数字编码的标准,最初由美国 ...
- #线性基,点分治#洛谷 3292 [SCOI2016]幸运数字
题目 分析 题目就是将\(x\)到\(y\)路径上的线性基合并求解, 这里用的是点分治,每次换根到重心的时候维护前缀线性基, 查询的时候如果属于不同的子树就能询问答案,记得\(x=y\)要特判 代码 ...
- #斯坦纳树#洛谷 4294 [WC2008]游览计划
题目 分析 几乎就是模板题,考虑不同点就是它是点权, 所以在求两个子集的时候要减去这个点的点权, 还有一点恶心的就是要输出方案,令人作呕 代码 #include <cstdio> #inc ...
- go~istio加载wasm的步骤
参考 https://github.com/higress-group/proxy-wasm-go-sdk/tree/main/proxywasm https://github.com/tetrate ...
- Apache Maven ToolChains的使用
目录 简介 Toolchains的介绍 Toolchains的例子 Toolchains支持 总结 简介 Maven是java中非常有用和常用的构建工具,基本上现在大型的java项目都是Maven和g ...
- Python 集合(Sets)2
访问项 您无法通过引用索引或键来访问集合中的项.但是,您可以使用for循环遍历集合项,或者使用in关键字检查集合中是否存在指定的值. 示例,遍历集合并打印值: thisset = {"app ...
- C# Dev GridControl小结
1. 如何解决单击记录整行选中的问题 View->OptionsBehavior->EditorShowMode 设置为:Click 2. 如何新增一条记录 (1).gridView.Ad ...