理解:使用printf函数打印数据,会跳转到fputc函数,每个字符都会跳转一次。
一.不需要use MicroLIB的方式:
1.Version5
Keil 5 version5且不使用use MicroLIB的配置界面
Keil 5 version5的代码:
#include <stdio.h>
//需包含#include "stdio.h"
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
FILE __stdin;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (uint8_t) ch;
return ch;
}
///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
uint8_t ch = 0;
while((USART1->SR&0X20)==0);//循环发送,直到发送完毕
ch = (uint8_t) USART1->DR;
return ch;
}
#endif
2. Version6
Keil 5 version6且不使用use MicroLIB的配置界面
Keil 5 version6的代码:
#include <stdio.h>
//需包含#include "stdio.h"
#if 1
struct FILE
{
int handle;
};
FILE __stdout;
FILE __stdin;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (uint8_t) ch;
return ch;
}
///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
uint8_t ch = 0;
while((USART1->SR&0X20)==0);//循环发送,直到发送完毕
ch = (uint8_t) USART1->DR;
return ch;
}
#endif
二.使用use MicroLIB的方式:
配置勾上Use MicroLIB
HAL库代码:
#include <stdio.h>
#if 1
//需包含#include "stdio.h"
int fputc(int ch, FILE *f)
{
uint8_t temp = ch;
HAL_UART_Transmit(&huart1, &temp, 1, 0xffff);//huart1需要根据你的配置修改
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
#endif
标准库代码:
#include <stdio.h>
#if 1
/// 重定向c库函数printf到USART1
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到USART1 */
USART_SendData(USART1, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
/// 重定向c库函数scanf到USART1
int fgetc(FILE *f)
{
/* 等待串口1输入数据 */
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USART1);
}
#endif
三、自定义函数的printf打印Debug方式:
(这里不需要使用微库)
实际项目中,当用到多个串口时,使用printf来Dedug打印数据非常不方便,这里可以自己定义每个串口的打印函数。
HAL库代码:
这里只要修改
HAL_UART_Transmit(&huart1, (uint8_t *)Uart_buf, len, 0xf);
中的串口句柄(&huart1)即可打印到指定串口
#include "usart.h"
#include "stdarg.h"
#include "stdio.h"
#define CONSOLEBUF_SIZE 64
void PrintfDebug1(const char *fmt, ...)
{
char Uart_buf[CONSOLEBUF_SIZE]; // 用于存储格式化后的字符串
uint16_t len = 0; // 存储格式化后的字符串长度
va_list args; // 声明一个可变参数列表
va_start(args, fmt); // 初始化可变参数列表,使其指向参数 fmt
// 使用 vsprintf 函数将格式化的字符串放入 Uart_buf 中,并获取格式化后的字符串长度
len = vsprintf(Uart_buf, fmt, args);
va_end(args); // 结束可变参数的使用
// 使用 HAL_UART_Transmit 函数将格式化后的字符串通过串口发送出去
HAL_UART_Transmit(&huart1, (uint8_t *)Uart_buf, len, 0xf);
}
标准库代码:
USART_SendData(USART1, (uint8_t)ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
改变USART1即可打印到指定的串口
#include "stdarg.h"
#include "stm32f10x_conf.h"
#include "stdio.h"
#define CONSOLEBUF_SIZE 64
// 发送单个字符到 USART1,阻塞等待发送完毕
void Send_char(char ch)
{
// 使用 USART_SendData 函数发送单个字符到 USART1
USART_SendData(USART1, (uint8_t)ch);
// 等待发送完毕
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
// 发送字符串到 USART1
// 参数 str: 要发送的字符串
// 参数 length: 字符串的长度
void Send_string(const char *str, uint16_t length)
{
while (length > 0)
{
Send_char(*str);
str++;
length--;
}
}
// 格式化输出到 USART1
// 参数 fmt: 格式字符串
// ...: 可变参数列表
void PrintfDebug1(const char *fmt, ...)
{
char Uart_buf[CONSOLEBUF_SIZE];
uint16_t len = 0;
va_list args;
va_start(args, fmt);
// 使用 vsnprintf 函数将格式化的字符串放入 Uart_buf 中,并获取格式化后的字符串长度
len = vsnprintf(Uart_buf, CONSOLEBUF_SIZE, fmt, args);
va_end(args);
// 将格式化后的字符串发送到 USART1
Send_string(Uart_buf, len);
}