【满分求教】单片机C程序,关于定时设置初值的n多疑问

原程序如下:
void main()
{
P2=0x00; // 关闭显示
TMOD = 0x01; // T0工作方式1
/* 16ms 定时设置 */
TH0 = (16000/256);
TL0 = (16000%256);
//定时器T0打开
TR0 = 1; //启动定时
ET0 = 1;
EA = 1; //开定时器中断
//待显示数据初始化
buf[3] = 3;
buf[2] = 2; //四个待显示数据单元初始为0,1,2,3
buf[1] = 1;
buf[0] = 0;
while(1); //等待定时数码管扫描显示
}

// 定时器0中断服务子程序,定时动态扫描显示
void time0_int(void) interrupt 1
{
/* 16ms 定时设置 */
TH0 = (16000/256); //定时数据重装
TL0 = (16000%256);
display(); //扫描显示更新
}

关于
TH0 = (16000/256);
TL0 = (16000%256);
问题一:为什么16ms对应的是16000??
问题二:为什么高八位要除256,低八位求余??
问题三:为什么要加小括号??是多余的吗?我在另一个程序(如下)中看到的初值还加上个负号是怎么回事??-5000是指50ms么??

程序二如下:
/* 定时器0中断服务子程序 */
void timer0() interrupt 1 using 1
{
while(cnter1--) ;
{
ET0=0; //关T0中断允许
TR0=0; //关闭定时器T0
TH0 = -5000/256; // 重设计数初值
TL0 = -5000%256;
TR0=1;
return;
}
cnter1=0x14;
sec++;
}

问题一:为什么16ms对应的是16000??
12MHz的晶振下,CPU得到的频率是1M,因为51单片机是内部十二分频的。那么对应的一个时钟的周期就是1us,16000us就是16ms,也就是16000个周期后将产生溢出,如果你的程序里全能了定时中断和全局中断,那么将会发生定时器中断。但你程序一里面的写法是有问题的。应该是
TH0 = (-16000/256);
TL0 = (-16000%256);
或者
TH0 = (65536-16000)/256;
TL0 = (65536-16000)%256;
问题二:为什么高八位要除256,低八位求余??
51单片机是八位的单片机的,里面的寄存器都是八位的(DPTR除外),所以一个十六位的数据需要用两个八位的的寄存器来存放。在定时器0工作方式1下,51单片机是十六位的定时器,所以要用TH0来存放定时数据的高八位,用TL0来存放数据的低八位。
一个十六位数除以256得到的就是这个数的高八位,再对256求余,得到的就是这个数的低八位。

问题三:为什么要加小括号??是多余的吗?我在另一个程序(如下)中看到的初值还加上个负号是怎么回事??-5000是指50ms么??
不加也是可以的,但并不是说多余的,这是编程风格的习惯,推荐这种习惯,不会容易出错。
使用负值的写法,其实是使用补码的方法写的,-5000的十六进制数也就是0xec78,刚好是等于65536-5000,所以在这个程序里,-5000/256=(65536-5000)/256,但是呢,不推荐这种写法,因为数据类型与编译器是有关的,应该并成记好的习惯,推荐用(65536-5000)/256的写法。
那么问题一一样-5000/256=(65536-5000)/256,可以看出定时是5ms,当然这个是有前的,就是你使用的晶振是12MHz的。

希望可以帮到你,对这三个问题还有什么疑问,可以扣我236376723
温馨提示:内容为网友见解,仅供参考
第1个回答  2011-05-09
1.有问题,如果是12MHz时,要产生16ms的溢出中断,那填写的初值应该是65536-16000才行,因为这时写入T0的数值是49536,要过16000个机器周期后才发生溢出,16000个机器周期就对应16ms。

2.一个16位数据除以256,得到的商是高8位,得到的余数是低8位,比如0x1234除以256(即0x100),就是0x1234÷0x100=0x12.....0x34,这样就得到了写入TH0和TL0的数值了。/和%就是分别求高8位和低8位的运算,即0x1234/0x100=0x12,0x1234%0x100=0x34。

3.不加括号也可以。-5000对应的16进制数是0xEC78,换算为无符号数就是60536,正好是65536-5000。所以这里用-5000作为初值,是得到5ms的定时。在中断中center=0x14=20,5ms延时重复20次就是5×20=100ms。所以这个程序还是有问题,如果是-50000(0x3CB0,无符号数15536=65535-50000)才能得到50ms延时,这样重复20次就得到1秒的定时。
第2个回答  2011-05-09
1、你的晶振是12MHZ的,12分频后程序运行的频率为1MHZ,每个程序周期为1us。16000就是16000uS,即16ms。
2、因为51单片机是8位机,一字节最大位只能为255(包括0就是最多可表示256个数)。而16000显示不能用一个字节表示,所以用16000/256到16位定时器的TH0表示高8位,TL0表示低8位。16000/256(相除的结果得数)表示高8位,16000%256(16000除256的余数,%为求余运算)表示低8位。
3、小括号在这里可要可不要,加了小括号只是表示16000/256是一个整体,是表示运动优先级最高。如果不加小括号在有些场合就出错。如:a=(b+c)*d表示b和c相加后再和d相剩。不加小括号,就表示,cd相剩后再加b。
4、-500是十六进制数FFFF的补,即0XFFFF-500=65035
第3个回答  2011-05-09
单片机晶振如果是12MHz的话,一个指令等于12个机器周期,每次定时=12/12MHz=1us,你用的是定时器0的工作方式1,最大可以定时65535个数,即65535us,TH0和TL0均为8位寄存器,两个合起来才是完整的16位,工作方式1采用上溢中断.
定时器初值=最长定时时间-需要定时的时间
.因此对于你的定时器设置我表示怀疑,16ms即16000,即初值应设置为65535-16000才对。
至于256就更好解释了,8位最大为255(0xFF),要把一个16位数高8位分到TH0里面,低8位分到TL0里面,数除以256相当于右移8位剩下的是高8为,余数自然就是低8位。至于-5000/256这样的效果其实和(65535-5000)/256一样的,因此根据前面的公式可以知道延时5000个计数值,每一个数1us自然就是延时5ms了。小括号我根据优先级看似乎是多余的,只是便于区分开来而已
第4个回答  2011-05-09
你这个问题上面都答过了,不过在这里面有一个问题,一般的视频教程里面一般把1000个机器周期当成是1ms,不过运行的话不是很准确,所以教学是可以的,但是用到实际的生产中就不太好了,这个实际中跟你的程序长短也有关系,如果要精确的时间的话,还是得不断地调试程序

