找回密码
 立即注册
查看: 36|回复: 3

串口发送的字节数和接收的字节数不一致 | 已解决

[复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:16
  • 最近打卡:2026-05-11 12:30:28

14

主题

25

回帖

242

积分

中级会员

积分
242
发表于 3 天前 | 显示全部楼层 |阅读模式
开发板:开天斧三.1 2022/8/27

mcu:stc8h8k64u
时钟:24Mhz
串口1,time0做超时定时器
上位机:V6.96V-plus
hex模式发送“1”;接收到2个字节,多字节发送同样是2N的字节长度
  1. #include <STC8H.H>
  2. #include "modbus_rtu.h"
  3. void Timer0_Init(void);                //1毫秒@24.000MHz
  4. void Uart1_Init(void);        //115200bps@24.000MHz
  5. void IO_Init(void);     // 初始化IO口
  6. uint16_t uart1_timeout = 0;         // 通讯超时计数器
  7. #define uart1_timeout_max 5         //通讯超时
  8. bit timeout_flag = 0;         // 超时标志位
  9. // 你只需要改这 2 个参数
  10. #define RX_BUF_MAX_LEN    64    // 接收缓冲区最大长度
  11. #define RX_TIMEOUT_MS     10    // 超时时间(单位:ms)
  12. // 全局变量
  13. unsigned char UART_RX_BUF[RX_BUF_MAX_LEN];  // 接收缓冲区
  14. unsigned int  UART_RX_LEN = 0;              // 已接收长度
  15. unsigned char UART_RX_FLAG = 0;             // 帧接收完成标志 1=完成
  16. unsigned int  UART_RX_TIMEOUT = 0;          // 超时计数器
  17. void Delay1ms(void)        //@24.000MHz
  18. {
  19.         unsigned char data i, j;
  20.         _nop_();
  21.         i = 32;
  22.         j = 40;
  23.         do
  24.         {
  25.                 while (--j);
  26.         } while (--i);
  27. }
  28. void main(void)
  29. {
  30.     uint16_t i = 0;
  31.     IO_Init();       // 初始化IO口
  32.     Timer0_Init();   // 初始化定时器0
  33.     Uart1_Init();    // 初始化串口1
  34.     EA = 1;
  35. //    P2 = 0x00;
  36.     while (1)
  37.     {
  38.         
  39.         if (UART_RX_FLAG == 1)      //接收完成标志
  40.         {
  41.             UART_RX_FLAG = 0;          // 清除接收完成标志
  42.             SBUF = UART_RX_LEN;
  43. /**            for (i = 0; i < UART_RX_LEN; i++)
  44.             {
  45.                 //SBUF = UART_RX_BUF[i];
  46.                 while (!TI);
  47.             }
  48. */                UART_RX_LEN = 0;
  49.         }
  50.         
  51.     }
  52.    
  53. }
  54. void Timer0_Isr(void) interrupt 1
  55. {
  56.     TF0 = 0;        // 清除TF0标志位
  57.     if(UART_RX_LEN > 0 && UART_RX_FLAG == 0) // 正在接收数据
  58.     {
  59.         UART_RX_TIMEOUT++;  // 每ms +1  
  60.         // 超时判断:超过设定时间 → 帧结束
  61.         if(UART_RX_TIMEOUT >= RX_TIMEOUT_MS)
  62.         {
  63.             UART_RX_FLAG = 1;   // 标记一帧接收完成
  64.             UART_RX_TIMEOUT = 0;        //清除超时标志位
  65.         }
  66.     }
  67.    
  68. }
  69. void Uart1_Isr(void) interrupt 4
  70. {
  71.         if (TI)                                //检测串口1发送中断
  72.         {
  73.                 TI = 0;                        //清除串口1发送中断请求位
  74.         }
  75.         if (RI)                                //检测串口1接收中断
  76.         {
  77.                 RI = 0;                        //清除串口1接收中断请求位
  78.         if(UART_RX_FLAG == 0)  // 还没接收完成
  79.         {
  80.             UART_RX_BUF[UART_RX_LEN++] = SBUF;   // 存数据
  81.             UART_RX_LEN++;
  82.             UART_RX_TIMEOUT = 0;                 // 收到数据,清空计时器
  83.             // 防止缓冲区溢出
  84.             if(UART_RX_LEN >= RX_BUF_MAX_LEN)
  85.             {
  86.                 UART_RX_LEN = 0;
  87.             }
  88.         }
  89.         }
  90. }
  91. void Uart1_Init(void)        //115200bps@24.000MHz
  92. {
  93.         SCON = 0x50;                //8位数据,可变波特率
  94.         AUXR |= 0x40;                //定时器时钟1T模式
  95.         AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
  96.         TMOD &= 0x0F;                //设置定时器模式
  97.         TL1 = 0xCC;                        //设置定时初始值
  98.         TH1 = 0xFF;                        //设置定时初始值
  99.         ET1 = 0;                        //使能定时器1中断
  100.         TR1 = 1;                        //定时器1开始计时
  101.         ES = 1;                                //使能串口1中断
  102. }
  103. void IO_Init(void)          // 初始化IO口
  104. {
  105.     P0M0 = 0x00; P0M1 = 0x00;
  106.     P1M0 = 0x00; P1M1 = 0x00;
  107.     P2M0 = 0x00; P2M1 = 0x00;
  108.     P3M0 = 0x00; P3M1 = 0x00;
  109.     P4M0 = 0x00; P4M1 = 0x00;
  110.     P5M0 = 0x00; P5M1 = 0x00;
  111.     P6M0 = 0x00; P6M1 = 0x00;
  112.     P7M0 = 0x00; P7M1 = 0x00;
  113. }
  114. void Timer0_Init(void)                //1毫秒@24.000MHz
  115. {
  116.         AUXR &= 0x7F;                        //定时器时钟12T模式
  117.         TMOD &= 0xF0;                        //设置定时器模式
  118.         TL0 = 0x30;                                //设置定时初始值
  119.         TH0 = 0xF8;                                //设置定时初始值
  120.         TF0 = 0;                                //清除TF0标志
  121.         TR0 = 1;                                //定时器0开始计时
  122.         ET0 = 1;                                //使能定时器0中断
  123. }
复制代码

捕获.PNG

回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:16
  • 最近打卡:2026-05-11 12:30:28

14

主题

25

回帖

242

积分

中级会员

积分
242
发表于 3 天前 | 显示全部楼层
#include <STC8H.H>
#include "modbus_rtu.h"

void Timer0_Init(void);                //1毫秒@24.000MHz
void Uart1_Init(void);        //115200bps@24.000MHz
void IO_Init(void);     // 初始化IO口



uint16_t uart1_timeout = 0;         // 通讯超时计数器
#define uart1_timeout_max 5         //通讯超时

bit timeout_flag = 0;         // 超时标志位

// 你只需要改这 2 个参数
#define RX_BUF_MAX_LEN    64    // 接收缓冲区最大长度
#define RX_TIMEOUT_MS     10    // 超时时间(单位:ms)

// 全局变量
unsigned char UART_RX_BUF[RX_BUF_MAX_LEN];  // 接收缓冲区
unsigned int  UART_RX_LEN = 0;              // 已接收长度
unsigned char UART_RX_FLAG = 0;             // 帧接收完成标志 1=完成
unsigned int  UART_RX_TIMEOUT = 0;          // 超时计数器


void Delay1ms(void)        //@24.000MHz
{
        unsigned char data i, j;

        _nop_();
        i = 32;
        j = 40;
        do
        {
                while (--j);
        } while (--i);
}

void main(void)
{
    uint16_t i = 0;

    IO_Init();       // 初始化IO口
    Timer0_Init();   // 初始化定时器0
    Uart1_Init();    // 初始化串口1
    EA = 1;
//    P2 = 0x00;
    while (1)
    {
        
        if (UART_RX_FLAG == 1)      //接收完成标志
        {
            UART_RX_FLAG = 0;          // 清除接收完成标志
            SBUF = UART_RX_LEN;
/**            for (i = 0; i < UART_RX_LEN; i++)
            {
                //SBUF = UART_RX_BUF[i];
                while (!TI);
            }
*/                UART_RX_LEN = 0;

        }
        
    }
   
}
void Timer0_Isr(void) interrupt 1
{
    TF0 = 0;        // 清除TF0标志位
    if(UART_RX_LEN > 0 && UART_RX_FLAG == 0) // 正在接收数据
    {
        UART_RX_TIMEOUT++;  // 每ms +1  
        // 超时判断:超过设定时间 → 帧结束
        if(UART_RX_TIMEOUT >= RX_TIMEOUT_MS)
        {
            UART_RX_FLAG = 1;   // 标记一帧接收完成
            UART_RX_TIMEOUT = 0;        //清除超时标志位
        }
    }
   
}

void Uart1_Isr(void) interrupt 4
{
        if (TI)                                //检测串口1发送中断
        {
                TI = 0;                        //清除串口1发送中断请求位
        }
        if (RI)                                //检测串口1接收中断
        {
                RI = 0;                        //清除串口1接收中断请求位
        if(UART_RX_FLAG == 0)  // 还没接收完成
        {
            UART_RX_BUF[UART_RX_LEN++] = SBUF;   // 存数据
            UART_RX_LEN++;
            UART_RX_TIMEOUT = 0;                 // 收到数据,清空计时器
            // 防止缓冲区溢出
            if(UART_RX_LEN >= RX_BUF_MAX_LEN)
            {
                UART_RX_LEN = 0;
            }
        }
        }
}

void Uart1_Init(void)        //115200bps@24.000MHz
{
        SCON = 0x50;                //8位数据,可变波特率
        AUXR |= 0x40;                //定时器时钟1T模式
        AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
        TMOD &= 0x0F;                //设置定时器模式
        TL1 = 0xCC;                        //设置定时初始值
        TH1 = 0xFF;                        //设置定时初始值
        ET1 = 0;                        //使能定时器1中断
        TR1 = 1;                        //定时器1开始计时
        ES = 1;                                //使能串口1中断
}
void IO_Init(void)          // 初始化IO口
{
    P0M0 = 0x00; P0M1 = 0x00;
    P1M0 = 0x00; P1M1 = 0x00;
    P2M0 = 0x00; P2M1 = 0x00;
    P3M0 = 0x00; P3M1 = 0x00;
    P4M0 = 0x00; P4M1 = 0x00;
    P5M0 = 0x00; P5M1 = 0x00;
    P6M0 = 0x00; P6M1 = 0x00;
    P7M0 = 0x00; P7M1 = 0x00;

}

void Timer0_Init(void)                //1毫秒@24.000MHz
{
        AUXR &= 0x7F;                        //定时器时钟12T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TL0 = 0x30;                                //设置定时初始值
        TH0 = 0xF8;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时
        ET0 = 1;                                //使能定时器0中断
}
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:111
  • 最近打卡:2026-05-11 13:32:35
已绑定手机

4

主题

278

回帖

6203

积分

论坛元老

积分
6203
发表于 3 天前 | 显示全部楼层
“UART_RX_LEN++”有重复,建议去掉其中一个。
建议将接收数据时读取SBUF操作放在“RI = 0;”之后“  if(UART_RX_FLAG == 0) ”之前,如果不读可能会重复引发中断。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:16
  • 最近打卡:2026-05-11 12:30:28

14

主题

25

回帖

242

积分

中级会员

积分
242
发表于 3 天前 | 显示全部楼层
ok啊,搞定了,没注意那条代码
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-5-14 16:45 , Processed in 0.107682 second(s), 60 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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