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正常了,救命
请问到底出了什么问题!!!!!!
通过你的描述我猜测问题可能出在多字节变量的一致性上
你定义了一个16位的变量 u16Time1ms
在定时器中断里面对它进行累加,在主循环里进行判断处理,这样就可能出现这种情况
当 u16Time1ms = 0x00ff 时,主循环里先读取 u16Time1ms 的低8位数据跟 500 的低8位进行相减比较
然后产生了中断,在中断里又对 u16Time1ms 进行了累加,结果 u16Time1ms = 0x0100
中断完成回到主循环后,继续读取 u16Time1ms 的高8位内容与 500 进行相减比较
这样的话,在主循环里与 500 进行比较的值实际上就变成 0x01ff,而非预期的 0x00ff
如果累加、判断都在中断里执行就不会遇到这种情况,所以你的 step3 是正常的。 乘风飞扬 发表于 2023-6-12 18:37
通过你的描述我猜测问题可能出在多字节变量的一致性上
你定义了一个16位的变量 u16Time1ms
在定时器中断里 ...
太感谢了,应该就是前后台系统临界的问题。 本帖最后由 熊仔 于 2023-7-21 13:43 编辑
中断中使用的全局变量,加上volatile修饰,禁止优化。
在中断外的函数读和修改变量,需要关闭中断,才能正确读取和赋值。
当然51单片机如果是8位变量,不需要关中断。
stc32 如果变量放edata,8,16,32位都不用关中断,也能正确运行。
页:
[1]