打印

大家帮我看一下keilC里C51定时器赋值问题

[复制链接]
5993|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
做的是让蜂鸣器间隔4S分别发出不同频率的声音。

程序写完,仿真时发现这个问题,看下图

图一:运行到中断时,注意红圈里的值




图二:重新赋值




图三:当加1计数器低八位赋值后,高八位变化很大



这个是为什么?如果在进入中断时,让中断停止工作,出中断最后那让中断开始工作的话,那上面的赋值又是正常的了。

请前辈们指教!谢谢

顺便附上源程序:让蜂鸣器间隔4秒,分别发出1hz,10hz等的声音


#include<reg52.h>    //头文件
#define uint unsigned int   
#define uchar unsigned char
uint a,b,hz;     //定义无符号整形
uchar c;      //定义无符号字符型
sbit bee=P1^4;     // 定义蜂鸣器管脚
void main()      //主文件
{         
hz=50000;     //hz赋值
TMOD=0x11;     //设置定时/计数器0,1的工作方式
TH0=(65536-hz)/256;   //定时器0加1计数器赋值(第一次50ms)
TL0=(65536-hz)%256;
TH1=(65536-50000)/256;  //定时器1加1计数器赋值(50ms)
TL1=(65536-50000)%256;
EA=1;      //开总中断
ET0=1;      //定时器0设为开
ET1=1;      //定时器1设为开
TR0=1;      //定时器0开始工作
TR1=1;      //定时器1开始工作
bee=1;      //蜂鸣器关闭
while(1);     //主程序完(等待中断)
}
void timer0() interrupt 1  //定时器0中断程序
{
TR0=0;      //定时器0停止工作,不停止的话下一步加1计数器赋值会出错(??)
TH0=(65536-hz)/256;   // 加1计数器重新赋值
TL0=(65536-hz)%256;
b++;      //b作为1hz定时的基准
if(a>=0&&a<80)    //如果a在0到80之间,进入函数,a由定时器1决定,1a=50ms
  if(b==10)    //如果b=10,进入函数(暨500ms时)
  {
   b=0;    //b归零
   bee=~bee;   //蜂鸣器开或关
   }

if(a>=80&&a<160)   //如果a在80到160之间
{
  bee=~bee;    //蜂鸣器开或关
}

if(a>=160&&a<240)
{
  hz=10000;    //hz重新赋值,10000=10ms
  bee=~bee;    //蜂鸣器开或关
}

if(a>=240&&a<320)
{
  hz=5000;
  bee=~bee;
}
if(a>=320&&a<400)
{
  hz=2500;
     bee=~bee;
}
if(a>=400&&a<480)
{
  hz=1250;
  bee=~bee;
}
if(a>=480&&a<560)
{
  hz=625;
  bee=~bee;
}
if(a>=560&&a<640)
{
  hz=500;
  bee=~bee;
}
if(a>=640&&a<720)
{
  hz=250;
  bee=~bee;
}
if(a>=720&&a<800)
{
  hz=125;
  bee=~bee;
}
TR0=1;         //定时器0开始工作
}
void timer1() interrupt 3     //定时器1中断函数
{
TH1=(65536-50000)/256;     //定时器1加1计数器重新赋值
TL1=(65536-50000)%256;
++a;
if(a==801)        //如果a=801,暨第一个周期结束,进入以下函数
{
  a=0;        //a归零
  hz=50000;       //hz重新赋值50000
  b=0;        //b也归零,满足定时器0的第一条1hz的语句
}
}

相关帖子

沙发
zhaoyu2005| | 2010-2-22 08:22 | 只看该作者
将两个赋值语句调下顺序看下,另外进到汇编窗口看下汇编程序的运行,并跟踪下,怀疑是运算占用了时间,但是数值有点大了,不应该用那么多的指令周期,在定时器1中设个断点或者定时器0中断后禁止总中断,看定时器1是不是发生了中断嵌套

