找回密码
 立即注册
查看: 21|回复: 6

请教下串口打印的问题

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2025-05-09 09:37:52
已绑定手机

2

主题

1

回帖

18

积分

新手上路

积分
18
发表于 昨天 16:17 | 显示全部楼层 |阅读模式
我在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"

#define  u8 unsigned char
#define  u16 unsigned int
#define  u32 unsigned int

#endif  

回复

使用道具 举报 送花

3

主题

1102

回帖

915

积分

等待验证会员

积分
915
发表于 昨天 16:18 | 显示全部楼层
针对您遇到的串口打印异常问题,结合代码结构和常见故障场景,建议从以下几个方面进行系统性排查:

一、串口初始化配置验证
1. 波特率一致性检查  
   确认UARTinit()中设置的波特率与接收端(PC串口工具/逻辑分析仪)完全一致。常见误差源包括:
时钟源配置错误(如误用HSI未校准时钟)
分频系数计算误差(建议使用波特率计算公式验证)
  
  1. c
  2.    // 示例:UART时钟分频计算(需适配具体主频)
  3.    #define FCPU 8000000UL  // 假设系统主频8MHz
  4.    #define BAUD 115200
  5.    uartdiv = (FCPU + (BAUD/2)) / BAUD;  // 四舍五入计算分频值
复制代码

2. 数据帧格式匹配性  
   检查数据位(8/9bit)、停止位(1/2bit)、校验位(None/Even/Odd)是否与接收端严格匹配。典型配置示例:
  
  1. c
  2.    USARTInitTypeDef USARTInitStruct;
  3.    USARTInitStruct.USARTBaudRate = 115200;
  4.    USARTInitStruct.USARTWordLength = USARTWordLength8b;
  5.    USARTInitStruct.USARTStopBits = USARTStopBits1;
  6.    USARTInitStruct.USARTParity = USARTParityNo;
  7.    USARTInitStruct.USARTMode = USARTModeTx;  // 需显式使能发送模式
复制代码

二、标准输出重定向实现
1. 重定向printf到串口  
   需在工程中重写write或fputc函数(不同编译器实现方式不同):
  
  1. c
  2.    // GCC编译器重定向示例
  3.    int write(int fd, char ptr, int len) {
  4.        (void)fd;
  5.        while(ptr && len--) {
  6.            USARTSendData(USART1, ptr++);
  7.            while(USARTGetFlagStatus(USART1, USARTFLAGTXE) == RESET);
  8.        }
  9.        return len;
  10.    }
复制代码

2. MicroLib优化支持  
   若使用Keil MDK,请确认勾选Use MicroLib选项(Project -> Options -> Target)。此优化库可显著减少printf内存占用。

三、硬件链路诊断
1. 物理层信号检测  
使用示波器测量TX引脚波形,验证实际波特率(测量1bit时间=1/BAUD)
检查电平标准是否匹配(3.3V TTL与PC串口需经过电平转换)
交叉验证TX/RX线路(尝试交换测试)

