pljhc 发表于 2025-10-14 11:43:46

串口接收超时触发不正确,已解决,STC8H8K64U芯片不支持接收超时中断功能

使用串口1,进行DMA发送和接收,想在接收时,使用串口的接收超时中断来接收不定长的数据,

void UART1_Init(void)
{
#ifdef BAUDRATE
#undef BAUDRATE
#endif
#define BAUDRATE                (115200)
#define T2_RELOAD               (65536 - (SYSCLK / BAUDRATE + 2) / 4)

    UART1_SwitchP3637();                //设置串口数据端口: RxD (P3.6), TxD (P3.7)

    UART1_Timer2BRT();                  //选择定时器2作为串口1波特率发生器
    TIMER2_TimerMode();               //设置定时器2为定时模式
    TIMER2_1TMode();                  //设置定时器2为1T模式
    TIMER2_SetPrescale(0);            //设置定时器2的8位预分频
    TIMER2_SetReload16(T2_RELOAD);      //设置定时器2的16位重载值
    TIMER2_Run();                     //定时器2开始运行

    UART1_EnableRx();                   //使能串口1接收数据
    UART1_Mode1();                      //设置串口1为模式1 (8位数据可变波特率)
    UART1_SetIntPriority(0);            //设置中断为最低优先级
    UART1_EnableInt();                  //使能串口1中断

    DMA_UART1_SetTxAmount(99);          //设置串口DMA发送总字节数
    DMA_UART1_SetTxAddress(pu8UR1DMATxBuffer); //设置串口DMA发送缓冲区地址
    DMA_UART1_ClearTxFlag();            //清除串口发送DMA中断标志
    DMA_UART1_SetTxBusPriority(0);      //设置总线访问为最低优先级
    DMA_UART1_SetTxIntPriority(0);      //设置中断为最低优先级
    DMA_UART1_EnableTxInt();            //使能串口1DMA发送中断
    DMA_UART1_EnableTx();               //使能串口1DMA发送功能
//DMA_UART1_TriggerTx();            //触发串口1DMA发送

    DMA_UART1_SetRxAmount(99);          //设置串口DMA接收总字节数
    DMA_UART1_SetRxAddress(pu8UR1DMARxBuffer); //设置串口DMA接收缓冲区地址
    DMA_UART1_ClearFIFO();            //清空串口DMA接收FIFO缓冲区
    DMA_UART1_ClearRxFlag();            //清除串口接收DMA中断标志
    DMA_UART1_SetRxBusPriority(0);      //设置总线访问为最低优先级
    DMA_UART1_SetRxIntPriority(0);      //设置中断为最低优先级
    DMA_UART1_EnableRxInt();            //使能串口1DMA接收中断
    DMA_UART1_EnableRx();               //使能串口1DMA接收功能
//DMA_UART1_TriggerRx();            //触发串口1DMA接收

    //<<AICUBE_USER_UART1_INITIAL_BEGIN>>
    // 在此添加用户初始化代码
      DMA_UART1_TriggerRx();            //触发串口1DMA接收
    //<<AICUBE_USER_UART1_INITIAL_END>>
}


串口超时设置,说实话不知道这个超时时长怎么去设置,在论坛上看的别人的

UR1TOCR = 0xC0; //开启超时中断,SCALE(bit5) = 0:使用波特率bit时钟周期; 1:使用系统时钟周期
    UR1TOTL = 0x80; //设置超时时间:128个位时钟周期=(1000000/115200)*128us
    UR1TOTH = 0x00;
    UR1TOTE = 0x00; //写完TE超时时间才会生效




////////////////////////////////////////
// 串口1中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void UART1_ISR(void) interrupt UART1_VECTOR
{
    //<<AICUBE_USER_UART1_ISR_CODE1_BEGIN>>
    // 在此添加中断函数用户代码
    if (UART1_CheckTxFlag())            //判断串口发送中断
    {
      UART1_ClearTxFlag();            //清除串口发送中断标志
    }

    if (UART1_CheckRxFlag())            //判断串口接收中断
    {
      UART1_ClearRxFlag();            //清除串口接收中断标志
                UART1_EnableTimeout();                        //使能串口接收超时中断功能控制位
    }
      
      if (UART1_CheckTimeoutFlag())       //判断串口超时中断请求标志位
    {
      UART1_ClearTimeoutFlag();       //清除串口超时中断请求标志位
                UART1_DisableTimeout();                        //清除串口接收超时中断功能控制位
                Usart1.RecvFlag=1;
                Usart1.RecvCnt=DMA_UART1_ReadRxDone();
                DMA_UART1_DisableRx();                        //清零DMA_UART1_ReadRxDone
                DMA_UART1_EnableRx();
                DMA_UART1_TriggerRx();                        //触发串口1DMA接收
    }
    //<<AICUBE_USER_UART1_ISR_CODE1_END>>
}


现在的现象是每次超时中断后,Usart1.RecvCnt=DMA_UART1_ReadRxDone();通过DMA_UART1_ReadRxDone()读取的DMA已经接收的数据为1或是2,不知道是哪一块出了问题,求教

