新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 一個(gè)從定時(shí)計(jì)數(shù)器賦初值引起的故事

一個(gè)從定時(shí)計(jì)數(shù)器賦初值引起的故事

作者: 時(shí)間:2016-11-29 來源:網(wǎng)絡(luò) 收藏
最近單片機(jī)課講到了定時(shí)計(jì)數(shù)器,在C語言中定時(shí)計(jì)數(shù)器的初值可以采用這種方式(假設(shè)計(jì)數(shù)10000次)TH0=(65536-10000)/256;TL0=(65536-10000)%256;這是通用的方法,65536-10000=55536=0xD8F0;賦值后TH0=0xD8,TL0=0xF0。我聯(lián)想到補(bǔ)碼的規(guī)則,65536-10000的數(shù)值在計(jì)算機(jī)中和-10000數(shù)據(jù)存儲(chǔ)是一樣的,于是我就簡單賦值為TH0=(-10000)/256.;TL0=(-10000)%256;可以少寫一個(gè)數(shù)據(jù),減少敲字的工作。我就這樣給學(xué)生講了。這兩種方法都可以。

在一天李老師看到我的學(xué)生作業(yè)都是寫TH0=(-10000)/256.;TL0=(-10000)%256;她說-10000可能使用不對(duì)。當(dāng)天晚上的時(shí)候在QQ上發(fā)消息過來說,經(jīng)驗(yàn)證,在Keil中,TH0=(65536-10000)/256;TL0=(65536-10000)%256;的賦值方式TH0=0xD8,TL0=0xF0。但是TH0=(-10000)/256.;TL0=(-10000)%256;的賦值方式TH0=0xD9,TL0=0xF0。TH0的數(shù)值總是要大1,而且取不同的數(shù)值驗(yàn)證均是這個(gè)結(jié)果,兩種方式TH0總是相差1,而TL0數(shù)值是一樣的。我打開Keil,輸入程序,然后調(diào)試查看匯編指令,得到如下結(jié)果:

本文引用地址:http://www.2s4d.com/article/201611/323235.htm

8: TH0=(65536-10000)/256;
C:0x009B 758CD8 MOV TH0(0x8C),#0xD8
9: TH1=(-10000)/256;
C:0x009E 758DD9 MOV TH1(0x8D),#0xD9

發(fā)現(xiàn)匯編指令直接對(duì)于TH0和TH1進(jìn)行賦值,沒有經(jīng)過任何的運(yùn)算,但是就是相差1,這是為什么呢?我無法理解,后來在百度知道上提問,得到的回答是:這個(gè)和默認(rèn)數(shù)據(jù)類型有關(guān),TH0=(65536-10000)/256,默認(rèn)unsigned char,即TH0=0xD8;TH0=(-10000)/256,默認(rèn)signed char,二進(jìn)制最高位為符號(hào)位,負(fù)數(shù)為1,所以TH0=0xD9 。

原來是Keil編譯器計(jì)算數(shù)據(jù)的時(shí)候默認(rèn)的數(shù)據(jù)類型不一樣,65536-10000=55536是unsigned類型,55536/256=216=0xD8,而-10000是signed類型,(-10000)/256=-39=0xD9。原來如此,Keil的編譯器預(yù)先處理的時(shí)候根據(jù)不同類型的數(shù)據(jù)進(jìn)行了不同的運(yùn)算,然后直接賦值。我又驗(yàn)證了一下,TH0=(unsigned int)(-10000)/256;發(fā)現(xiàn)先把-10000強(qiáng)制轉(zhuǎn)換為unsigned類型后,得到的結(jié)果就是正確的了TH0=0xD8。得到答案后臉紅了,不過多虧是在放假期間,沒有學(xué)生看到。開學(xué)后立即在課堂上更正了。╮(╯▽╰)╭,這次糗大了。

我重新寫了一個(gè)程序,#include
void main()
{
unsigned int i;
unsigned char j;
i= - 10000;
j=i/256;

while(1)
;
}

中間加一個(gè)變量,看Keil會(huì)怎么處理,結(jié)果發(fā)現(xiàn)

2: void main()
3: {
4: unsigned int i;
5: unsigned char j;
6: i=-10000;
C:0x000F 7ED8 MOV R6,#0xD8
7: j=i/256;
8:
C:0x0011 8E08 MOV 0x08,R6
9: while(1)
C:0x0013 80FE SJMP C:0013

還是直接賦值,編譯器太聰明了,知道80C51對(duì)于數(shù)據(jù)運(yùn)算非常非常的不擅長,于是直接處理完數(shù)據(jù),然后用賦值的方式來寫匯編的指令。而且還知道,i的低字節(jié)沒有用到,在指令里根本沒有出現(xiàn),這也太聰明了吧。Keil軟件是最流行,最好用的編譯器,不是浪得虛名的。

我再修改:

include
void main()
{
unsigned int i;
unsigned char j;
i=-10000;
i++;
j=i/256;

while(1)
;
}

結(jié)果發(fā)現(xiàn)代碼只增加了一點(diǎn)。

2: void main()
3: {
4: unsigned int i;
5: unsigned char j;
6: i=-10000;
C:0x0003 7FF0 MOV R7,#B(0xF0)
C:0x0005 7ED8 MOV R6,#0xD8
7: i++;
C:0x0007 0F INC R7
C:0x0008 BF0001 CJNE R7,#0x00,C:000C
C:0x000B 0E INC R6
8: j=i/256;
9:
C:0x000C 8E08 MOV 0x08,R6
10: while(1)
C:0x000E 80FE SJMP C:000E

但對(duì)于j的運(yùn)算還是用賦值的方式。我再改,把i類型變成signed類型,結(jié)果大吃一驚:

include
void main()
{
int i;
unsigned char j;
i=-10000;

j=i/256;

while(1)
;
}


上一頁 1 2 下一頁

評(píng)論


技術(shù)專區(qū)

關(guān)閉