2. 电源稳定性分析  
   测量MCU供电电压纹波(建议

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

3

主题

1102

回帖

915

积分

等待验证会员

积分
915
发表于 昨天 16:18 | 显示全部楼层
针对您描述的串口通信异常问题,结合提供的代码片段分析,可能涉及以下几个技术要点需要排查:

一、基础配置检查
1. UART初始化验证
确认UARTinit()函数正确配置以下参数:
   
  1. c
  2.      //示例配置参数(需根据实际硬件调整)
  3.      #define BAUDRATE 115200       // 必须与接收端一致
  4.      #define DATABITS 8            // 数据位
  5.      #define STOPBITS 1            // 停止位
  6.      #define PARITY    UARTParityNone // 校验位
复制代码
检查时钟源配置(HSE/HSI),波特率计算公式是否与主频匹配:  
     波特率 = APBxCLK / (USARTDIV  16)  
     若时钟分频系数计算错误,将直接导致通信失败

2. 硬件连接完整性
确认TX/RX引脚与串口模块物理连接正确(避免交叉错接)
使用示波器测量TX引脚波形,验证实际波特率是否与配置一致

二、输出重定向实现
1. 标准库重定向缺失
  
  1. c
  2.    //需在工程中添加以下重定向代码(以ARMCC为例)
  3.    int fputc(int ch, FILE f) {
  4.        while(USARTGetFlagStatus(UARTx, USARTFLAGTXE) == RESET);
  5.        USARTSendData(UARTx, (uint8t)ch);
  6.        return ch;
  7.    }
复制代码
若未实现重定向,printf将无法通过串口输出
检查编译工具链是否启用微库(Microlib)特性

2. 缓冲区刷新机制
  
  1. c
  2.    setvbuf(stdout, NULL, IONBF, 0); // 禁用缓冲区
复制代码
添加此语句可避免因缓冲区未满导致的输出延迟

三、系统时序分析
1. 初始化顺序优化
  
  1. c
  2.    int main(void) {
  3.        SystemClockConfig(); // 必须优先初始化时钟
  4.        HALInit();           // HAL库初始化
  5.        UARTinit();          // 串口初始化需在printf前完成
  6.        printf("Boot Message\r\n");
  7.    }
复制代码
确保时钟树配置正确,特别是USART外设时钟使能

2. 电源稳定性验证
测量MCU供电电压是否稳定(推荐范围:2.7-3.6V)
检查复位电路是否正常,异常复位可能导致外设状态异常

四、故障现象专项排查
1. 乱码定位方法
发送固定字节序列(如0x55/0xAA)验证波形
使用以下公式计算实际波特率偏差:  
     误差百分比 = |(理论周期 - 实测周期)/理论周期| × 100%  
     建议偏差控制在2%以内

2. 特殊字符解析异常
接收端软件(如Putty)需配置为相同编码格式(推荐UTF-8)
检查流控设置是否匹配(RTS/CTS使能状态)

五、增强代码健壮性
1. 添加状态检测机制
  
  1. c
  2.    void SafePrintf(const char msg) {
  3.        if(USARTGetFlagStatus(UARTx, USARTFLAGTXE)) {
  4.            printf("%s", msg);
  5.        }
  6.    }
复制代码
2. 异常处理建议
  
  1. c
  2.    if(HALUARTGetState(&huart1) != HALUARTSTATEREADY) {
  3.        ErrorHandler();
  4.    }
复制代码

六、推荐调试流程
1. 使用最小系统测试(仅保留UART相关功能)
2. 通过寄存器直接操作验证发送功能:
  
  1. c
  2.    USARTx->DR = 'A'; // 直接写入数据寄存器
  3.    while(!(USARTx->SR & USARTSRTC)); // 等待发送完成
复制代码
3. 交叉验证硬件:更换串口模块或测试PC端接收软件

建议按照上述步骤进行系统性排查。若问题仍未解决,可进一步提供UART初始化代码段及硬件连接示意图以便深入分析。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

3

主题

1102

回帖

915

积分

等待验证会员

积分
915
发表于 昨天 16:18 | 显示全部楼层
针对您描述的串口通信问题,结合提供的代码片段,以下是可能的原因分析及排查建议:

一、基础问题排查
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供电电压:
上电瞬间电压跌落情况
发送数据时的纹波幅度(应

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

3

主题

1102

回帖

915

积分

等待验证会员

积分
915
发表于 昨天 16:18 | 显示全部楼层
针对您遇到的串口打印异常问题,结合代码及常见嵌入式开发经验,可从以下几个方面进行系统性排查:

一、串口初始化问题
1. 波特率一致性验证  
   确保UARTinit()函数中设置的波特率与上位机工具(如串口助手、Putty等)的接收波特率完全一致。若存在±5%以上的偏差,将导致数据采样错误,表现为乱码或数据丢失。

2. 时钟源配置核查  
   串口模块的时钟源(如HSE、HSI、PLL)必须与初始化代码中的时钟树配置匹配。若实际时钟频率与预设值不符,将导致波特率计算错误。建议通过以下方式验证:
  
  1. c
  2.    // 在初始化后添加时钟频率输出
  3.    printf("System Clock: %d Hz", SystemCoreClock);
复制代码
   输出值应与预期时钟频率一致。

3. 数据帧格式检查  
   确认UARTinit()中数据位(8/9位)、停止位(1/2位)、校验位(奇/偶/无)与上位机设置完全一致。典型配置示例:
  
  1. c
  2.    // 8位数据位、无校验、1位停止位
  3.    USARTInitStructure.USARTWordLength = USARTWordLength8b;
  4.    USARTInitStructure.USARTParity = USARTParityNo;
  5.    USARTInitStructure.USARTStopBits = USARTStopBits1;
复制代码

二、标准输出重定向问题
1. 检查fputc重定向  
   printf依赖fputc函数将字符发送至串口。若未重定向或重定向错误,将无输出。需在代码中添加:
  
  1. c
  2.    #include
  3.    int fputc(int ch, FILE f) {
  4.        while (USARTGetFlagStatus(USART1, USARTFLAGTXE) == RESET);
  5.        USARTSendData(USART1, (uint8t)ch);
  6.        return ch;
  7.    }
复制代码
   注意替换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. 初始化顺序调整  
   确保外设初始化顺序符合数据手册要求。建议按以下顺序:
  
  1. c
  2.    void main(void) {
  3.        SystemClockConfig();  // 时钟配置优先
  4.        ioinit();             // GPIO初始化
  5.        UARTinit();           // 串口初始化
  6.        // 其他外设初始化
  7.        printf("hell");        // 初始化完成后输出
  8.    }
复制代码

2. 添加延时稳定性处理  
   部分MCU需在初始化后等待时钟稳定,可添加短暂延时:
  
  1. c
  2.    UARTinit();
  3.    delayms(50);       // 等待串口模块稳定
  4.    printf("hell");
复制代码

3. 简化测试代码  
   暂时屏蔽OLED、PWM等无关功能,构建最小测试系统:
  
  1. c
  2.    void main(void) {
  3.        UARTinit();
  4.        while(1) {
  5.            printf("test\r\n");
  6.            delayms(1000);
  7.        }
  8.    }
复制代码

五、编译环境配置
1. 检查优化等级  
   避免使用-O3等高优化等级导致代码被异常裁剪。建议调试阶段设置为-O0。

2. 链接脚本验证  
   确认堆栈空间充足(至少128字节),避免printf因栈溢出导致异常。

六、扩展调试建议
1. 中断冲突排查  
   若使用中断接收数据,需检查中断优先级配置,避免与定时器、PWM等外设中断冲突。

2. DMA发送模式检查  
   若使用DMA传输,需验证通道配置、传输完成标志及内存地址对齐。

通过以上步骤逐步排查,可定位问题根源。若仍无法解决,请提供UARTinit()函数实现及硬件型号,以便进一步分析。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:170
  • 最近打卡:2025-05-09 07:56:57
已绑定手机

58

主题

1369

回帖

3056

积分

荣誉版主

无情的代码机器

积分
3056
发表于 昨天 17:43 | 显示全部楼层
上传完整工程和硬件原理图看看。
还有用例程试下。
三天不学习,赶不上刘少奇~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:466
  • 最近打卡:2025-05-09 18:07:45
已绑定手机
已实名认证

110

主题

2240

回帖

5536

积分

版主

积分
5536
发表于 昨天 18:07 | 显示全部楼层
存在一个小问题,可能导致你所说的上电不打印


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发送都是使用的这种方式
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-10 06:48 , Processed in 0.138368 second(s), 91 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表