在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 第46節(jié):利用AT24C02進(jìn)行掉電后的數(shù)據(jù)保存

            第46節(jié):利用AT24C02進(jìn)行掉電后的數(shù)據(jù)保存

            作者: 時(shí)間:2016-11-22 來源:網(wǎng)絡(luò) 收藏
            開場白:
            一個(gè)AT24C02可以存儲256個(gè)字節(jié),地址范圍是(0至255)。利用AT24C02存儲數(shù)據(jù)時(shí),要教會(huì)大家六個(gè)知識點(diǎn):
            第一個(gè):單片機(jī)操作AT24C02的通訊過程也就是IIC的通訊過程, IIC通訊過程是一個(gè)要求一氣呵成的通訊過程,中間不能被其它中斷影響時(shí)序出錯(cuò),因此在整個(gè)通訊過程中應(yīng)該先關(guān)閉總中斷,完成之后再開中斷。
            第二個(gè):在寫入或者讀取完一個(gè)字節(jié)之后,一定要加上一段延時(shí)時(shí)間。在11.0592M晶振的系統(tǒng)中,寫入數(shù)據(jù)時(shí)經(jīng)驗(yàn)值用delay_short(2000),讀取數(shù)據(jù)時(shí)經(jīng)驗(yàn)值用delay_short(800)。否則在連續(xù)寫入或者讀取一串?dāng)?shù)據(jù)時(shí)容易丟失數(shù)據(jù)。如果一旦發(fā)現(xiàn)丟失數(shù)據(jù),應(yīng)該適當(dāng)繼續(xù)把這個(gè)時(shí)間延長,尤其是在寫入數(shù)據(jù)時(shí)。
            第三個(gè):如何初始化EEPROM數(shù)據(jù)的方法。系統(tǒng)第一次上電時(shí),我們從EEPROM讀取出來的數(shù)據(jù)有可能超出了范圍,可能是ff。這個(gè)時(shí)候我們應(yīng)該給它填入一個(gè)初始化的數(shù)據(jù),這一步千萬別漏了。
            第四個(gè):在時(shí)序中,發(fā)送ACK確認(rèn)信號時(shí),要記得把數(shù)據(jù)線eeprom_sda_dr_s設(shè)置為輸入的狀態(tài)。對于51單片機(jī)來說,只要把eeprom_sda_dr_s=1就可以。而對于PIC或者AVR單片機(jī)來說,它們都是帶方向寄存器的,就不能直接eeprom_sda_dr_s=1,而要直接修改方向寄存器,把它設(shè)置為輸入狀態(tài)。在本驅(qū)動(dòng)程序中,我沒有對ACK信號進(jìn)行出錯(cuò)判斷,因?yàn)槲疫@么多年一直都是這樣用也沒出現(xiàn)過什么問題。
            第五個(gè): 提醒各位讀者在硬件上應(yīng)該注意的問題,單片機(jī)跟AT24C02通訊的2根IO口都要加上一個(gè)4.7K左右的上拉電阻。凡是在IIC通訊場合,都要加上拉電阻。AT24C02的WP引腳一定要接地,否則存不進(jìn)數(shù)據(jù)。
            第六個(gè):舊版的朱兆祺51學(xué)習(xí)板在硬件上有一個(gè)bug,AT24C02的第8個(gè)引腳VCC懸空了!!!,讀者記得把它飛線連接到5V電源處。新版的朱兆祺51學(xué)習(xí)板已經(jīng)改過來了。
            具體內(nèi)容,請看源代碼講解。

            (1)硬件平臺:
            基于朱兆祺51單片機(jī)學(xué)習(xí)板。

            (2)實(shí)現(xiàn)功能:
            4個(gè)被更改后的參數(shù)斷電后不丟失,數(shù)據(jù)可以保存,斷電再上電后還是上一次最新被修改的數(shù)據(jù)。
            顯示和獨(dú)立按鍵部分根據(jù)第29節(jié)的程序來改編,用朱兆祺51單片機(jī)學(xué)習(xí)板中的S1,S5,S9作為獨(dú)立按鍵。
            一共有4個(gè)窗口。每個(gè)窗口顯示一個(gè)參數(shù)。
            第8,7,6,5位數(shù)碼管顯示當(dāng)前窗口,P-1代表第1個(gè)窗口,P-2代表第2個(gè)窗口,P-3代表第3個(gè)窗口,P-4代表第1個(gè)窗口。
            第4,3,2,1位數(shù)碼管顯示當(dāng)前窗口被設(shè)置的參數(shù)。范圍是從0到9999。S1是加按鍵,按下此按鍵會(huì)依次增加當(dāng)前窗口的參數(shù)。S5是減按鍵,按下此按鍵會(huì)依次減少當(dāng)前窗口的參數(shù)。S9是切換窗口按鍵,按下此按鍵會(huì)依次循環(huán)切換不同的窗口。
            (3)源代碼講解如下:
            1. #include "REG52.H"
            2. #define const_voice_short40 //蜂鳴器短叫的持續(xù)時(shí)間
            3. #define const_key_time120 //按鍵去抖動(dòng)延時(shí)的時(shí)間
            4. #define const_key_time220 //按鍵去抖動(dòng)延時(shí)的時(shí)間
            5. #define const_key_time320 //按鍵去抖動(dòng)延時(shí)的時(shí)間
            6. void initial_myself(void);
            7. void initial_peripheral(void);
            8. void delay_short(unsigned int uiDelayShort);
            9. void delay_long(unsigned int uiDelaylong);
            10. //驅(qū)動(dòng)數(shù)碼管的74HC595
            11. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);
            12. void display_drive(void); //顯示數(shù)碼管字模的驅(qū)動(dòng)函數(shù)
            13. void display_service(void); //顯示的窗口菜單服務(wù)程序
            14. //驅(qū)動(dòng)LED的74HC595
            15. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);
            16. void start24(void);//開始位
            17. void ack24(void);//確認(rèn)位
            18. void stop24(void);//停止位
            19. unsigned char read24(void);//讀取一個(gè)字節(jié)的時(shí)序
            20. void write24(unsigned char dd); //發(fā)送一個(gè)字節(jié)的時(shí)序
            21. unsigned char read_eeprom(unsigned int address); //從一個(gè)地址讀取出一個(gè)字節(jié)數(shù)據(jù)
            22. void write_eeprom(unsigned int address,unsigned char dd); //往一個(gè)地址存入一個(gè)字節(jié)數(shù)據(jù)
            23. unsigned int read_eeprom_int(unsigned int address); //從一個(gè)地址讀取出一個(gè)int類型的數(shù)據(jù)
            24. void write_eeprom_int(unsigned int address,unsigned int uiWriteData); //往一個(gè)地址存入一個(gè)int類型的數(shù)據(jù)
            25. void T0_time(void);//定時(shí)中斷函數(shù)
            26. void key_service(void); //按鍵服務(wù)的應(yīng)用程序
            27. void key_scan(void);//按鍵掃描函數(shù) 放在定時(shí)中斷里
            28. sbit key_sr1=P0^0; //對應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
            29. sbit key_sr2=P0^1; //對應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
            30. sbit key_sr3=P0^2; //對應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
            31. sbit key_gnd_dr=P0^4; //模擬獨(dú)立按鍵的地GND,因此必須一直輸出低電平
            32. sbit beep_dr=P2^7; //蜂鳴器的驅(qū)動(dòng)IO口
            33. sbit eeprom_scl_dr=P3^7; //時(shí)鐘線
            34. sbit eeprom_sda_dr_sr=P3^6; //數(shù)據(jù)的輸出線和輸入線
            35. sbit dig_hc595_sh_dr=P2^0; //數(shù)碼管的74HC595程序
            36. sbit dig_hc595_st_dr=P2^1;
            37. sbit dig_hc595_ds_dr=P2^2;
            38. sbit hc595_sh_dr=P2^3; //LED燈的74HC595程序
            39. sbit hc595_st_dr=P2^4;
            40. sbit hc595_ds_dr=P2^5;
            41. unsigned char ucKeySec=0; //被觸發(fā)的按鍵編號
            42. unsigned intuiKeyTimeCnt1=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
            43. unsigned char ucKeyLock1=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
            44. unsigned intuiKeyTimeCnt2=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
            45. unsigned char ucKeyLock2=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
            46. unsigned intuiKeyTimeCnt3=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
            47. unsigned char ucKeyLock3=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
            48. unsigned intuiVoiceCnt=0;//蜂鳴器鳴叫的持續(xù)時(shí)間計(jì)數(shù)器
            49. unsigned charucVoiceLock=0;//蜂鳴器鳴叫的原子鎖
            50. unsigned char ucDigShow8;//第8位數(shù)碼管要顯示的內(nèi)容
            51. unsigned char ucDigShow7;//第7位數(shù)碼管要顯示的內(nèi)容
            52. unsigned char ucDigShow6;//第6位數(shù)碼管要顯示的內(nèi)容
            53. unsigned char ucDigShow5;//第5位數(shù)碼管要顯示的內(nèi)容
            54. unsigned char ucDigShow4;//第4位數(shù)碼管要顯示的內(nèi)容
            55. unsigned char ucDigShow3;//第3位數(shù)碼管要顯示的內(nèi)容
            56. unsigned char ucDigShow2;//第2位數(shù)碼管要顯示的內(nèi)容
            57. unsigned char ucDigShow1;//第1位數(shù)碼管要顯示的內(nèi)容
            58. unsigned char ucDigDot8;//數(shù)碼管8的小數(shù)點(diǎn)是否顯示的標(biāo)志
            59. unsigned char ucDigDot7;//數(shù)碼管7的小數(shù)點(diǎn)是否顯示的標(biāo)志
            60. unsigned char ucDigDot6;//數(shù)碼管6的小數(shù)點(diǎn)是否顯示的標(biāo)志
            61. unsigned char ucDigDot5;//數(shù)碼管5的小數(shù)點(diǎn)是否顯示的標(biāo)志
            62. unsigned char ucDigDot4;//數(shù)碼管4的小數(shù)點(diǎn)是否顯示的標(biāo)志
            63. unsigned char ucDigDot3;//數(shù)碼管3的小數(shù)點(diǎn)是否顯示的標(biāo)志
            64. unsigned char ucDigDot2;//數(shù)碼管2的小數(shù)點(diǎn)是否顯示的標(biāo)志
            65. unsigned char ucDigDot1;//數(shù)碼管1的小數(shù)點(diǎn)是否顯示的標(biāo)志
            66. unsigned char ucDigShowTemp=0; //臨時(shí)中間變量
            67. unsigned char ucDisplayDriveStep=1;//動(dòng)態(tài)掃描數(shù)碼管的步驟變量
            68. unsigned char ucWd1Update=1; //窗口1更新顯示標(biāo)志
            69. unsigned char ucWd2Update=0; //窗口2更新顯示標(biāo)志
            70. unsigned char ucWd3Update=0; //窗口3更新顯示標(biāo)志
            71. unsigned char ucWd4Update=0; //窗口4更新顯示標(biāo)志
            72. unsigned char ucWd=1;//本程序的核心變量,窗口顯示變量。類似于一級菜單的變量。代表顯示不同的窗口。
            73. unsigned intuiSetData1=0;//本程序中需要被設(shè)置的參數(shù)1
            74. unsigned intuiSetData2=0;//本程序中需要被設(shè)置的參數(shù)2
            75. unsigned intuiSetData3=0;//本程序中需要被設(shè)置的參數(shù)3
            76. unsigned intuiSetData4=0;//本程序中需要被設(shè)置的參數(shù)4
            77. unsigned char ucTemp1=0;//中間過渡變量
            78. unsigned char ucTemp2=0;//中間過渡變量
            79. unsigned char ucTemp3=0;//中間過渡變量
            80. unsigned char ucTemp4=0;//中間過渡變量
            81. //根據(jù)原理圖得出的共陰數(shù)碼管字模表
            82. code unsigned char dig_table[]=
            83. {
            84. 0x3f,//0 序號0
            85. 0x06,//1 序號1
            86. 0x5b,//2 序號2
            87. 0x4f,//3 序號3
            88. 0x66,//4 序號4
            89. 0x6d,//5 序號5
            90. 0x7d,//6 序號6
            91. 0x07,//7 序號7
            92. 0x7f,//8 序號8
            93. 0x6f,//9 序號9
            94. 0x00,//無 序號10
            95. 0x40,//- 序號11
            96. 0x73,//P 序號12
            97. };
            98. void main()
            99. {
            100. initial_myself();
            101. delay_long(100);
            102. initial_peripheral();
            103. while(1)
            104. {
            105. key_service(); //按鍵服務(wù)的應(yīng)用程序
            106. display_service(); //顯示的窗口菜單服務(wù)程序
            107. }
            108. }
            109. //AT24C02驅(qū)動(dòng)程序
            110. void start24(void)//開始位
            111. {
            112. eeprom_sda_dr_sr=1;
            113. eeprom_scl_dr=1;
            114. delay_short(15);
            115. eeprom_sda_dr_sr=0;
            116. delay_short(15);
            117. eeprom_scl_dr=0;
            118. }
            119. void ack24(void)//確認(rèn)位時(shí)序
            120. {
            121. eeprom_sda_dr_sr=1; //51單片機(jī)在讀取數(shù)據(jù)之前要先置一,表示數(shù)據(jù)輸入
            122. eeprom_scl_dr=1;
            123. delay_short(15);
            124. eeprom_scl_dr=0;
            125. delay_short(15);
            126. //在本驅(qū)動(dòng)程序中,我沒有對ACK信號進(jìn)行出錯(cuò)判斷,因?yàn)槲疫@么多年一直都是這樣用也沒出現(xiàn)過什么問題。
            127. //有興趣的朋友可以自己增加出錯(cuò)判斷,不一定非要按我的方式去做。
            128. }
            129. void stop24(void)//停止位
            130. {
            131. eeprom_sda_dr_sr=0;
            132. eeprom_scl_dr=1;
            133. delay_short(15);
            134. eeprom_sda_dr_sr=1;
            135. }
            136. unsigned char read24(void)//讀取一個(gè)字節(jié)的時(shí)序
            137. {
            138. unsigned char outdata,tempdata;
            139. outdata=0;
            140. eeprom_sda_dr_sr=1; //51單片機(jī)的IO口在讀取數(shù)據(jù)之前要先置一,表示數(shù)據(jù)輸入
            141. delay_short(2);
            142. for(tempdata=0;tempdata<8;tempdata++)
            143. {
            144. eeprom_scl_dr=0;
            145. delay_short(2);
            146. eeprom_scl_dr=1;
            147. delay_short(2);
            148. outdata<<=1;
            149. if(eeprom_sda_dr_sr==1)outdata++;
            150. eeprom_sda_dr_sr=1; //51單片機(jī)的IO口在讀取數(shù)據(jù)之前要先置一,表示數(shù)據(jù)輸入
            151. delay_short(2);
            152. }
            153. return(outdata);
            154. }
            155. void write24(unsigned char dd) //發(fā)送一個(gè)字節(jié)的時(shí)序
            156. {
            157. unsigned char tempdata;
            158. for(tempdata=0;tempdata<8;tempdata++)
            159. {
            160. if(dd>=0x80)eeprom_sda_dr_sr=1;
            161. else eeprom_sda_dr_sr=0;
            162. dd<<=1;
            163. delay_short(2);
            164. eeprom_scl_dr=1;
            165. delay_short(4);
            166. eeprom_scl_dr=0;
            167. }
            168. }
            169. unsigned char read_eeprom(unsigned int address) //從一個(gè)地址讀取出一個(gè)字節(jié)數(shù)據(jù)
            170. {
            171. unsigned char dd,cAddress;
            172. cAddress=address; //把低字節(jié)地址傳遞給一個(gè)字節(jié)變量。
            173. /* 注釋一:
            174. * IIC通訊過程是一個(gè)要求一氣呵成的通訊過程,中間不能被其它中斷影響時(shí)序出錯(cuò),因此
            175. * 在整個(gè)通訊過程中應(yīng)該先關(guān)閉總中斷,完成之后再開中斷。但是,這樣就會(huì)引起另外一個(gè)新
            176. * 問題,如果關(guān)閉總中斷的時(shí)間太長,會(huì)導(dǎo)致動(dòng)態(tài)數(shù)碼管不能及時(shí)均勻的掃描,在操作EEPROM時(shí),
            177. * 數(shù)碼管就會(huì)出現(xiàn)閃爍的現(xiàn)象,解決這個(gè)問題最好的辦法就是在做項(xiàng)目中盡量不要用動(dòng)態(tài)掃描數(shù)碼管
            178. * 的方案,應(yīng)該用靜態(tài)顯示的方案。那么程序上還有沒有改善的方法?有的,下一節(jié)我會(huì)講這個(gè)問題
            179. * 的改善方法。
            180. */
            181. EA=0; //禁止中斷
            182. start24(); //IIC通訊開始
            183. write24(0xA0); //此字節(jié)包含讀寫指令和芯片地址兩方面的內(nèi)容。
            184. //指令為寫指令。地址為"000"的信息,此信息由A0,A1,A2的引腳決定
            185. ack24(); //發(fā)送應(yīng)答信號
            186. write24(cAddress); //發(fā)送讀取的存儲地址(范圍是0至255)
            187. ack24(); //發(fā)送應(yīng)答信號
            188. start24(); //開始
            189. write24(0xA1); //此字節(jié)包含讀寫指令和芯片地址兩方面的內(nèi)容。
            190. //指令為讀指令。地址為"000"的信息,此信息由A0,A1,A2的引腳決定
            191. ack24(); //發(fā)送應(yīng)答信號
            192. dd=read24(); //讀取一個(gè)字節(jié)
            193. ack24(); //發(fā)送應(yīng)答信號
            194. stop24();//停止
            195. /* 注釋二:
            196. * 在寫入或者讀取完一個(gè)字節(jié)之后,一定要加上一段延時(shí)時(shí)間。在11.0592M晶振的系統(tǒng)中,
            197. * 寫入數(shù)據(jù)時(shí)經(jīng)驗(yàn)值用delay_short(2000),讀取數(shù)據(jù)時(shí)經(jīng)驗(yàn)值用delay_short(800)。
            198. * 否則在連續(xù)寫入或者讀取一串?dāng)?shù)據(jù)時(shí)容易丟失數(shù)據(jù)。如果一旦發(fā)現(xiàn)丟失數(shù)據(jù),
            199. * 應(yīng)該適當(dāng)繼續(xù)把這個(gè)時(shí)間延長,尤其是在寫入數(shù)據(jù)時(shí)。
            200. */
            201. delay_short(800);//此處最關(guān)鍵,此處的延時(shí)時(shí)間一定要,而且要足夠長,此處也是導(dǎo)致動(dòng)態(tài)數(shù)碼管閃爍的根本原因
            202. EA=1; //允許中斷
            203. return(dd);
            204. }
            205. void write_eeprom(unsigned int address,unsigned char dd) //往一個(gè)地址存入一個(gè)字節(jié)數(shù)據(jù)
            206. {
            207. unsigned char cAddress;
            208. cAddress=address; //把低字節(jié)地址傳遞給一個(gè)字節(jié)變量。
            209. EA=0; //禁止中斷
            210. start24(); //IIC通訊開始
            211. write24(0xA0); //此字節(jié)包含讀寫指令和芯片地址兩方面的內(nèi)容。
            212. //指令為寫指令。地址為"000"的信息,此信息由A0,A1,A2的引腳決定
            213. ack24(); //發(fā)送應(yīng)答信號
            214. write24(cAddress); //發(fā)送寫入的存儲地址(范圍是0至255)
            215. ack24(); //發(fā)送應(yīng)答信號
            216. write24(dd);//寫入存儲的數(shù)據(jù)
            217. ack24(); //發(fā)送應(yīng)答信號
            218. stop24();//停止
            219. delay_short(2000);//此處最關(guān)鍵,此處的延時(shí)時(shí)間一定要,而且要足夠長,此處也是導(dǎo)致動(dòng)態(tài)數(shù)碼管閃爍的根本原因
            220. EA=1; //允許中斷
            221. }
            222. unsigned int read_eeprom_int(unsigned int address) //從一個(gè)地址讀取出一個(gè)int類型的數(shù)據(jù)
            223. {
            224. unsigned char ucReadDataH;
            225. unsigned char ucReadDataL;
            226. unsigned intuiReadDate;
            227. ucReadDataH=read_eeprom(address); //讀取高字節(jié)
            228. ucReadDataL=read_eeprom(address+1);//讀取低字節(jié)
            229. uiReadDate=ucReadDataH;//把兩個(gè)字節(jié)合并成一個(gè)int類型數(shù)據(jù)
            230. uiReadDate=uiReadDate<<8;
            231. uiReadDate=uiReadDate+ucReadDataL;
            232. return uiReadDate;
            233. }
            234. void write_eeprom_int(unsigned int address,unsigned int uiWriteData) //往一個(gè)地址存入一個(gè)int類型的數(shù)據(jù)
            235. {
            236. unsigned char ucWriteDataH;
            237. unsigned char ucWriteDataL;
            238. ucWriteDataH=uiWriteData>>8;
            239. ucWriteDataL=uiWriteData;
            240. write_eeprom(address,ucWriteDataH); //存入高字節(jié)
            241. write_eeprom(address+1,ucWriteDataL); //存入低字節(jié)
            242. }
            243. void display_service(void) //顯示的窗口菜單服務(wù)程序
            244. {
            245. switch(ucWd)//本程序的核心變量,窗口顯示變量。類似于一級菜單的變量。代表顯示不同的窗口。
            246. {
            247. case 1: //顯示P--1窗口的數(shù)據(jù)
            248. if(ucWd1Update==1)//窗口1要全部更新顯示
            249. {
            250. ucWd1Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來掃描
            251. ucDigShow8=12;//第8位數(shù)碼管顯示P
            252. ucDigShow7=11;//第7位數(shù)碼管顯示-
            253. ucDigShow6=1; //第6位數(shù)碼管顯示1
            254. ucDigShow5=10;//第5位數(shù)碼管顯示無
            255. //先分解數(shù)據(jù)
            256. ucTemp4=uiSetData1/1000;
            257. ucTemp3=uiSetData1%1000/100;
            258. ucTemp2=uiSetData1%100/10;
            259. ucTemp1=uiSetData1%10;
            260. //再過渡需要顯示的數(shù)據(jù)到緩沖變量里,讓過渡的時(shí)間越短越好
            261. if(uiSetData1<1000)
            262. {
            263. ucDigShow4=10;//如果小于1000,千位顯示無
            264. }
            265. else
            266. {
            267. ucDigShow4=ucTemp4;//第4位數(shù)碼管要顯示的內(nèi)容
            268. }
            269. if(uiSetData1<100)
            270. {
            271. ucDigShow3=10;//如果小于100,百位顯示無
            272. }
            273. else
            274. {
            275. ucDigShow3=ucTemp3;//第3位數(shù)碼管要顯示的內(nèi)容
            276. }
            277. if(uiSetData1<10)
            278. {
            279. ucDigShow2=10;//如果小于10,十位顯示無
            280. }
            281. else
            282. {
            283. ucDigShow2=ucTemp2;//第2位數(shù)碼管要顯示的內(nèi)容
            284. }
            285. ucDigShow1=ucTemp1;//第1位數(shù)碼管要顯示的內(nèi)容
            286. }
            287. break;
            288. case 2://顯示P--2窗口的數(shù)據(jù)
            289. if(ucWd2Update==1)//窗口2要全部更新顯示
            290. {
            291. ucWd2Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來掃描
            292. ucDigShow8=12;//第8位數(shù)碼管顯示P
            293. ucDigShow7=11;//第7位數(shù)碼管顯示-
            294. ucDigShow6=2;//第6位數(shù)碼管顯示2
            295. ucDigShow5=10; //第5位數(shù)碼管顯示無
            296. ucTemp4=uiSetData2/1000; //分解數(shù)據(jù)
            297. ucTemp3=uiSetData2%1000/100;
            298. ucTemp2=uiSetData2%100/10;
            299. ucTemp1=uiSetData2%10;
            300. if(uiSetData2<1000)
            301. {
            302. ucDigShow4=10;//如果小于1000,千位顯示無
            303. }
            304. else
            305. {
            306. ucDigShow4=ucTemp4;//第4位數(shù)碼管要顯示的內(nèi)容
            307. }
            308. if(uiSetData2<100)
            309. {
            310. ucDigShow3=10;//如果小于100,百位顯示無
            311. }
            312. else
            313. {
            314. ucDigShow3=ucTemp3;//第3位數(shù)碼管要顯示的內(nèi)容
            315. }
            316. if(uiSetData2<10)
            317. {
            318. ucDigShow2=10;//如果小于10,十位顯示無
            319. }
            320. else
            321. {
            322. ucDigShow2=ucTemp2;//第2位數(shù)碼管要顯示的內(nèi)容
            323. }
            324. ucDigShow1=ucTemp1;//第1位數(shù)碼管要顯示的內(nèi)容
            325. }
            326. break;
            327. case 3://顯示P--3窗口的數(shù)據(jù)
            328. if(ucWd3Update==1)//窗口3要全部更新顯示
            329. {
            330. ucWd3Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來掃描
            331. ucDigShow8=12;//第8位數(shù)碼管顯示P
            332. ucDigShow7=11;//第7位數(shù)碼管顯示-
            333. ucDigShow6=3;//第6位數(shù)碼管顯示3
            334. ucDigShow5=10; //第5位數(shù)碼管顯示無
            335. ucTemp4=uiSetData3/1000; //分解數(shù)據(jù)
            336. ucTemp3=uiSetData3%1000/100;
            337. ucTemp2=uiSetData3%100/10;
            338. ucTemp1=uiSetData3%10;
            339. if(uiSetData3<1000)
            340. {
            341. ucDigShow4=10;//如果小于1000,千位顯示無
            342. }
            343. else
            344. {
            345. ucDigShow4=ucTemp4;//第4位數(shù)碼管要顯示的內(nèi)容
            346. }
            347. if(uiSetData3<100)
            348. {
            349. ucDigShow3=10;//如果小于100,百位顯示無
            350. }
            351. else
            352. {
            353. ucDigShow3=ucTemp3;//第3位數(shù)碼管要顯示的內(nèi)容
            354. }
            355. if(uiSetData3<10)
            356. {
            357. ucDigShow2=10;//如果小于10,十位顯示無
            358. }
            359. else
            360. {
            361. ucDigShow2=ucTemp2;//第2位數(shù)碼管要顯示的內(nèi)容
            362. }
            363. ucDigShow1=ucTemp1;//第1位數(shù)碼管要顯示的內(nèi)容
            364. }
            365. break;
            366. case 4://顯示P--4窗口的數(shù)據(jù)
            367. if(ucWd4Update==1)//窗口4要全部更新顯示
            368. {
            369. ucWd4Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來掃描
            370. ucDigShow8=12;//第8位數(shù)碼管顯示P
            371. ucDigShow7=11;//第7位數(shù)碼管顯示-
            372. ucDigShow6=4;//第6位數(shù)碼管顯示4
            373. ucDigShow5=10; //第5位數(shù)碼管顯示無
            374. ucTemp4=uiSetData4/1000; //分解數(shù)據(jù)
            375. ucTemp3=uiSetData4%1000/100;
            376. ucTemp2=uiSetData4%100/10;
            377. ucTemp1=uiSetData4%10;
            378. if(uiSetData4<1000)
            379. {
            380. ucDigShow4=10;//如果小于1000,千位顯示無
            381. }
            382. else
            383. {
            384. ucDigShow4=ucTemp4;//第4位數(shù)碼管要顯示的內(nèi)容
            385. }
            386. if(uiSetData4<100)
            387. {
            388. ucDigShow3=10;//如果小于100,百位顯示無
            389. }
            390. else
            391. {
            392. ucDigShow3=ucTemp3;//第3位數(shù)碼管要顯示的內(nèi)容
            393. }
            394. if(uiSetData4<10)
            395. {
            396. ucDigShow2=10;//如果小于10,十位顯示無
            397. }
            398. else
            399. {
            400. ucDigShow2=ucTemp2;//第2位數(shù)碼管要顯示的內(nèi)容
            401. }
            402. ucDigShow1=ucTemp1;//第1位數(shù)碼管要顯示的內(nèi)容
            403. }
            404. break;
            405. }
            406. }
            407. void key_scan(void)//按鍵掃描函數(shù) 放在定時(shí)中斷里
            408. {
            409. if(key_sr1==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
            410. {
            411. ucKeyLock1=0; //按鍵自鎖標(biāo)志清零
            412. uiKeyTimeCnt1=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
            413. }
            414. else if(ucKeyLock1==0)//有按鍵按下,且是第一次被按下
            415. {
            416. uiKeyTimeCnt1++; //累加定時(shí)中斷次數(shù)
            417. if(uiKeyTimeCnt1>const_key_time1)
            418. {
            419. uiKeyTimeCnt1=0;
            420. ucKeyLock1=1;//自鎖按鍵置位,避免一直觸發(fā)
            421. ucKeySec=1; //觸發(fā)1號鍵
            422. }
            423. }
            424. if(key_sr2==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
            425. {
            426. ucKeyLock2=0; //按鍵自鎖標(biāo)志清零
            427. uiKeyTimeCnt2=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
            428. }
            429. else if(ucKeyLock2==0)//有按鍵按下,且是第一次被按下
            430. {
            431. uiKeyTimeCnt2++; //累加定時(shí)中斷次數(shù)
            432. if(uiKeyTimeCnt2>const_key_time2)
            433. {
            434. uiKeyTimeCnt2=0;
            435. ucKeyLock2=1;//自鎖按鍵置位,避免一直觸發(fā)
            436. ucKeySec=2; //觸發(fā)2號鍵
            437. }
            438. }
            439. if(key_sr3==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
            440. {
            441. ucKeyLock3=0; //按鍵自鎖標(biāo)志清零
            442. uiKeyTimeCnt3=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
            443. }
            444. else if(ucKeyLock3==0)//有按鍵按下,且是第一次被按下
            445. {
            446. uiKeyTimeCnt3++; //累加定時(shí)中斷次數(shù)
            447. if(uiKeyTimeCnt3>const_key_time3)
            448. {
            449. uiKeyTimeCnt3=0;
            450. ucKeyLock3=1;//自鎖按鍵置位,避免一直觸發(fā)
            451. ucKeySec=3; //觸發(fā)3號鍵
            452. }
            453. }
            454. }
            455. void key_service(void) //按鍵服務(wù)的應(yīng)用程序
            456. {
            457. switch(ucKeySec) //按鍵服務(wù)狀態(tài)切換
            458. {
            459. case 1:// 加按鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
            460. switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
            461. {
            462. case 1:
            463. uiSetData1++;
            464. if(uiSetData1>9999) //最大值是9999
            465. {
            466. uiSetData1=9999;
            467. }
            468. write_eeprom_int(0,uiSetData1); //存入EEPROM 由于內(nèi)部有延時(shí)函數(shù),所以此處會(huì)引起數(shù)碼管閃爍
            469. ucWd1Update=1;//窗口1更新顯示
            470. break;
            471. case 2:
            472. uiSetData2++;
            473. if(uiSetData2>9999) //最大值是9999
            474. {
            475. uiSetData2=9999;
            476. }
            477. write_eeprom_int(2,uiSetData2); //存入EEPROM,由于內(nèi)部有延時(shí)函數(shù),所以此處會(huì)引起數(shù)碼管閃爍
            478. ucWd2Update=1;//窗口2更新顯示
            479. break;
            480. case 3:
            481. uiSetData3++;
            482. if(uiSetData3>9999) //最大值是9999
            483. {
            484. uiSetData3=9999;
            485. }
            486. write_eeprom_int(4,uiSetData3); //存入EEPROM,由于內(nèi)部有延時(shí)函數(shù),所以此處會(huì)引起數(shù)碼管閃爍
            487. ucWd3Update=1;//窗口3更新顯示
            488. break;
            489. case 4:
            490. uiSetData4++;
            491. if(uiSetData4>9999) //最大值是9999
            492. {
            493. uiSetData4=9999;
            494. }
            495. write_eeprom_int(6,uiSetData4); //存入EEPROM,由于內(nèi)部有延時(shí)函數(shù),所以此處會(huì)引起數(shù)碼管閃爍
            496. ucWd4Update=1;//窗口4更新顯示
            497. break;
            498. }
            499. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            500. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
            501. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            502. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
            503. break;
            504. case 2:// 減按鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
            505. switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
            506. {
            507. case 1:
            508. uiSetData1--;
            509. if(uiSetData1>9999)
            510. {
            511. uiSetData1=0;//最小值是0
            512. }
            513. write_eeprom_int(0,uiSetData1); //存入EEPROM,由于內(nèi)部有延時(shí)函數(shù),所以此處會(huì)引起數(shù)碼管閃爍
            514. ucWd1Update=1;//窗口1更新顯示
            515. break;
            516. case 2:
            517. uiSetData2--;
            518. if(uiSetData2>9999)
            519. {
            520. uiSetData2=0;//最小值是0
            521. }
            522. write_eeprom_int(2,uiSetData2); //存入EEPROM,由于內(nèi)部有延時(shí)函數(shù),所以此處會(huì)引起數(shù)碼管閃爍
            523. ucWd2Update=1;//窗口2更新顯示
            524. break;
            525. case 3:
            526. uiSetData3--;
            527. if(uiSetData3>9999)
            528. {
            529. uiSetData3=0;//最小值是0
            530. }
            531. write_eeprom_int(4,uiSetData3); //存入EEPROM,由于內(nèi)部有延時(shí)函數(shù),所以此處會(huì)引起數(shù)碼管閃爍
            532. ucWd3Update=1;//窗口3更新顯示
            533. break;
            534. case 4:
            535. uiSetData4--;
            536. if(uiSetData4>9999)
            537. {
            538. uiSetData4=0;//最小值是0
            539. }
            540. write_eeprom_int(6,uiSetData4); //存入EEPROM,由于內(nèi)部有延時(shí)函數(shù),所以此處會(huì)引起數(shù)碼管閃爍
            541. ucWd4Update=1;//窗口4更新顯示
            542. break;
            543. }
            544. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            545. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
            546. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            547. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
            548. break;
            549. case 3:// 切換窗口按鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
            550. ucWd++;//切換窗口
            551. if(ucWd>4)
            552. {
            553. ucWd=1;
            554. }
            555. switch(ucWd)//在不同的窗口下,在不同的窗口下,更新顯示不同的窗口
            556. {
            557. case 1:
            558. ucWd1Update=1;//窗口1更新顯示
            559. break;
            560. case 2:
            561. ucWd2Update=1;//窗口2更新顯示
            562. break;
            563. case 3:
            564. ucWd3Update=1;//窗口3更新顯示
            565. break;
            566. case 4:
            567. ucWd4Update=1;//窗口4更新顯示
            568. break;
            569. }
            570. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            571. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
            572. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            573. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
            574. break;
            575. }
            576. }
            577. void display_drive(void)
            578. {
            579. //以下程序,如果加一些數(shù)組和移位的元素,還可以壓縮容量。但是鴻哥追求的不是容量,而是清晰的講解思路
            580. switch(ucDisplayDriveStep)
            581. {
            582. case 1://顯示第1位
            583. ucDigShowTemp=dig_table[ucDigShow1];
            584. if(ucDigDot1==1)
            585. {
            586. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            587. }
            588. dig_hc595_drive(ucDigShowTemp,0xfe);
            589. break;
            590. case 2://顯示第2位
            591. ucDigShowTemp=dig_table[ucDigShow2];
            592. if(ucDigDot2==1)
            593. {
            594. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            595. }
            596. dig_hc595_drive(ucDigShowTemp,0xfd);
            597. break;
            598. case 3://顯示第3位
            599. ucDigShowTemp=dig_table[ucDigShow3];
            600. if(ucDigDot3==1)
            601. {
            602. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            603. }
            604. dig_hc595_drive(ucDigShowTemp,0xfb);
            605. break;
            606. case 4://顯示第4位
            607. ucDigShowTemp=dig_table[ucDigShow4];
            608. if(ucDigDot4==1)
            609. {
            610. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            611. }
            612. dig_hc595_drive(ucDigShowTemp,0xf7);
            613. break;
            614. case 5://顯示第5位
            615. ucDigShowTemp=dig_table[ucDigShow5];
            616. if(ucDigDot5==1)
            617. {
            618. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            619. }
            620. dig_hc595_drive(ucDigShowTemp,0xef);
            621. break;
            622. case 6://顯示第6位
            623. ucDigShowTemp=dig_table[ucDigShow6];
            624. if(ucDigDot6==1)
            625. {
            626. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            627. }
            628. dig_hc595_drive(ucDigShowTemp,0xdf);
            629. break;
            630. case 7://顯示第7位
            631. ucDigShowTemp=dig_table[ucDigShow7];
            632. if(ucDigDot7==1)
            633. {
            634. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            635. }
            636. dig_hc595_drive(ucDigShowTemp,0xbf);
            637. break;
            638. case 8://顯示第8位
            639. ucDigShowTemp=dig_table[ucDigShow8];
            640. if(ucDigDot8==1)
            641. {
            642. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            643. }
            644. dig_hc595_drive(ucDigShowTemp,0x7f);
            645. break;
            646. }
            647. ucDisplayDriveStep++;
            648. if(ucDisplayDriveStep>8)//掃描完8個(gè)數(shù)碼管后,重新從第一個(gè)開始掃描
            649. {
            650. ucDisplayDriveStep=1;
            651. }
            652. }
            653. //數(shù)碼管的74HC595驅(qū)動(dòng)函數(shù)
            654. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01)
            655. {
            656. unsigned char i;
            657. unsigned char ucTempData;
            658. dig_hc595_sh_dr=0;
            659. dig_hc595_st_dr=0;
            660. ucTempData=ucDigStatusTemp16_09;//先送高8位
            661. for(i=0;i<8;i++)
            662. {
            663. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
            664. else dig_hc595_ds_dr=0;
            665. dig_hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
            666. delay_short(1);
            667. dig_hc595_sh_dr=1;
            668. delay_short(1);
            669. ucTempData=ucTempData<<1;
            670. }
            671. ucTempData=ucDigStatusTemp08_01;//再先送低8位
            672. for(i=0;i<8;i++)
            673. {
            674. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
            675. else dig_hc595_ds_dr=0;
            676. dig_hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
            677. delay_short(1);
            678. dig_hc595_sh_dr=1;
            679. delay_short(1);
            680. ucTempData=ucTempData<<1;
            681. }
            682. dig_hc595_st_dr=0;//ST引腳把兩個(gè)寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來
            683. delay_short(1);
            684. dig_hc595_st_dr=1;
            685. delay_short(1);
            686. dig_hc595_sh_dr=0; //拉低,抗干擾就增強(qiáng)
            687. dig_hc595_st_dr=0;
            688. dig_hc595_ds_dr=0;
            689. }
            690. //LED燈的74HC595驅(qū)動(dòng)函數(shù)
            691. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)
            692. {
            693. unsigned char i;
            694. unsigned char ucTempData;
            695. hc595_sh_dr=0;
            696. hc595_st_dr=0;
            697. ucTempData=ucLedStatusTemp16_09;//先送高8位
            698. for(i=0;i<8;i++)
            699. {
            700. if(ucTempData>=0x80)hc595_ds_dr=1;
            701. else hc595_ds_dr=0;
            702. hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
            703. delay_short(1);
            704. hc595_sh_dr=1;
            705. delay_short(1);
            706. ucTempData=ucTempData<<1;
            707. }
            708. ucTempData=ucLedStatusTemp08_01;//再先送低8位
            709. for(i=0;i<8;i++)
            710. {
            711. if(ucTempData>=0x80)hc595_ds_dr=1;
            712. else hc595_ds_dr=0;
            713. hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
            714. delay_short(1);
            715. hc595_sh_dr=1;
            716. delay_short(1);
            717. ucTempData=ucTempData<<1;
            718. }
            719. hc595_st_dr=0;//ST引腳把兩個(gè)寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來
            720. delay_short(1);
            721. hc595_st_dr=1;
            722. delay_short(1);
            723. hc595_sh_dr=0; //拉低,抗干擾就增強(qiáng)
            724. hc595_st_dr=0;
            725. hc595_ds_dr=0;
            726. }
            727. void T0_time(void) interrupt 1 //定時(shí)中斷
            728. {
            729. TF0=0;//清除中斷標(biāo)志
            730. TR0=0; //關(guān)中斷
            731. /* 注釋三:
            732. * 此處多增加一個(gè)原子鎖,作為中斷與主函數(shù)共享數(shù)據(jù)的保護(hù),實(shí)際上是借鑒了"紅金龍吸味"關(guān)于原子鎖的建議.
            733. */
            734. if(ucVoiceLock==0) //原子鎖判斷
            735. {
            736. if(uiVoiceCnt!=0)
            737. {
            738. uiVoiceCnt--; //每次進(jìn)入定時(shí)中斷都自減1,直到等于零為止。才停止鳴叫
            739. beep_dr=0;//蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
            740. }
            741. else
            742. {
            743. ; //此處多加一個(gè)空指令,想維持跟if括號語句的數(shù)量對稱,都是兩條指令。不加也可以。
            744. beep_dr=1;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
            745. }
            746. }
            747. key_scan(); //按鍵掃描函數(shù)
            748. display_drive();//數(shù)碼管字模的驅(qū)動(dòng)函數(shù)
            749. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
            750. TL0=0x0b;
            751. TR0=1;//開中斷
            752. }
            753. void delay_short(unsigned int uiDelayShort)
            754. {
            755. unsigned int i;
            756. for(i=0;i
            757. {
            758. ; //一個(gè)分號相當(dāng)于執(zhí)行一條空語句
            759. }
            760. }
            761. void delay_long(unsigned int uiDelayLong)
            762. {
            763. unsigned int i;
            764. unsigned int j;
            765. for(i=0;i
            766. {
            767. for(j=0;j<500;j++)//內(nèi)嵌循環(huán)的空指令數(shù)量
            768. {
            769. ; //一個(gè)分號相當(dāng)于執(zhí)行一條空語句
            770. }
            771. }
            772. }
            773. void initial_myself(void)//第一區(qū) 初始化單片機(jī)
            774. {
            775. /* 注釋四:
            776. * 矩陣鍵盤也可以做獨(dú)立按鍵,前提是把某一根公共輸出線輸出低電平,
            777. * 模擬獨(dú)立按鍵的觸發(fā)地,本程序中,把key_gnd_dr輸出低電平。
            778. * 朱兆祺51學(xué)習(xí)板的S1就是本程序中用到的一個(gè)獨(dú)立按鍵。
            779. */
            780. key_gnd_dr=0; //模擬獨(dú)立按鍵的地GND,因此必須一直輸出低電平
            781. beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時(shí)不叫。
            782. hc595_drive(0x00,0x00);//關(guān)閉所有經(jīng)過另外兩個(gè)74HC595驅(qū)動(dòng)的LED燈
            783. TMOD=0x01;//設(shè)置定時(shí)器0為工作方式1
            784. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
            785. TL0=0x0b;
            786. }
            787. void initial_peripheral(void) //第二區(qū) 初始化外圍
            788. {
            789. ucDigDot8=0; //小數(shù)點(diǎn)全部不顯示
            790. ucDigDot7=0;
            791. ucDigDot6=0;
            792. ucDigDot5=0;
            793. ucDigDot4=0;
            794. ucDigDot3=0;
            795. ucDigDot2=0;
            796. ucDigDot1=0;
            797. EA=1; //開總中斷
            798. ET0=1; //允許定時(shí)中斷
            799. TR0=1; //啟動(dòng)定時(shí)中斷
            800. /* 注釋五:
            801. * 如何初始化EEPROM數(shù)據(jù)的方法。在使用EEPROM時(shí),這一步初始化很關(guān)鍵!
            802. * 第一次上電時(shí),我們從EEPROM讀取出來的數(shù)據(jù)有可能超出了范圍,可能是ff。
            803. * 這個(gè)時(shí)候我們應(yīng)該給它填入一個(gè)初始化的數(shù)據(jù),這一步千萬別漏了。另外,
            804. * 由于int類型數(shù)據(jù)占用2個(gè)字節(jié),所以以下4個(gè)數(shù)據(jù)挨著的地址是0,2,4,6.
            805. */
            806. uiSetData1=read_eeprom_int(0);//讀取uiSetData1,內(nèi)部占用2個(gè)字節(jié)地址
            807. if(uiSetData1>9999) //不在范圍內(nèi)
            808. {
            809. uiSetData1=0; //填入一個(gè)初始化數(shù)據(jù)
            810. write_eeprom_int(0,uiSetData1); //存入uiSetData1,內(nèi)部占用2個(gè)字節(jié)地址
            811. }
            812. uiSetData2=read_eeprom_int(2);//讀取uiSetData2,內(nèi)部占用2個(gè)字節(jié)地址
            813. if(uiSetData2>9999)//不在范圍內(nèi)
            814. {
            815. uiSetData2=0;//填入一個(gè)初始化數(shù)據(jù)
            816. write_eeprom_int(2,uiSetData2); //存入uiSetData2,內(nèi)部占用2個(gè)字節(jié)地址
            817. }
            818. uiSetData3=read_eeprom_int(4);//讀取uiSetData3,內(nèi)部占用2個(gè)字節(jié)地址
            819. if(uiSetData3>9999)//不在范圍內(nèi)
            820. {
            821. uiSetData3=0;//填入一個(gè)初始化數(shù)據(jù)
            822. write_eeprom_int(4,uiSetData3); //存入uiSetData3,內(nèi)部占用2個(gè)字節(jié)地址
            823. }
            824. uiSetData4=read_eeprom_int(6);//讀取uiSetData4,內(nèi)部占用2個(gè)字節(jié)地址
            825. if(uiSetData4>9999)//不在范圍內(nèi)
            826. {
            827. uiSetData4=0;//填入一個(gè)初始化數(shù)據(jù)
            828. write_eeprom_int(6,uiSetData4); //存入uiSetData4,內(nèi)部占用2個(gè)字節(jié)地址
            829. }
            830. }
            總結(jié)陳詞:
            IIC通訊過程是一個(gè)要求一氣呵成的通訊過程,中間不能被其它中斷影響時(shí)序出錯(cuò),因此,在整個(gè)通訊過程中應(yīng)該先關(guān)閉總中斷,完成之后再開中斷。但是,這樣就會(huì)引起另外一個(gè)新問題,如果關(guān)閉總中斷的時(shí)間太長,會(huì)導(dǎo)致動(dòng)態(tài)數(shù)碼管不能及時(shí)均勻的掃描,在按鍵更改參數(shù),內(nèi)部操作EEPROM時(shí),數(shù)碼管就會(huì)出現(xiàn)短暫明顯的閃爍現(xiàn)象,解決這個(gè)問題最好的辦法就是在做項(xiàng)目中盡量不要用動(dòng)態(tài)掃描數(shù)碼管的方案,應(yīng)該用靜態(tài)顯示的方案。那么在程序上還有沒有改善這種現(xiàn)象的方法?當(dāng)然有。欲知詳情,請聽下回分解-----操作AT24C02時(shí),利用“一氣呵成的定時(shí)器方式”改善數(shù)碼管的閃爍現(xiàn)象。


            評論


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

            關(guān)閉