国芯人工智能 发表于 2025-10-14 11:48:00

关于串口接收超时触发不正确的问题分析与解决方案

一、问题现象描述
在使用串口1进行DMA收发操作时,采用接收超时中断接收不定长数据包时出现异常。具体表现为:
1. 超时中断触发时机不准确
2. 数据接收完整性无法保证
3. 存在数据包截断或合并现象

二、硬件配置分析
当前配置使用定时器2作为波特率发生器,工作在模式1(8位异步串行通信模式),DMA传输配置未在代码片段中体现。关键配置参数:
波特率:115200 bps
定时器模式:1T模式
重载值计算:T2RELOAD = 65536 - (SYSCLK / BAUDRATE + 2) / 4

三、超时机制实现要点
1. 硬件超时中断触发条件
串口控制器检测到接收线上空闲时间超过设定阈值
通常以帧时间为基准(1帧=10bit)
触发后产生UARTxRTOF标志位

2. 软件配置关键点
超时计数器加载值设置(RTOR寄存器)
超时中断使能控制(IERx.RTIE)
FIFO接收触发阈值配置(FCRx.RFTL)

四、典型问题排查方向
1. 时钟配置验证
SYSCLK参数是否正确定义
定时器2分频系数是否匹配系统时钟
实际波特率误差是否超过允许范围(建议

[本文内容由国芯人工智能辅助生成,仅供参考]

乘风飞扬 发表于 2025-10-14 12:09:06

可能只是读取 DMA_UR1R_DONE 的时间不对,可参考这个帖子介绍:

关于寄存器DMA_UR1R_DONE的应用问题
https://www.stcaimcu.com/thread-4675-1-1.html
(出处: 国芯人工智能技术交流网站)

pljhc 发表于 2025-10-14 14:03:34

芯片使用的是STC8H8K64U,串口波特率配置等使用的是AiCube软件生成

////////////////////////////////////////
// 串口1初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void UART1_Init(void)
{
#ifdef BAUDRATE
#undef BAUDRATE
#endif
#define BAUDRATE                (115200)
#define T2_RELOAD               (65536 - (SYSCLK / BAUDRATE + 2) / 4)

    UART1_SwitchP3637();                //设置串口数据端口: RxD (P3.6), TxD (P3.7)

    UART1_Timer2BRT();                  //选择定时器2作为串口1波特率发生器
    TIMER2_TimerMode();               //设置定时器2为定时模式
    TIMER2_1TMode();                  //设置定时器2为1T模式
    TIMER2_SetPrescale(0);            //设置定时器2的8位预分频
    TIMER2_SetReload16(T2_RELOAD);      //设置定时器2的16位重载值
    TIMER2_Run();                     //定时器2开始运行

    UART1_EnableRx();                   //使能串口1接收数据
    UART1_Mode1();                      //设置串口1为模式1 (8位数据可变波特率)
    UART1_SetIntPriority(0);            //设置中断为最低优先级
    UART1_EnableInt();                  //使能串口1中断

    DMA_UART1_SetTxAmount(99);          //设置串口DMA发送总字节数
    DMA_UART1_SetTxAddress(pu8UR1DMATxBuffer); //设置串口DMA发送缓冲区地址
    DMA_UART1_ClearTxFlag();            //清除串口发送DMA中断标志
    DMA_UART1_SetTxBusPriority(0);      //设置总线访问为最低优先级
    DMA_UART1_SetTxIntPriority(0);      //设置中断为最低优先级
    DMA_UART1_EnableTxInt();            //使能串口1DMA发送中断
    DMA_UART1_EnableTx();               //使能串口1DMA发送功能
//DMA_UART1_TriggerTx();            //触发串口1DMA发送

    DMA_UART1_SetRxAmount(99);          //设置串口DMA接收总字节数
    DMA_UART1_SetRxAddress(pu8UR1DMARxBuffer); //设置串口DMA接收缓冲区地址
    DMA_UART1_ClearFIFO();            //清空串口DMA接收FIFO缓冲区
    DMA_UART1_ClearRxFlag();            //清除串口接收DMA中断标志
    DMA_UART1_SetRxBusPriority(0);      //设置总线访问为最低优先级
    DMA_UART1_SetRxIntPriority(0);      //设置中断为最低优先级
    DMA_UART1_EnableRxInt();            //使能串口1DMA接收中断
    DMA_UART1_EnableRx();               //使能串口1DMA接收功能
//DMA_UART1_TriggerRx();            //触发串口1DMA接收

    //<<AICUBE_USER_UART1_INITIAL_BEGIN>>
    // 在此添加用户初始化代码
        DMA_UART1_TriggerRx();            //触发串口1DMA接收
    //<<AICUBE_USER_UART1_INITIAL_END>>
}

现在其实我怀疑是串口超时这一块没有配置好,另外就是想要1个字节的超时,不知道怎么去配置,将指教{:4_165:}

jwd 发表于 2025-10-14 14:18:38

pljhc 发表于 2025-10-14 14:03
芯片使用的是STC8H8K64U,串口波特率配置等使用的是AiCube软件生成

//////////////////////////////////// ...

STC8H8K64U没有硬件超时吧

_奶咖君_ 发表于 2025-10-14 15:47:00

pljhc 发表于 2025-10-14 14:03
芯片使用的是STC8H8K64U,串口波特率配置等使用的是AiCube软件生成

//////////////////////////////////// ...

这个片子没有超时中断啊,,看过手册了么?

pljhc 发表于 2025-10-14 18:16:30

刚查了,STC8H8K64U是没有接收超时中断功能,谢谢大家

xyzdh 发表于 2026-2-24 17:21:41

我用的是stc8h4k64TL, 因为带串口接收超时中断毕竟是少数,如果还开串口发送接收中断,就失去了使用DMA的意义,因此我换了一个思路接收不定长的数据,那就是周期读取DMA_UR1R_DONE的大小,获取已经接收的数据大小,如果大于1,说明已经开始接收,如果不在增大,说明接收完成。

我是30M主频,115200波特率,1ms定时中断查询。实际测试通过,挺好用。

void Timer0_Isr(void) interrupt TMR0_VECTOR
{       
        // 帧接收计时
        if( uart1.stu == 10 )
        {
                // 开始DMA接收
                if( (DMA_UR1R_DONE - uart1.recv_cnt) < 8 )
                {
                        // 帧接收完成
                        uart1.stu = 20;
                }
                uart1.recv_cnt = DMA_UR1R_DONE;
                uart1.idle_tov        = ee.idle_tset;       
               
                if( uart1.idle_tov != 0 )
                {
                        uart1.idle_tov--;
                }
        }
        // 接收空闲计时
        else if( uart1.stu == 0 )
        {
                // 开始DMA接收
                if( (DMA_UR1R_DONE - uart1.recv_cnt) > 1 )
                {
                        uart1.stu = 10;
                        uart1.recv                = buf;
                        uart1.recv_cnt = DMA_UR1R_DONE;
                        uart1.idle_tov        = ee.idle_tset;       
                }
      }
}


void UART1_DMA_Transmit(char* ptr, int len)
{
    DMA_UR1T_CFG = 0x80;                        //中断允许和中断优先级
    DMA_UR1T_STA = 0x00;                        //状态寄存器全部清零
    DMA_UR1T_TXAH = (u8)((u16)ptr >> 8);        //发送数组地址高
    DMA_UR1T_TXAL = (u8)((u16)ptr);               //发送数组地址低

    DMA_UR1T_STA = 0x00;            //状态寄存器全部清零
    DMA_UR1T_AMT = (u8)len-1;       //设置传输总字节数:n+1
    DMA_UR1T_CR = 0xc0;             //bit7 1:使能 UART1_DMA, bit6 1:开始 UART1_DMA 自动发送
}

void UART1_DMA_Receive(char* ptr, int len)
{
    DMA_UR1R_CFG = 0x80;                        //中断允许和中断优先级
    DMA_UR1R_STA = 0x00;                        //状态寄存器全部清零
    DMA_UR1R_RXAH = (u8)((u16)ptr >> 8);        //数组地址高
    DMA_UR1R_RXAL = (u8)((u16)ptr);              //数组地址低

    DMA_UR1R_STA = 0x00;            //状态寄存器全部清零
    DMA_UR1R_AMT = (u8)len;              //设置传输总字节数:n+1
    DMA_UR1R_CR = 0x00;
    DMA_UR1R_CR = 0xa1;             //bit7 1:使能 UART1_DMA, bit5 1:开始 UART4_DMA 自动接收, bit0 1:清除 FIFO
    uart1.recv_cnt = DMA_UR1R_DONE;
}

//========================================================================
// 函数: void UART1_DMA_Interrupt (void) interrupt 50/51
// 描述: UART1 DMA中断函数
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-5-8
// 备注:
//========================================================================
void UART1_DMA_Isr(void) interrupt USER_VECTOR
{
    if (DMA_UR1T_STA & 0x01)      //发送完成
    {
                DMA_UR1T_STA &= ~0x01;
                uart1.stu = 0;
                UART1_DMA_Receive(uart1.recv ,250);
    }
    if (DMA_UR1T_STA & 0x04)      //数据覆盖
    {
                DMA_UR1T_STA &= ~0x04;
    }
   
    if (DMA_UR1R_STA & 0x01)      //接收完成
    {      
                DMA_UR1R_STA &= ~0x01;
    }
    if (DMA_UR1R_STA & 0x02)      //数据丢弃
    {
                DMA_UR1R_STA &= ~0x02;
    }
}


陈家乐 发表于 2026-3-4 11:40:32

pljhc 发表于 2025-10-14 16:16
刚查了,STC8H8K64U是没有接收超时中断功能,谢谢大家

我有STC8H8K64U的uCOSII软件定时器实现串口超时接收模拟的代码,这几个片子不支持硬件串口超时接收中断的,得模拟
页: [1]
查看完整版本: 串口接收超时触发不正确,已解决,STC8H8K64U芯片不支持接收超时中断功能