51单片机学习--数字时钟数字电压表
生活随笔
收集整理的這篇文章主要介紹了
51单片机学习--数字时钟数字电压表
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
一、學(xué)習(xí)要求?
1.功能 1:數(shù)字電壓表(0808或stc A/D)。?
2.功能 2:數(shù)字時鐘,顯示時、分、秒,可通過按鍵設(shè)定時間。?
3.將功能 1、功能 2 合并。?
4.擴(kuò)展功能。(發(fā)送“cx”字符串到單片機(jī),單片機(jī)將會返回電壓值和時間)
解:
proteus原理圖及仿真、代碼和使用方法等相關(guān)文件:https://download.csdn.net/download/chenger_32123/10577316
實(shí)現(xiàn)了LCD1602里光標(biāo)的移動、閃爍的同時電壓值可以同步顯示。
基本功能:
?
串口:
?
?
?
/*********************main.c**********************/
?
/*********************main.c**********************//******************************************* //2017/12/4 //芯片:STC89C52? //晶振:12MHz ?12T模式:12個時鐘周期做一個機(jī)器周期 //功能:lcd1602顯示adc0808采集到的電壓值,同時顯示時鐘,時鐘可通過按鍵設(shè)置。 //串口波特率:2400bps@12.000MHz *******************************************/ #include<reg52.h> #include"main.h" #include"lcd1602.h" #include"adc0808.h" #include"read_key.h" /************************************** //主函數(shù) ***************************************/ void main() {?? ?uchar value[COUNT];uchar count=0;uint voltage;uchar display_flag=0;?? ?//lcd1602顯示標(biāo)志initialize();?? ?//初始化LCD_StringOut(0x80,"Time:");//lcd1602第一行顯示LCD_StringOut(0x80+0x40,"Voltage:"); //lcd1602第二行顯示while(1){value[count]=digital_out();?? ?//獲取adc808數(shù)字輸出量并保存在數(shù)組中count++;if(COUNT==count) ? //若獲取夠了COUNT個數(shù)則求均值{?? ?voltage=filter(value,count)*1.0/255*VOLTAGE_REFER;count=0;}if(key_flag) ? //約每20mS掃描一次鍵盤{key_process(read_key()); //讀鍵盤值并處理key_flag=0;display_flag++;}if(display_flag>=10)?? ?//約每200mS更新一次LCD1602顯示{lcd_display(voltage); //LCD1602顯示電壓值display_flag=0;?? ??? ? //顯示標(biāo)志變量清零}if(inquire_flag)?? ? ? //發(fā)送時間到PC{?? ?serial_send();inquire_flag=0;?? ?//查詢標(biāo)志清零}} } /************************************** //初始化函數(shù) ***************************************/ void initialize() {key_set=1;?? ?//定義連接按鍵的IO口為讀取模式key_cursor=1;key_add=1;LCD_Initialize();?? ?//lcd1602初始化adc0808_initialize();//ADC0808初始化serial_initialize(); //串口初始化ET0=1;?? ? ?//開啟定時器0中斷ES=1; ? ? //開串口中斷EA=1; ? ?//開總中斷TR0=1; ? //啟動定時器0 } /************************************** //串口初始化函數(shù) ***************************************/ void serial_initialize()?? ? ?//2400bps@12.000MHz {PCON &= 0x7F;?? ??? ?//波特率不倍速SCON = 0x50;?? ??? ?//8位數(shù)據(jù),可變波特率 //?? ?AUXR &= 0xBF;?? ??? ?//定時器1時鐘為Fosc/12,即12T //?? ?AUXR &= 0xFE;?? ??? ?//串口1選擇定時器1為波特率發(fā)生器TMOD &= 0x0F;?? ??? ?//清除定時器1模式位TMOD |= 0x20;?? ??? ?//設(shè)定定時器1為8位自動重裝方式TL1 = 0xF3;?? ??? ?//設(shè)定定時初值TH1 = 0xF3;?? ??? ?//設(shè)定定時器重裝值ET1 = 0;?? ??? ?//禁止定時器1中斷TR1 = 1;?? ??? ?//啟動定時器1 } /************************************** //定時器0中斷函數(shù) ***************************************/ void timer0_interrtupt() interrupt 1? {static uchar i=0;i++;if(200==i)?? ?//約每20mS進(jìn)入一次{i=0;key_flag=1;?? ? ?//掃描鍵盤標(biāo)志變量}if(count_flag)?? ??{counter++;if(10000==counter){counter=0;second++;if(60==second){second=0;minute++;if(60==minute){minute=0;hour++;if(24==hour){hour=0;}}}}}clock=!clock;?? ?//ADC0808時鐘 } /************************************** //串口中斷函數(shù) ***************************************/ void serial_interrupt() interrupt 4 {static bit count=0;?? ??? ? //定義靜態(tài)局部變量static uchar temp_str[3];if(RI)?? ?//接收{(diào)?? ??? ??? ??? ??? ??? ? ?RI=0;?? ??? ??? ??? ? ?//接收中斷標(biāo)志位清零temp_str[count]=SBUF;if('c'==temp_str[count] && 0==count){?? ??? ??? ??? ??? ??? ?/*含有"cx"字符即為查詢*/count=1;}else if(1==count && 'x'==temp_str[count]){count=0;inquire_flag=1;?? ? ?//表示收到"cx"字符,標(biāo)志位置1}else count=0;}if(TI)?? ? //發(fā)送{TI=0;?? ??? ?//發(fā)送中斷標(biāo)志位清零send++;?? ??? ?//發(fā)送下一個字符if(*send != '\0'){SBUF=*send;?? ?//未遇到"\0"結(jié)束字符,則繼續(xù)發(fā)送}} } /************************************** //lcd1602顯示函數(shù) ***************************************/ void lcd_display(uint _voltage) {display2[0]=_voltage/1000 + '0';display2[2]=_voltage%1000/100 + '0';display2[3]=_voltage%1000%100/10 + '0';display2[4]=_voltage%1000%100%10 + '0';LCD_StringOut(0x80+0x49,display2); //顯示電壓值if(cursor_blink){display1[0]=hour/10 +'0';?? ? //時十位display1[1]=hour%10 +'0';?? ? //時個位display1[3]=minute/10+'0';?? ?//分十位display1[4]=minute%10+'0'; ?//分個位display1[6]=second/10+'0';?? ?//秒十位display1[7]=second%10+'0';?? ?//秒個位LCD_StringOut(0x80+0x06,display1);?? ?//lcd1602顯示時間}else{switch(cursor)?? ?//判斷光標(biāo)位置{case 0:display1[0]='_';display1[1]='_';break;case 1:display1[3]='_';break;case 2:display1[4]='_';break;case 3:display1[6]='_';break;case 4:display1[7]='_';break;}LCD_StringOut(0x80+0x06,display1);//光標(biāo)閃爍}if(set_flag){if(0 == cursor_blink){cursor_blink=8; //約每1.6秒閃爍一次光標(biāo)}else{cursor_blink--;}}else{cursor_blink=1;} } /************************************** //濾波函數(shù) //功能:接收一維數(shù)組,length是數(shù)組長度。中位值平均濾波法(防脈沖干擾平均濾波法), //采樣length個數(shù)據(jù),去掉一個最大值和最小值,然后計(jì)算length-2個數(shù)據(jù)的算術(shù)平均值 //input:數(shù)組首地址,數(shù)組長度。 //output:去除最小值和最大值后的算術(shù)平均值 //注意:由于定義為無符號,所以只能計(jì)算非負(fù)數(shù)。且length>=3。 ***************************************/ uchar filter(uchar *_value,uchar length) {uchar temp;uchar i,j;uint sum=0;for(j=1;j<length;j++){?? ? ? //冒泡法。從小到大排列for(i=0;i<length-j;i++){if(*(_value+i) > *(_value+i+1)){temp=*(_value+i);*(_value+i)=*(_value+i+1);*(_value+i+1)=temp;}}}for(i=1;i<length-1;i++){?? ??? ??? ?//去掉最大和最小值求和sum=*(_value+i)+sum;//求和}return (uchar)((sum+(length-2)/2)/(length-2)); } /********************************************************/ /*鍵值處理函數(shù)*/? /********************************************************/ void key_process(uchar key_temp) {switch(key_temp){case 0:?? ? ?//count+鍵,數(shù)值加if(set_flag){time_setting();?? ?//設(shè)置時間counter=0;}else?? ?//功能2,清零{hour=0;minute=0;second=0;}break;case 1:?? ? ?//cursor鍵,光標(biāo)移動if(set_flag) ?//功能1{/*?? ?if(4==cursor) ?//光標(biāo)循環(huán){cursor=0;}else{cursor++; //光標(biāo)移動}?? ??? ? */?? ??? ??? ??? ?cursor++;cursor%=5;cursor_blink=0;?? ?//lcd1602顯示光標(biāo)閃爍}else ?//功能2,啟動或暫停{/*?? ?if(count_flag){count_flag=0; //暫停}else{count_flag=1;//啟動計(jì)時}?? ??? ? ? */?? ??? ??? ??? ?count_flag=~count_flag;}?? ??? ??? ??? ??? ??? ? ?break;case 2:?? ? ?//set鍵,時間設(shè)置if(set_flag){set_flag=0;?? ? //取消時間設(shè)置狀態(tài)}else?? ? //set_flag==0,即不在時間設(shè)置狀態(tài){count_flag=0;//停止計(jì)時set_flag=1;?? ?//進(jìn)入時間設(shè)置狀態(tài)cursor=0;?? ?//默認(rèn)光標(biāo)位置在時的十位cursor_blink=0;?? ?//lcd1602顯示光標(biāo)閃爍}break;} } /********************************************************/ /*時間設(shè)置函數(shù)*/? /********************************************************/ void time_setting() {switch(cursor){case 0:?? ? ? //光標(biāo)在時位/*?? ?if(23 == hour){?? ??? ??? ??? ??? ? ?//hour++;hour%=24;hour=0;}else?{hour++;}?? ??? ??? ? ?*/hour++;hour%=24;break;case 1:?? ? ?//光標(biāo)在分的十位/*?? ?if(5 == minute/10)?? ??? ? //minute+=10;minute%=60;{minute-=50;?? ??? ? ?}else{minute+=10;}?? ??? ??? ??? ?*/?? ? minute+=10;minute%=60;break;case 2:?? ? ?//光標(biāo)在分的個位if(9 == minute%10){minute-=9;}else{minute++;}break;case 3:?? ? ?//光標(biāo)在秒的十位/*?? ??? ?if(5 == second/10)?? ? ? //second+=10;second%=60;{second-=50;}else{second+=10;}?? ??? ?*/?? ??? ? second+=10;second%=60;break;case 4:?? ? ?//光標(biāo)在秒的個位if(9 == second%10){second-=9;}else{second++;}break;} } /************************************** //串口發(fā)送 ***************************************/ void serial_send() {static uchar send_str[26];uchar i=0,j=0;if(set_flag) //如果正在設(shè)置時間{while(busy_str[i] != '\0'){send_str[i]=busy_str[i];i++;}send_str[i]='\r';i++;send_str[i]='\n';i++;?? ? ?//"\r\n"是回車符while(display2[j] != '\0'){send_str[i+j]=display2[j];j++;}send_str[i+j]='\r';send_str[i+j+1]='\n'; //"\r\n"是回車符send_str[i+j+2]='\0';send = send_str;SBUF=*send;?? ?}else{while(display1[i] != '\0'){send_str[i]=display1[i];i++;}send_str[i]='\t';i++;while(display2[j] != '\0'){send_str[i+j]=display2[j];j++;}send_str[i+j]='\r';send_str[i+j+1]='\n'; //"\r\n"是回車符send_str[i+j+2]='\0'; //結(jié)束符send=send_str;SBUF=*send;} }?
總結(jié)
以上是生活随笔為你收集整理的51单片机学习--数字时钟数字电压表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: web 界面设计 Axure元件样式
- 下一篇: 因变量 方差膨胀系数_请问如何计算潜变量