【满分求教】单片机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,不过运行的话不是很准确,所以教学是可以的,但是用到实际的生产中就不太好了,这个实际中跟你的程序长短也有关系,如果要精确的时间的话,还是得不断地调试程序