printf重定向
Posted 旭日初扬
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了printf重定向相关的知识,希望对你有一定的参考价值。
目录
串口,最大支持数据位长度为9bit。(DATA) <= 0x1FF 是断言检测数据位是否不大于9bit 0001 1111 1111
1.1.2、宏定义的参数检查函数( assert_param())
一、printf重定向简介
c语言中printf函数默认输出设备是显示器,如果实现在串口或者LCD上显示,必须重定义标准库函数里面调用的输出设备定义的相关函数。
如:使用printf输出到串口,需要将fputc里面的输出指向串口,这一过程称为重定向。
int fputc(int ch,FILE *p) // 函数默认的,在使用printf函数时自动调用
{
USART_SendDate(USART1,(u8)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
return ch;
}
// 此函数定义在stdio.h中,调用此函数需先导入stdio.h头文件
1.1、fputc函数解析
使用此函数需要导入stdio.h头文件
/**
* @brief Transmits single data through the USARTx peripheral. 通过USARTx外设传输单个数据
* @param USARTx: Select the USART or the UART peripheral. 选择USART或UART外设
* This parameter can be one of the following values:
* USART1, USART2, USART3, UART4 or UART5.
* @param Data: the data to transmit. 传输的数据
* @retval None
*/
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)/*
*/
{
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));/*#define IS_USART_ALL_PERIPH(PERIPH) (((PERIPH) == USART1) || \\
((PERIPH) == USART2) || \\
((PERIPH) == USART3) || \\
((PERIPH) == UART4) || \\
((PERIPH) == UART5))USART1, USART2, USART3, UART4 or UART5
*/
assert_param(IS_USART_DATA(Data));
/*#define IS_USART_DATA(DATA) ((DATA) <= 0x1FF) // 串口,最大支持数据位长度为9bit。(DATA) <= 0x1FF 是断言检测数据位是否不大于9bit 0001 1111 1111
*/
/* Transmit Data */
USARTx->DR = (Data & (uint16_t)0x01FF); Data & 0000 0001 1111 1111
}
1.1.1、0x01FF 解析
十进制: 1*16*16 + 16*15 +15 = 511
0*16*16*16(16的3次方) + 1*16*16(16平方)+15*16(F的十进制位15,16的一次方)+15*16的0次方
二进制 0000 0001 1111 1111
左边的0000 可省略不改变其真值
八进制:
串口,最大支持数据位长度为9bit。(DATA) <= 0x1FF 是断言检测数据位是否不大于9bit 0001 1111 1111
1.1.2、宏定义的参数检查函数( assert_param())
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
assert参数宏用于函数的参数检查。
* @param expr: If expr is false, it calls assert_failed function which reports
* the name of the source file and the source line number of the call
* that failed. If expr is true, it returns no value.
expr:如果expr为false,它将调用assert失败的函数,该函数返回失败调用的源文件的名称和源行号。如果expr为真,则不返回任何值
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) // 调用失败
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line); // 调用此函数 显示调用失败的文件 与代码行
#else
#define assert_param(expr) ((void)0) // 调用成功
#endif /* USE_FULL_ASSERT */
1.1.3、USART数据寄存器(DR)
1.1.4、USART结构框图
1.2、USART_GetFlagStatus()函数
/**
* @brief Checks whether the specified USART flag is set or not.
检测设置的串口标志是否修改
* @param USARTx: Select the USART or the UART peripheral.
选择串口或串口外设
* This parameter can be one of the following values:
这个参数有以下值
* USART1, USART2, USART3, UART4 or UART5.
* @param USART_FLAG: specifies the flag to check.
检查设置标志
* This parameter can be one of the following values:
* @arg USART_FLAG_CTS: CTS Change flag (not available for UART4 and UART5)
CTS 改变标志 (不适合于串口2和串口4)
* @arg USART_FLAG_LBD: LIN Break detection flag
Lin 中断检查标志
* @arg USART_FLAG_TXE: Transmit data register empty flag
发送寄存器 空的标志
* @arg USART_FLAG_TC: Transmission Complete flag
发送完成标志
* @arg USART_FLAG_RXNE: Receive data register not empty flag
接收数据寄存器不为空的标志
* @arg USART_FLAG_IDLE: Idle Line detection flag
空闲线路探测标志
* @arg USART_FLAG_ORE: OverRun Error flag
覆盖错误标志
* @arg USART_FLAG_NE: Noise Error flag
噪声错误标志
* @arg USART_FLAG_FE: Framing Error flag
框架错误标志
* @arg USART_FLAG_PE: Parity Error flag
奇偶校验错误标志
* @retval The new state of USART_FLAG (SET or RESET).
*/
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
{
FlagStatus bitstatus = RESET;
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_FLAG(USART_FLAG));
/* The CTS flag is not available for UART4 and UART5 */
if (USART_FLAG == USART_FLAG_CTS)
{
assert_param(IS_USART_123_PERIPH(USARTx));
}
if ((USARTx->SR & USART_FLAG) != (uint16_t)RESET) // SR状态寄存器
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
return bitstatus;
}
USART1->SR&0X40 !=set or reset
- 串口1操作状态寄存器的第7位 置0或置1
- stm32中很多标记位,只能硬件置1,软件写1是没有效果的,但是可以软件写0。
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); // USART_FLAG_TXE 发送数据寄存器空标志位
1.3、USART_ClearFlag()
功能:清除 USARTx 的待处理标志位。
注意:
- PE (Parity error 奇偶错误 ), FE (Framing error帧错误), NE (Noise error噪声错误), ORE (OverRun error 溢出错误) and IDLE (Idle line detected 检测到空闲线路错误) flags are cleared by software sequence: a read operation to USART_SR register (USART_GetFlagStatus()) followed by a read operation to USART_DR register (USART_ReceiveData()). - RXNE flag can be also cleared by a read to the USART_DR register (USART_ReceiveData()).
- PE (Parity error), FE (Framing error), NE (Noise error), ORE (OverRun error)和IDLE (IDLE line detected)标志被软件序列清除:一个读操作到USART SR寄存器(USART GetFlagStatus()),然后一个读操作到USART DR。
- TC标志也可以通过软件序列清除:一个到USART SR寄存器的读操作(USART GetFlagStatus()),接着一个到USART DR寄存器的写操作(USART SendData())。
- TXE标志仅通过写入USART DR寄存器来清除 (USART SendData())。
/**
* @brief Clears the USARTx's pending flags.
* @param USARTx: Select the USART or the UART peripheral.
* This parameter can be one of the following values:
* USART1, USART2, USART3, UART4 or UART5.
* @param USART_FLAG: specifies the flag to clear.
* This parameter can be any combination of the following values:
* @arg USART_FLAG_CTS: CTS Change flag (not available for UART4 and UART5).
* @arg USART_FLAG_LBD: LIN Break detection flag.
* @arg USART_FLAG_TC: Transmission Complete flag.
* @arg USART_FLAG_RXNE: Receive data register not empty flag.
*
* @note
* - PE (Parity error), FE (Framing error), NE (Noise error), ORE (OverRun
* error) and IDLE (Idle line detected) flags are cleared by software
* sequence: a read operation to USART_SR register (USART_GetFlagStatus())
* followed by a read operation to USART_DR register (USART_ReceiveData()).
* - RXNE flag can be also cleared by a read to the USART_DR register
* (USART_ReceiveData()).
* - TC flag can be also cleared by software sequence: a read operation to
* USART_SR register (USART_GetFlagStatus()) followed by a write operation
* to USART_DR register (USART_SendData()).
* - TXE flag is cleared only by a write to the USART_DR register
* (USART_SendData()).
* @retval None
*/
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)
{
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_CLEAR_FLAG(USART_FLAG));
/* The CTS flag is not available for UART4 and UART5 */
if ((USART_FLAG & USART_FLAG_CTS) == USART_FLAG_CTS)
{
assert_param(IS_USART_123_PERIPH(USARTx));
}
二、printf函数格式
printf("<格式化字符串>",<参量表>)
2.1、常用格式化规定字符:
- %d 按照十进制整形数打印
- %6d 按照十进制整形数打印,至少6个字符宽
- %f 按照浮点数打印
- %6f 按照浮点数打印,至少6个字符宽
- %.2f 按照浮点数打印,小数点后2位小数
- %6.2f 按照浮点数打印,至少6个字符宽,小数点后有2位小数
- %x 按照十六进制打印
- %c 打印字符
- %s 打印字符串
三、编写printf重定向
int fputc(int ch,FILE *p) //函数默认的,在使用printf函数时自动调用
{
USART_SendData(USART1,(u8)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); // USART_FLAG_TXE 发送数据寄存器空标志位
return ch;
}
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
int main()
{
u8 i=0;
u16 data=1234;
float fdata=12.34;
char str[]="Hello World!";
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
LED_Init();
USART1_Init(115200);
while(1)
{
i++;
if(i%50==0)
{
LED1=!LED1;
printf("输出整型数data=%d\\r\\n",data);
printf("输出浮点型数fdata=%0.2f\\r\\n",fdata);
printf("输出十六进制数data=%X\\r\\n",data);
printf("输出八进制数data=%o\\r\\n",data);
printf("输出字符串str=%s\\r\\n",str);
}
delay_ms(10); // i每次自加的延时时间 500ms LED状态翻转一次 50*10ms = 500ms
}
}
usart .c
#include "usart.h"
int fputc(int ch,FILE *p) //函数默认的,在使用printf函数时自动调用
{
USART_SendData(USART1,(u8)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); // USART_FLAG_TXE 发送数据寄存器空标志位
return ch;
}
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART1_RX_STA=0; //接收状态标记
/*******************************************************************************
* 函 数 名 : USART1_Init
* 函数功能 : USART1初始化函数
* 输 入 : bound:波特率
* 输 出 : 无
*******************************************************************************/
void USART1_Init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
/* 配置GPIO的模式和IO口 */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX //串口输出PA9
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入IO */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX //串口输入PA10
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */
//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_Cmd(USART1, ENABLE); //使能串口1
USART_ClearFlag(USART1, USART_FLAG_TC);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
}
/*******************************************************************************
* 函 数 名 : USART1_IRQHandler
* 函数功能 : USART1中断函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 r;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
r =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
if((USART1_RX_STA&0x8000)==0)//接收未完成
{
if(USART1_RX_STA&0x4000)//接收到了0x0d
{
if(r!=0x0a)USART1_RX_STA=0;//接收错误,重新开始
else USART1_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(r==0x0d)USART1_RX_STA|=0x4000;
else
{
USART1_RX_BUF[USART1_RX_STA&0X3FFF]=r;
USART1_RX_STA++;
if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
usart.h
#ifndef _usart_H
#define _usart_H
#include "system.h"
#include "stdio.h"
#define USART1_REC_LEN 200 //定义最大接收字节数 200
extern u8 USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART1_RX_STA; //接收状态标记
void USART1_Init(u32 bound);
#endif
以上是关于printf重定向的主要内容,如果未能解决你的问题,请参考以下文章