專家支招:?jiǎn)纹瑱C(jī)中無(wú)符號(hào)數(shù)運(yùn)算出現(xiàn)的問(wèn)題
發(fā)布時(shí)間:2015-10-05 責(zé)任編輯:susan
【導(dǎo)讀】在單片機(jī)編程中,我們經(jīng)常會(huì)用到一些無(wú)符號(hào)數(shù)與有符號(hào)數(shù)的混合運(yùn)算,另外我們所用的單片機(jī)很有可能是16位或者8位的,這樣,編程時(shí)所用的一些變量的取值范圍會(huì)對(duì)我們的運(yùn)算有所限制。
比如說(shuō)8位的單片機(jī)無(wú)符號(hào)數(shù)最大值為255,有符號(hào)最大數(shù)為127;16位單片機(jī)無(wú)符號(hào)數(shù)最大值為65535,有符號(hào)數(shù)最大值為32767.對(duì)于32的單片機(jī)來(lái)說(shuō),因?yàn)槲覀円话闼幚淼闹岛苌倌艹^(guò)有符號(hào)數(shù)的最大取值,所以比較少遇到下面出現(xiàn)的問(wèn)題.
在一些運(yùn)算中,我們希望有些數(shù)能表示正負(fù),這就得用有符號(hào)數(shù),而有些數(shù)的取值會(huì)超過(guò)有符號(hào)數(shù)的最大值,這時(shí)我們就得用無(wú)符數(shù)來(lái)表示.下面是我編程時(shí)遇到的兩個(gè)問(wèn)題(用的是MC9S12XS128處理器,16位的單片機(jī)).
變量的聲明如下:
int iError;
unsigned int uiExpectSpeed;
unsigned int uiCurrentSpeed;
語(yǔ)句如下:
iError = (uiExpectSpeed - uiCurrentSpeed)/3; //(1) 第一個(gè)語(yǔ)句
在調(diào)試的過(guò)程中發(fā)現(xiàn)這個(gè)iError的值有時(shí)候會(huì)特別大,最后才發(fā)現(xiàn)是上面的這句語(yǔ)句出錯(cuò)了!然后修改成下面兩句結(jié)果就對(duì)了:
iError = uiExpectSpeed - uiCurrentSpeed; //(2)第二個(gè)語(yǔ)句
iError = iError/3; //(3)第三個(gè)語(yǔ)句
不同類(lèi)型的數(shù)據(jù)在進(jìn)行混合運(yùn)算時(shí)會(huì)有一個(gè)隱試的類(lèi)型轉(zhuǎn)換過(guò)程,有符號(hào)數(shù)與無(wú)符號(hào)數(shù)混合運(yùn)算,有符號(hào)數(shù)會(huì)被轉(zhuǎn)換成無(wú)符號(hào)數(shù)后再參加運(yùn)算.
在上面的第一個(gè)語(yǔ)句中,如果uiExpectSpeed 比uiCurrentSpeed的值大,也就是uiExpectSpeed - uiCurrentSpeed結(jié)果為一正值,那不會(huì)出現(xiàn)啥問(wèn)題,但當(dāng)uiExpectSpeed 比uiCurrentSpeed的值小時(shí)就出現(xiàn)問(wèn)題了,此時(shí)uiExpectSpeed - uiCurrentSpeed的臨時(shí)結(jié)果存放在16位的寄存器中,且最高位1,對(duì)于有符號(hào)數(shù)來(lái)說(shuō)會(huì)把這一個(gè)位解釋為符號(hào)位,1表示負(fù)數(shù),而對(duì)于無(wú)符號(hào)來(lái)說(shuō)這個(gè)位就表示數(shù)值,接著這個(gè)臨時(shí)的結(jié)果除以3后,所得到的結(jié)果的最高位變?yōu)榱?此時(shí)該結(jié)果會(huì)轉(zhuǎn)換為一個(gè)有符合數(shù)(不管是有符號(hào)數(shù),還是無(wú)符號(hào)數(shù),最高位為0時(shí),所表示的數(shù)值就是一樣的),賦給iError.本應(yīng)該得到一個(gè)負(fù)數(shù)的,但最終卻得到了一個(gè)比較大的正數(shù)!在第一個(gè)語(yǔ)句中,如果沒(méi)有除以3,而是兩個(gè)數(shù)作差后直接賦給iError則是不會(huì)出錯(cuò)的,雖然uiExpectSpeed - uiCurrentSpeed運(yùn)算的結(jié)果是一個(gè)很大的正數(shù)(寄存器的最高位為1),但在這個(gè)臨時(shí)結(jié)果賦給iError這個(gè)變量時(shí),會(huì)先把這個(gè)值轉(zhuǎn)換為一個(gè)有符號(hào)數(shù)賦給iError.其實(shí),在把uiExpectSpeed - uiCurrentSpeed運(yùn)算的結(jié)果賦給iError時(shí)是把所有的位原封不動(dòng)的復(fù)制到iErrorr所表示的內(nèi)存單元中的,只是我們是以有符號(hào)數(shù)來(lái)解釋這個(gè)內(nèi)存單元中的內(nèi)容,所以這個(gè)很大的正數(shù)就變成了一個(gè)負(fù)數(shù)!(數(shù)據(jù)在處理器內(nèi)是以補(bǔ)碼表示的,對(duì)于數(shù)據(jù)是正還是負(fù)只是人們的解釋不同而已).所以我就用后面的兩句替換了第一句,這樣不管uiExpectSpeed - uiCurrentSpeed的差值是正還是負(fù)都能得到正確的結(jié)果了.
下面是我在做超聲波測(cè)距時(shí)遇到的又一個(gè)很隱蔽的問(wèn)題:
unsigned int start; //表示計(jì)時(shí)開(kāi)始時(shí)計(jì)數(shù)器的值
unsigned int end; //表示計(jì)時(shí)結(jié)束時(shí)計(jì)數(shù)器的值
unsigned int error;
unsigned int distance; //表示距離
unsigned int time; //表示從計(jì)時(shí)開(kāi)始到結(jié)束所用的時(shí)間
unsigned int remainder;//余數(shù)
start = TCNT;// 計(jì)時(shí)開(kāi)始, TCNT為16位的計(jì)時(shí)器寄存器
..............一段時(shí)間后(這段時(shí)間小于計(jì)時(shí)器TCNT從0計(jì)數(shù)到最大值65535所表示的時(shí)間)...........
end = TCNT; //計(jì)時(shí)結(jié)束
error = end - start; //注意,end有可能比start小,但由于都是無(wú)符號(hào)數(shù),所以最后得到的差值就是這段時(shí)間內(nèi)計(jì)數(shù)器TCNT的增量.
time = error/625; //單位為ms TCNT每1ms內(nèi)數(shù)值增加625(這個(gè)數(shù)與TCNT所用的時(shí)鐘有關(guān))
distance = 17*time; //單位為cm, 距離為速度乘以時(shí)間再除以2就是聲波所傳波的距離
這塊由于是分步計(jì)算的,所以會(huì)有比較大的誤差(主要是由于error/625后的余數(shù)被丟棄了) 于是我改成如下語(yǔ)句:
start = TCNT;// 計(jì)時(shí)開(kāi)始, TCNT為16位的計(jì)時(shí)器寄存器
..............一段時(shí)間后(這段時(shí)間小于計(jì)時(shí)器TCNT從0計(jì)數(shù)到最大值65535所表示的時(shí)間)...........
end = TCNT; //計(jì)時(shí)結(jié)束
error = end - start; //注意,end有可能比start小,但由于都是無(wú)符號(hào)數(shù),所以最后得到的差值就是這段時(shí)間內(nèi)計(jì)數(shù)器TCNT的增量.
distance = (17*error)/625; //單位為cm, 將上面的最后兩句結(jié)合成一句,先乘后除就會(huì)減小誤差
但改后上面distance = (17*error)/625; 這句就錯(cuò)了,因?yàn)閑rror的值可能很大,最大可以達(dá)到65535,所以17*error結(jié)果很有可能會(huì)超過(guò)65535,但這個(gè)處理器是16位的,也就是說(shuō)這個(gè)處理器的數(shù)據(jù)寄存器為16位,最大的表示數(shù)值也就65535,所以17*error大于65535后就會(huì)被截?cái)啻嫒爰拇嫫髦?也就是說(shuō)存入寄存器中的值為(17*error)%65536,當(dāng)再用這個(gè)值除以625時(shí)得到的很有可能就是0或者個(gè)位數(shù)的值,不管怎樣,此時(shí)得到的結(jié)果都是錯(cuò)誤的值了!!
結(jié)合上面兩種情況,最后我改成如下:
start = TCNT;// 計(jì)時(shí)開(kāi)始, TCNT為16位的計(jì)時(shí)器寄存器
..............一段時(shí)間后(這段時(shí)間小于計(jì)時(shí)器TCNT從0計(jì)數(shù)到最大值65535所表示的時(shí)間)...........
end = TCNT; //計(jì)時(shí)結(jié)束
error = end - start; //注意,end有可能比start小,但由于都是無(wú)符號(hào)數(shù),所以最后得到的差值就是這段時(shí)間內(nèi)計(jì)數(shù)器TCNT的增量.
time = error/625; //單位為ms
remainder = error - time*625;//計(jì)算上一句中丟棄的余數(shù),沒(méi)有用remainder = error%625,是因?yàn)槌ê芎臅r(shí)!!
distance = 17*time + (17*remainder + 312)/625; //單位為cm,此處的312(625/2)是考慮到四舍五入的.
特別推薦
- 高精度低噪聲 or 大功率強(qiáng)驅(qū)動(dòng)??jī)x表放大器與功率放大器選型指南
- 高壓BMS:電池儲(chǔ)能系統(tǒng)的安全守護(hù)者與壽命延長(zhǎng)引擎
- 2025西部電博會(huì)啟幕在即,中文域名“西部電博會(huì).網(wǎng)址”正式上線
- IOTE 2025上海物聯(lián)網(wǎng)展圓滿收官!AIoT+5G生態(tài)引爆智慧未來(lái)
- 如何設(shè)計(jì)高性能CCM反激式轉(zhuǎn)換器?中等功率隔離應(yīng)用解析
- 攻克次諧波振蕩:CCM反激斜坡補(bǔ)償?shù)墓β史旨?jí)指南
- 羅姆助力英偉達(dá)800V HVDC重塑AI數(shù)據(jù)中心能源架構(gòu)
技術(shù)文章更多>>
- EA電池模擬器:重構(gòu)電池研發(fā)全流程的技術(shù)引擎
- 造物數(shù)科亮相華為開(kāi)發(fā)者大會(huì)2025:技術(shù)創(chuàng)新與數(shù)字服務(wù),加速電子電路產(chǎn)業(yè)數(shù)智化轉(zhuǎn)型
- 一文讀懂SiC Combo JFET技術(shù)
- 破局電動(dòng)車(chē)?yán)m(xù)航!羅姆第4代SiC MOSFET驅(qū)動(dòng)助力豐田bZ5性能躍遷
- 安森美SiC技術(shù)賦能AI數(shù)據(jù)中心,助力高能效電源方案
技術(shù)白皮書(shū)下載更多>>
- 車(chē)規(guī)與基于V2X的車(chē)輛協(xié)同主動(dòng)避撞技術(shù)展望
- 數(shù)字隔離助力新能源汽車(chē)安全隔離的新挑戰(zhàn)
- 汽車(chē)模塊拋負(fù)載的解決方案
- 車(chē)用連接器的安全創(chuàng)新應(yīng)用
- Melexis Actuators Business Unit
- Position / Current Sensors - Triaxis Hall
熱門(mén)搜索
壓控振蕩器
壓力傳感器
壓力開(kāi)關(guān)
壓敏電阻
揚(yáng)聲器
遙控開(kāi)關(guān)
醫(yī)療電子
醫(yī)用成像
移動(dòng)電源
音頻IC
音頻SoC
音頻變壓器
引線電感
語(yǔ)音控制
元件符號(hào)
元器件選型
云電視
云計(jì)算
云母電容
真空三極管
振蕩器
振蕩線圈
振動(dòng)器
振動(dòng)設(shè)備
震動(dòng)馬達(dá)
整流變壓器
整流二極管
整流濾波
直流電機(jī)
智能抄表