您的位置 首页 元件

第47节:操作AT24C02使用定时器延时改进数码管的闪耀

开场白:上一节在按键更改参数时,会出现短暂明显的数码管闪烁现象。这节通过教大家使用新型延时函数可以有效的改善闪烁现象。要教会大家三

开场白:
上一节在按键更改参数时,会呈现时刻短显着的数码管闪耀现象。这节通过教我们运用新式延时函数能够有用的改进闪耀现象。要教会我们三个知识点:
榜首个:怎么编写趁热打铁的守时器延时函数。
第二个:怎么编写查看EEPROM芯片是否存在短路,虚焊或许芯片坏了的监控程序。
第三个:通过网友“cjseng”的提示,我主张我们今后在用EEPROM芯片时,假如单片机IO口足够多,WP引脚应该专门接一个IO口,而且加一个上拉电阻,需求更改EEPROM存储数据时置低,其他任何一个时刻都置高,这样能够愈加有用地维护EEPROM内部数据不会被意外更改。

具体内容,请看源代码解说。

(1)硬件渠道:
依据朱兆祺51单片机学习板。旧版的朱兆祺51学习板在硬件上有一个bug,AT24C02的第8个引脚VCC悬空了!!!,读者记得把它飞线连接到5V电源处。新版的朱兆祺51学习板现已改正来了。

(2)完成功用:
4个被更改后的参数断电后不丢掉,数据能够保存,断电再上电后仍是上一次最新被修正的数据。假如AT24C02短路,虚焊,或许坏了,体系能够查看出来,而且蜂鸣器会间歇性鸣叫报警。按更改参数按键时,数码管比上一节大大降低了闪耀现象。
显现和独立按键部分依据第29节的程序来改编,用朱兆祺51单片机学习板中的S1,S5,S9作为独立按键。
一共有4个窗口。每个窗口显现一个参数。
第8,7,6,5位数码管显现当时窗口,P-1代表第1个窗口,P-2代表第2个窗口,P-3代表第3个窗口,P-4代表第1个窗口。
第4,3,2,1位数码管显现当时窗口被设置的参数。规模是从0到9999。S1是加按键,按下此按键会顺次添加当时窗口的参数。S5是减按键,按下此按键会顺次削减当时窗口的参数。S9是切换窗口按键,按下此按键会顺次循环切换不同的窗口。

