liuyuhe 发表于 2026-5-11 12:30:28

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

开发板:开天斧三.1 2022/8/27

mcu:stc8h8k64u
时钟:24Mhz
串口1,time0做超时定时器
上位机:V6.96V-plus
hex模式发送“1”;接收到2个字节,多字节发送同样是2N的字节长度
#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;// 接收缓冲区
unsigned intUART_RX_LEN = 0;            // 已接收长度
unsigned char UART_RX_FLAG = 0;             // 帧接收完成标志 1=完成
unsigned intUART_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;
                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 = 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中断
}



liuyuhe 发表于 2026-5-11 12:31:52

#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;// 接收缓冲区
unsigned intUART_RX_LEN = 0;            // 已接收长度
unsigned char UART_RX_FLAG = 0;             // 帧接收完成标志 1=完成
unsigned intUART_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;
                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 = 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中断
}

lcwswust 发表于 2026-5-11 13:32:35

“UART_RX_LEN++”有重复,建议去掉其中一个。
建议将接收数据时读取SBUF操作放在“RI = 0;”之后“if(UART_RX_FLAG == 0) ”之前,如果不读可能会重复引发中断。

liuyuhe 发表于 2026-5-11 14:08:27

ok啊,搞定了,没注意那条代码
页: [1]
查看完整版本: 串口发送的字节数和接收的字节数不一致 | 已解决