打印

89S51单片机出现的诡异问题

[复制链接]
1910|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
2001myp|  楼主 | 2009-3-17 17:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include <REG51.H>    
#define uchar unsigned char
#define uint unsigned int
uchar code SEG7[10]={0x12,0xb7,0x19,0x91,0xb4,0xd0,0x50,0x97,0x10,0x90};
uchar ACT[4]={0xfe,0xfd,0xfb,0xf7}; 
uint ms,cnt;            
/****************************/
void initial(void)        
{                    
TMOD=0x02;            
TH0=0xf0;            
TL0=0xf0;                            
TR0=1;
P0=0xff;                
}
/*************************************************/    
void main(void)            
{
     ms=0;cnt=0;
     initial();
     while(1)                            
      {  
      if(TF0==1){cnt++; TF0=0;}
      if(cnt>=20){cnt=0;ms++;P0=~P0;}
      if(ms>999)ms=0;
        P1=SEG7[ms/100];    
        P2=ACT[0];                            
        P1=SEG7[(ms%100)/10];
        P2=ACT[1];
        P1=SEG7[ms%10];
        P2=ACT[2];    
      }
                 
}
上面的程序是为了做时间显示,至于时间系数先不必管他,我用了P0并在后面的循环里面每隔一毫秒取一下反,目的就是通过示波器看时间对不对,结果发现波形出现了两个周期,就是10毫秒方波延续一会,4点几或者几毫秒延续一会,并且是交替周期性出现这种现象的。我把if(ms>999)这个语句中的ms改的小些就可以,我专门试了一下,可能200以下的数就可以,不会出现周期交替变化的现象了,为什么呢,请高手指教

相关帖子

来自 2楼
quakegod| | 2009-3-18 17:50 | 只看该作者

偶怀疑跟Keil的优化有关

你那个程序涉及到了多字节的除法,
Keil在优化这个程序的时候执行时间并不相同,
比如2字节时,它先判断高字节是否为0,如果为0,直接用硬件触发器,
如果不为0,才用软件触发器模拟,
所以,当你的ms在0到999之间变化时,前255次执行都非常快,是硬件除法,
256-999次执行都非常慢,是软件模拟。
这是关于这个问题,

另外一个问题,偶看你的程序不能做到准确的计时。因为内循环里耗时操作太多了,尤其是除法运算是一个奢侈的东西,
像偶的程序里,多字节除法运算都是当做一个可挂起的操作,像操作外部设备那样使用它,也就是说,一个程序想运行多字节除法,发出执行指令后,就继续干别的去了,再需要用到结果的地方再不停得判断执行结果并等待,然后除法指令是在另外一个任务中运行的。

其实你的程序只不过是要把二进制数转化为BCD码,完全不用使用除法,用加法和DA就能实现。


使用特权

评论回复
板凳
2001myp|  楼主 | 2009-3-17 20:05 | 只看该作者

顶一下

各位高手不吝指教啊

使用特权

评论回复
地板
mohanwei| | 2009-3-17 20:20 | 只看该作者

3个if应该是是钳套的……建议按照标准风格编写代码

那样子不容易出错

使用特权

评论回复
5
mohanwei| | 2009-3-17 20:23 | 只看该作者

改为如下代码卡看看:

while(1)
{
    if(TF0==1)
    {
        cnt++;
        TF0=0;
        if(cnt>=20)
        {
            cnt=0;
            ms++;
            P0=~P0;
            if(ms>999)
            {
                ms=0;
            }
            P1=SEG7[ms/100];
            P2=ACT[0];
            P1=SEG7[(ms%100)/10];
            P2=ACT[1];
            P1=SEG7[ms%10];
            P2=ACT[2];
        }
    }
}

使用特权

评论回复
6
2001myp|  楼主 | 2009-3-17 20:48 | 只看该作者

谢谢支持

谢谢楼上老师指教,我现试试看

使用特权

评论回复
7
2001myp|  楼主 | 2009-3-18 12:11 | 只看该作者

报告