(3)源代码解说如下:

  1. #include “REG52.H”
  2. #define const_voice_short40 //蜂鸣器短叫的持续时刻
  3. #define const_key_time120 //按键去颤动延时的时刻
  4. #define const_key_time220 //按键去颤动延时的时刻
  5. #define const_key_time320 //按键去颤动延时的时刻
  6. #define const_eeprom_1s 400 //大约1秒的时刻
  7. void initial_myself(void);
  8. void initial_peripheral(void);
  9. void delay_short(unsigned int uiDelayShort);
  10. void delay_long(unsigned int uiDelaylong);
  11. void delay_timer(unsigned int uiDelayTimerTemp); //趁热打铁的守时器延时方法
  12. //驱动数码管的74HC595
  13. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);
  14. void display_drive(void); //显现数码管字模的驱动函数
  15. void display_service(void); //显现的窗口菜单服务程序
  16. //驱动LED的74HC595
  17. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);
  18. void start24(void);//开端位
  19. void ack24(void);//承认位
  20. void stop24(void);//中止位
  21. unsigned char read24(void);//读取一个字节的时序
  22. void write24(unsigned char dd); //发送一个字节的时序
  23. unsigned char read_eeprom(unsigned int address); //从一个地址读取出一个字节数据
  24. void write_eeprom(unsigned int address,unsigned char dd); //往一个地址存入一个字节数据
  25. unsigned int read_eeprom_int(unsigned int address); //从一个地址读取出一个int类型的数据
  26. void write_eeprom_int(unsigned int address,unsigned int uiWriteData); //往一个地址存入一个int类型的数据
  27. void T0_time(void);//守时中止函数
  28. void key_service(void); //按键服务的应用程序
  29. void key_scan(void);//按键扫描函数 放在守时中止里
  30. void eeprom_alarm_service(void); //EEPROM犯错报警
  31. sbit key_sr1=P0^0; //对应朱兆祺学习板的S1键
  32. sbit key_sr2=P0^1; //对应朱兆祺学习板的S5键
  33. sbit key_sr3=P0^2; //对应朱兆祺学习板的S9键
  34. sbit key_gnd_dr=P0^4; //模仿独立按键的地GND,因而有必要一向输出低电平
  35. sbit beep_dr=P2^7; //蜂鸣器的驱动IO口
  36. sbit eeprom_scl_dr=P3^7; //时钟线
  37. sbit eeprom_sda_dr_sr=P3^6; //数据的输出线和输入线
  38. sbit dig_hc595_sh_dr=P2^0; //数码管的74HC595程序
  39. sbit dig_hc595_st_dr=P2^1;
  40. sbit dig_hc595_ds_dr=P2^2;
  41. sbit hc595_sh_dr=P2^3; //LED灯的74HC595程序
  42. sbit hc595_st_dr=P2^4;
  43. sbit hc595_ds_dr=P2^5;
  44. unsigned char ucKeySec=0; //被触发的按键编号
  45. unsigned intuiKeyTimeCnt1=0; //按键去颤动延时计数器
  46. unsigned char ucKeyLock1=0; //按键触发后自锁的变量标志
  47. unsigned intuiKeyTimeCnt2=0; //按键去颤动延时计数器
  48. unsigned char ucKeyLock2=0; //按键触发后自锁的变量标志
  49. unsigned intuiKeyTimeCnt3=0; //按键去颤动延时计数器
  50. unsigned char ucKeyLock3=0; //按键触发后自锁的变量标志
  51. unsigned intuiVoiceCnt=0;//蜂鸣器鸣叫的持续时刻计数器
  52. unsigned charucVoiceLock=0;//蜂鸣器鸣叫的原子锁
  53. unsigned char ucDigShow8;//第8位数码管要显现的内容
  54. unsigned char ucDigShow7;//第7位数码管要显现的内容
  55. unsigned char ucDigShow6;//第6位数码管要显现的内容
  56. unsigned char ucDigShow5;//第5位数码管要显现的内容
  57. unsigned char ucDigShow4;//第4位数码管要显现的内容
  58. unsigned char ucDigShow3;//第3位数码管要显现的内容
  59. unsigned char ucDigShow2;//第2位数码管要显现的内容
  60. unsigned char ucDigShow1;//第1位数码管要显现的内容
  61. unsigned char ucDigDot8;//数码管8的小数点是否显现的标志
  62. unsigned char ucDigDot7;//数码管7的小数点是否显现的标志
  63. unsigned char ucDigDot6;//数码管6的小数点是否显现的标志
  64. unsigned char ucDigDot5;//数码管5的小数点是否显现的标志
  65. unsigned char ucDigDot4;//数码管4的小数点是否显现的标志
  66. unsigned char ucDigDot3;//数码管3的小数点是否显现的标志
  67. unsigned char ucDigDot2;//数码管2的小数点是否显现的标志
  68. unsigned char ucDigDot1;//数码管1的小数点是否显现的标志
  69. unsigned char ucDigShowTemp=0; //暂时中心变量
  70. unsigned char ucDisplayDriveStep=1;//动态扫描数码管的过程变量
  71. unsigned char ucWd1Update=1; //窗口1更新显现标志
  72. unsigned char ucWd2Update=0; //窗口2更新显现标志
  73. unsigned char ucWd3Update=0; //窗口3更新显现标志
  74. unsigned char ucWd4Update=0; //窗口4更新显现标志
  75. unsigned char ucWd=1;//本程序的中心变量,窗口显现变量。类似于一级菜单的变量。代表显现不同的窗口。
  76. unsigned intuiSetData1=0;//本程序中需求被设置的参数1
  77. unsigned intuiSetData2=0;//本程序中需求被设置的参数2
  78. unsigned intuiSetData3=0;//本程序中需求被设置的参数3
  79. unsigned intuiSetData4=0;//本程序中需求被设置的参数4
  80. unsigned char ucTemp1=0;//中心过渡变量
  81. unsigned char ucTemp2=0;//中心过渡变量
  82. unsigned char ucTemp3=0;//中心过渡变量
  83. unsigned char ucTemp4=0;//中心过渡变量
  84. unsigned char ucDelayTimerLock=0; //原子锁
  85. unsigned intuiDelayTimer=0;
  86. unsigned char ucCheckEeprom=0;//查看EEPROM芯片是否正常
  87. unsigned char ucEepromError=0; //EEPROM芯片是否正常的标志
  88. unsigned char ucEepromLock=0;//原子锁
  89. unsigned intuiEepromCnt=0; //间歇性蜂鸣器报警的计时器
  90. //依据原理图得出的共阴数码管字模表
  91. code unsigned char dig_table[]=
  92. {
  93. 0x3f,//0 序号0
  94. 0x06,//1 序号1
  95. 0x5b,//2 序号2
  96. 0x4f,//3 序号3
  97. 0x66,//4 序号4
  98. 0x6d,//5 序号5
  99. 0x7d,//6 序号6
  100. 0x07,//7 序号7
  101. 0x7f,//8 序号8
  102. 0x6f,//9 序号9
  103. 0x00,//无 序号10
  104. 0x40,//- 序号11
  105. 0x73,//P 序号12
  106. };
  107. void main()
  108. {
  109. initial_myself();
  110. delay_long(100);
  111. initial_peripheral();
  112. while(1)
  113. {
  114. key_service(); //按键服务的应用程序
  115. display_service(); //显现的窗口菜单服务程序
  116. eeprom_alarm_service(); //EEPROM犯错报警
  117. }
  118. }
  119. void eeprom_alarm_service(void) //EEPROM犯错报警
  120. {
  121. if(ucEepromError==1) //EEPROM犯错
  122. {
  123. if(uiEepromCnt
  124. {
  125. ucEepromLock=1;//原子锁加锁
  126. uiEepromCnt=0; //计时器清零
  127. ucEepromLock=0;//原子锁解锁
  128. ucVoiceLock=1;//原子锁加锁,维护主函数与中止函数的同享变量uiVoiceCnt
  129. uiVoiceCnt=const_voice_short; //蜂鸣器声响触发,滴一声就停。
  130. ucVoiceLock=0;//原子锁解锁,维护主函数与中止函数的同享变量uiVoiceCnt
  131. }
  132. }
  133. }
  134. //AT24C02驱动程序
  135. void start24(void)//开端位
  136. {
  137. eeprom_sda_dr_sr=1;
  138. eeprom_scl_dr=1;
  139. delay_short(15);
  140. eeprom_sda_dr_sr=0;
  141. delay_short(15);
  142. eeprom_scl_dr=0;
  143. }
  144. void ack24(void)//承认位时序
  145. {
  146. eeprom_sda_dr_sr=1; //51单片机在读取数据之前要先置一,表明数据输入
  147. eeprom_scl_dr=1;
  148. delay_short(15);
  149. eeprom_scl_dr=0;
  150. delay_short(15);
  151. //在本驱动程序中,我没有对ACK信号进行犯错判别,因为我这么多年一向都是这样用也没呈现过什么问题。
  152. //有爱好的朋友能够自己添加犯错判别,纷歧定非要按我的方法去做。
  153. }
  154. void stop24(void)//中止位
  155. {
  156. eeprom_sda_dr_sr=0;
  157. eeprom_scl_dr=1;
  158. delay_short(15);
  159. eeprom_sda_dr_sr=1;
  160. }
  161. unsigned char read24(void)//读取一个字节的时序
  162. {
  163. unsigned char outdata,tempdata;
  164. outdata=0;
  165. eeprom_sda_dr_sr=1; //51单片机的IO口在读取数据之前要先置一,表明数据输入
  166. delay_short(2);
  167. for(tempdata=0;tempdata<8;tempdata++)
  168. {
  169. eeprom_scl_dr=0;
  170. delay_short(2);
  171. eeprom_scl_dr=1;
  172. delay_short(2);
  173. outdata<<=1;
  174. if(eeprom_sda_dr_sr==1)outdata++;
  175. eeprom_sda_dr_sr=1; //51单片机的IO口在读取数据之前要先置一,表明数据输入
  176. delay_short(2);
  177. }
  178. return(outdata);
  179. }
  180. void write24(unsigned char dd) //发送一个字节的时序
  181. {
  182. unsigned char tempdata;
  183. for(tempdata=0;tempdata<8;tempdata++)
  184. {
  185. if(dd>=0x80)eeprom_sda_dr_sr=1;
  186. else eeprom_sda_dr_sr=0;
  187. dd<<=1;
  188. delay_short(2);
  189. eeprom_scl_dr=1;
  190. delay_short(4);
  191. eeprom_scl_dr=0;
  192. }
  193. }
  194. unsigned char read_eeprom(unsigned int address) //从一个地址读取出一个字节数据
  195. {
  196. unsigned char dd,cAddress;
  197. cAddress=address; //把低字节地址传递给一个字节变量。
  198. EA=0; //制止中止
  199. start24(); //IIC通讯开端
  200. write24(0xA0); //此字节包括读写指令和芯片地址两方面的内容。
  201. //指令为写指令。地址为”000″的信息,此信息由A0,A1,A2的引脚决议
  202. ack24(); //发送应对信号
  203. write24(cAddress); //发送读取的存储地址(规模是0至255)
  204. ack24(); //发送应对信号
  205. start24(); //开端
  206. write24(0xA1); //此字节包括读写指令和芯片地址两方面的内容。
  207. //指令为读指令。地址为”000″的信息,此信息由A0,A1,A2的引脚决议
  208. ack24(); //发送应对信号
  209. dd=read24(); //读取一个字节
  210. ack24(); //发送应对信号
  211. stop24();//中止
  212. EA=1; //答应中止
  213. delay_timer(2); //趁热打铁的守时器延时方法,在延时的时分还能够动态扫描数码管
  214. return(dd);
  215. }
  216. void write_eeprom(unsigned int address,unsigned char dd) //往一个地址存入一个字节数据
  217. {
  218. unsigned char cAddress;
  219. cAddress=address; //把低字节地址传递给一个字节变量。
  220. EA=0; //制止中止
  221. start24(); //IIC通讯开端
  222. write24(0xA0); //此字节包括读写指令和芯片地址两方面的内容。
  223. //指令为写指令。地址为”000″的信息,此信息由A0,A1,A2的引脚决议
  224. ack24(); //发送应对信号
  225. write24(cAddress); //发送写入的存储地址(规模是0至255)
  226. ack24(); //发送应对信号
  227. write24(dd);//写入存储的数据
  228. ack24(); //发送应对信号
  229. stop24();//中止
  230. EA=1; //答应中止
  231. delay_timer(4); //趁热打铁的守时器延时方法,在延时的时分还能够动态扫描数码管
  232. }
  233. unsigned int read_eeprom_int(unsigned int address) //从一个地址读取出一个int类型的数据
  234. {
  235. unsigned char ucReadDataH;
  236. unsigned char ucReadDataL;
  237. unsigned intuiReadDate;
  238. ucReadDataH=read_eeprom(address); //读取高字节
  239. ucReadDataL=read_eeprom(address+1);//读取低字节
  240. uiReadDate=ucReadDataH;//把两个字节合并成一个int类型数据
  241. uiReadDate=uiReadDate<<8;
  242. uiReadDate=uiReadDate+ucReadDataL;
  243. return uiReadDate;
  244. }
  245. void write_eeprom_int(unsigned int address,unsigned int uiWriteData) //往一个地址存入一个int类型的数据
  246. {
  247. unsigned char ucWriteDataH;
  248. unsigned char ucWriteDataL;
  249. ucWriteDataH=uiWriteData>>8;
  250. ucWriteDataL=uiWriteData;
  251. write_eeprom(address,ucWriteDataH); //存入高字节
  252. write_eeprom(address+1,ucWriteDataL); //存入低字节
  253. }
  254. void display_service(void) //显现的窗口菜单服务程序
  255. {
  256. switch(ucWd)//本程序的中心变量,窗口显现变量。类似于一级菜单的变量。代表显现不同的窗口。
  257. {
  258. case 1: //显现P–1窗口的数据
  259. if(ucWd1Update==1)//窗口1要悉数更新显现
  260. {
  261. ucWd1Update=0;//及时清零标志,防止一向进来扫描
  262. ucDigShow8=12;//第8位数码管显现P
  263. ucDigShow7=11;//第7位数码管显现-
  264. ucDigShow6=1; //第6位数码管显现1
  265. ucDigShow5=10;//第5位数码管显现无
  266. //先分化数据
  267. ucTemp4=uiSetData1/1000;
  268. ucTemp3=uiSetData1%1000/100;
  269. ucTemp2=uiSetData1%100/10;
  270. ucTemp1=uiSetData1%10;
  271. //再过渡需求显现的数据到缓冲变量里,让过渡的时刻越短越好
  272. if(uiSetData1<1000)
  273. {
  274. ucDigShow4=10;//假如小于1000,千位显现无
  275. }
  276. else
  277. {
  278. ucDigShow4=ucTemp4;//第4位数码管要显现的内容
  279. }
  280. if(uiSetData1<100)
  281. {
  282. ucDigShow3=10;//假如小于100,百位显现无
  283. }
  284. else
  285. {
  286. ucDigShow3=ucTemp3;//第3位数码管要显现的内容
  287. }
  288. if(uiSetData1<10)
  289. {
  290. ucDigShow2=10;//假如小于10,十位显现无
  291. }
  292. else
  293. {
  294. ucDigShow2=ucTemp2;//第2位数码管要显现的内容
  295. }
  296. ucDigShow1=ucTemp1;//第1位数码管要显现的内容
  297. }
  298. break;
  299. case 2://显现P–2窗口的数据
  300. if(ucWd2Update==1)//窗口2要悉数更新显现
  301. {
  302. ucWd2Update=0;//及时清零标志,防止一向进来扫描
  303. ucDigShow8=12;//第8位数码管显现P
  304. ucDigShow7=11;//第7位数码管显现-
  305. ucDigShow6=2;//第6位数码管显现2
  306. ucDigShow5=10; //第5位数码管显现无
  307. ucTemp4=uiSetData2/1000; //分化数据
  308. ucTemp3=uiSetData2%1000/100;
  309. ucTemp2=uiSetData2%100/10;
  310. ucTemp1=uiSetData2%10;
  311. if(uiSetData2<1000)
  312. {
  313. ucDigShow4=10;//假如小于1000,千位显现无
  314. }
  315. else
  316. {
  317. ucDigShow4=ucTemp4;//第4位数码管要显现的内容
  318. }
  319. if(uiSetData2<100)
  320. {
  321. ucDigShow3=10;//假如小于100,百位显现无
  322. }
  323. else
  324. {
  325. ucDigShow3=ucTemp3;//第3位数码管要显现的内容
  326. }
  327. if(uiSetData2<10)
  328. {
  329. ucDigShow2=10;//假如小于10,十位显现无
  330. }
  331. else
  332. {
  333. ucDigShow2=ucTemp2;//第2位数码管要显现的内容
  334. }
  335. ucDigShow1=ucTemp1;//第1位数码管要显现的内容
  336. }
  337. break;
  338. case 3://显现P–3窗口的数据
  339. if(ucWd3Update==1)//窗口3要悉数更新显现
  340. {
  341. ucWd3Update=0;//及时清零标志,防止一向进来扫描
  342. ucDigShow8=12;//第8位数码管显现P
  343. ucDigShow7=11;//第7位数码管显现-
  344. ucDigShow6=3;//第6位数码管显现3
  345. ucDigShow5=10; //第5位数码管显现无
  346. ucTemp4=uiSetData3/1000; //分化数据
  347. ucTemp3=uiSetData3%1000/100;
  348. ucTemp2=uiSetData3%100/10;
  349. ucTemp1=uiSetData3%10;
  350. if(uiSetData3<1000)
  351. {
  352. ucDigShow4=10;//假如小于1000,千位显现无
  353. }
  354. else
  355. {
  356. ucDigShow4=ucTemp4;//第4位数码管要显现的内容
  357. }
  358. if(uiSetData3<100)
  359. {
  360. ucDigShow3=10;//假如小于100,百位显现无
  361. }
  362. else
  363. {
  364. ucDigShow3=ucTemp3;//第3位数码管要显现的内容
  365. }
  366. if(uiSetData3<10)
  367. {
  368. ucDigShow2=10;//假如小于10,十位显现无
  369. }
  370. else
  371. {
  372. ucDigShow2=ucTemp2;//第2位数码管要显现的内容
  373. }
  374. ucDigShow1=ucTemp1;//第1位数码管要显现的内容
  375. }
  376. break;
  377. case 4://显现P–4窗口的数据
  378. if(ucWd4Update==1)//窗口4要悉数更新显现
  379. {
  380. ucWd4Update=0;//及时清零标志,防止一向进来扫描
  381. ucDigShow8=12;//第8位数码管显现P
  382. ucDigShow7=11;//第7位数码管显现-
  383. ucDigShow6=4;//第6位数码管显现4
  384. ucDigShow5=10; //第5位数码管显现无
  385. ucTemp4=uiSetData4/1000; //分化数据
  386. ucTemp3=uiSetData4%1000/100;
  387. ucTemp2=uiSetData4%100/10;
  388. ucTemp1=uiSetData4%10;
  389. if(uiSetData4<1000)
  390. {
  391. ucDigShow4=10;//假如小于1000,千位显现无
  392. }
  393. else
  394. {
  395. ucDigShow4=ucTemp4;//第4位数码管要显现的内容
  396. }
  397. if(uiSetData4<100)
  398. {
  399. ucDigShow3=10;//假如小于100,百位显现无
  400. }
  401. else
  402. {
  403. ucDigShow3=ucTemp3;//第3位数码管要显现的内容
  404. }
  405. if(uiSetData4<10)
  406. {
  407. ucDigShow2=10;//假如小于10,十位显现无
  408. }
  409. else
  410. {
  411. ucDigShow2=ucTemp2;//第2位数码管要显现的内容
  412. }
  413. ucDigShow1=ucTemp1;//第1位数码管要显现的内容
  414. }
  415. break;
  416. }
  417. }
  418. void key_scan(void)//按键扫描函数 放在守时中止里
  419. {
  420. if(key_sr1==1)//IO是高电平,阐明按键没有被按下,这时要及时清零一些标志位
  421. {
  422. ucKeyLock1=0; //按键自锁标志清零
  423. uiKeyTimeCnt1=0;//按键去颤动延时计数器清零,此行十分奇妙,是我实战中探索出来的。
  424. }
  425. else if(ucKeyLock1==0)//有按键按下,且是榜首次被按下
  426. {
  427. uiKeyTimeCnt1++; //累加守时中止次数
  428. if(uiKeyTimeCnt1>const_key_time1)
  429. {
  430. uiKeyTimeCnt1=0;
  431. ucKeyLock1=1;//自锁按键置位,防止一向触发
  432. ucKeySec=1; //触发1号键
  433. }
  434. }
  435. if(key_sr2==1)//IO是高电平,阐明按键没有被按下,这时要及时清零一些标志位
  436. {
  437. ucKeyLock2=0; //按键自锁标志清零
  438. uiKeyTimeCnt2=0;//按键去颤动延时计数器清零,此行十分奇妙,是我实战中探索出来的。
  439. }
  440. else if(ucKeyLock2==0)//有按键按下,且是榜首次被按下
  441. {
  442. uiKeyTimeCnt2++; //累加守时中止次数
  443. if(uiKeyTimeCnt2>const_key_time2)
  444. {
  445. uiKeyTimeCnt2=0;
  446. ucKeyLock2=1;//自锁按键置位,防止一向触发
  447. ucKeySec=2; //触发2号键
  448. }
  449. }
  450. if(key_sr3==1)//IO是高电平,阐明按键没有被按下,这时要及时清零一些标志位
  451. {
  452. ucKeyLock3=0; //按键自锁标志清零
  453. uiKeyTimeCnt3=0;//按键去颤动延时计数器清零,此行十分奇妙,是我实战中探索出来的。
  454. }
  455. else if(ucKeyLock3==0)//有按键按下,且是榜首次被按下
  456. {
  457. uiKeyTimeCnt3++; //累加守时中止次数
  458. if(uiKeyTimeCnt3>const_key_time3)
  459. {
  460. uiKeyTimeCnt3=0;
  461. ucKeyLock3=1;//自锁按键置位,防止一向触发
  462. ucKeySec=3; //触发3号键
  463. }
  464. }
  465. }
  466. void key_service(void) //按键服务的应用程序
  467. {
  468. switch(ucKeySec) //按键服务状况切换
  469. {
  470. case 1:// 加按键 对应朱兆祺学习板的S1键
  471. switch(ucWd)//在不同的窗口下,设置不同的参数
  472. {
  473. case 1:
  474. uiSetData1++;
  475. if(uiSetData1>9999) //最大值是9999
  476. {
  477. uiSetData1=9999;
  478. }
  479. write_eeprom_int(0,uiSetData1); //存入EEPROM 因为内部有延时函数,所以此处会引起数码管闪耀
  480. ucWd1Update=1;//窗口1更新显现
  481. break;
  482. case 2:
  483. uiSetData2++;
  484. if(uiSetData2>9999) //最大值是9999
  485. {
  486. uiSetData2=9999;
  487. }
  488. write_eeprom_int(2,uiSetData2); //存入EEPROM,因为内部有延时函数,所以此处会引起数码管闪耀
  489. ucWd2Update=1;//窗口2更新显现
  490. break;
  491. case 3:
  492. uiSetData3++;
  493. if(uiSetData3>9999) //最大值是9999
  494. {
  495. uiSetData3=9999;
  496. }
  497. write_eeprom_int(4,uiSetData3); //存入EEPROM,因为内部有延时函数,所以此处会引起数码管闪耀
  498. ucWd3Update=1;//窗口3更新显现
  499. break;
  500. case 4:
  501. uiSetData4++;
  502. if(uiSetData4>9999) //最大值是9999
  503. {
  504. uiSetData4=9999;
  505. }
  506. write_eeprom_int(6,uiSetData4); //存入EEPROM,因为内部有延时函数,所以此处会引起数码管闪耀
  507. ucWd4Update=1;//窗口4更新显现
  508. break;
  509. }
  510. ucVoiceLock=1;//原子锁加锁,维护主函数与中止函数的同享变量uiVoiceCnt
  511. uiVoiceCnt=const_voice_short; //按键声响触发,滴一声就停。
  512. ucVoiceLock=0;//原子锁解锁,维护主函数与中止函数的同享变量uiVoiceCnt
  513. ucKeySec=0;//呼应按键服务处理程序后,按键编号清零,防止共同触发
  514. break;
  515. case 2:// 减按键 对应朱兆祺学习板的S5键
  516. switch(ucWd)//在不同的窗口下,设置不同的参数
  517. {
  518. case 1:
  519. uiSetData1–;
  520. if(uiSetData1>9999)
  521. {
  522. uiSetData1=0;//最小值是0
  523. }
  524. write_eeprom_int(0,uiSetData1); //存入EEPROM,因为内部有延时函数,所以此处会引起数码管闪耀
  525. ucWd1Update=1;//窗口1更新显现
  526. break;
  527. case 2:
  528. uiSetData2–;
  529. if(uiSetData2>9999)
  530. {
  531. uiSetData2=0;//最小值是0
  532. }
  533. write_eeprom_int(2,uiSetData2); //存入EEPROM,因为内部有延时函数,所以此处会引起数码管闪耀
  534. ucWd2Update=1;//窗口2更新显现
  535. break;
  536. case 3:
  537. uiSetData3–;
  538. if(uiSetData3>9999)
  539. {
  540. uiSetData3=0;//最小值是0
  541. }
  542. write_eeprom_int(4,uiSetData3); //存入EEPROM,因为内部有延时函数,所以此处会引起数码管闪耀
  543. ucWd3Update=1;//窗口3更新显现
  544. break;
  545. case 4:
  546. uiSetData4–;
  547. if(uiSetData4>9999)
  548. {
  549. uiSetData4=0;//最小值是0
  550. }
  551. write_eeprom_int(6,uiSetData4); //存入EEPROM,因为内部有延时函数,所以此处会引起数码管闪耀
  552. ucWd4Update=1;//窗口4更新显现
  553. break;
  554. }
  555. ucVoiceLock=1;//原子锁加锁,维护主函数与中止函数的同享变量uiVoiceCnt
  556. uiVoiceCnt=const_voice_short; //按键声响触发,滴一声就停。
  557. ucVoiceLock=0;//原子锁解锁,维护主函数与中止函数的同享变量uiVoiceCnt
  558. ucKeySec=0;//呼应按键服务处理程序后,按键编号清零,防止共同触发
  559. break;
  560. case 3:// 切换窗口按键 对应朱兆祺学习板的S9键
  561. ucWd++;//切换窗口
  562. if(ucWd>4)
  563. {
  564. ucWd=1;
  565. }
  566. switch(ucWd)//在不同的窗口下,在不同的窗口下,更新显现不同的窗口
  567. {
  568. case 1:
  569. ucWd1Update=1;//窗口1更新显现
  570. break;
  571. case 2:
  572. ucWd2Update=1;//窗口2更新显现
  573. break;
  574. case 3:
  575. ucWd3Update=1;//窗口3更新显现
  576. break;
  577. case 4:
  578. ucWd4Update=1;//窗口4更新显现
  579. break;
  580. }
  581. ucVoiceLock=1;//原子锁加锁,维护主函数与中止函数的同享变量uiVoiceCnt
  582. uiVoiceCnt=const_voice_short; //按键声响触发,滴一声就停。
  583. ucVoiceLock=0;//原子锁解锁,维护主函数与中止函数的同享变量uiVoiceCnt
  584. ucKeySec=0;//呼应按键服务处理程序后,按键编号清零,防止共同触发
  585. break;
  586. }
  587. }
  588. void display_drive(void)
  589. {
  590. //以下程序,假如加一些数组和移位的元素,还能够紧缩容量。可是鸿哥寻求的不是容量,而是明晰的解说思路
  591. switch(ucDisplayDriveStep)
  592. {
  593. case 1://显现第1位
  594. ucDigShowTemp=dig_table[ucDigShow1];
  595. if(ucDigDot1==1)
  596. {
  597. ucDigShowTemp=ucDigShowTemp|0x80;//显现小数点
  598. }
  599. dig_hc595_drive(ucDigShowTemp,0xfe);
  600. break;
  601. case 2://显现第2位
  602. ucDigShowTemp=dig_table[ucDigShow2];
  603. if(ucDigDot2==1)
  604. {
  605. ucDigShowTemp=ucDigShowTemp|0x80;//显现小数点
  606. }
  607. dig_hc595_drive(ucDigShowTemp,0xfd);
  608. break;
  609. case 3://显现第3位
  610. ucDigShowTemp=dig_table[ucDigShow3];
  611. if(ucDigDot3==1)
  612. {
  613. ucDigShowTemp=ucDigShowTemp|0x80;//显现小数点
  614. }
  615. dig_hc595_drive(ucDigShowTemp,0xfb);
  616. break;
  617. case 4://显现第4位
  618. ucDigShowTemp=dig_table[ucDigShow4];
  619. if(ucDigDot4==1)
  620. {
  621. ucDigShowTemp=ucDigShowTemp|0x80;//显现小数点
  622. }
  623. dig_hc595_drive(ucDigShowTemp,0xf7);
  624. break;
  625. case 5://显现第5位
  626. ucDigShowTemp=dig_table[ucDigShow5];
  627. if(ucDigDot5==1)
  628. {
  629. ucDigShowTemp=ucDigShowTemp|0x80;//显现小数点
  630. }
  631. dig_hc595_drive(ucDigShowTemp,0xef);
  632. break;
  633. case 6://显现第6位
  634. ucDigShowTemp=dig_table[ucDigShow6];
  635. if(ucDigDot6==1)
  636. {
  637. ucDigShowTemp=ucDigShowTemp|0x80;//显现小数点
  638. }
  639. dig_hc595_drive(ucDigShowTemp,0xdf);
  640. break;
  641. case 7://显现第7位
  642. ucDigShowTemp=dig_table[ucDigShow7];
  643. if(ucDigDot7==1)
  644. {
  645. ucDigShowTemp=ucDigShowTemp|0x80;//显现小数点
  646. }
  647. dig_hc595_drive(ucDigShowTemp,0xbf);
  648. break;
  649. case 8://显现第8位
  650. ucDigShowTemp=dig_table[ucDigShow8];
  651. if(ucDigDot8==1)
  652. {
  653. ucDigShowTemp=ucDigShowTemp|0x80;//显现小数点
  654. }
  655. dig_hc595_drive(ucDigShowTemp,0x7f);
  656. break;
  657. }
  658. ucDisplayDriveStep++;
  659. if(ucDisplayDriveStep>8)//扫描完8个数码管后,从头从榜首个开端扫描
  660. {
  661. ucDisplayDriveStep=1;
  662. }
  663. }
  664. //数码管的74HC595驱动函数
  665. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01)
  666. {
  667. unsigned char i;
  668. unsigned char ucTempData;
  669. dig_hc595_sh_dr=0;
  670. dig_hc595_st_dr=0;
  671. ucTempData=ucDigStatusTemp16_09;//先送高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引脚的上升沿把数据送入寄存器
  677. delay_short(1);
  678. dig_hc595_sh_dr=1;
  679. delay_short(1);
  680. ucTempData=ucTempData<<1;
  681. }
  682. ucTempData=ucDigStatusTemp08_01;//再先送低8位
  683. for(i=0;i<8;i++)
  684. {
  685. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
  686. else dig_hc595_ds_dr=0;
  687. dig_hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器
  688. delay_short(1);
  689. dig_hc595_sh_dr=1;
  690. delay_short(1);
  691. ucTempData=ucTempData<<1;
  692. }
  693. dig_hc595_st_dr=0;//ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上而且锁存起来
  694. delay_short(1);
  695. dig_hc595_st_dr=1;
  696. delay_short(1);
  697. dig_hc595_sh_dr=0; //拉低,抗干扰就增强
  698. dig_hc595_st_dr=0;
  699. dig_hc595_ds_dr=0;
  700. }
  701. //LED灯的74HC595驱动函数
  702. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)
  703. {
  704. unsigned char i;
  705. unsigned char ucTempData;
  706. hc595_sh_dr=0;
  707. hc595_st_dr=0;
  708. ucTempData=ucLedStatusTemp16_09;//先送高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引脚的上升沿把数据送入寄存器
  714. delay_short(1);
  715. hc595_sh_dr=1;
  716. delay_short(1);
  717. ucTempData=ucTempData<<1;
  718. }
  719. ucTempData=ucLedStatusTemp08_01;//再先送低8位
  720. for(i=0;i<8;i++)
  721. {
  722. if(ucTempData>=0x80)hc595_ds_dr=1;
  723. else hc595_ds_dr=0;
  724. hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器
  725. delay_short(1);
  726. hc595_sh_dr=1;
  727. delay_short(1);
  728. ucTempData=ucTempData<<1;
  729. }
  730. hc595_st_dr=0;//ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上而且锁存起来
  731. delay_short(1);
  732. hc595_st_dr=1;
  733. delay_short(1);
  734. hc595_sh_dr=0; //拉低,抗干扰就增强
  735. hc595_st_dr=0;
  736. hc595_ds_dr=0;
  737. }
  738. void T0_time(void) interrupt 1 //守时中止
  739. {
  740. TF0=0;//铲除中止标志
  741. TR0=0; //关中止
  742. if(ucVoiceLock==0) //原子锁判别
  743. {
  744. if(uiVoiceCnt!=0)
  745. {
  746. uiVoiceCnt–; //每次进入守时中止都自减1,直到等于零中止。才中止鸣叫
  747. beep_dr=0;//蜂鸣器是PNP三极管操控,低电平就开端鸣叫。
  748. }
  749. else
  750. {
  751. ; //此处多加一个空指令,想保持跟if括号句子的数量对称,都是两条指令。不加也能够。
  752. beep_dr=1;//蜂鸣器是PNP三极管操控,高电平就中止鸣叫。
  753. }
  754. }
  755. if(ucDelayTimerLock==0) //原子锁判别
  756. {
  757. if(uiDelayTimer>0)
  758. {
  759. uiDelayTimer–; //趁热打铁的守时器延时方法的计时器
  760. }
  761. }
  762. if(ucEepromError==1) //EEPROM犯错
  763. {
  764. if(ucEepromLock==0)//原子锁判别
  765. {
  766. uiEepromCnt++;//间歇性蜂鸣器报警的计时器
  767. }
  768. }
  769. key_scan(); //按键扫描函数
  770. display_drive();//数码管字模的驱动函数
  771. TH0=0xfe; //重装初始值(65535-500)=65035=0xfe0b
  772. TL0=0x0b;
  773. TR0=1;//开中止
  774. }
  775. void delay_short(unsigned int uiDelayShort)
  776. {
  777. unsigned int i;
  778. for(i=0;i
  779. {
  780. ; //一个分号相当于履行一条空句子
  781. }
  782. }
  783. void delay_long(unsigned int uiDelayLong)
  784. {
  785. unsigned int i;
  786. unsigned int j;
  787. for(i=0;i
  788. {
  789. for(j=0;j<500;j++)//内嵌循环的空指令数量
  790. {
  791. ; //一个分号相当于履行一条空句子
  792. }
  793. }
  794. }
  795. void delay_timer(unsigned int uiDelayTimerTemp)
  796. {
  797. ucDelayTimerLock=1; //原子锁加锁
  798. uiDelayTimer=uiDelayTimerTemp;
  799. ucDelayTimerLock=0; //原子锁解锁
  800. /* 注释一:
  801. *延时等候,一向比及守时中止把它减到0中止.这种趁热打铁的守时器方法,
  802. *能够在延时的时分动态扫描数码管,改进数码管的闪耀现象
  803. */
  804. while(uiDelayTimer!=0);//趁热打铁的守时器方法延时等候
  805. }
  806. void initial_myself(void)//榜首区 初始化单片机
  807. {
  808. key_gnd_dr=0; //模仿独立按键的地GND,因而有必要一向输出低电平
  809. beep_dr=1; //用PNP三极管操控蜂鸣器,输出高电平时不叫。
  810. hc595_drive(0x00,0x00);//封闭一切通过别的两个74HC595驱动的LED灯
  811. TMOD=0x01;//设置守时器0为作业方法1
  812. TH0=0xfe; //重装初始值(65535-500)=65035=0xfe0b
  813. TL0=0x0b;
  814. }
  815. void initial_peripheral(void) //第二区 初始化外围
  816. {
  817. ucDigDot8=0; //小数点悉数不显现
  818. ucDigDot7=0;
  819. ucDigDot6=0;
  820. ucDigDot5=0;
  821. ucDigDot4=0;
  822. ucDigDot3=0;
  823. ucDigDot2=0;
  824. ucDigDot1=0;
  825. EA=1; //开总中止
  826. ET0=1; //答应守时中止
  827. TR0=1; //发动守时中止
  828. /* 注释二:
  829. * 查看AT24C02芯片是否存在短路,虚焊,芯片坏了等不作业现象。
  830. * 在一个特定的地址里把数据读出来,假如发现不等于0x5a,则从头写入0x5a,再读出来
  831. * 判别是不是等于0x5a,假如不相等,则芯片有问题,犯错报警提示。
  832. */
  833. ucCheckEeprom=read_eeprom(254); //判别AT24C02是否正常
  834. if(ucCheckEeprom!=0x5a)//假如不等于特定内容。则从头写入数据再判别一次
  835. {
  836. write_eeprom(254,0x5a);//从头写入标志数据
  837. ucCheckEeprom=read_eeprom(254); //判别AT24C02是否正常
  838. if(ucCheckEeprom!=0x5a)//假如仍是不等于特定数字,则芯片不正常
  839. {
  840. ucEepromError=1;//表明AT24C02芯片犯错报警
  841. }
  842. }
  843. uiSetData1=read_eeprom_int(0);//读取uiSetData1,内部占用2个字节地址
  844. if(uiSetData1>9999) //不在规模内
  845. {
  846. uiSetData1=0; //填入一个初始化数据
  847. write_eeprom_int(0,uiSetData1); //存入uiSetData1,内部占用2个字节地址
  848. }
  849. uiSetData2=read_eeprom_int(2);//读取uiSetData2,内部占用2个字节地址
  850. if(uiSetData2>9999)//不在规模内
  851. {
  852. uiSetData2=0;//填入一个初始化数据
  853. write_eeprom_int(2,uiSetData2); //存入uiSetData2,内部占用2个字节地址
  854. }
  855. uiSetData3=read_eeprom_int(4);//读取uiSetData3,内部占用2个字节地址
  856. if(uiSetData3>9999)//不在规模内
  857. {
  858. uiSetData3=0;//填入一个初始化数据
  859. write_eeprom_int(4,uiSetData3); //存入uiSetData3,内部占用2个字节地址
  860. }
  861. uiSetData4=read_eeprom_int(6);//读取uiSetData4,内部占用2个字节地址
  862. if(uiSetData4>9999)//不在规模内
  863. {
  864. uiSetData4=0;//填入一个初始化数据
  865. write_eeprom_int(6,uiSetData4); //存入uiSetData4,内部占用2个字节地址
  866. }
  867. }

总结陈词:
下一节开端讲关于单片机驱动实时时钟芯片的内容,欲知概况,请听下回分化—–使用DS1302做一个实时时钟。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/yuanjian/262074.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部