gosoyi 发表于 2025-6-20 20:48:26

求助,关于串口2中断打开后定时器3不能工作的问题

8H3K32S2,
T1做串口1波特率发生器9600
T0,5ms
T2串口2,波特率38400
T3.10ms
T4,300us

void init_485_uart()   //38400@11.0592 串口2
{
        S2CON = 0x10;                //8位数据,可变波特率
        AUXR |= 0x04;                //定时器时钟1T模式
        T2L = 0xB8;                //设置定时初始值
        T2H = 0xFF;                //设置定时初始值
        AUXR |= 0x10;                //定时器2开始计时

// IE2 = ES2;   //使能串口中断
//IP2 |= 0x20;    // 置位IP2.5,串口2中断优先级为高(1<<5 = 0x20)
       
}
void Timer3_Init(void)                //10毫秒@11.0592MHz
{
        T4T3M &= 0xFD;                        //定时器时钟12T模式
        T3L = 0x00;                                //设置定时初始值
        T3H = 0xDC;                                //设置定时初始值
        T4T3M |= 0x08;                        //定时器3开始计时,定时器4开始计时
       
        //IE2 |=ET3;   //打开定时器3中断


}
void Timer4_Init(void)                //300微秒@11.0592MHz
{
        T4T3M &= 0xDF;                        //定时器时钟12T模式
        T4L = 0xEC;                                //设置定时初始值
        T4H = 0xFE;                                //设置定时初始值
        T4T3M |= 0x80;                        //定时器4开始计时

        //IE2 |=ET4;         // 启用定时器4中断(ET4 = 1)
        IE2 |=0x61;         // 启用定时器4中断(ET4 = 1)
}
void Timer0_Init(void)                //5毫秒@11.0592MHz
{

        AUXR |= 0x80;                        //定时器时钟1T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TL0 = 0x00;                                //设置定时初始值
        TH0 = 0x28;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时

        ET0 = 1;
}
void init_debug_uart()//9600bps@11.0592MH 串口1
{       
       
        PCON &= 0x7F;                //波特率不倍速
        SCON = 0x50;                //8位数据,可变波特率
        AUXR |= 0x40;                //定时器1时钟为Fosc,即1T
        AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
        TMOD &= 0x0F;                //清除定时器1模式位
TMOD |= 0x20;                //设定定时器1为8位自动重装方式
        TL1 = 0xDC;                //设定定时初值
        TH1 = 0xDC;                //设定定时器重装值
        ET1 = 0;                //禁止定时器1中断
        TR1 = 1;                //启动定时器1
}


IE2 |= 0x01;// 使能串口2中断 ES2
IE2 |= 0x20;// 使能定时器3中断 ET3
IE2 |= 0x40;// 使能定时器4中断 ET4

发现ES2被置1后T3,T4就不工作了,不知道是什么原因,望大神帮忙解答一下,谢谢


神农鼎 发表于 2025-6-20 21:06:58

建议用下面的思路写中断服务程序,
中断服务程序,需要处理:
【A,特急的事件;B,不是特急的部分事件】
A,特急的事件在中断服务程序中及时处理;
B,不是特急的部分事件,中断服务程序中,
      树个标志位,在主循环中查询到再处理;



#include <AI8051U.H>                        //包含AI8051U的头文件

#include"ai_usb.h"                        //USB库和USB虚拟设备的头文件,需要在项目文件中添加对应的USB库
                                                                //由于在USB库函数的代码中已经定义了,不停电ISP下载命令字”@STCISP#”,
                                                                //只需要在下载软件的“收到用户命令后复位到ISP监控程序区”选项卡中进行相应的设置,
                                                                //即可实现USB不停电ISP下载功能,或串口不停电ISP下载功能。

#include "intrins.h"                        //使用_nop_()函数所必须要包含的头文件,
                                                                //否则延时函数中调用的_nop_()函数没有被头文件引用过来,
                                                                //会导致编译器找不到这个而函数而报错。

bit         int0_flag = 0;                        //定义1个位变量,INT0事件位变量标志,记录INT0已产生中断
// 供主循环查询INT0是否已产生中断,在主循环中处理INT0的中断事件任务,不堵塞其他中断
bit         int1_flag = 0;                        //定义1个位变量,INT1事件位变量标志,记录INT1已产生中断
// 供主循环查询INT1是否已产生中断,在主循环中处理INT1的中断事件任务,不堵塞其他中断
bit         t0_flag = 0;                        //定义1个位变量,T0事件位变量标志,记录定时器0已产生中断
// 供主循环查询定时器0是否已产生中断,在主循环中处理定时器0的中断事件任务,不堵塞其他中断
bit         t1_flag = 0;                        //定义1个位变量,T1事件位变量标志,记录定时器1已产生中断
// 供主循环查询定时器1是否已产生中断,在主循环中处理定时器1的中断事件任务,不堵塞其他中断