楼上老师的程序我烧写后还是有那种问题,反正就是if(ms>999)这句,超过200多次就波形时密时缓,低于200多次P0口就可以输出正常波形,郁闷

使用特权

评论回复
8
2001myp|  楼主 | 2009-3-18 13:32 | 只看该作者

顶一下

我测了一下,200MS内计时很准确,超过200MS后就不准确了,走的慢了很多
高手指点啊

使用特权

评论回复
9
vrgood| | 2009-3-18 14:17 | 只看该作者

TH0=0XF0???

1)TIME0工作在模式2,晶振是多少?你的1MS定时是如何计算的?
2)按你程序TH0=0XF0,16个机器周期产生1次TF0,但你后面的处理已经超过了16个机器周期,能够保证定时准确?
3)重新配置TH0、CNT再试验下

使用特权

评论回复
10
2001myp|  楼主 | 2009-3-18 17:30 | 只看该作者

楼上老师你好

我试过8M和12M的晶振都不行,后面的处理的确是累赘,但我不知道怎么办,呵呵,菜鸟,没办法,另外即使定时不准确,但也应该P0方波输出为统一的周期啊,为什么脉冲宽一下窄一下周期性变化呢?

使用特权

评论回复
11
mohanwei| | 2009-3-18 18:39 | 只看该作者

晕,没注意到前面的0xF0这个常数……

一般定时常数会设置为5ms或者10ms的,毕竟利用定时器来做键盘扫描,显示更新什么的30ms都不会有问题

使用特权

评论回复
12
2001myp|  楼主 | 2009-3-18 19:14 | 只看该作者

谢谢楼上两位

quekegod老师说的KEIL优化问题,但我在实际使用的时候用示波器检测出了实际的200MS后出现问题,而不是软件仿真的时候出的问题,为什么说和KEIL优化有关呢?另外您说的比如数码管动态扫描部分能够挂起么,如何挂起能指点一下么。
另外mohaiwei老师,谢谢您的关注,我的TH和TL中设置的数字F0是后来改的,以前是38H,是计算过后的,这里1MS系数不准确的,是我后来为了试验改的

使用特权

评论回复
13
mohanwei| | 2009-3-18 20:32 | 只看该作者

想要稳定,必须让执行时间固定,而你的程序里

执行时间是不确定的,具体原因就是10楼所说的了。
如果是学习马表显示,你已经达到目的了;
如果想更进一步钻研,可以用一下思路:
使用定时器中断,在中断里:
//定时器常数重载
……
if(Disp_Flag)//需要刷新显示
{
    P1=Disp_Buff[0];
    P2=Disp_Buff[1];
……
    Disp_Flag=0;
}
if(Flag_20ms)//20ms定时到
{
    Flag_20ms=0;
    //计算显示码并保存到Disp_Buff数组中
    Disp_Flag=1;//下一次中断更新显示
}
//处理Flag_20ms的累加

使用特权

评论回复
14
vrgood| | 2009-3-19 08:52 | 只看该作者

原因是:漏掉很多个TF0

你的问题在于每次“T0溢出”的时间不够后面程序的处理,所以可能会漏掉很多个TF0,按照你的程序,假如12M晶振,你的算法应该是16*20=320us,P0翻转一下。

这样吧,你晶振12M,然后对应处修改为如下:
TH0=0x06;            
TL0=0x06;
if(cnt>=4){cnt=0;ms++;P0=~P0;}
应该可以基本保证方波的输出了

使用特权

评论回复
15
2001myp|  楼主 | 2009-3-19 08:54 | 只看该作者

回去钻研下

谢谢楼上,回去钻研下

使用特权

评论回复
16
vrgood| | 2009-3-19 09:01 | 只看该作者

需要修改结构

先禁止掉这些语句:

        P1=SEG7[ms/100];    
        P2=ACT[0];                            
        P1=SEG7[(ms%100)/10];
        P2=ACT[1];
        P1=SEG7[ms%10];
        P2=ACT[2];    

你就会发现你的定时问题解决了。
所以要完成你原来的功能,必须修改结构,采用16位T0或者用中断,楼上已经有人提出。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

59

主题

210

帖子

0

粉丝