本文轉(zhuǎn)自: Flywithliye本次設(shè)計(jì)要求,依據(jù)實(shí)驗(yàn)數(shù)據(jù),設(shè)計(jì)簡(jiǎn)易的電池電量監(jiān)測(cè)電路。該3AH的電池,在某固定環(huán)境下放電實(shí)驗(yàn)數(shù)據(jù)如表 1所示。要求依據(jù)測(cè)量電壓推算時(shí)間,以此作為電量標(biāo)識(shí),并采用某種方式進(jìn)行顯示。 表 1 放電實(shí)驗(yàn)數(shù)據(jù) 2. 設(shè)計(jì)思路
2.1. 設(shè)計(jì)假設(shè) 本次設(shè)計(jì)基于以下假設(shè)。在任意時(shí)刻t測(cè)得開(kāi)路電壓值 ,不考慮其在t時(shí)刻前的具體放電過(guò)程。即認(rèn)為該時(shí)刻電池開(kāi)路電壓V,是持續(xù)以放電實(shí)驗(yàn)中使用的放電電流 (500mA),由滿電量電壓4.35V,放電 時(shí)間得到的。即,認(rèn)為,電池剩余電量與電池兩端開(kāi)路電壓具有一一對(duì)應(yīng)關(guān)系。 2.2. 設(shè)計(jì)方案通過(guò)AD芯片獲取電池兩端開(kāi)路電壓,將模擬量電壓值轉(zhuǎn)換為單片機(jī)可處理的數(shù)字量。隨后依據(jù)該測(cè)得的電壓值按照所建立數(shù)學(xué)模型進(jìn)行運(yùn)算。然后將該數(shù)字電壓值及其運(yùn)算結(jié)果通過(guò)數(shù)碼管顯示,并同時(shí)通過(guò)串行口發(fā)送至上位機(jī)。上位機(jī)接收到數(shù)據(jù)后做相關(guān)處理顯示工作。 2.3. 數(shù)學(xué)實(shí)現(xiàn) 的值由插值的方式計(jì)算。依據(jù)表 1中的實(shí)驗(yàn)數(shù)據(jù),通過(guò)測(cè)得的電壓V,由下列公式逆向計(jì)算,其中 為測(cè)得電壓兩側(cè)的實(shí)驗(yàn)數(shù)據(jù)點(diǎn)時(shí)間及電壓。則測(cè)得該電壓時(shí),各量值如下所示。(電壓處于實(shí)驗(yàn)數(shù)據(jù)邊界的情況已在程序?qū)崿F(xiàn)中完成,此處省略) 放電時(shí)間: 已用電量: 剩余電量: 剩余電量百分比: 其中時(shí)間單位為min,電流單位為mA,電量單位為mA min。 按照如上方式使用實(shí)驗(yàn)數(shù)據(jù),運(yùn)用Matlab繪圖得到如下結(jié)果。 圖 1 實(shí)驗(yàn)曲線 其繪圖過(guò)程如下述程序所示。 圖 2 實(shí)驗(yàn)曲線繪制 3. 電路設(shè)計(jì)
3.1. 整體電路結(jié)構(gòu)整體電路原理圖由Protues軟件進(jìn)行繪制并仿真。為簡(jiǎn)化連線便于觀察邏輯,其中使用了網(wǎng)絡(luò)標(biāo)簽的方式,對(duì)實(shí)際物理上相連而原理圖中未連接的管腳,給予了相同的名稱,則在邏輯上他們互相連接。具體電路原理圖見(jiàn)附件1。 3.2. 單片機(jī)最小系統(tǒng)單片機(jī)最小系統(tǒng)是單片機(jī)能夠正常執(zhí)行內(nèi)置程序,發(fā)揮其基礎(chǔ)功能的必須組成部分。包括單片機(jī),電源部分,時(shí)鐘電路部分及復(fù)位電路部分。 3.2.1. 原理圖圖 3 AT89C52最小系統(tǒng) 3.2.2. AT89C52單片機(jī)本次設(shè)計(jì)中主要用到了該型單片機(jī)的IO口,串口及定時(shí)器。其中,P0口用于和AD轉(zhuǎn)換電路交換數(shù)據(jù)。P2口部分管腳用于控制AD轉(zhuǎn)換芯片工作及讀取其狀態(tài)。P3口3.1管腳用作第二功能串行口數(shù)據(jù)輸出,其余用到的管腳用于進(jìn)行數(shù)碼管位選。P1口用于數(shù)碼管段選。 本次設(shè)計(jì)未使用片外數(shù)據(jù)/程序存儲(chǔ)器,因此 均處于懸空狀態(tài)。且本次設(shè)計(jì)中,與ADC芯片的數(shù)據(jù)交換未采用外部拓展總線的方式,將其視為普通IO設(shè)備值直接進(jìn)行操作和讀取。 3.2.3. 時(shí)鐘電路時(shí)鐘電路為單片機(jī)最小系統(tǒng)組成之一,用于提供時(shí)鐘信號(hào),驅(qū)動(dòng)CPU指令的執(zhí)行,并為定時(shí)器等提供內(nèi)部時(shí)間基準(zhǔn)。本次設(shè)計(jì)采用無(wú)源晶振,為保證串口通信波特率準(zhǔn)確,其頻率選定為11.0592Mhz。 3.2.4. 復(fù)位電路復(fù)位電路用于在單片機(jī)程序執(zhí)行出現(xiàn)異常時(shí),重新初始化運(yùn)行,從而防止由數(shù)字電路競(jìng)爭(zhēng)冒險(xiǎn)及環(huán)境干擾引起的,單片機(jī)系統(tǒng)的不正常工作。本次設(shè)計(jì)中的復(fù)位電路同時(shí)具有上電自動(dòng)復(fù)位及按鍵復(fù)位的功能。其中上電時(shí)由電容C5將RST引腳拉高,提供復(fù)位信號(hào)。 3.2.5. 電源單片機(jī)由5V穩(wěn)壓電源供電,由于仿真軟件對(duì)其供電電路進(jìn)行了省略,因此在圖 3中并未繪出電源系統(tǒng)。本次設(shè)計(jì)中部分其余芯片也未繪出電源。 3.3. AD轉(zhuǎn)換電路設(shè)計(jì)AD轉(zhuǎn)換芯片用于將模擬量的電壓值轉(zhuǎn)換為可用數(shù)字電路處理的數(shù)字量值。該部分電路是本次設(shè)計(jì)中最為核心的部分。用于測(cè)試得到電池兩端電壓值,供單片機(jī)進(jìn)行數(shù)學(xué)處理和相關(guān)顯示處理。 由于軟件仿真限制,在本次設(shè)計(jì)中采用電位器RV1模擬電池兩端電壓。同時(shí),為簡(jiǎn)化電路,該芯片模擬地同數(shù)字地連在一起。 圖中AIN0管腳上的U3(AIN0)箭頭為Protues軟件提供的電壓探針。用于直觀顯示輸入電壓值,與通過(guò)ADS7825轉(zhuǎn)換后的結(jié)果做對(duì)比參考。 3.3.1. 原理圖圖 4 ADC轉(zhuǎn)換電路 3.3.2. ADS7825為提高測(cè)量分辨率,本次設(shè)計(jì)ADC芯片選用ADS7825。ADS7825為四通道輸入,16位AD轉(zhuǎn)換芯片,5V供電, 輸入電壓范圍,內(nèi)置2.5V參考電壓,最大采樣轉(zhuǎn)換時(shí)間25us。其輸出方式可由 設(shè)置為并行輸出和串行輸出。本次設(shè)計(jì)采用并行輸出。 其中,當(dāng)BYTE為0時(shí),D7-D0輸出高八位;BYTE為1時(shí),D7-D0輸出低八位。 用于控制轉(zhuǎn)換和讀寫(xiě),當(dāng)該位為0時(shí),啟動(dòng)依次轉(zhuǎn)換;為1時(shí),啟動(dòng)數(shù)據(jù)輸出,外部設(shè)備可讀取。 用于指示目前是否轉(zhuǎn)換完成,當(dāng)該位為0時(shí),正在轉(zhuǎn)換;為1時(shí),轉(zhuǎn)換完成。 其基本串行輸出操作流程如下所述。 首先通過(guò)A1,A0管腳選擇輸入通道。將 拉低40ns(最大12us)即可啟動(dòng)一次AD轉(zhuǎn)換。(由此處可知,可使用賦值語(yǔ)句連讀對(duì) 進(jìn)行操作,依次連續(xù)令其為1,0,1,由于單片機(jī)執(zhí)行指令需要消耗指令周期的時(shí)間,可以滿足40ns的要求)轉(zhuǎn)換開(kāi)始時(shí), 引腳被拉低,并將持續(xù)為低,直至轉(zhuǎn)換完成,輸出寄存器被更新后,該位被拉高。若BYTE位為低,則在 上升沿時(shí),轉(zhuǎn)換結(jié)果高8位輸出,反之,低八位輸出。在 為0(即轉(zhuǎn)換進(jìn)行時(shí))時(shí),所有的轉(zhuǎn)換指令都將被忽略。 其內(nèi)部結(jié)構(gòu)如圖 5所示。截取自其數(shù)據(jù)手冊(cè)。 圖 5 ADS7825內(nèi)部結(jié)構(gòu)圖 本次設(shè)計(jì)采用AIN0通道輸入電池電壓,在仿真過(guò)程中,由電位器RV1分壓模擬變化的電池電壓。注意到其輸入電阻并不高,因此在實(shí)際應(yīng)用時(shí),輸入端應(yīng)添加電壓跟隨器提高后級(jí)輸入阻抗。 3.4. 數(shù)碼管電路設(shè)計(jì)
3.4.1. 原理圖圖 6數(shù)碼管驅(qū)動(dòng)控制電路 3.4.2. 數(shù)碼管本次設(shè)計(jì)采用八位共陰極數(shù)碼管用于顯示結(jié)果,其中高四位用于顯示當(dāng)前電池兩端電壓,低四位用于顯示當(dāng)前電池剩余電量百分比(最低為未用)。采用74LS138進(jìn)行數(shù)碼管位選,進(jìn)行動(dòng)態(tài)掃描。74LS373采用直通方式,用于傳送數(shù)碼管段碼及提供驅(qū)動(dòng)電流。 3.4.3. 74LS13874LS138是3線-8線譯碼器,有三個(gè)選擇輸入端,三個(gè)允許輸入端和八個(gè)輸出端。其真值表如表 2所示。G1, , 為控制端,A、B、C為輸入端, Y0~Y7為輸出端,低有效.當(dāng) G1, , =1 0 0 時(shí)才能進(jìn)行譯碼輸出,否則8個(gè)輸出端Y0~Y7全為1。 表 2 74LS138真值表 3.4.4. 74LS37374LS373是8數(shù)據(jù)鎖存器。主要用于數(shù)碼管、按鍵等等的控制,以及總線擴(kuò)展時(shí),P0口地址的鎖存。其真值表如表 3所示。 表 3 74HC373 真值表
3.5. 串行口電路設(shè)計(jì)
3.5.1. 原理圖圖 7串行口通訊電路 3.5.2. MAX232由于RS-232標(biāo)準(zhǔn)采用負(fù)邏輯,即邏輯1為-3V~-15V,邏輯0為+3~+15V。而本單片機(jī)系統(tǒng)為TTL信號(hào)系統(tǒng)。TTL電平規(guī)定,+5V等價(jià)于邏輯“1”,0V等價(jià)于邏輯“0”。因此,DB-9與單片機(jī)的連接需要進(jìn)行電平轉(zhuǎn)換,如圖 8所示,選用MAX232芯片完成上述功能。 圖 8 MAX232引腳圖及典型應(yīng)用電路 3.5.3. DB-9由于 RS-232C 并未定義連接器的物理特性,因此,出現(xiàn)DB-25 和 DB-9 各種類型的連接器,其引腳的定義也各不相同。如圖 7右側(cè)P1組件所示即為 DB-9 連接器。本次設(shè)計(jì)僅使用其TXD,GND引腳。 如圖所示,使用MAX232芯片進(jìn)行電平轉(zhuǎn)換后,MAX232輸入管腳T1IN與AT89C52串行口P3.1/TXD連接。(由于軟件特殊原因,在MAX232芯片1通道T1OUT處增加74LS04非門進(jìn)行處理。本次設(shè)計(jì)中單片機(jī)僅使用發(fā)送功能,未連接AT89C52接收端P3.0/RXD) 4. 程序設(shè)計(jì)
4.1. 單片機(jī)程序設(shè)計(jì)
4.1.1. 程序流程圖圖 9 下位機(jī)程序流程圖 4.1.2. 程序設(shè)計(jì)本次單片機(jī)程序設(shè)計(jì)中,使用T1作為串口波特率發(fā)生器,T0作為定時(shí)器用于定時(shí)刷新動(dòng)態(tài)數(shù)碼管。 主函數(shù)對(duì)各功能函數(shù)進(jìn)行調(diào)用,其形式較為簡(jiǎn)單。在程序右側(cè)添加由詳細(xì)功能注釋說(shuō)明。其中兩次測(cè)量間隔使用的是軟件延時(shí)。通過(guò)for語(yǔ)句消耗單片機(jī)執(zhí)行指令的時(shí)間,實(shí)現(xiàn)延時(shí)。 該函數(shù)用于控制ADS7825對(duì)模擬電壓進(jìn)行采集轉(zhuǎn)換,并將16位轉(zhuǎn)換結(jié)果儲(chǔ)存在16位整數(shù)中。其具體操作過(guò)程如3.3.2中文字所述。 該函數(shù)主要用于電池電壓值,已用時(shí)間,剩余電量的計(jì)算。其中,對(duì)小數(shù)的處理采用了擴(kuò)大1000或100倍后四舍五入取整的方式,這樣為后續(xù)取出原小數(shù)部分各位數(shù)值提供了便利。 電壓值U計(jì)算公式如下。 其中result為ADS7825輸出16位數(shù)據(jù)。由于該芯片支持負(fù)電壓輸入,因此上式中分母中指數(shù)部分為15而非16。 已用時(shí)間t由插值函數(shù)Linear(double v)運(yùn)算得到。 剩余電量計(jì)算公式如下。 其中,t為已用時(shí)間,單位min;180000為電池容量Q,單位mA min;500為放電電流,單位mA。 該函數(shù)用于實(shí)現(xiàn)由測(cè)得電壓U反向計(jì)算當(dāng)前已放電時(shí)間。計(jì)算結(jié)果以u(píng)nsigned int型變量返回。采用線性插值方式計(jì)算,其中當(dāng)測(cè)得電壓正好與實(shí)驗(yàn)數(shù)據(jù)點(diǎn)相同時(shí),直接取用對(duì)應(yīng)數(shù)據(jù)點(diǎn)的時(shí)間值。 用于進(jìn)行插值的實(shí)驗(yàn)數(shù)據(jù)以code標(biāo)識(shí)符標(biāo)識(shí),另其存放在程序存儲(chǔ)器當(dāng)中,以節(jié)省RAM空間。當(dāng)測(cè)得電壓值超出實(shí)驗(yàn)數(shù)據(jù)時(shí),分別認(rèn)為以放電時(shí)間為0和360,即認(rèn)為電池充滿電未使用和電池電量已完全釋放完畢。 該函數(shù)主要用于,依據(jù)最新獲得的數(shù)值型電壓值,電量值,更新數(shù)碼管顯示緩沖區(qū)。但實(shí)際上,數(shù)碼管的動(dòng)態(tài)掃描不在本函數(shù)中完成,由定時(shí)器T0定時(shí)掃描。刷新過(guò)程中對(duì)電壓值最高位小數(shù)點(diǎn)及電量百分比最高位0進(jìn)行了顯示處理。 該函數(shù)用于組織一幀通信數(shù)據(jù)并由串口發(fā)送至上位機(jī)。為測(cè)試方便,其中使用了中文字符。定義回車換行符為一幀數(shù)據(jù)結(jié)束,供上位機(jī)識(shí)別所需。 其他函數(shù)包括定時(shí)器T0/T1的工作模式配置函數(shù)及其中斷相應(yīng)函數(shù),還包括用于串行口發(fā)送字符/字符串的函數(shù)。 以上提到的函數(shù)在附件2中給出。 4.2. 上位機(jī)程序設(shè)計(jì)為有效縮短開(kāi)發(fā)時(shí)間,本次設(shè)計(jì)中的上位機(jī)設(shè)計(jì)采用圖形化編程語(yǔ)言Labview設(shè)計(jì)完成,其主要功能即為通過(guò)串行口接收由下位機(jī)傳送的字符串?dāng)?shù)據(jù),并對(duì)其進(jìn)行解析,隨后使用圖形化的方式顯示當(dāng)前剩余電量百分比等。 4.2.1. 程序流程圖圖 10 上位機(jī)程序流程圖 4.2.2. 界面設(shè)計(jì)圖 11 上位機(jī)界面設(shè)計(jì) 4.2.3. 程序設(shè)計(jì)上位機(jī)使用圖形化編程語(yǔ)言Labview設(shè)計(jì)完成,其程序框圖(即源程序)如下所示。其中主要使用了平鋪式順序結(jié)構(gòu),while循環(huán),條件結(jié)構(gòu)。 圖 12 下位機(jī)程序設(shè)計(jì) 5. 系統(tǒng)調(diào)試5.1. 串口參數(shù)設(shè)置本次設(shè)計(jì)約定串口通信有關(guān)參數(shù)如下。 表 4串口參數(shù)約定 按照表1設(shè)置串口參數(shù)如下。
圖 13 MCU串口配置 圖 14 上位機(jī)串口配置
5.2. 調(diào)整滑動(dòng)變阻器調(diào)整圖 4中滑動(dòng)變阻器RV1動(dòng)觸點(diǎn)的位置合理。 5.3. 啟動(dòng)MCU軟件仿真點(diǎn)擊下圖第一個(gè)按鈕啟動(dòng)仿真。 圖 15 Protues啟動(dòng) 出現(xiàn)如下圖所示內(nèi)容說(shuō)明仿真成功執(zhí)行。 圖 16仿真正在進(jìn)行 5.4. 打開(kāi)上位機(jī)串口連接點(diǎn)擊下圖第一個(gè)按鈕啟動(dòng)上位機(jī)程序。 圖 17 Labview啟動(dòng) 上圖變換為下圖顯示時(shí)說(shuō)明上位機(jī)成功啟動(dòng)。 圖 18Labview已啟動(dòng) 5.5. 觀察數(shù)碼管顯示及上位機(jī)顯示下圖中左側(cè)顯示當(dāng)前測(cè)得的電壓值,右側(cè)顯示當(dāng)前剩余電量(最高位0做處理后并未顯示),最右側(cè)數(shù)碼管在本次程序設(shè)計(jì)中被禁止使能,始終處于關(guān)閉狀態(tài)。 圖 19 下位機(jī)數(shù)碼管顯示 圖 20上位機(jī)顯示電池電壓及剩余電量 6. 總結(jié)本次設(shè)計(jì)主要解決了AD轉(zhuǎn)換及數(shù)據(jù)處理問(wèn)題。其次主要包括串行口配置使用,數(shù)碼管動(dòng)態(tài)定時(shí)刷新等的設(shè)計(jì)。在設(shè)計(jì)開(kāi)始,查找了較多的AD轉(zhuǎn)換芯片,并通過(guò)仿真軟件,對(duì)照數(shù)據(jù)手冊(cè),對(duì)其進(jìn)行功能驗(yàn)證。早期驗(yàn)證的主要為ADC0808/0809,AD1674,ADS7824等,考慮分辨率及仿真軟件限制等因素,最后選擇了16位ADS7825芯片。仿真邏輯關(guān)系與數(shù)據(jù)手冊(cè)顯示基本全部對(duì)應(yīng)。 下位機(jī)軟件設(shè)計(jì)中,將各功能模塊單獨(dú)寫(xiě)成函數(shù),使得主函數(shù)基本流程較為清晰。對(duì)各變量,常量,函數(shù)等進(jìn)行了較多的注釋說(shuō)明,以提高程序可讀性和后續(xù)修改的便利性。為節(jié)省開(kāi)發(fā)設(shè)計(jì)時(shí)間,編程過(guò)程中對(duì)同一數(shù)值進(jìn)行了多次運(yùn)算,并未考慮存儲(chǔ)后再使用的方式,有可能造成了不必要的程序執(zhí)行時(shí)間開(kāi)銷。考慮了電壓值最高位(個(gè)位)處的小數(shù)點(diǎn)處理,及電池電量百分比最高位為0時(shí)的處理,適應(yīng)了閱讀習(xí)慣。 ADC芯片輸入端在設(shè)計(jì)時(shí)未考慮測(cè)量電池電壓時(shí)的負(fù)載效應(yīng),可能會(huì)引起較大誤差?梢酝ㄟ^(guò)引入電壓跟隨器提高輸入阻抗的方式,進(jìn)一步降低誤差。 上位機(jī)設(shè)計(jì)中主要完成的工作是對(duì)下位機(jī)傳送來(lái)的字符串的解析和顯示。每次采樣轉(zhuǎn)換完成后,下位機(jī)發(fā)送一條以回車換行結(jié)尾的字符串,上位機(jī)通過(guò)該結(jié)束位檢測(cè)一幀數(shù)據(jù)傳輸完畢,隨后對(duì)接收到的數(shù)據(jù)幀進(jìn)行字符串分離解析等工作。
7. 附件1(硬件原理圖)
單片機(jī)源程序如下:
- #include<reg52.h>
-
- sbit PARSER = P2^0; //串并行控制位
- sbit BYTE = P2^1; //高低字節(jié)控制位
- sbit RC = P2^4; //讀取轉(zhuǎn)換控制位
- sbit BUSY = P2^2; //忙狀態(tài)位
- sbit ADDR_A = P3^5; //低位地址控制位
- sbit ADDR_B = P3^6; //低位地址控制位
- sbit ADDR_C = P3^7; //高位地址控制位
-
- void ConfigUART(unsigned int baud); //串行口配置函數(shù)
- void ConfigTimer0(); //定時(shí)器0配置函數(shù)
- void SendData(unsigned char ch); //字符發(fā)送函數(shù)
- void SendString(char *s); //字符串發(fā)送函數(shù)
- void GetVoltage(); //ADC電壓獲取函數(shù)
- unsigned int Linear(double v); //線性插值函數(shù),參數(shù)v為實(shí)測(cè)電壓
- void DataProcess(); //數(shù)據(jù)處理函數(shù)
- void LedBufRefresh(); //數(shù)碼管顯示緩沖區(qū)刷新函數(shù)
- void UartSend(); //串口數(shù)據(jù)發(fā)送函數(shù)
-
- unsigned char voltage[] = {'0','.','0','0','0',0};
- unsigned char time_used[] = {'0','0','0',0};
- unsigned char percentage[] = {'0','0','0',0};
- unsigned long j,time_used_value,result,percentage_value,voltage_value;
- unsigned int code time_sample[21]={0,18,36,54,72,90,108,126,144,162,180,198,216,234,252,270,288,306,324,342,360};
- double code voltage_sample[21]={4.35,4.24,4.135,4.005,3.92,3.889,3.858,3.826,3.8,3.78,3.762,3.743,3.725,3.705,3.686,3.667,3.65,3.628,3.492,3.05,2};
-
- //數(shù)碼管顯示字符轉(zhuǎn)換表
- unsigned char code LedChar[] = {
- 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
- 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
- };
- //數(shù)碼管顯示緩沖區(qū),初值0x00確保啟動(dòng)時(shí)都不亮
- unsigned char LedBuff[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
-
- void main()
- {
- ConfigUART(9600); //配置串行口工作模式及參數(shù)
- ConfigTimer0(); //配置定時(shí)器0用于數(shù)碼管刷新
- EA = 1; //打開(kāi)總中斷
- while(1)
- {
- GetVoltage(); //獲取ADC電壓值
- DataProcess(); //數(shù)據(jù)處理
- LedBufRefresh(); //顯示緩沖區(qū)刷新
- UartSend(); //串口發(fā)送
- for(j=0;j<30000;j++); //延時(shí)讀取
- }
- }
- /* 數(shù)據(jù)處理函數(shù) */
- void DataProcess()
- {
- /* 計(jì)算電壓值 */
- voltage_value = (unsigned long)(((double)result * 10 / 32767) * 1000 + 0.5);
- /* 電壓值數(shù)組 */
- voltage[4] = '0' + voltage_value % 10;
- voltage[3] = '0' + (voltage_value /10) % 10;
- voltage[2] = '0' + (voltage_value /100) % 10;
- voltage[0] = '0' + (voltage_value /1000) % 10;
- /* 剩余用時(shí)數(shù)組 */
- time_used_value = Linear((double)result * 10 / 32767);
- time_used[2] = '0' + time_used_value % 10;
- time_used[1] = '0' + (time_used_value / 10) % 10;
- time_used[0] = '0' + (time_used_value / 100) % 10;
- /* 百分比數(shù)組 */
- percentage_value = (unsigned long)((double)(180000 - time_used_value * 500) / 180000 * 100 + 0.5);
- percentage[2] = '0' + percentage_value % 10;
- percentage[1] = '0' + (percentage_value / 10) % 10;
- percentage[0] = '0' + (percentage_value / 100) % 10;
- if((percentage_value / 100) % 10)
- {
- percentage[0] = '0' + (percentage_value / 100) % 10;
- }
- else
- {
- percentage[0] = ' ';
- }
- }
- /* 線性插值函數(shù),參數(shù)v為實(shí)測(cè)電壓 */
- unsigned int Linear(double v)
- {
- unsigned int i,t1,t2,t;
- double v1,v2;
- if(v >= 4.35) //大于最大電壓
- {
- t = 0;
- return t;
- }
- if(v <= 2) //小于最小電壓
- {
- t = 360;
- return t;
- }
- for(i=0; i<21; i++) //遍歷插值范圍
- {
- if(voltage_sample[i] < v)
- {
- v1 = voltage_sample[i-1];
- v2 = voltage_sample[i];
- t1 = time_sample[i-1];
- t2 = time_sample[i];
- t = t2 - (v - v2) * (double)(t2 - t1) / (v1 - v2);
- break; //計(jì)算插值結(jié)果t
- }
- else if(voltage_sample[i] == v)
- {
- t = time_sample[i]; //恰好取采樣值
- break;
- }
- }
- return t;
- }
- /* ADC電壓獲取函數(shù) */
- void GetVoltage()
- {
- unsigned char high,low;
- PARSER = 1; //并行輸出
- RC = 1; //啟動(dòng)轉(zhuǎn)換
- RC = 0;
- RC = 1;
-
- while(!BUSY); //等待轉(zhuǎn)換完畢
-
- P0 = 0xFF; //讀取高八位
- BYTE = 0;
- high = P0;
-
- P0 = 0xFF; //讀取低八位
- BYTE = 1;
- low = P0;
-
- result = high * 256 + low; //合并高低字節(jié)
- }
- /* 定時(shí)器0中斷服務(wù)函數(shù) */
- void InterruptTimer0() interrupt 1
- {
- static unsigned char i = 0; //動(dòng)態(tài)掃描的索引
- TH0 = 0xFC; //重新加載初值
- TL0 = 0x67;
- //以下代碼完成數(shù)碼管動(dòng)態(tài)掃描刷新
- P1 = 0x00; //顯示消隱
- switch(i)
- {
- case 0: ADDR_C = 0; ADDR_B = 0; ADDR_A = 0; i++; P1=LedBuff[0]; break;
- case 1: ADDR_C = 0; ADDR_B = 0; ADDR_A = 1; i++; P1=LedBuff[1]; break;
- case 2: ADDR_C = 0; ADDR_B = 1; ADDR_A = 0; i++; P1=LedBuff[2]; break;
- case 3: ADDR_C = 0; ADDR_B = 1; ADDR_A = 1; i++; P1=LedBuff[3]; break;
- case 4: ADDR_C = 1; ADDR_B = 0; ADDR_A = 0; i++; P1=LedBuff[4]; break;
- case 5: ADDR_C = 1; ADDR_B = 0; ADDR_A = 1; i++; P1=LedBuff[5]; break;
- case 6: ADDR_C = 1; ADDR_B = 1; ADDR_A = 0; i=0; P1=LedBuff[6]; break;
- //case 7: ADDR_C = 1; ADDR_B = 1; ADDR_A = 1; i=0; P1=LedBuff[7]; break;
- default: break;
- }
- }
- /* 數(shù)碼管顯示緩沖區(qū)刷新函數(shù) */
- void LedBufRefresh()
- {
- LedBuff[6] = ~LedChar[percentage_value % 10];
- LedBuff[5] = ~LedChar[(percentage_value / 10) % 10];
- if((percentage_value / 100) % 10)
- {
- LedBuff[4] = ~LedChar[(percentage_value / 100) % 10];
- }
- else
- {
- LedBuff[4] = 0;
- }
- LedBuff[3] = ~LedChar[voltage_value % 10];
- LedBuff[2] = ~LedChar[(voltage_value /10) % 10];
- LedBuff[1] = ~LedChar[(voltage_value /100) % 10];
- LedBuff[0] = ~(LedChar[(voltage_value /1000) % 10] &0x7F);
- }
- void UartSend()
- {
- SendString("當(dāng)前電壓:");
- SendString(voltage);
- SendString("V");
- // SendString(" 已用時(shí)間:");
- // SendString(time_used);
- // SendString("Min");
- SendString(" 剩余電量:");
- SendString(percentage);
- SendString("%\r\n");
- }
- /* 串口配置函數(shù),baud-通信波特率 */
- void ConfigUART(unsigned int baud)
- {
- SCON = 0x50; //配置串口為模式1
- TMOD &= 0x0F; //清零T1的控制位
- TMOD |= 0x20; //配置T1為模式2
- TH1 = 256 - (11059200/12/32)/baud; //計(jì)算T1重載值
- TL1 = TH1; //初值等于重載值
- ET1 = 0; //禁止T1中斷
- ES = 1; //使能串口中斷
- TR1 = 1; //啟動(dòng)T1
- }
- /* 定時(shí)器0配置函數(shù) */
- void ConfigTimer0()
- {
- TMOD &= 0xF0; //清零T0的控制位
- TMOD |= 0x01; //設(shè)置T0為模式1
- TH0 = 0xFC; //為T0賦初值0xFC67,定時(shí)1ms
- TL0 = 0x67;
- ET0 = 1; //使能T0中斷
- TR0 = 1; //啟動(dòng)T0
- }
- /* UART中斷服務(wù)函數(shù) */
- void InterruptUART() interrupt 4
- {
- if(RI) //接收到字節(jié)
- {
- RI = 0; //清零接收中斷標(biāo)志位
- }
- if(TI) //字節(jié)發(fā)送完畢
- {
- TI = 0; //清零發(fā)送中斷標(biāo)志位
- }
- }
- /* UART字符發(fā)送函數(shù) */
- void SendData(unsigned char ch)
- {
- SBUF = ch; //啟動(dòng)發(fā)送
- while(!TI); //等待結(jié)束
- }
- /* UART字符串發(fā)送函數(shù) */
- void SendString(unsigned char *s)
- {
- while(*s) //循環(huán)發(fā)送
- {
- SendData(*s++);
- }
- }
復(fù)制代碼
|