void Timer0_Init(void)                        //定时器0初始化,2秒@40.000MHz
{
      TM0PS = 0x65;                              //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
      AUXR &= 0x7F;                              //定时器时钟12T模式
      TMOD &= 0xF0;                              //设置定时器模式
      TL0 = 0xB1;                                        //设置定时初始值
      TH0 = 0x00;                                        //设置定时初始值
      TF0 = 0;                                        //清除TF0标志
      TR0 = 1;                                        //定时器0开始计时
      ET0 = 1;                                        //使能定时器0中断
}

void Timer1_Init(void)                        //定时器1初始化,500毫秒@40.000MHz
{
      TM1PS = 0x19;                              //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
      AUXR &= 0xBF;                              //定时器时钟12T模式
      TMOD &= 0x0F;                              //设置定时器模式
      TL1 = 0x99;                                        //设置定时初始值
      TH1 = 0x05;                                        //设置定时初始值
      TF1 = 0;                                        //清除TF1标志
      TR1 = 1;                                        //定时器1开始计时
      ET1 = 1;                                        //使能定时器1中断
}

void main (void)
{
      EAXFR = 1;                                        //允许访问扩展的特殊寄存器,XFR
      WTST = 0;                                        //设置取程序代码等待时间,赋值为0表示不等待,程序以最快速度运行
      CKCON = 0;                                        //设置访问片内的xdata速度,赋值为0表示用最快速度访问,不增加额外的等待时间

      P0M0 = 0x00; P0M1 = 0x00;         //设置 P0 口为准双向口模式
      P1M0 = 0x00; P1M1 = 0x00;         //设置 P1 口为准双向口模式
      P2M0 = 0x00; P2M1 = 0x00;         //设置 P2 口为准双向口模式
      //P3M0 = 0x00; P3M1 = 0x00; //设置 P3 口为准双向口模式
      P3M0 = 0x00; P3M1 = 0x0c;         //P32、P33设置为高阻输入(需要同步开启上拉电阻)
      P4M0 = 0x00; P4M1 = 0x00;         //设置 P4 口为准双向口模式
      P5M0 = 0x00; P5M1 = 0x00;         //设置 P5 口为准双向口模式
      P6M0 = 0x00; P6M1 = 0x00;         //设置 P6 口为准双向口模式
      P7M0 = 0x00; P7M1 = 0x00;         //设置 P7 口为准双向口模式

      P3PU = 0x0c;                                 //P32、P33打开上拉电阻

      IT0 = 0;                                       //使能 INT0 上升沿和下降沿中断
      //      IT0 = 1;                                 //使能 INT0 下降沿中断
      EX0 = 1;                                       //使能 INT0 中断

      //      IT1 = 0;                                 //使能 INT1 上升沿和下降沿中断
      IT1 = 1;                                       //使能 INT1 下降沿中断
      EX1 = 1;                                       //使能 INT1 中断

      IE0 = 0;                                        //清INT0中断标志
      IE1 = 0;                                        //清INT1中断标志

      int0_flag = 0;                              //初始化用户标志位
      int1_flag = 0;                              //初始化用户标志位

      Timer0_Init();                              //调用定时器0初始化函数
      Timer1_Init();                              //调用定时器1初始化函数

      usb_init();                                        //调用USB初始化函数,不需要立即判断电脑已正确识别到USB从设备
      /* USB型单片机从设备,如需要主动向电脑发送数据,
      在执行USB_SendData( )函数和printf_usb( )函数时,
      这两个函数已增加了判断电脑是否已正确识别到USB从设备的程序。
      如果电脑要主动发送数据给USB从设备,电脑自己会主动判断与USB从设备是否已正确连接。
      */

      EA = 1;                                                //总中断允许位打开
      P40 = 0;                                       //打开LED灯供电
      while(1)                                       //主循环中查询需要处理的各种事件,如T0/T1中断事件,并打印输出状态
      {
                /*本演示程序中,主循环查询各中断有无需要继续处理的事件的次序,
                依次是 INT0/INT1/T0/T1, 用户可以自己根据实际情况,
                调整查询各中断有无需要继续处理的事件的优先次序*/

                if(int0_flag)                        //主循环中查询,INT0是否已产生中断,是否有需要处理的INT 0事件
                {
                        int0_flag = 0;                //清0,INT0事件位变量标志
                        _nop_();                        //用户在此添加需要处理的事件
                        _nop_();
                }

                if(int1_flag)                        //主循环中查询,INT1是否已产生中断,是否有需要处理的INT1事件
                {
                        int1_flag = 0;                //清0,INT1事件位变量标志
                        _nop_();                        //用户在此添加需要处理的事件
                        _nop_();
                }

                if(t0_flag)                              //主循环中查询,定时器0是否已产生中断,是否有需要处理的定时器0事件
                {
                        t0_flag = 0;                //清0,T0事件位变量标志
                        printf_usb("Timer0!\r\n");
                        //向电脑USB-CDC串口助手输出“Timer0!”字符串,代表主循环在处理T0不急的任务
                }

                if(t1_flag)                              //主循环中查询,定时器1是否已产生中断,是否有需要处理的定时器1事件
                {
                        t1_flag = 0;                //清0,T1事件位变量标志
                        printf_usb("Timer1!\r\n");
                        //向电脑USB-CDC串口助手输出“Timer1!”字符串,代表主循环在处理T1不急的任务
                }
      }
}

