找回密码
 立即注册
查看: 10|回复: 2

帮忙测试一个串口发送接收程序

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:430
  • 最近打卡:2026-05-03 14:14:42

34

主题

177

回帖

2067

积分

金牌会员

积分
2067
发表于 1 小时前 | 显示全部楼层 |阅读模式
stc89c52rc,keilc

不管是发送文本模式还是hex模式,明明程序SBUF=SBUF=2;得到的全是+1.

但是如果把代码改成+4或者+1,都是得到正确结果。怪哉!!!
REN = 0; // 暂时禁止接收
REN = 1;          // 重新允许接收

是deepseek给出的修改建议,加不加都一样。。

  1. #include <STC89C5xRC.H>
  2. void UART_Init(void);
  3. void main(void)
  4. {
  5.     UART_Init();         // 调用串口初始化,配置 9600, 8N1
  6.     while(1)             // 无限循环,不断执行回显功能
  7.     {
  8.         // 1. 等待接收一个字节
  9.         while(!RI);      // RI 是接收中断标志位,硬件在接收到一帧完整数据后自动置 1
  10.                          // 这里用查询方式:只要 RI 为 0,就在这里死等,直到接收完成
  11.         RI = 0;          // 接收完成后,必须由软件手动清除 RI 标志,
  12.                          // 否则下一次 while(!RI) 会立刻通过,造成重复回显
  13.                                 REN = 0;          // 暂时禁止接收
  14.         // 2. 将接收到的字节发送回去(实现回显)
  15.         SBUF = SBUF+2;     // 当读出 SBUF 时,得到的是接收到的数据;
  16.                          // 当写入 SBUF 时,会启动一次串行发送。
  17.                          // 这条语句相当于:
  18.                          //   unsigned char temp = SBUF;  // 读接收到的数据
  19.                          //   SBUF = temp;                // 写入发送缓冲器,启动发送
  20.                                 REN = 1;          // 重新允许接收
  21.         while(!TI);      // TI 是发送中断标志位,硬件在发送完一帧数据后自动置 1
  22.                          // 等待发送完成,避免在发送过程中又去写 SBUF 造成数据破坏
  23.         TI = 0;          // 发送完成后,软件清除 TI 标志,为下一次发送做准备
  24.     }
  25. }
  26. void UART_Init(void)
  27. {
  28.     SCON = 0x50;      // 方式1,允许接收。注意这里是0x50,TI/RI由硬件操作,通常初始0即可
  29.     // 或直接 SCON = 0x51; 也完全没问题,手动物清了TI和RI
  30.     TMOD &= 0x0F;     // 修改的是 高 4 位(定时器 1),而 低 4 位(定时器 0)完全没有改变。
  31.         //TMOD的高四位是关于TImer1,低四位是Timer0.
  32.     TMOD |= 0x20;     // 设定定时器1为方式2 (8位自动重装)
  33.     TH1 = 0xFD;       // 波特率9600 (晶振11.0592MHz)
  34.     TL1 = 0xFD;
  35.     ET1 = 0;          // 禁止定时器1中断,用作波特率发生器时通常不产生中断
  36.     TR1 = 1;          // 启动定时器1
  37.     // 如果用到中断接收,再开总中断和串口中断
  38.     ES = 0;           // 允许串口中断
  39.     EA = 0;           // CPU开总中断
  40. }
复制代码



回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:878
  • 最近打卡:2026-05-03 00:50:54

14

主题

1362

回帖

7372

积分

论坛元老

积分
7372
发表于 1 小时前 | 显示全部楼层
你这个现象本质上不是“串口硬件把 +2 变成了 +1”,而是 你在读写同一个 SBUF 时发生了写回/读回混淆,再加上表达式里对 SBUF 的访问顺序不可靠,导致结果看起来像“总是少 1”。8051 的 SBUF 不是普通 RAM,它是两个物理上不同的寄存器:写 SBUF 是发射缓冲,读 SBUF 是接收缓冲;SBUF 不能被当成一个可读可写且值一致的变量来用 。

正确写法
建议改成下面这种方式:

  1. #include <STC89C5xRC.H>
  2. void UART_Init(void)
  3. {
  4.     SCON = 0x50;      // 8位UART, REN=1
  5.     TMOD &= 0x0F;
  6.     TMOD |= 0x20;     // T1方式2
  7.     TH1 = 0xFD;       // 11.0592MHz, 9600bps
  8.     TL1 = 0xFD;
  9.     TR1 = 1;
  10.     ES = 0;
  11.     EA = 0;
  12. }
  13. void main(void)
  14. {
  15.     unsigned char dat;
  16.     UART_Init();
  17.     while(1)
  18.     {
  19.         while(!RI);
  20.         dat = SBUF;     // 先把接收到的数据存到普通变量
  21.         RI = 0;
  22.         dat += 2;       // 再做运算
  23.         while(!TI);     // 如果你要等发送完成,先确保初始TI状态正确
  24.         TI = 0;
  25.         SBUF = dat;     // 最后发送
  26.     }
  27. }
复制代码

1 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:430
  • 最近打卡:2026-05-03 14:14:42

34

主题

177

回帖

2067

积分

金牌会员

积分
2067
发表于 1 小时前 | 显示全部楼层
angm*** 发表于 2026-5-3 14:29
你这个现象本质上不是“串口硬件把 +2 变成了 +1”,而是 你在读写同一个 SBUF 时发生了写回/读回混淆,再 ...


我现在用的是没有dat+2,而是原样输出,也没有输出。根本没报告接收。

  1. #include <STC89C5xRC.H>
  2. void UART_Init(void);
  3. void main(void)
  4. {
  5.                 unsigned char dat;
  6.     UART_Init();         // 调用串口初始化,配置 9600, 8N1
  7.     while(1)             // 无限循环,不断执行回显功能
  8.     {
  9.         // 1. 等待接收一个字节
  10.         while(!RI);
  11.                                 dat=SBUF;
  12.         RI = 0;//dat+=2;
  13.         while(!TI);
  14.         TI = 0;
  15.                         SBUF=dat;
  16.                 }
  17. }
  18. void UART_Init(void)
  19. {
  20.     SCON = 0x50;      // 方式1,允许接收。注意这里是0x50,TI/RI由硬件操作,通常初始0即可
  21.     // 或直接 SCON = 0x51; 也完全没问题,手动物清了TI和RI
  22.     TMOD &= 0x0F;     // 修改的是 高 4 位(定时器 1),而 低 4 位(定时器 0)完全没有改变。
  23.         //TMOD的高四位是关于TImer1,低四位是Timer0.
  24.     TMOD |= 0x20;     // 设定定时器1为方式2 (8位自动重装)
  25.     TH1 = 0xFD;       // 波特率9600 (晶振11.0592MHz)
  26.     TL1 = 0xFD;
  27.     ET1 = 0;          // 禁止定时器1中断,用作波特率发生器时通常不产生中断
  28.     TR1 = 1;          // 启动定时器1
  29.     // 如果用到中断接收,再开总中断和串口中断
  30.     ES = 0;           // 允许串口中断
  31.     EA = 0;           // CPU开总中断
  32. }
  33. // 串口中断服务函数(空实现,什么都不做)
  34. void UART_ISR(void) interrupt 4
  35. {
  36.     // 空函数体
  37.     // 这里可以后续添加接收/发送处理
  38. }
复制代码

截图202605031503231482.jpg

回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-5-3 16:12 , Processed in 0.117225 second(s), 63 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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