keil的比较运算出错
本帖最后由 yongxiangu 于 2020-2-19 12:04 编辑keil的版本V5.28.0.0
main.c代码
#include <REGX51.H>
#include "delay.h"
void main()
{
timer0_init();
while(1)
{
P1 = 0x00;
delay(500);
P1 = 0xff;
delay(500);
}
}
delay.c代码
#include "delay.h"
static unsigned int count;
void timer0_init()
{
TMOD = 0x01; //设置T0为工作方式1,即16位定时器
TH0 = (65536-1000) >> 8;
TL0 = 65536-1000;
ET0 = 1;//开放T0中断
EA = 1; //开放总中断开关
TR0 = 1;//T0开跑
}
void timer0_interrput() interrupt 1
{
TH0 = (65536-1000) >> 8;
TL0 = 65536-1000;
if(count>0) count--;
}
void delay(unsigned int t)
{
count = t;
while(count>0); //这一句经常在count为0x00ff的时候跳出
while(count>0);//增加一句才行
}
while(count>0); 这一句经常在count为0x00ff的时候就跳出(keil debug可以发现,proteus仿真也是),增加一句while(count>0)才行。不清楚怎么回事,我也考虑过count = t之前关中断,之后开中断,也不能解决问题,只有再增加一句while(count>0)才行,但是觉得很别扭。
volatile都没有是不是可以不用看了? 将工程文件也上传一下 takashiki 发表于 2020-2-19 12:07
volatile都没有是不是可以不用看了?
刚加了,还是出错 takashiki 发表于 2020-2-19 12:07
volatile都没有是不是可以不用看了?
8位机就有这毛病。非原子操作很容易出错(比如之前把0搬到r中,然后中断,然后再搬另一个0)。 本帖最后由 lcw_swust 于 2020-2-19 12:20 编辑
主函数对count赋值时可能中断将之打断且中断里也对count赋值,从而出现意外。
估计因为16位变量在8位机里是分两次操作的。
读取count的值时也可能中途被中断修改出现意外
所以建议主函数里对count赋值或读取时先关中断。
记着加ul lcw_swust 发表于 2020-2-19 12:18
主函数对count赋值时可能中断将之打断且中断里也对count赋值,从而出现意外。
估计因为16位变量在8位机里是 ...
恩,这个做了,也是出错 楼主的中断服务函数和delay函数都在操作counter变量,冲突了 yongxiangu 发表于 2020-2-19 12:19
恩,这个做了,也是出错
补充一下,读取也要关中断。如
int x=1;
while(x)
{
EA=0;
x=count;
EA=1;
} 本帖最后由 lcw_swust 于 2020-2-19 12:31 编辑
比如
count=0x0100;
执行while(count>0); 时,分两步判断
先判断低字节为0,不满足条件,
然后中断将之减1,count=0x00FF;退出中断;
再判断高字节为0,也不满足条件,退出循环。
所以,建议主函数与中断都要使用的变量尽量只用一个字节,
这个地方呢就可以将定时器频率降低(或程序中做个分频)达到长延时的目的。 lcw_swust 发表于 2020-2-19 12:28
比如
count=0x0100;
执行while(count>0); 时,分两步判断
非常感谢!之前只考虑了,写的时候原子操作,读取的时候也要原子操作
void delay(unsigned int t)
{
unsigned int temp = 1;
EA = 0;
count = t; //赋值操作要原子操作
EA = 1;
while(temp>0)
{
EA = 0;
temp = count; //读取操作要原子操作
EA = 1;
}
} 原子操作很重要! 只是单步调试有问题还是整个延时就不正确? Count声明前加volatile试试 楼主问题算是解决了吧。 xingjianpeng 发表于 2020-2-19 18:37
楼主问题算是解决了吧。
解决了,按照13楼的办法 大部分情况下超过1ms我都不会去用delay的 变量在中断中修改,外部函数一般只读取最好。 delay执行到一半时,进中断了,因为count>0 这比较不是一条汇编指令就能完成的 记住,中断及外部程序都对16 位变量修改时,外部程序中要原子操作。
页:
[1]