void int0_isr(void) interrupt INT0_VECTOR
{
      int0_flag = 1;                              // int0_flag置1是通知主循环处理部分INT0中断事件不需要特急处理的任务
                                                                //置1,记录INT0已产生中断,供主循环查询判断有无需处理的INT0任务

      if(INT0)                                       //边沿中断,进入后再次判断电平从而判断是什么样的电平
      {
                //      P01 = 0;                        //判断为高电平,则当前为上升沿,点亮P01端口上的LED灯
                //      _nop_();                        //可以在这里插入断点进行观察现象
                //      P01 = 1;                        //关闭LED灯
                P01 = ~P01;                              //如果用外部按键触发INT0,则需另外添加去抖动处理
      }
      else
      {
                //      P06 = 0;                        //判断为低电平,则当前为下降沿,点亮P06端口上的LED灯
                //      _nop_();                        //可以在这里插入断点进行观察现象
                //      P06 = 1;                        //关闭LED灯
                P06 = ~P06;                         //如果用外部按键触发INT0,则需另外添加去抖动处理
      }
}
//INT0中断服务程序,INT0_VECTOR在AI8051U.H头文件中已宏定义为0

void int1_isr(void) interrupt INT1_VECTOR
{
      int1_flag = 1;                              // int1_flag置1是通知主循环处理部分INT1中断事件不需要特急处理的任务
                                                                //置1,记录INT1已产生中断,供主循环查询判断有无需处理的INT1任务

      //      P02= 0;                                        //点亮P02端口上的LED灯
      //      _nop_();                              //可以在这里插入断点观察现象
      //      P02 = 1;                              //关闭LED灯
      P02 = ~P02;                                 //如果用外部按键触发INT1,则需另外添加去抖动处理
}
//INT1中断服务程序,INT1_VECTOR在AI8051U.H头文件中已宏定义为2

void Timer0_Isr(void) interrupt TMR0_VECTOR                //定时器0中断服务程序
{
      P00 = ~P00;                                        //P00灯闪烁,中断服务程序中尽量少执行长的任务,防止堵塞其他中断
      //以上程序代表部分需特急处理的中断事件,可在中断服务程序中直接处理
      //但时间不要太长,否则会影响其他中断事件的实时响应速度
      t0_flag = 1;                              // t0_flag置1是通知主循环处理部分T0中断事件不需要特急处理的任务
                                                                //置1,记录定时器0已产生中断,供主循环查询判断有无需处理的定时器0任务
}
//定时器0中断服务程序,TMR0_VECTOR在AI8051U.H头文件中已宏定义为1

void Timer1_Isr(void) interrupt TMR1_VECTOR
{
      P07 = ~P07;                                        //P07灯闪烁,中断服务程序中尽量少执行长的任务,防止堵塞其他中断
      //以上程序代表部分需特急处理的中断事件,可在中断服务程序中直接处理
      //但时间不要太长,否则会影响其他中断事件的实时响应速度
      t1_flag = 1;                              // t1_flag置1是通知主循环处理部分T1中断事件不需要特急处理的任务
                                                                //置1,记录定时器1已产生中断,供主循环查询判断有无需处理的定时器1任务
}
//定时器1中断服务程序,TMR1_VECTOR在AI8051U.H头文件中已宏定义为3






神农鼎 发表于 2025-6-20 21:12:42















晓飛飛 发表于 2025-6-20 23:39:55

串口2中断和定时器3本没有什么瓜葛,
大概率是串口使能中断后RX脚收到数据但程序里面没有编写中断处理函数,
导致程序卡死无法响应定时器3中断。

gosoyi 发表于 2025-6-21 20:03:26

晓飛飛 发表于 2025-6-20 23:39
串口2中断和定时器3本没有什么瓜葛,
大概率是串口使能中断后RX脚收到数据但程序里面没有编写中断处理函数 ...

程序其他部分运行正常,串口1,2都能发送接收,只是定时器3,定时器4不进中断,在定时器3,4中断函数里加引脚翻转用示波器测试发现,串口2每接收一次数据定时器3,4就中断一次,说明定时器3,4跟串口2中断是有关系的。

DebugLab 发表于 6 天前

你的程序中未搜索到interrupt关键字
打开的中断必须要有中断函数
否则程序跑飞

新手必读:
https://www.stcaimcu.com/thread-16535-1-1.html

各种中断问题:
打开的中断必须要有中断函数,哪怕是空的也行,否则硬件产生中断后,PC LJMP到中断向量处,无中断程序也无RETI,程序直接跑飞,导致意外死机或复位
中断频率不能过高,也不能在中断函数内执行耗时操作
如中断函数执行时间占比大于100%,中断还没退出就再次请求中断,就会卡在中断里一直循环出不来,主程序和优先级更低或查询次序靠后的中断会被阻塞
注意中断重入和互锁问题,此类逻辑错误可能导致各种异常



页: [1]
查看完整版本: 求助,关于串口2中断打开后定时器3不能工作的问题