在学习单片机时,我们会经常使用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函数的更多相关文章

  1. Qt 自定义model实现文件系统的文件名排序(重定义sort函数即可。忽然开窍了:其实捕捉点击Header事件,内部重排序,全部刷新显示即可)

    前段时间,需要做一个功能是要做文件系统的排序的功能.由于是自己写的model, 自己定义的数据结构.最初的想法只有一个自己去实现文件夹跟文件名的排序算法,不过感觉比较费时间.后来想到的是QFileSy ...

  2. 【转】深入理解C++的动态绑定和静态绑定 & 不要重定义虚函数中的默认参数

    为了支持c++的多态性,才用了动态绑定和静态绑定.理解他们的区别有助于更好的理解多态性,以及在编程的过程中避免犯错误.需要理解四个名词:1.对象的静态类型:对象在声明时采用的类型.是在编译期确定的.2 ...

  3. 《STM32CubeMX配置STM32H743XI工程》第一讲《初始化UART,重定义printf函数,点亮一个LED灯》

    1.打开STM32CubeMX软件->新建一个工程(软件自行到ST官网下载安装) 2.输入对应的芯片型号(本次基于野火STM32H743XI Pro 开发板)点击Start Project生成项 ...

  4. C++函数重载,重写,重定义

    目录 1 重载 2 重写 3 重定义 4 函数重载二义性   笔者原创,转载请注明出处   C++中经常会提到重载,除了重载,还有重写,重定义,下面对这三个概念逐一进行区分 1 重载   函数重载是同 ...

  5. C++ 类的多态二(函数重载--函数重写--函数重定义)

    //函数重载--函数重写--函数重定义 #include<iostream> using namespace std; /* 函数重载: 必须在一个类中进行(子类无法重载父类中的函数) 子 ...

  6. 事件Qevent的接受和忽略 和重定义 事件过滤器(转)

    转载来源:http://blog.csdn.net/seanyxie/article/details/5821970 事件处理流程:某个事件发生------>exec()循环会接收到这个事件-- ...

  7. C++ 虚函数及重载、重定义、重写

    #include<iostream> usingnamespace std; class BASE { public: BASE()=default; BASE(int publicVal ...

  8. C++纯虚函数、虚函数、实函数、抽象类,重载、重写、重定义

    首先,面向对象程序设计(object-oriented programming)的核心思想是数据抽象.继承.动态绑定.通过数据抽象,可以使类的接口与实现分离,使用继承,可以更容易地定义与其他类相似但不 ...

  9. C++编译错误 --- 成员函数定义在 .h 文件中出现重定义错误(Error LNK 2005)

    今天写了一个简单的类,定义在 .h 文件中, 类很简单就将其成员函数定义在了一起(class类后面).运行的时候出现了如下图所示的编译错误(error LNK2005) 查资料,大部分都是说需要加上 ...

  10. c++中的函数重载、函数重写、函数重定义

    目录 一.函数重载 二.函数重写 三.函数重定义 为了更加深刻的理解 函数重载.重写.重定义,我们可以带着如下这两个问题去思考: 1.子类中是否可以定义父类中的同名成员?为什么? 可以,因为子类与父类 ...

随机推荐

  1. GPT-SoVITS教程,接入酒馆AI,SillyTavern-1.11.5,让AI女友声若幽兰

    本次分享一下如何将GPT-SoVITS接入SillyTavern-1.11.5项目,让让AI女友声若幽兰,首先明确一下,SillyTavern-1.11.5只是一个前端项目,它没有任何大模型文本生成能 ...

  2. Anaconda 创建新环境

    使用conda 命令创建一个名为 python311 的python版本为3.11的环境 conda create -n python311 python=3.11 接着使用 conda activa ...

  3. Nancy支持跨域请求

    public class NancyBootstrapper : DefaultNancyBootstrapper { /// <summary> /// nancy配置 /// < ...

  4. java 计算两个日期相差工作日天数

    import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.DayOfWeek; impo ...

  5. C# 获取QQ会话聊天信息

    利用UIAutomation获取QQ会话聊天信息 AutomationElement window = AutomationElement.FromHandle(get.WindowHwnd); Au ...

  6. KingbaseES 逻辑读与物理读

    oracle数据库中逻辑读,物理读 数据访问方式:数据库少不了和操作系统进行数据交互,表数据最好的方式是从数据库共享池中访问到,避免发生磁盘IO,当然如果共享池中没有访问到数据就难免发生磁盘IO. 物 ...

  7. KingbaseES变更表结构表重写问题

    在实际项目使用数据库的过程中修改字段类型这类需求比较常见. 一.修改表字段类型需要知道: 1.修改表结构可能会导致表进行重写(表OID发生变化). 2.修改表结构带有索引或者字段类型长度或者精度操作时 ...

  8. 12 CSS 的float属性

    12 CSS 的float属性 流动布局 流动模型(Flow),即文档流,浏览器打开HTML网页时,从上往下,从左往右,逐一加载. 在正常情况下,HTML元素都会根据文档流来分布网页内容的. 文档流有 ...

  9. #Kruskal重构树,Dijkstra,倍增#洛谷 4768 [NOI2018]归程

    题目传送门 分析 首先Dijkstra是必需的(关于SPFA,它死了233) 无向图,所以先求出1号节点到所有点的距离,然后肯定希望起点能驾驶到离一号点最短的汽车可到的地方 但是怎么办,考虑海拔大的边 ...

  10. #线段树分治,线性基,并查集#CF938G Shortest Path Queries

    题目 给出一个连通带权无向图,边有边权,要求支持 \(q\) 个操作: \(x\) \(y\) \(d\) 在原图中加入一条 \(x\) 到 \(y\) 权值为 \(b\) 的边 \(x\) \(y\ ...