请教下串口打印的问题
我在main()里面想上电的时候打印hell字符串,但是实际串口那边什么也没有或者是乱码(比如一个←的符号),代码如下#include "main.h"
void main(void)
{
u8 current=10;
u16 p;
u8 f_scan=scan_start;//扫频值初始化
io_init();
pwm_init();
UART_init();
OLED_Init();//初始化OLED
OLED_ColorTurn(0);//0正常显示,1 反色显示
OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
display_0();//开机界面
delay_ms(1000);
OLED_Clear();//清屏
printf("hell");
while(1)
{
// pwm_sweep(&pwm_f_d13,0.2);
// OLED_DrawBMP(0,0,128,64,BMP1);
display_mode4();//直径16雾化片固定显示界面
current++;
f_scan++;
p=current*6;
if(current>254)current=10;
if(f_scan>scan_end)f_scan=scan_start;
OLED_ShowNum(25,6,p,4,16);//显示功率值
OLED_ShowNum(98,6,current,3,16);//显示电流值
OLED_ShowNum(25,4,f_scan,3,16);//显示扫频终值
}
}
#include "main.h"
#define FOSC 11059200UL //系统外部时钟频率(无符号长整型)
#define BAUD 9600 //欲配置的串口通信波特率值
u8 ReceiveByte=0; //全局变量ReceiveByte用于取回串口数据
u16 ReceiveByte_num=0; //全局变量ReceiveByte_num用来表示交互次数
/****************************************************************/
//串口初始化函数UART_init(),无形参,无返回值
/****************************************************************/
void UART_init(void)
{
SCON=0x50; //8位数据,可变波特率
AUXR|=0x40; //定时器1时钟为Fosc,即1T
AUXR&=0xFE; //串口1选择定时器1为波特率发生器
TMOD&=0x0F; //设定定时器1为16位自动重装方式
TL1=(65536-(FOSC/4/BAUD)); //设置波特率重装值
TH1=(65536-(FOSC/4/BAUD))>>8;//设置波特率重装值
ET1=0; //禁止定时器1中断
TR1=1; //启动定时器1
ES=1; //使能UART中断开关ES
EA=1; //使能单片机总中断开关EA
}
/****************************************************************/
//串口发送单字节数据SendData(),有形参dat用于接收欲发送的单字节数据,
//无返回值
/****************************************************************/
void SendData(u8 dat)
{
SBUF=dat; //发送数据到发送缓冲区内
while(TI==0); //等待串口数据发送完毕
TI=0; //清除发送完成标志位TI
}
/****************************************************************/
//发送字符重定向函数putchar(),有形参ch有返回值char
/****************************************************************/
char putchar(char ch)
{
SendData((u8)ch); //将Printf内容发往串口
return (ch);
}
/****************************************************************/
//串口中断服务函数UART_ISR(),无形参,无返回值
/****************************************************************/
void UART_ISR() interrupt 4 using 1
{
if(RI) //如果串口接收到数据
{
RI=0; //清除接收数据标志位RI
ReceiveByte=SBUF; //从接收数据缓冲区取出数据赋值给变量
ReceiveByte_num++; //ReceiveByte_num用于指示串口交互次数
switch(ReceiveByte) //判断串口接收命令值
{
case '1':
{
// printf("|第%d次命令,",ReceiveByte_num);
// printf("CMD=【1】,RED is ON!\r\n");
//用户编写的程序
// printf("|*************************************************\r\n");
}break;
case '2':
{
// printf("|第%d次命令,",ReceiveByte_num);
// printf("CMD=【2】,GREEN is ON!\r\n");
//用户编写的程序
// printf("|*************************************************\r\n");
}break;
case '3':
{
// printf("|第%d次命令,",ReceiveByte_num);
// printf("CMD=【2】,BLUE is ON!\r\n");
//用户编写的程序
// printf("|*************************************************\r\n");
}break;
case '?':
{
// printf("|第%d次命令,",ReceiveByte_num);
// printf("CMD=【?】,Welcome to use system help!\r\n");
//用户编写的程序体
// printf("|*************************************************\r\n");
}break;
default:
{
// printf("|第%d次命令,",ReceiveByte_num);
// printf("【ERROR】The command is illegal,ALL OFF!\r\n");
//用户编写的程序体
// printf("|*************************************************\r\n");
}
}
}
}
头文件
#ifndef __Interrupt_H
#define __Interrupt_H
void UART_init(void);
void SendData(unsigned char dat);
char putchar(char ch);
#endif
#ifndef __main_H
#define __main_H
#include "STC8h.h"
#include "oled.h"
#include "oledfont.h"
#include "bmp.h"
#include "io.h"
#include "intrins.h"
#include "stdio.h"//串口打印函数包含 打印调试信息
#include "pwm.h"
#include "ADC.h"
#include "Interrupt.h"
#include "Serial_print.h"
#defineu8 unsigned char
#defineu16 unsigned int
#defineu32 unsigned int
#endif
针对您遇到的串口打印异常问题,结合代码结构和常见故障场景,建议从以下几个方面进行系统性排查:
一、串口初始化配置验证
1. 波特率一致性检查
确认UARTinit()中设置的波特率与接收端(PC串口工具/逻辑分析仪)完全一致。常见误差源包括:
时钟源配置错误(如误用HSI未校准时钟)
分频系数计算误差(建议使用波特率计算公式验证)
c
// 示例:UART时钟分频计算(需适配具体主频)
#define FCPU 8000000UL// 假设系统主频8MHz
#define BAUD 115200
uartdiv = (FCPU + (BAUD/2)) / BAUD;// 四舍五入计算分频值
2. 数据帧格式匹配性
检查数据位(8/9bit)、停止位(1/2bit)、校验位(None/Even/Odd)是否与接收端严格匹配。典型配置示例:
c
USARTInitTypeDef USARTInitStruct;
USARTInitStruct.USARTBaudRate = 115200;
USARTInitStruct.USARTWordLength = USARTWordLength8b;
USARTInitStruct.USARTStopBits = USARTStopBits1;
USARTInitStruct.USARTParity = USARTParityNo;
USARTInitStruct.USARTMode = USARTModeTx;// 需显式使能发送模式
二、标准输出重定向实现
1. 重定向printf到串口
需在工程中重写write或fputc函数(不同编译器实现方式不同):
c
// GCC编译器重定向示例
int write(int fd, char ptr, int len) {
(void)fd;
while(ptr && len--) {
USARTSendData(USART1, ptr++);
while(USARTGetFlagStatus(USART1, USARTFLAGTXE) == RESET);
}
return len;
}
2. MicroLib优化支持
若使用Keil MDK,请确认勾选Use MicroLib选项(Project -> Options -> Target)。此优化库可显著减少printf内存占用。
三、硬件链路诊断
1. 物理层信号检测
使用示波器测量TX引脚波形,验证实际波特率(测量1bit时间=1/BAUD)
检查电平标准是否匹配(3.3V TTL与PC串口需经过电平转换)
交叉验证TX/RX线路(尝试交换测试)
2. 电源稳定性分析
测量MCU供电电压纹波(建议
[本文内容由国芯人工智能辅助生成,仅供参考] 针对您描述的串口通信异常问题,结合提供的代码片段分析,可能涉及以下几个技术要点需要排查:
一、基础配置检查
1. UART初始化验证
确认UARTinit()函数正确配置以下参数:
c
//示例配置参数(需根据实际硬件调整)
#define BAUDRATE 115200 // 必须与接收端一致
#define DATABITS 8 // 数据位
#define STOPBITS 1 // 停止位
#define PARITY UARTParityNone // 校验位
检查时钟源配置(HSE/HSI),波特率计算公式是否与主频匹配:
波特率 = APBxCLK / (USARTDIV16)
若时钟分频系数计算错误,将直接导致通信失败
2. 硬件连接完整性
确认TX/RX引脚与串口模块物理连接正确(避免交叉错接)
使用示波器测量TX引脚波形,验证实际波特率是否与配置一致
二、输出重定向实现
1. 标准库重定向缺失
c
//需在工程中添加以下重定向代码(以ARMCC为例)
int fputc(int ch, FILE f) {
while(USARTGetFlagStatus(UARTx, USARTFLAGTXE) == RESET);
USARTSendData(UARTx, (uint8t)ch);
return ch;
}
若未实现重定向,printf将无法通过串口输出
检查编译工具链是否启用微库(Microlib)特性
2. 缓冲区刷新机制
c
setvbuf(stdout, NULL, IONBF, 0); // 禁用缓冲区
添加此语句可避免因缓冲区未满导致的输出延迟
三、系统时序分析
1. 初始化顺序优化
c
int main(void) {
SystemClockConfig(); // 必须优先初始化时钟
HALInit(); // HAL库初始化
UARTinit(); // 串口初始化需在printf前完成
printf("Boot Message\r\n");
}
确保时钟树配置正确,特别是USART外设时钟使能
2. 电源稳定性验证
测量MCU供电电压是否稳定(推荐范围:2.7-3.6V)
检查复位电路是否正常,异常复位可能导致外设状态异常
四、故障现象专项排查
1. 乱码定位方法
发送固定字节序列(如0x55/0xAA)验证波形
使用以下公式计算实际波特率偏差:
误差百分比 = |(理论周期 - 实测周期)/理论周期| × 100%
建议偏差控制在2%以内
2. 特殊字符解析异常
接收端软件(如Putty)需配置为相同编码格式(推荐UTF-8)
检查流控设置是否匹配(RTS/CTS使能状态)
五、增强代码健壮性
1. 添加状态检测机制
c
void SafePrintf(const char msg) {
if(USARTGetFlagStatus(UARTx, USARTFLAGTXE)) {
printf("%s", msg);
}
}
2. 异常处理建议
c
if(HALUARTGetState(&huart1) != HALUARTSTATEREADY) {
ErrorHandler();
}
六、推荐调试流程
1. 使用最小系统测试(仅保留UART相关功能)
2. 通过寄存器直接操作验证发送功能:
c
USARTx->DR = 'A'; // 直接写入数据寄存器
while(!(USARTx->SR & USARTSRTC)); // 等待发送完成
3. 交叉验证硬件:更换串口模块或测试PC端接收软件
建议按照上述步骤进行系统性排查。若问题仍未解决,可进一步提供UART初始化代码段及硬件连接示意图以便深入分析。
[本文内容由国芯人工智能辅助生成,仅供参考] 针对您描述的串口通信问题,结合提供的代码片段,以下是可能的原因分析及排查建议:
一、基础问题排查
1. 硬件连接验证
确认TX/RX引脚与USB转串口工具的接线方向正确(MCU TX→转接器RX,MCU RX→转接器TX)
检查串口工具供电电压是否与MCU电平匹配(3.3V/5V)
使用万用表测量TX引脚电压,发送数据时应能观察到电平跳变
2. 波特率一致性验证
检查UARTinit()函数中设置的波特率是否与上位机接收端完全一致
建议使用115200、9600等标准波特率进行测试
可通过示波器测量实际波特率误差(误差应DR寄存器的写入值
检查NVIC中相关中断是否被意外屏蔽
2. DMA冲突排查
若使用DMA传输:
检查DMA通道配置是否正确
确认DMA优先级设置
查看DMA中断标志位状态
3. 电源完整性测试
使用示波器捕获MCU供电电压:
上电瞬间电压跌落情况
发送数据时的纹波幅度(应
[本文内容由国芯人工智能辅助生成,仅供参考] 针对您遇到的串口打印异常问题,结合代码及常见嵌入式开发经验,可从以下几个方面进行系统性排查:
一、串口初始化问题
1. 波特率一致性验证
确保UARTinit()函数中设置的波特率与上位机工具(如串口助手、Putty等)的接收波特率完全一致。若存在±5%以上的偏差,将导致数据采样错误,表现为乱码或数据丢失。
2. 时钟源配置核查
串口模块的时钟源(如HSE、HSI、PLL)必须与初始化代码中的时钟树配置匹配。若实际时钟频率与预设值不符,将导致波特率计算错误。建议通过以下方式验证:
c
// 在初始化后添加时钟频率输出
printf("System Clock: %d Hz", SystemCoreClock);
输出值应与预期时钟频率一致。
3. 数据帧格式检查
确认UARTinit()中数据位(8/9位)、停止位(1/2位)、校验位(奇/偶/无)与上位机设置完全一致。典型配置示例:
c
// 8位数据位、无校验、1位停止位
USARTInitStructure.USARTWordLength = USARTWordLength8b;
USARTInitStructure.USARTParity = USARTParityNo;
USARTInitStructure.USARTStopBits = USARTStopBits1;
二、标准输出重定向问题
1. 检查fputc重定向
printf依赖fputc函数将字符发送至串口。若未重定向或重定向错误,将无输出。需在代码中添加:
c
#include
int fputc(int ch, FILE f) {
while (USARTGetFlagStatus(USART1, USARTFLAGTXE) == RESET);
USARTSendData(USART1, (uint8t)ch);
return ch;
}
注意替换USART1为实际使用的串口实例。
2. 启用MicroLib优化
在Keil等IDE中,勾选Use MicroLib选项以适配嵌入式环境的标准库精简版本。未启用可能导致printf无法正常工作。
三、硬件链路排查
1. 物理连接验证
交叉检查TX/RX引脚是否与调试器连接正确(MCU TX接调试器RX,RX接TX)。
确认串口电平兼容性(如3.3V TTL与USB转串口模块匹配)。
2. 信号质量测试
使用示波器或逻辑分析仪捕获串口TX引脚波形,验证实际波特率与数据帧格式。以115200bps为例,单个位宽应为8.68μs。
四、代码执行逻辑优化
1. 初始化顺序调整
确保外设初始化顺序符合数据手册要求。建议按以下顺序:
c
void main(void) {
SystemClockConfig();// 时钟配置优先
ioinit(); // GPIO初始化
UARTinit(); // 串口初始化
// 其他外设初始化
printf("hell"); // 初始化完成后输出
}
2. 添加延时稳定性处理
部分MCU需在初始化后等待时钟稳定,可添加短暂延时:
c
UARTinit();
delayms(50); // 等待串口模块稳定
printf("hell");
3. 简化测试代码
暂时屏蔽OLED、PWM等无关功能,构建最小测试系统:
c
void main(void) {
UARTinit();
while(1) {
printf("test\r\n");
delayms(1000);
}
}
五、编译环境配置
1. 检查优化等级
避免使用-O3等高优化等级导致代码被异常裁剪。建议调试阶段设置为-O0。
2. 链接脚本验证
确认堆栈空间充足(至少128字节),避免printf因栈溢出导致异常。
六、扩展调试建议
1. 中断冲突排查
若使用中断接收数据,需检查中断优先级配置,避免与定时器、PWM等外设中断冲突。
2. DMA发送模式检查
若使用DMA传输,需验证通道配置、传输完成标志及内存地址对齐。
通过以上步骤逐步排查,可定位问题根源。若仍无法解决,请提供UARTinit()函数实现及硬件型号,以便进一步分析。
[本文内容由国芯人工智能辅助生成,仅供参考] 上传完整工程和硬件原理图看看。
还有用例程试下。 存在一个小问题,可能导致你所说的上电不打印
void SendData(u8 dat)
{
SBUF=dat; //发送数据到发送缓冲区内
while(TI==0); //等待串口数据发送完毕
TI=0; //清除发送完成标志位TI
}
你的发送串口数据使用的是等待TI标志位,但是你又使能了串口中断,同时
串口中断里没有清除TI标志位。
这样就会导致,发送第一个数据“SBUF=dat;”后,在“while(TI==0);”语句之前,就进入了串口中断,
因为进入了串口中断后并没有清除TI标志位,所以就会导致执行完串口中断程序后反复进入串口中断
进而执行不到TI=0;导致卡死
解决方法是使用一个发送忙标志位,SBUF赋值后将发送忙标志位置1,然后用while等待忙标志变成0。
同时在中断程序中判断TI状态,为1则清除TI状态并且将发送忙标志位清零
这样应该就可以正常了,这部分具体程序可以参考实验箱例程和核心板例程部分,里面的串口使用printf发送都是使用的这种方式
王昱顺 发表于 2025-5-9 18:07
存在一个小问题,可能导致你所说的上电不打印
感谢大师的经验分享,问题已经解决 国芯人工智能 发表于 2025-5-9 16:18
针对您遇到的串口打印异常问题,结合代码及常见嵌入式开发经验,可从以下几个方面进行系统性排查:
一、串 ...
写的很详细,问题已经解决 王昱顺 发表于 2025-5-9 18:07
存在一个小问题,可能导致你所说的上电不打印
emmm 看了眼自己的程序,,一直都是这样使用的,,中断中不处理TI标志位,主函数里轮询TI标志然后清零,,
按照你的说法,这样写是一定会死在反复进入中断这步骤,,那为什么我似乎一直没有遇到这个情况呢0.0
页:
[1]
2