lywang 发表于 2023-6-12 10:49:02

STC89系列单片机程序运行异常(疑似全局变量突变)

本帖最后由 lywang 于 2023-6-12 10:56 编辑

最近用STC89C52做一个小例程,发现出现了意想不到的问题。

我的调试过程如下,求大神帮助解惑。
keil默认8级优化。
1.从官网下载STCISP下载例程,用的定时器0产生1ms中断.代码如下

#include "reg51.h"
//-----------------------------------------------

/* define constants */
#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   //1ms timer calculation method in 12T mode


sbit TEST_LED = P1^0;               //work LED, flash once per second
sbit TEST_LED2 = P1^1;               //work LED, flash once per second
sbit TEST_LED3 = P1^2;               //work LED, flash once per second
/* define variables */
unsigned intu16Time1ms;                                                //1000 times counter

//-----------------------------------------------

/* Timer0 interrupt routine */
void tm0_isr() interrupt 1
{
    TL0 = T1MS;                     //reload timer0 low byte
    TH0 = T1MS >> 8;                //reload timer0 high byte
      
    TEST_LED = !TEST_LED;
    u16Time1ms++;
}

//-----------------------------------------------

/* main program */
void main()
{               
    TMOD = 0x01;                  //set timer0 as mode1 (16-bit)
    TL0 = T1MS;                     //initial timer0 low byte
    TH0 = T1MS >> 8;                //initial timer0 high byte
    TR0 = 1;                        //timer0 start running
    ET0 = 1;                        //enable timer0 interrupt
    EA = 1;                         //open global interrupt switch
    u16Time1ms = 0;                      //initial counter

      
    while (1)
{

//                        if(u16Time1ms > 500)               //1ms * 1000 -> 1s
//                        {
//                              TEST_LED2 = !TEST_LED2;
//                              u16Time1ms = 0;
//                        }                     



                }
}
step1:测试中断是否产生1ms时基,中断反装P1.0,结果如下图

step2:1ms中断里添加全局变量,while中进行循环执行500ms翻转P1.1,程序与结果如下

#include "reg51.h"



//-----------------------------------------------

/* define constants */
#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   //1ms timer calculation method in 12T mode


sbit TEST_LED = P1^0;               //work LED, flash once per second
sbit TEST_LED2 = P1^1;               //work LED, flash once per second
sbit TEST_LED3 = P1^2;               //work LED, flash once per second
/* define variables */
unsigned intu16Time1ms;                                                //1000 times counter



//-----------------------------------------------

/* Timer0 interrupt routine */
void tm0_isr() interrupt 1
{
    TL0 = T1MS;                     //reload timer0 low byte
    TH0 = T1MS >> 8;                //reload timer0 high byte
      
                TEST_LED = !TEST_LED;
                u16Time1ms++;


}

//-----------------------------------------------

/* main program */
void main()
{               
    TMOD = 0x01;                  //set timer0 as mode1 (16-bit)
    TL0 = T1MS;                     //initial timer0 low byte
    TH0 = T1MS >> 8;                //initial timer0 high byte
    TR0 = 1;                        //timer0 start running
    ET0 = 1;                        //enable timer0 interrupt
    EA = 1;                         //open global interrupt switch
    u16Time1ms = 0;                      //initial counter

      
                while (1)
                {



                        if(u16Time1ms > 500)               //1ms * 1000 -> 1s
                        {
                              TEST_LED2 = !TEST_LED2;
                              u16Time1ms = 0;
                        }                     



                }
}


要命的是,时间不对了。我立马查看了变量定义的unsigned int类型没问题不会一出的。

看了下放在中断里的P1.0,还是1ms正常的。


此刻我觉得不妙,全局变量被异常改变了。可是我没有数据和指针哇,头大
step3:我把while(1)里的500ms逻辑放到中断执行,惊人的正常了。程序与结果如下


#include "reg51.h"



//-----------------------------------------------

/* define constants */
#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   //1ms timer calculation method in 12T mode


sbit TEST_LED = P1^0;               //work LED, flash once per second
sbit TEST_LED2 = P1^1;               //work LED, flash once per second
sbit TEST_LED3 = P1^2;               //work LED, flash once per second
/* define variables */
unsigned intu16Time1ms;                                                //1000 times counter



//-----------------------------------------------

/* Timer0 interrupt routine */
void tm0_isr() interrupt 1
{
    TL0 = T1MS;                     //reload timer0 low byte
    TH0 = T1MS >> 8;                //reload timer0 high byte
      
                TEST_LED = !TEST_LED;
                u16Time1ms++;

                        if(u16Time1ms > 500)               //1ms * 1000 -> 1s
                        {
                              TEST_LED2 = !TEST_LED2;
                              u16Time1ms = 0;
                        }               
}

//-----------------------------------------------

/* main program */
void main()
{               
    TMOD = 0x01;                  //set timer0 as mode1 (16-bit)
    TL0 = T1MS;                     //initial timer0 low byte
    TH0 = T1MS >> 8;                //initial timer0 high byte
    TR0 = 1;                        //timer0 start running
    ET0 = 1;                        //enable timer0 interrupt
    EA = 1;                         //open global interrupt switch
    u16Time1ms = 0;                      //initial counter

      
                while (1)
                {



//                        if(u16Time1ms > 500)               //1ms * 1000 -> 1s
//                        {
//                              TEST_LED2 = !TEST_LED2;
//                              u16Time1ms = 0;
//                        }                     



                }
}
P1.1正常了,救命



请问到底出了什么问题!!!!!!

乘风飞扬 发表于 2023-6-12 18:37:46

通过你的描述我猜测问题可能出在多字节变量的一致性上
你定义了一个16位的变量 u16Time1ms
在定时器中断里面对它进行累加,在主循环里进行判断处理,这样就可能出现这种情况
当 u16Time1ms = 0x00ff 时,主循环里先读取 u16Time1ms 的低8位数据跟 500 的低8位进行相减比较
然后产生了中断,在中断里又对 u16Time1ms 进行了累加,结果 u16Time1ms = 0x0100
中断完成回到主循环后,继续读取 u16Time1ms 的高8位内容与 500 进行相减比较
这样的话,在主循环里与 500 进行比较的值实际上就变成 0x01ff,而非预期的 0x00ff

如果累加、判断都在中断里执行就不会遇到这种情况,所以你的 step3 是正常的。

lywang 发表于 2023-6-13 09:56:28

乘风飞扬 发表于 2023-6-12 18:37
通过你的描述我猜测问题可能出在多字节变量的一致性上
你定义了一个16位的变量 u16Time1ms
在定时器中断里 ...

太感谢了,应该就是前后台系统临界的问题。

熊仔 发表于 2023-7-21 13:39:35

本帖最后由 熊仔 于 2023-7-21 13:43 编辑

中断中使用的全局变量,加上volatile修饰,禁止优化。
在中断外的函数读和修改变量,需要关闭中断,才能正确读取和赋值。

当然51单片机如果是8位变量,不需要关中断。
stc32 如果变量放edata,8,16,32位都不用关中断,也能正确运行。
页: [1]
查看完整版本: STC89系列单片机程序运行异常(疑似全局变量突变)