yongxiangu 发表于 2020-2-19 12:04:19

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)才行,但是觉得很别扭。

takashiki 发表于 2020-2-19 12:07:44

volatile都没有是不是可以不用看了?

yongxiangu 发表于 2020-2-19 12:08:10

将工程文件也上传一下

yongxiangu 发表于 2020-2-19 12:09:48

takashiki 发表于 2020-2-19 12:07
volatile都没有是不是可以不用看了?

刚加了,还是出错

wye11083 发表于 2020-2-19 12:14:04

takashiki 发表于 2020-2-19 12:07
volatile都没有是不是可以不用看了?

8位机就有这毛病。非原子操作很容易出错(比如之前把0搬到r中,然后中断,然后再搬另一个0)。

lcw_swust 发表于 2020-2-19 12:18:32

本帖最后由 lcw_swust 于 2020-2-19 12:20 编辑

主函数对count赋值时可能中断将之打断且中断里也对count赋值,从而出现意外。
估计因为16位变量在8位机里是分两次操作的。
读取count的值时也可能中途被中断修改出现意外
所以建议主函数里对count赋值或读取时先关中断。

carefree1986 发表于 2020-2-19 12:19:05

记着加ul

yongxiangu 发表于 2020-2-19 12:19:10

yongxiangu 发表于 2020-2-19 12:19:55

lcw_swust 发表于 2020-2-19 12:18
主函数对count赋值时可能中断将之打断且中断里也对count赋值,从而出现意外。
估计因为16位变量在8位机里是 ...

恩,这个做了,也是出错

nokia007 发表于 2020-2-19 12:20:58

楼主的中断服务函数和delay函数都在操作counter变量,冲突了

lcw_swust 发表于 2020-2-19 12:22:02

yongxiangu 发表于 2020-2-19 12:19
恩,这个做了,也是出错

补充一下,读取也要关中断。如
int x=1;
while(x)
{
EA=0;
x=count;
EA=1;
}

lcw_swust 发表于 2020-2-19 12:28:03

本帖最后由 lcw_swust 于 2020-2-19 12:31 编辑

比如
count=0x0100;
执行while(count>0); 时,分两步判断
先判断低字节为0,不满足条件,
然后中断将之减1,count=0x00FF;退出中断;
再判断高字节为0,也不满足条件,退出循环。

所以,建议主函数与中断都要使用的变量尽量只用一个字节,
这个地方呢就可以将定时器频率降低(或程序中做个分频)达到长延时的目的。

yongxiangu 发表于 2020-2-19 12:38:35

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;
        }
}

dbwu8280 发表于 2020-2-19 14:03:49

原子操作很重要!

小西西 发表于 2020-2-19 14:32:52

只是单步调试有问题还是整个延时就不正确?

snic_k 发表于 2020-2-19 14:54:01

Count声明前加volatile试试

xingjianpeng 发表于 2020-2-19 18:37:33

楼主问题算是解决了吧。

yongxiangu 发表于 2020-2-19 21:02:31

xingjianpeng 发表于 2020-2-19 18:37
楼主问题算是解决了吧。

解决了,按照13楼的办法

isakura 发表于 2020-2-19 21:20:36

大部分情况下超过1ms我都不会去用delay的

chengsong 发表于 2020-2-20 14:41:52

变量在中断中修改,外部函数一般只读取最好。

gmajvfhpa 发表于 2020-2-20 21:47:52

delay执行到一半时,进中断了,因为count>0 这比较不是一条汇编指令就能完成的

eddia2012 发表于 2020-6-19 23:11:00

记住,中断及外部程序都对16

eddia2012 发表于 2020-6-19 23:12:10

位变量修改时,外部程序中要原子操作。
页: [1]
查看完整版本: keil的比较运算出错