【满分求教】单片机C程序,关于定时设置初值的n多疑问
12MHz的晶振下,CPU得到的频率是1M,因为51单片机是内部十二分频的。那么对应的一个时钟的周期就是1us,16000us就是16ms,也就是16000个周期后将产生溢出,如果你的程序里全能了定时中断和全局中断,那么将会发生定时器中断。但你程序一里面的写法是有问题的。应该是 TH0 = (-16000\/256);TL0 = (-...

单片机定时器初值计算方法
1 可以按定时时间的计算公式, 计算出定时器的时间常数X:定时时间T=(2的N次方-X)12\/单片机晶振频率 2 N为定时器的工作方式:方式0时,N=13 方式1时,N=16 方式2时,N=8 3 根据定时时间和工作方式,计算出时间常数X 把X转换成二进制数,高8位送给TH1,低8位送给TL1,就可以启动定时器开始定...

单片机C语言小疑问
你用的晶振应该是12M的吧,其实这段C程序编译成汇编就是三条MOV指令和三条DJNZ指令,程序的大部分时间是反复的执行DJNZ这条指令,DJNZ指令周期是2us,所以这段程序的时间大约是20*20*248=0.2S左右.那为什么用K=248而不是250呢,因为在一个循环(第三个for循环),即248个对变量k的DJNZ后,还会有一个...

51单片机c程序求助,程序会在main()函数里循环执行,这是怎么回事?当main...
keil做了下仿真,虽然你的主函数结束了,但是你的计时器仍然在工作,单步下去,总会进入中断函数。但是在protues下你的定时器初值要设置合理,也就是在主函数结束前溢出,中断就能发生。然后一直会有定时中断.挺神奇的 还是烧在板上做吧

单片机汇编语言的几个疑问
可以用EQU伪指令对其定义,程序体中使用。同样,这一点C语言要好的多,至少不需要去分配寄存器了。还有一个最容易出错的地方,就是关于标志位C:比如CJNE指令,它的判断是会影响C标志位的,如果程序后面有对C标志位判断的语句又没有考虑这种情况,问题极难查。很多人包括我自己会忽略这种细节。这类问题...

有关单片机定时器的使用和定时器的介绍
定时器是由两个寄存器组成的,其中一个寄存器是用来确定计数器的工作形式和功能的,另外一个计时器是用来控制单片机的启动和停止的,同时它也是设置溢出的一个标志。计数过程 每来一个脉冲计数器加1,当加到计数器为全1(即FFFFH)时,再输入一个脉冲就使计数器回零,且计数器的溢出使TCON中TF0或TF1置...

8051单片机计数器初值计算问题
TMOD=0x20是使用T1作波特率发生器,初值自动加载,所以TH1=TL1, 每过(256-0xf3)=13个机器周期定时器就溢出一次,所以每s溢出1000000\/6.5次,由于PCON里面SMOD设置为1,表示波特率倍增,所以,T1每溢出16次就会传输一位数据,那么,每溢出1000000\/6.5\/16次发送一位数据位,所以波特率就是9615.4bps 公式...

单片机如何计算初值
计数位数n由选用的单片机确定,通常等于8,12,16或32等等,即8位、12位等计数器。计数周期t由定时器基础时钟确定,可通过设置定时器时钟源和选择时钟分频数确定。这两项灵活性不大,一般在程序初始化时就应设定。初值x可以在应用时,根据定时需求进行修改确定。协调好n,t和x三者的设定,就可以完美实现...

定时时间T=(2的N次方- X)12\/单片机晶振频率?
定时时间T=(2的N次方-X)12\/单片机晶振频率 定时器工作原理图 最大定时时间就是初值为0时的时间:(2^13-0)*12\/6=16.384ms 选择方式0:13位 TMOD:M0 M1方式选择:所以TMOD:0x00 TCON:TCON:0x40 (2^13-x)*12\/6=10000us=>x=3192=0x0C78 TH1:0x0C TL1:0x78 ...

求助,关于51单片机的自锁开关C程序。
P0 ^ 3;sbit D5 = P0 ^ 4;sbit D6 = P0 ^ 5;void main( void ){while(1){P1 = 0xff;if( !(P1&KEY1) ){D1 = ~D1;while( !(P1&KEY1) );}if( !(P1&KEY2) ){D2 = ~D2;while( !(P1&KEY2) );}if( !(P1&KEY3) ){D3 = ~D3;while( !(P1&KEY3) );...

相似回答
大家正在搜