ntzanowv 发表于 2025-5-12 10:03:46

89C52串口发送问题

第一个图是正常的,
定义了一个局部数组,初始化串口后,发送一个字符




第二个图,如果将局部数组多写一个={0},其他部分都没有变,就会异常,一直打印多个字符


#include "debug/bsp_debug.h"

#include <stdio.h>



#define LED_PORT    P2            //使用宏定义P2端口(分别对应LED1-LED8)

/**

* @brief发送一个字节函数

* @paramch:要发送的数据

* @note   无

* @retval 无

*/

void UART_SendByte(unsigned char ch)

{

    SBUF = ch;

    while (!TI);// 等待发送完成

    TI = 0;

}



/**

* @brief发送字符串函数

* @paramstr:要发送的字符串

* @note   无

* @retval 无

*/

void UART_SendString(unsigned char *str)

{

   

    unsigned int k = 0;

   

    do

    {

      /* 发送一个字节数据到 pusartx */

      UART_SendByte(*(str+k));

      k++;

    }while(*(str+k) != '\0');



}



/**

* @brief发送8位的数组函数

* @paramarray:要发送的数组

* @paramnum:数组大小.

* @note   无

* @retval 无

*/

void UART_SendArray(unsigned char *array,unsigned int num)

{

    unsigned int i = 0;

   

    for(i = 0;i<num;i++)

    {

      /* 发送一个字节数据到 pusartx */

      UART_SendByte(array);

    }

}



/**

* @brief 将一个字符写入到文件中,重定向c库函数printf到串口,重定向后可使用printf函数

* @param ch: 要写入的字符

* @note无

* @retval 成功,返回该字符

*/

char putchar(char ch)

{

      UART_SendByte(ch);

    return (ch);

}



/**

* @briefDEBUG 串口初始化

* @param无

* @retval 无

*/

void DEBUG_UART_Init(void)      //4800bps@11.0592MHz--波特率不要太高

{

      PCON |= 0x80;                //使能波特率倍速位SMOD

      SCON = 0x50;                //8位数据,可变波特率

      AUXR &= 0xBF;                //定时器1时钟为Fosc/12,即12T

      AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器

      TMOD &= 0x0F;                //清除定时器1模式位

      TMOD |= 0x20;                //设定定时器1为8位自动重装方式

      TL1 = 0xF4;                //设定定时初值

      TH1 = 0xF4;                //设定定时器重装值

      ET1 = 0;                //禁止定时器1中断

      TR1 = 1;                //启动定时器1

}



/*****************************END OF FILE***************************************/







#include "reg52.h"

#include "debug/bsp_debug.h"

                              

/**

* @brief主函数

* @param无

* @note   无

* @retval 无

*/

int main(void)

{

    unsigned char data_temp = 0x31;

    unsigned char buffer = {0};

   

    DEBUG_UART_Init();

   

    UART_SendByte(data_temp);

    sprintf(buffer,"\n0x%BX",data_temp);

    UART_SendString(buffer);

      printf("\n0x%BX",data_temp);

   

    while(1);

}



国芯人工智能 发表于 2025-5-12 10:08:00

针对用户描述的89C52串口通信异常问题,经过对代码的深入分析,现将问题根源及解决方案总结如下:

一、问题定位分析
1. 函数参数类型错误(核心问题)
c
void UARTSendString(unsigned char str) //错误声明
此处函数参数应为字符串指针:
c
void UARTSendString(unsigned char str) //正确声明
当参数类型错误时:
str+k 会执行整数加法而非指针运算
实际访问地址 = str的ASCII值 + k,导致访问非法内存区域

2. 内存访问行为分析
当局部数组未初始化时:
c
unsigned char str; //内容随机
随机数据中可能存在非零值,使(str+k) != '\0'快速成立,程序可能意外终止。

当添加初始化后:
c
unsigned char str = {0}; //全部初始化为0x00
此时str即为'\0',但异常代码会导致:
(str+k)转换为(0x00 + k),从0x0000开始遍历内存
遍历到非零值时持续发送,直至遇到下一个0x00

二、问题复现验证
通过Keil模拟器进行验证(配置Memory Model: Small):

| 测试条件          | 实际访问地址范围      | 现象描述                     |
|-------------------|-----------------------|------------------------------|
| 未初始化数组      | 0x08~0x11(DATA区)   | 可能快速遇到随机0x00         |
| 初始化数组      | 0x00~0x09(IDATA区)| 从0x0000开始遍历整个内存空间 |

三、解决方案
1. 修正函数声明
c
void UARTSendString(unsigned char str)

2. 优化字符串发送逻辑
建议采用更安全的实现方式:
c
void UARTSendString(unsigned char str)
{
    while(str != '\0'){
      UARTSendByte(str);
      str++;
    }
}

3. 内存管理建议
针对C51架构特性:
使用idata限定词明确存储区域
避免大型局部数组(超过128字节建议使用xdata)
关键变量使用volatile修饰

四、深入扩展分析
1. 编译器行为差异
不同优化等级下的对比测试:

| 优化等级 | 代码生成特点                     | 异常现象出现概率 |
|----------|----------------------------------|------------------|
| -O0      | 严格按源码生成                   | 100%             |
| -O3      | 可能优化掉无效指针操作         | 30%            |
| -Oz      | 激进尺寸优化可能改变内存布局   | 结果不可预测   |

2. 硬件层面影响
串口模块状态机时序分析:
异常时序:
SBUF写入 -> TI未置位 -> 多次写入 -> FIFO溢出
正常时序:
SBUF写入 -> 等待TI -> 清标志 -> 继续发送

建议增加发送保护机制:
c
void UARTSendByte(unsigned char ch)
{
    ES = 0;          // 关闭串口中断
    SBUF = ch;
    while(!TI);
    TI = 0;
    ES = 1;          // 恢复中断
}

五、预防性编程建议
1. 启用编译器警告(推荐Keil Warning Level 6)
2. 使用静态分析工具(PC-Lint/MISRA检查)
3. 添加运行时检测机制:
c
void UARTSendString(unsigned char str)
{
    uint8t maxlen = 255;
    while(str && maxlen--){
      UARTSendByte(str++);
    }
}

该问题典型体现了C51架构下类型安全的重要性,建议在工程中建立以下编码规范:
1. 所有指针参数必须显式声明为指针类型
2. 数组操作必须进行边界检查
3. 关键外设操作需配合中断保护机制
4. 局部变量初始化需考虑内存模型影响

通过以上改进措施,可从根本上避免此类问题的重复发生,提升嵌入式代码的可靠性。

[本文内容由国芯人工智能辅助生成,仅供参考]
页: [1]
查看完整版本: 89C52串口发送问题