使用特权

评论回复
板凳
qingqiu647| | 2010-2-22 10:48 | 只看该作者
如果是仿真的单步执行,是有时间间隔的,T0始终运行,当然一直会计数,还有TL0运算占用时间。没仔细看你下面的程序,对于中断处理函数,建议尽量简短,减少运算。例如TH1=(65536-hz)/256;可以改成TH0=((0x10000-hz)&0xff00)>>8;

使用特权

评论回复
地板
lovelyegle| | 2010-2-22 20:21 | 只看该作者
好贴,学习了额

使用特权

评论回复
5
ljk5214227|  楼主 | 2010-2-23 18:10 | 只看该作者
汇编跟踪了下,之前都正常,走完下图黄色那行就变3F了……

使用特权

评论回复
6
ljk5214227|  楼主 | 2010-2-23 18:28 | 只看该作者
如果是仿真的单步执行,是有时间间隔的,T0始终运行,当然一直会计数,还有TL0运算占用时间。没仔细看你下面的程序,对于中断处理函数,建议尽量简短,减少运算。例如TH1=(65536-hz)/256;可以改成TH0=((0x10000-hz ...
qingqiu647 发表于 2010-2-22 10:48


按照您的方法,顺利解决问题。看来我在逻辑运算这块上还有欠缺。

顺便问下,我把TH0改成16进制逻辑运算后,只运算了TH0,为何TL0也会自动被算出来?难道这是个技巧?
看图



使用特权

评论回复
7
ljk5214227|  楼主 | 2010-2-23 18:35 | 只看该作者
但是定时器1就不行?

使用特权

评论回复
8
ljk5214227|  楼主 | 2010-2-23 18:38 | 只看该作者
检查定时器0赋值时候的汇编,是在走完红箭头哪行给TL0赋值,走完蓝箭头那行给TH0赋值

使用特权

评论回复
9
ljk5214227|  楼主 | 2010-2-23 18:39 | 只看该作者
为何同样的语句,对待定时器0和定时器1的结果却不同呢?哪里的问题?

使用特权

评论回复
10
t86964988| | 2010-2-24 17:04 | 只看该作者
hz的定义有问题,你定义了unsigned int ,它的范围不超过256,但是你在下面的赋值中50000,这必然会出错!

使用特权

评论回复
11
冷漠| | 2010-2-24 17:13 | 只看该作者
hz的定义有问题,你定义了unsigned int ,它的范围不超过256,但是你在下面的赋值中50000,这必然会出错!


LZ没错。uint 范围是65536。LS冤枉好人了。

使用特权

评论回复
12
冷漠| | 2010-2-24 17:47 | 只看该作者
void timer1() interrupt 3     //定时器1中断函数
{
TH1=(65536-50000)/256;     //定时器1加1计数器重新赋值
TL1=(65536-50000)%256;
.....
定时器1都是常量,编译器自动计算好了。计算表达式再复杂也无所谓,汇编码总是
MOV  TH1,#3CH
MOV  TL1,#B0H

这是编译器的智能特性,计算过程不会显示在OBJ代码中。

定时器0计算表达式含有变量hz,需要随即时环境变化而变化,编译器无法知道结果。还是免不了程序计算。倒不如使用T2,
T2=-hz;
一条语句就替代了下面复杂表达式。汇编结果一样是最简的。
“TH0=(65536-hz)/256;   // 加1计数器重新赋值
TL0=(65536-hz)%256;   ”

再写个简单的:
DPTR=-hz;
TH0=DPH;
TL0=TL0+DPL;  //修正流失的时钟个数,不需要关闭TR0=0。

使用特权

评论回复
13
ljk5214227|  楼主 | 2010-3-1 17:55 | 只看该作者
:)恩,这样啊,谢谢LS回答,我研究研究!

使用特权

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

本版积分规则

10

主题

112

帖子

1

粉丝