




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
基于Mini51板的數(shù)字示波器設計基于Mini51板硬件資源,構思數(shù)字示波器的方案已經思考很久了,總是沒有集中的時間,一個稍微復雜的設計完成創(chuàng)作需要集中的時間才能完成,這次利用學期結束的一段集中時間,完成了基于LCD12864顯示的數(shù)字示波器程序設計,現(xiàn)在將文檔寫出來供大家交流學習用。在此聲明,這個教程是寫給初學者看的,我會從簡單到復雜一步一步詳細介紹設計過程,甚至是調試的過程,還包括一些經驗總結,特別是提供了完整的keil工程附件。希望讀者立足示波器工程,學到更多關于軟硬件開發(fā)的一些經驗技巧。1簡易數(shù)字示波器原理數(shù)字示波器根本原理可以簡單理解為:數(shù)據(jù)采集+圖形顯示,該過程循環(huán)進行,如圖1-1所示。首先是數(shù)據(jù)采集,這一版我們直接用Mini51板上的ADC“TLC1549”?!踩绻銢]有ADC,也可能沒有信號發(fā)生器,后面會介紹一種正弦表調試方法?!砊LC1549驅動函數(shù)unsignedintread_adc(void)。圖1-1簡易數(shù)字示波器流程圖unsignedintread_adc(void){unsignedchari;unsignedinttemp=0;ADC_CS=0;//開啟控制電路,使能DA和CKIO引腳for(i=0;i<10;i++){//采集10次,即10bitADC_CK=0;temp<<=1;if(ADC_DA)temp++;ADC_CK=1;}ADC_CS=1;return(temp);}注:帶背景色的源碼都是直接從演示程序中拷貝的。以上是是驅動TLC1549的函數(shù),如果你還想徹底弄清TLC1549的各種參數(shù),請參考數(shù)據(jù)手冊TLC1549.pdf,使用該函數(shù)需要注意的是,兩次調用該函數(shù)之間的間隔要超過21us,AD轉換是要一段時間的,在高速系統(tǒng)中時間控制尤其關鍵。Mini51板單片機在22.1184M晶振時鐘頻率下運行,連續(xù)兩次AD采集數(shù)據(jù)并將數(shù)據(jù)寫入外部擴展RAM變量緩沖區(qū),之間的時間間隔實測略小于21us的,需要適當延時。這在高速檔數(shù)據(jù)采集時增加了一定延時等待就是這個原因。圖形顯示有很多種,LCD顯示稍難,ADC得到的結果如何在LCD上描點,這確實是一個難點,涉及LCD驅動問題,需要花費很大篇幅才能完成。最初調試我們可以選用串口來做,借助他人現(xiàn)成的工具軟件。下面介紹基于串口和上位機工具軟件的波形顯示程序設計。串口初始化函數(shù)rs232_port_init(void)。voidrs232_port_init(void)//串口初始化{ SCON=0x50; //串口工作在方式1,異步模式 PCON=0x80; //波特率翻倍 TMOD=0x20;//定時器1工作在方式2 TH1=0xff; //波特率115200bps,單片機時鐘晶振為22.1184MHz TL1=0xff; TR1=1; //開啟時鐘 RI=0; //清空接受標志位 TI=0; //清空發(fā)送標志位}往串口寫1字節(jié)函數(shù)voiduart_put_uchar(unsignedcharc)。voiduart_put_uchar(unsignedcharc)//往串口寫1字節(jié)無符號數(shù)據(jù){ SBUF=c; while(!TI); TI=0;}從串口讀1字節(jié)函數(shù)unsignedcharuart_get_uchar()。unsignedcharuart_get_uchar()//從串口讀1字節(jié)無符號數(shù)據(jù){ while(!RI); RI=0; returnSBUF;}以上這幾個函數(shù)是學單片機的人一定要掌握的,能夠隨手拿來就用,通過串口調試程序,很方便。有了以上4個函數(shù),再建一個keil工程,添加一個主函數(shù),就可以演示了。#include"mini51b.h" //所有與硬件相關的接口函數(shù)定義#include"uart.h"voidmain(){ rs232_port_init();//串口初始化 read_adc();//首個ADC數(shù)據(jù)喪失 while(1){ if(uart_get_uchar()==0x55)uart_put_uchar(read_adc()/4); //10bit/4變8bit }}在主程序循環(huán)中,接收到上位機下發(fā)的數(shù)據(jù)0x55后,讀取ADC數(shù)據(jù)并發(fā)送一次,在串口調試助手〔例如SSCOM〕里,設置相關端口和波特率后,發(fā)送0x55,注意HEX〔十六進制格式〕選項,就可以看到ADC的結果,如圖1-2所示。圖1-2串口調試ADC調試ADC還有一種更方便的方法,結果直接在Mini51板上的數(shù)碼管上顯示出來,不管你對數(shù)碼管硬件熟悉不熟悉,只要使用模板程序提供的數(shù)碼管驅動函數(shù)led_disp(uintnumber)即可。Mini51板數(shù)碼管驅動函數(shù)led_disp(unsignedint)。voidled_disp(uintnumber)//Mini51板數(shù)碼管顯示函數(shù),傳入整數(shù)0~9999{ unsignedcharcodetab1[20]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,}; unsignedchartemp,flag=0; if(number<10000) { temp=number/1000%10;//千位數(shù)碼管 if(temp){ SEG_Q=tab1[temp]; flag=1; } else{ SEG_Q=0xff;//數(shù)碼管熄滅 flag=0; } temp=number/100%10;//百位數(shù)碼管 if(flag|temp) { SEG_B=tab1[temp]; flag=1; } else{ SEG_B=0xff;//數(shù)碼管熄滅 flag=0; } temp=number/10%10;//十位數(shù)碼管 if(flag|temp)SEG_S=tab1[temp]; elseSEG_S=0xff;//數(shù)碼管熄滅 temp=number%10;//個位數(shù)碼管 SEG_G=tab1[temp]; } else{ SEG_Q=0xbf;//"-" SEG_B=0xbf; SEG_S=0xbf; SEG_G=0xbf; }}以上演示源程序keil工程請參考附件【串口調試1】這里我再介紹兩款串口繪圖軟件【MyOsc】和【ComCalWave】,可以直接把串口接收到的數(shù)據(jù)按X-Y軸繪圖,顯示結果更直觀。主程序這樣改:#include"mini51b.n" //所有與硬件相關的接口函數(shù)定義#include"uart.h"voidmain(){ rs232_port_init(); read_adc(); delay_ms(1); while(1){ uart_put_uchar(read_adc()/4); //seg7_disp(read_adc()); delay_ms(1); //這里的延時起到調節(jié)采樣率的作用 }}運行【MyOsc】,設置串口和波特率后“OPEN”,適當調節(jié)輸入信號頻率后可以看到如圖1-3所示的圖案。圖1-3串口繪圖軟件例如運行【ComCalWave】,選擇正確的串口號和波特率,“OpenCOM”,再設置“WaveShow”,看到了什么?圖形!在圖形窗口嘗試用鼠標右鍵操作,還可選擇特定范圍顯示,如圖1-4所示。圖1-4串口繪圖軟件例如2要看到以上漂亮的波形,還有一些硬件連接要做,需要將信號發(fā)生器和Mini51板上ADCin接口連接,注意,TLC1549只能進行0到5V之間的信號轉換,你還需要調整信號發(fā)生器,產生滿足條件的信號才行。以上演示源程序keil工程請參考附件【串口調試2】實際在調試程序中,缺少必要硬件設備的,還可以用正弦表代替實際ADC,這里再介紹一款正弦表生成器軟件【正弦表發(fā)生器】,軟件界面如圖1-5所示。圖1-5正弦表發(fā)生器【量化階數(shù)】就是ADC位數(shù),例如tlc1549是10階,ADC0809是8階;【采樣點數(shù)】就是在一個正弦周期內,均勻分布多少個采樣點,例如在128點的lcd上顯示2個以上周期的話,采樣點數(shù)要小于64點,這里選用30點數(shù)來舉例,源程序如下。#include"mini51b.h"http://所有與硬件相關的接口函數(shù)定義#include"uart.h"unsignedcharcodedot[30]={//正弦表,注意數(shù)據(jù)類型是“code”,存放在rom當中 0x80,0x9a,0xb4,0xcb,0xdf,0xee,0xf9,0xff,0xff,0xf9, 0xee,0xdf,0xcb,0xb4,0x9a,0x80,0x65,0x4c,0x34,0x21, 0x11,0x6,0x0,0x0,0x6, 0x10,0x20,0x34,0x4b,0x65,};voidmain(){ unsignedchari; rs232_port_init(); delay_ms(1); while(1){ for(i=0;i<128;i++){ uart_put_uchar(dot[i%30]); delay_ms(1);//此處延時當于調節(jié)了采樣率 } }}用以上調試軟件同樣可以看到漂亮的正弦信號圖形。以上調試成功后,是不是感覺很棒,如果你是第一次親自完成ADC將數(shù)據(jù)采集,再用軟件繪圖顯示復原信號波形圖,一定是一件特別令人沖動的事情。2圖形液晶LCD12864繪圖驅動設計根底下面我們學習如何在LCD12864上顯示同樣的正弦波形。關于LCD的硬件接口電路,在前面的教程中有詳細介紹,涉及單片機總線知識和CPLD內部電路,需要專門學習,這里我們借助現(xiàn)成的驅動函數(shù),重點講解LCD繪圖程序設計。LCD12864的電路接口在【mini51b.h】頭文件中定義。#defineLCD_LCWXBYTE[0xf4ea] //左屏命令寫入#defineLCD_LDWXBYTE[0xf5ea]//左屏數(shù)據(jù)寫入#defineLCD_LCRXBYTE[0xf6ea] //左屏命令讀出#defineLCD_LDRXBYTE[0xf7ea] //左屏數(shù)據(jù)讀出#defineLCD_RCWXBYTE[0xf8ea] //右屏命令寫入#defineLCD_RDWXBYTE[0xf9ea]//右屏數(shù)據(jù)寫入#defineLCD_RCRXBYTE[0xfaea] //右屏命令讀出#defineLCD_RDRXBYTE[0xfbea]//右屏數(shù)據(jù)讀出后面所有對LCD的編程操作都是基于以上接口定義〔總線編址〕進行的讀寫操作。首先來看LCD點陣結構圖,這里以不帶字庫的LCD12864來講解,如圖2-1所示。圖2-1LCD點陣分布結構圖此LCD屏由水平128列,垂直64行組成。水平128列分左右各64列兩個半屏構成。垂直64行又分8頁,每頁8行〔1列8點剛好1字節(jié)〕。程序每次對LCD的繪圖操作就是以最小單位1字節(jié)進行操作的。理解這點至關重要。也就是每次只能針對8點進行操作,而不是1點進行操作。左右屏由單獨地址線控制〔前面的接口定義就是分左右屏定義的〕。實際打點只需往指定“位置”寫入數(shù)據(jù),“1”亮,“0”LCD驅動函數(shù):忙檢測函數(shù)voidloop_lcd12864_is_busy(unsignedcharright)。voidloop_lcd12864_is_busy(unsignedcharright){unsignedchartmp,counter=0;do{ if(right)tmp=LCD_RCR; elsetmp=LCD_LCR; if(counter++>50)break;//超時跳出}while((tmp|0x7f)==0xff);//bit7為1那么表示LCD內部執(zhí)行命令,處于“忙”狀態(tài)}對LCD進行讀寫操作時,需要進行“忙”檢測,LCD內部也是由控制器來完成一些列LCD屏顯示操作的,執(zhí)行各種操作都是需要一定的時間的,也就是說不是任何時候外部控制器都可以操作LCD的,只有LCD為空閑狀態(tài)時才可以操作,忙檢測就是循環(huán)讀取LCD狀態(tài)標志位,判斷是否空閑,關于命令的細節(jié)請參考數(shù)據(jù)手冊。命令寫入函數(shù)voidlcd_cmd_wr(unsignedcharcmd,right)。voidlcd_cmd_wr(unsignedcharcmd,right){loop_lcd12864_is_busy(right); //忙檢測if(right)LCD_RCW=cmd; //右屏命令寫入elseLCD_LCW=cmd; //左屏命令寫入}數(shù)據(jù)寫入函數(shù)voidlcd_dat_wr(unsignedchardata,right)。voidlcd_dat_wr(unsignedchardata,right){loop_lcd12864_is_busy(right);if(right)LCD_RDW=data;elseLCD_LDW=data;}lcd_cmd_wr()和lcd_dat_wr()兩個函數(shù)分別是給LCD寫命令和寫數(shù)據(jù)函數(shù),通過寫命令函數(shù)設定地址。每個函數(shù)都分左右屏,用0,非0選擇。讀數(shù)據(jù)函數(shù)unsignedcharlcd_dat_rd(unsignedcharright)。unsignedcharlcd_dat_rd(unsignedcharright){loop_lcd12864_is_busy(right);if(right)return(LCD_RDR);elseretuen(LCD_LDR);}該函數(shù)完成對LCD已顯示的數(shù)據(jù)讀出,首次操作需要讀2次數(shù)據(jù)才有效。LCD清屏函數(shù)voidlcd12864_clr(void)。voidlcd12864_clr(void){ unsignedchari,j; for(i=0;i<8;i++){//從0到7共8頁 lcd_cmd_wr(ORGX,0);//分頁設定左屏0點地址 lcd_cmd_wr(ORGY+i,0); lcd_cmd_wr(ORGX,1);//分頁設定右屏0點地址 lcd_cmd_wr(ORGY+i,1); for(j=0;j<64;j++){ lcd_data_wr(0,0); lcd_data_wr(0,1); } }}該函數(shù)對LCD所有點陣寫0,完成一次清屏操作。這里的ORGY,PRGX是設定光標的命令,光標指向(0,0)字節(jié),是一個固定值。實際在執(zhí)行數(shù)據(jù)寫入的時,x坐標范圍從0到63,在連續(xù)寫入過程中能夠實現(xiàn)自動加1,y軸頁地址范圍從0到7,需要逐頁設定。LCD初始化函數(shù)voidlcd12864_init(void)。voidlcd12864_init(void){lcd_cmd_wr(DISPON,0); //顯示開啟lcd_cmd_wr(DISPFIRST,0);//設定顯示首行地址 //修改首行地址可以實現(xiàn)屏幕滾動顯示效果lcd_cmd_wr(ORGY,0);//設定初始光標lcd_cmd_wr(ORGX,0);lcd_cmd_wr(DISPON,1);//初始另外一半lcd_cmd_wr(DISPFIRST,1);lcd_cmd_wr(ORGY,1);lcd_cmd_wr(ORG,1);lcd12864_clr();//執(zhí)行清屏,非必須操作}該函數(shù)用來初始化LCD,設置顯示模式,光標位置等,在對LCD繪圖時,最多的命令就是設定當前光標位置,通過光標位置來指定將要操作的LCD顯示點。在對LCD編程操作以前,一定要執(zhí)行此函數(shù)對LCD進行初始化操作。例如給左半屏〔0,0〕首字節(jié)寫入數(shù)據(jù)0x55,應該執(zhí)行以下程序。lcd12864_init();//LCD初始化lcd_cmd_wr(ORGX,0);//設定水平軸X地址lcd_cmd_wr(ORGY,0);//設定垂直軸Y地址lcd_dat_wr(0x55,0);//寫入數(shù)據(jù),從下至上為01010101lcd_dat_wr(0xaa,0);//寫入數(shù)據(jù),從下至上為10101010,連續(xù)寫入,X地址自動加1這樣在如圖0字節(jié)和1字節(jié)就將交替有4點亮,4點暗,構成如圖2-2所示圖案。圖2-2LCD顯示例如圖2-3LCD顯示例如又如執(zhí)行程序:lcd12864_init();lcd_cmd_wr(ORGX,1);lcd_cmd_wr(ORGY,1);lcd_dat_wr(0x55,1); 顯示效果如圖2-3所示。如果執(zhí)行以下程序:lcd12864_init();lcd_cmd_wr(ORGX+1,0);lcd_cmd_wr(ORGY+1,0);lcd_data_wr(0x55,0); 顯示效果如圖2-4所示。圖2-4LCD顯示例如圖2-5LCD顯示例如從驅動函數(shù)可見,一次對LCD寫入數(shù)據(jù)是以字節(jié)為單位,通過寫命令確定坐標,Y坐標從0頁到7頁,X坐標從0列到63列,分左右屏,左上角為坐標〔0,0〕點,這和我們習慣的左下角為〔0,0〕坐標軸是不一樣的。因為每次操作LCD是一個字節(jié)為單位,對應8點,如果我們希望以任意點為坐標顯示,還得另外尋找別的方法編程實現(xiàn)真正“點”顯示。如圖2-5所示,在屏幕上指定位置畫點,水平軸就是x,與lcd坐標一致,y軸需要將點坐標變成字節(jié)為單位的坐標,我們先按習慣將y軸64點從下至上編號0到63,其中0到7點為字節(jié)0,8到15點為字節(jié)1,依此類推對應8字節(jié)。第一點Y軸為30,應該是哪字節(jié)哪bit呢?30/8取整為3,前3字節(jié)〔0,1,2三字節(jié)〕對應0到23點跳過,實際30點應該在第4字節(jié)〔24到31〕的bit6上,這就要用算法計算出字節(jié)數(shù)和bit位,前面30/8=3,這里的3似乎就是要找的字節(jié)數(shù),那么30%8〔30除8取余數(shù)〕呢,余數(shù)是6,不是剛好是bit位嗎?所以可以這樣將y值映射到某字節(jié)的某點上,如果Y軸64點對應8字節(jié)變量Da[n],n從0到7,那么:da[y/8]=1<<(y%8);或da[y>>3]=0x01<<(y&0x07);后一種算法更優(yōu)。通過總結規(guī)律,用以上算法可以將任意0到63之間的數(shù)據(jù)作為坐標描點到對應的8個字節(jié)中,然后將8個字節(jié)全部寫入LCD,那么通過剛剛算法就會有一點與所給坐標一致。第一點:da[30/8]=1<<30%8;即da[3]=0x40;第二點:da[10/8]=1<<10%8;即da[1]=0x04;下面我們來設計的函數(shù)??偨Y以上算法,編寫出在LCD任何坐標位置上描點繪圖函數(shù)voidlcd_disp(unsignedcharx,y)。列更新子函數(shù)lcd_row_wr(unsignedcharx,unsignedchar*da)。voidlcd_row_wr(unsignedcharx,unsignedchar*da)//x是列坐標,*da是8字節(jié)列數(shù)據(jù){ unsignedcharj; if(x<64){//根據(jù)列坐標選擇左右半屏 for(j=0;j<8;j++){//寫左半屏 lcd_cmd_wr(ORGY+j,0); lcd_cmd_wr(ORGX+x,0); lcd_data_wr(da[j],0); } } else{ x-=64;//坐標調整 for(j=0;j<8;j++){//寫右半屏 lcd_cmd_wr(ORGY+j,1); lcd_cmd_wr(ORGX+x,1); lcd_data_wr(da[j],1); } }}voidlcd_disp(unsignedcharx,y)//x水平坐標,y垂直坐標{ unsignedchardat[8]; unsignedcharj; for(j=0;j<8;j++)dat[j]=0x0; dat[y/8]|=0x01<<(y&0x07); lcd_row_wr(x,dat);}以上函數(shù)能夠在指定坐標〔x,y〕上描點,例如執(zhí)行程序:lcd_init();lcd_disp(0,0);lcd_disp(1,1);lcd_disp(2,2);lcd_disp(3,3);lcd_disp(4,4);lcd_disp(5,5);lcd_disp(6,6);lcd_disp(7,7);lcd_disp(70,10);lcd_disp(71,20);lcd_disp(72,30);lcd_disp(73,40);效果如圖2-6所示。圖2-6LCD顯示例如圖2-7LCD顯示例如以上演示源程序keil工程請參考附件【LCD驅動exa1】。如圖2-6所示效果,Y軸“反了”,是的,這很好辦,在lcd_disp()函數(shù)中增加一句:y=63-y;就可以實現(xiàn)。在下面的例子中將做到與我們習慣的坐標一致。voidmain(){ unsignedchari; lcd_init(); for(i=0;i<128;i++){ lcd_disp(i,i/2); } while(1);}效果如圖2-7所示。以上演示源程序keil工程請參考附件【LCD驅動exa2】。如果將正弦表的數(shù)據(jù)送LCD顯示,程序:voidmain(){ unsignedchari; lcd_init(); for(i=0;i<128;i++){ lcd_disp(i,dot[i%30]/4);//除以4是變8bit為6bit〔0-63〕進行LCD映射 } while(1);}效果如圖2-8所示。圖2-8LCD顯示例如圖2-9矢量繪圖例如以上演示源程序keil工程請參考附件【LCD驅動exa3】。以上是逐點繪圖,其實矢量繪圖效果會更好,矢量繪圖原理在本文第7節(jié)介紹。進一步完善繪圖函數(shù)lcd_disp〔〕。voidlcd_disp(unsignedcharx,unsignedchary,charl)//x水平坐標,y垂直坐標,l矢量繪圖參數(shù){ unsignedchardat[8]; unsignedcharj; y=63-y; for(j=0;j<8;j++)dat[j]=0x0; if(l==0)dat[y>>3]|=0x01<<(y&0x07); elseif(l>0)for(j=0;j<l;j++)dat[(y+j)/8]|=0x01<<((y+j)&0x07); elsefor(j=0;j<(-l);j++)dat[(y-j)/8]|=0x01<<((y-j)&0x07); lcd_row_wr(x,dat);}主函數(shù)也要傳遞對應參數(shù)。voidmain(){ unsignedchari; chark; lcd_init(); for(i=0;i<128;i++){ k=dot[i%30]-dot[(i+1)%30]; lcd_disp(i,dot[i%30]/4,k/4); } while(1);}效果如圖2-9所示。以上演示源程序keil工程請參考附件【LCD驅動exa3s】。繼續(xù)改良參數(shù),嘗試將adc的值采集送lcd顯示。再按時間軸X軸順序將不同時刻采集到的Y值順序寫入LCD,這是我們就可以在LCD上看到隨時間變化的電壓曲線了。voidmain(){ unsignedchari; lcd12864_init(); for(i=0;i<128;i++){ lcd_disp(i,read_adc(0)/16);//從10bit映射到6bit,要除16 } while(1);}效果如圖2-9所示。圖2-9LCD顯示例如圖2-10LCD顯示例如調整信號頻率,可以得到滿意的波形圖了,效果如圖2-10所示。如果你成功做到了這一步,可喜可賀,具備了做一款數(shù)字示波器的根底了。還要繼續(xù)完善。從驅動函數(shù)可見,單片機對LCD上每點都要重復計算,是不是覺得單片機運行會很辛苦呢〔很慢〕?其實這就是計算機的優(yōu)勢,最擅長重復做有規(guī)律事情,單片機通過高速的運行指令,實現(xiàn)了這些任務的“瞬時”完成效果,實際運行效果很好的?!疽稽c經驗】作為終端輸出顯示裝置,并不需要很高的更新〔刷新〕速度,因為它是給“人”看的,每秒超過10次的變化,對人眼睛產生不了有用的效果。教程寫到這里,對于完成示波器圖形顯示LCD驅動程序應該差不多學會了吧。實際上完整的示波器程序還需要在LCD上顯示網格〔背景格〕和可移動游標線,還有一些指示符號,我們來繼續(xù)深入學習。3圖形液晶LCD12864繪圖驅動設計提高如何在現(xiàn)實波形顯示的根底上,同時將定標網格也顯示出來了?我們繼續(xù)完善LCD圖形顯示驅動。首先我們看一種C語法,A=0x05;A|=0x50;運行以上指令后,A=0x55;也可以說第二個數(shù)據(jù)0x50是疊加到第一個數(shù)據(jù)上的,我們可以用這種算法把需要顯示的亮點〔也就是“1”〕按一定的算法疊加在一起,送LCD顯示,就出現(xiàn)了我們希望的在波形上增加背景網格的效果。因為網格與水平X軸是嚴格關聯(lián)的,所以我們可以對X軸數(shù)據(jù)進行判斷,有規(guī)律的將邊框和背景格點參加。改良帶背景格的lcd_disp()函數(shù)。voidlcd_disp(unsignedcharx,unsignedchary){ unsignedcharda[8]; unsignedcharj; y=63-y; for(j=0;j<8;j++)da[j]=0x0; da[y/8]|=0x01<<(y%8); if(x%5==0){da[2]|=0x01;da[5]|=0x80;}//添加網格數(shù)據(jù) lcd_row_wr(x,da);}效果如圖3-1所示。圖3-1LCD顯示例如圖3-2LCD顯示例如進一步完善:voidlcd_disp(unsignedcharx,unsignedchary){ unsignedcharda[8]; unsignedcharj; y=63-y; for(j=1;j<7;j++)da[j]=0x0; da[y/8]|=0x01<<(y%8); da[0]=0x01;//加邊框 da[7]=0x80;//加邊框 if(x%5==0){ da[21/8]|=0x01<<(21%8); da[42/8]|=0x01<<(42%8); } lcd_row_wr(x,da);}效果如圖3-2所示。看出問題來沒?再改良:voidlcd_disp(unsignedcharx,unsignedchary){ unsignedcharda[8]; unsignedcharj; y=63-y; for(j=1;j<7;j++)da[j]=0x0; da[0]=0x01; da[7]=0x80; if(x%5==0){ da[21/8]|=0x01<<(21%8); da[42/8]|=0x01<<(42%8); } da[y/8]|=0x01<<(y%8);//先加邊框再疊加波形數(shù)據(jù) lcd_row_wr(x,da);}效果如圖3-3所示。圖3-3LCD顯示例如圖3-4LCD顯示例如進一步完善:voidlcd_disp(unsignedcharx,unsignedchary){ unsignedcharda[8]; unsignedcharj; y=63-y; for(j=1;j<7;j++)da[j]=0x0; da[0]=0x01; da[7]=0x80; if(x%5==0){ da[21/8]|=0x01<<(21%8); da[42/8]|=0x01<<(42%8); } if((x==0)||(x==127)){//加兩端邊框 for(j=0;j<8;j++)da[j]=0xff; } da[y/8]|=0x01<<(y%8); lcd_row_wr(x,da);}效果如圖3-4所示。做到這里,似乎感覺驅動LCD圖形顯示很容易的嘛,就是!其實不難!驅動LCD是完成示波器的根底,后面還要介紹在LCD上顯示數(shù)字,顯示測量線等。4紅外遙控按鍵輸入下面我們來學習遙控器按鍵輸入。由于示波器控制需要很多按鍵輸入,Mini51板自帶按鍵只有4個,遠遠不夠,最初用那4個按鍵分多模式來做,使用不是很方便,后來改用遙控器做按鍵輸入,很方便。一種紅外編碼,如圖4-1所示?!?”,“1”用不同寬度〔周期中高電平局部〕的周期信號表示。這種編解碼原理網上資料很多,這里不多說。圖4-1常見紅外編碼這里介紹另外一種編碼方式,通過對金星遙控器G328111發(fā)射信號進行研究,總結得到,如圖4-2所示。圖4-2金星遙控器G328111編碼短周期信號為“0”,1/2長周期〔短周期2倍〕信號表示“1”,低電平開始,高電平結束。這種規(guī)律我們可以用數(shù)字示波器把波形存儲后分析得到,這里介紹一種不用數(shù)字示波器,直接用單片機測試紅外編碼的方法。程序設計思想:While〔低電平〕{計數(shù)1}While〔高電平〕{計數(shù)2}……用一個數(shù)組記錄一次按鍵所有周期上下電平計數(shù)數(shù)值,分析數(shù)據(jù)可以得到紅外編碼規(guī)律。實際程序:while(IRM_DQ)P1=0;//P1口LED燈亮表示可以按遙控器按鍵了P1=0xff;//燈熄滅,解碼開始 for(i=0;i<15;i++){ while(!M51_IRM_DQ){if(++da[i*2]>0x54)break;delay(10);}//低電平長度檢測 while(M51_IRM_DQ){if(++da[i*2+1]>0x54)break;delay(10);}//高電平長度檢測}這里的da[]就是記錄信號變化長短的數(shù)組,將這一數(shù)組通過串口發(fā)送到PC機就可以分析紅外信號上下電平的規(guī)律了。例如:1E1838171D191C1A1C181D181D311E181C1A38181D181D1D181E18371A1C191C191C181D181D181C331D1938181D實際信號周期只有兩種時長,我們可以把【17到1E】當成短周期,【31到38】當成長周期,從而可以繪出波形圖:1E1838171D191C1A1C181D181D311E181C1A38181D181D___---______----__----___----___----___----___--------___----___---______----___----___0100000100100以上演示源程序keil工程請參考附件【遙控解碼1】【感悟】我寫這篇教程,特別注重解決問題的方法總結,掌握一種解決問題的方法比掌握一種具體的知識要重要得多。金星遙控器G328111解碼程序分析:unsignedchari,flag;unsignedintda,unsignedinttemp=0;for(i=0;i<13;i++){ //實際測試,一個編碼有13個周期 da=0; while(!M51_IRM_DQ){if(++da>300)break;}//低電平檢測 if((da>10)&&(da<300)){//判斷電平時長是否有效 if(da>200)temp++;//長周期當“1 elseflag^=0xff;//雙短周期當“0 if(flag==0)temp<<=1; } da=0; while(M51_IRM_DQ){if(++da>300)break;}//高電平檢測 if((da>10)&&(da<300)){ if(da>200)temp++; elseflag^=0xff; if(flag==0)temp<<=1; }}Return(〔unsignedchar〕temp);//返回鍵值低8位以上演示源程序keil工程請參考附件【遙控解碼2】紅外遙控器按鍵輸入流程圖如圖4-3所示。圖4-3紅外遙控按鍵輸入流程圖紅外接收頭接收到遙控器輸出的紅外信號后,輸出低電平,該電平變化信號觸發(fā)單片機外部中斷,在中斷程序中完成鍵值解碼,得到有效鍵值后傳遞給一個全局鍵值變量,在主循環(huán)程序中,對全局鍵值變量檢測判斷,一旦檢測到有效鍵值,立即根據(jù)鍵值執(zhí)行相關程序,實現(xiàn)按鍵輸入。紅外中斷初始化函數(shù)voidint2_init(void)。voidint2_init(void){ IT2=1; //設置成下降沿中斷而不是低電平中斷 EX2=1; //開紅外接口外部中斷 EA=1; //開總中斷}紅外中斷函數(shù)voidirm_int(void)interrupt6,STC單片機特有的外部中斷INT2實現(xiàn)紅外解碼,解碼結果由數(shù)據(jù)緩沖區(qū)返回。voidirm_int(void)interrupt6{ unsignedchari,flag; unsignedintda; unsignedinttemp=0; EA=0; temp=0; da=0; flag=0; for(i=0;i<14;i++){ da=0; while(!M51_IRM_DQ){if(++da>300)break;} if((da>10)&&(da<500)){ if(da>200)temp++; elseflag^=0xff; if(flag==0)temp<<=1; } da=0; while(M51_IRM_DQ){if(++da>300)break;} if((da>10)&&(da<500)){ if(da>200)temp++; elseflag^=0xff; if(flag==0)temp<<=1; } } irm_code=(unsignedchar)(temp&0x00ff); IE2=0; EA=1; }這里irm_code為鍵值全局變量,在以上中斷函數(shù)當中,如果檢測到有效按鍵,那么修改此變量為解碼成功的鍵值。主程序:voidmain(){ int2_init(); while(1){ if(irm_code!=0xff){//對鍵值進行判斷 seg7_disp(irm_code);//顯示鍵值 irm_code=0xff;//去除當前鍵值 } }}在主程序循環(huán)中,對鍵值變量irm_code進行有效鍵值判斷。這里直接使用Mini51板上的數(shù)碼管顯示鍵值,對遙控器鍵值確認很方便。以上演示源程序keil工程請參考附件【紅外按鍵輸入1】下面我們對鍵值進行掃描判斷,完成對應按鍵任務。voidkey_task(void){ if(irm_code!=0xff){ switch(irm_code) { case36:counter++;break; case38:counter--;break; default:break; } //seg7_disp(irm_code);//調試用 irm_code=0xff; }}這里采用switchcase結構語句,很方便多按鍵任務自由添加。只要在主程循環(huán)中調用key_task()即可。unsignedcharcounter=0;voidmain(){ int2_init(); while(1){ key_task(); seg7_disp(counter);//結果顯示 delay_ms(10); }}這里演示了兩個按鍵對counter變量加減操作。以上演示源程序keil工程請參考附件【紅外按鍵輸入2】實際測試效果一般,容易出現(xiàn)連按鍵操作,即主觀按一次鍵,客觀執(zhí)行幾次加減操作的現(xiàn)象,那是因為按鍵解碼很快,一次按鍵,遙控器會連續(xù)發(fā)出多組鍵值信號。5圖形液晶LCD12864移動游標線繪圖驅動設計有了按鍵模塊,下面我們來設計可以移動的游標線〔測量線〕,也就是在lcd上顯示一條可以移動的線,最好是虛線,線的移動受遙控器控制。首先看水平線,水平線在Y軸方向由變量控制,X軸方向根據(jù)x坐標交替取值實現(xiàn)虛線效果。聲明控制水平線的變量【unsignedcharpointY=0;】可以從0到63變化。改良lcd_disp()函數(shù):voidlcd_disp(unsignedcharx,unsignedchary){ unsignedcharda[8]; unsignedcharj; y=63-y; for(j=1;j<7;j++)da[j]=0x0; {//繪制邊框 da[0]=0x01; da[7]=0x80; if((x==0)||(x==127)){ for(j=0;j<8;j++)da[j]=0xff; } } //繪制由變量pointY控制游標線 if(x%5==0)da[pointY>>3]|=0x01<<(pointY&0x07); //繪制信號波形 da[y/8]|=0x01<<(y%8); lcd_row_wr(x,da);}按鍵任務函數(shù)voidkey_task(void){ if(irm_code!=0){ switch(irm_code) { case34:pointY++;break;//游標移動變量調整 case35:pointY--;break; default:break; } //seg7_disp(irm_code);//調試用 irm_code=0; }}主程序while(1){ key_task(); for(i=0;i<128;i++){ lcd_disp(i,dot[i%30]/4);}}這時lcd_disp()需要放在循環(huán)體中運行,不斷刷新LCD,否那么變量修改后的效果出現(xiàn)不了。運行效果如圖5-1所示。圖5-1水平移動游標線例如圖5-2垂直移動游標線例如以上演示源程序keil工程請參考附件【LCD繪圖exa4】我們再來看垂直游標線,垂直線在X軸方向由變量控制,Y軸方向給出特定數(shù)據(jù)實現(xiàn)虛線效果。聲明控制垂直線的變量【unsignedcharpointX=0;】可以從0到127變化。進一步改良lcd_disp()函數(shù)voidlcd_disp(unsignedcharx,unsignedchary){ unsignedcharda[8]; unsignedcharj; y=63-y; for(j=1;j<7;j++)da[j]=0x0; {//繪制邊框 da[0]=0x01; da[7]=0x80; if((x==0)||(x==127)){ for(j=0;j<8;j++)da[j]=0xff; } } //繪制由變量pointY控制的水平游標線 if(x%5==0)da[pointY>>3]|=0x01<<(pointY&0x07); //繪制由變量pointX控制的垂直游標線 if(x==pointX) for(j=0;j<64;j++) if(j%5==0)da[j>>3]|=0x01<<(j&0x07); //繪制信號波形 da[y/8]|=0x01<<(y%8); lcd_row_wr(x,da);}按鍵任務voidkey_task(void){ if(irm_code!=0){ switch(irm_code) { case34:pointY++;break; case35:pointY--;break; case42:pointX++;break; case43:pointX--;break; default:break; } //seg7_disp(irm_code);//調試用 irm_code=0; }}主函數(shù)不變運行效果如圖5-2所示。以上演示源程序keil工程請參考附件【LCD繪圖exa5】6圖形液晶LCD12864數(shù)字符號顯示前面從繪圖角度完成了對LCD的驅動,下面我們還要學習在LCD上顯示數(shù)字,顯示字符,完成數(shù)字示波器所必需的量度顯示。圖形點陣LCD顯示數(shù)字,原理是把數(shù)字以點陣的形式取模,再把點陣模寫入特定的lcd空間即可。首先來看數(shù)字取模,如圖6-1所示,對數(shù)字“0”按8×5點取模。圖6-1數(shù)字取模例如圖縱向看,8點一列,從上至下對應bit0到bit7,我們用1表示“亮”,0表示“暗”,從左至右,依次確定為01111100,即0x7c;10000010,即0x82;10000010,即0x82;10000010,即0x82;01111100,即0x7c;如果我們依次將這5個字節(jié)寫入LCD某頁連續(xù)5個地址空間,lcd上就會顯示“0”。關于點陣取模,可以借助現(xiàn)成的軟件實現(xiàn),這里介紹一款字模提取軟件,軟件界面如圖6-2所示。圖6-2字模軟件界面我們首先將數(shù)字做成黑白點陣圖片,不直接輸入數(shù)字取模的原因是圖片修改更靈活,不受字體限制。圖6-3是數(shù)字0到9和小數(shù)點的點陣圖。圖6-3數(shù)字字模圖這里考慮到LCD空間限制,數(shù)字按8×4點陣取模,運行取模軟件,翻開圖片,如圖6-4所示。圖6-4取模軟件翻開圖片效果進行必要的參數(shù)設置,如圖6-5所示。圖6-5取模軟件參數(shù)設置按C51格式取模,取模后軟件界面如圖6-6所示。圖6-6C51格式取模下面我們把數(shù)字變量在LCD上動態(tài)顯示,就是數(shù)值變了,顯示跟著變。字符顯示Lcd驅動函數(shù)voidlcd_put_xyns(unsignedcharx,y,n,unsignedchar*s)。//8×n點陣字符寫入函數(shù)voidlcd_put_xyns(unsignedcharx,y,n,unsignedchar*s){ unsignedchari; for(i=0;i<n;i++){ if((x+i)>63){ lcd_cmd_wr(ORGY+y,1); lcd_cmd_wr(ORGX+x+i-64,1); lcd_dat_wr(s[i],1); } else{ lcd_cmd_wr(ORGY+y,0); lcd_cmd_wr(ORGX+x+i,0); lcd_dat_wr(s[i],0); } } }參數(shù):【x,y】是坐標,這里y是頁坐標,取值從0到7,【n】是點陣模字節(jié)數(shù),【*s】是點陣模起始地址。將字模生成字模表:unsignedcharcodenumber[]={/*--寬度x高度=41x8--*/0x7C,0x82,0x82,0x7C,0x84,0xFE,0x80,0x00,0xCC,0xA2,0x92,0x8C,0x44,0x92,0x92,0x6C,0x38,0x24,0xFE,0x20,0x9E,0x92,0x92,0x62,0x7C,0x92,0x92,0x64,0x06,0xF2,0x0E,0x02,0x6C,0x92,0x92,0x6C,0x4C,0x92,0x92,0x7C,0x80,};執(zhí)行:lcd_put_xyns(0,0,4,number+0*4);//直接顯示字符0lcd_put_xyns(4,0,4,number+1*4);//直接顯示字符1lcd_put_xyns(8,0,4,number+2*4);//直接顯示字符2lcd_put_xyns(12,0,4,number+3*4);//直接顯示字符3tmp=3421;//以下代碼顯示變量tmplcd_put_xyns(80,2,4,number+(tmp/1000)*4);lcd_put_xyns(84,2,4,number+(tmp/100%10)*4);lcd_put_xyns(88,2,4,number+(tmp/10%10)*4);lcd_put_xyns(92,2,4,number+(tmp%10)*4);運行效果如圖6-7所示。圖6-7LCD顯示數(shù)字例如圖6-8LCD顯示數(shù)字例如調整坐標間隔,顯示效果更好。lcd_put_xyns(0,0,4,number+0*4);lcd_put_xyns(5,0,4,number+1*4);lcd_put_xyns(10,0,4,number+2*4);lcd_put_xyns(15,0,4,number+3*4);tmp=3421;lcd_put_xyns(80,2,4,number+(tmp/1000)*4);lcd_put_xyns(85,2,4,number+(tmp/100%10)*4);lcd_put_xyns(90,2,4,number+(tmp/10%10)*4);lcd_put_xyns(95,2,4,number+(tmp%10)*4);運行效果如圖6-8所示。用這個函數(shù),可以把我們希望的各種圖案符號顯示在LCD上,同樣先設計圖片,再給圖片取模。以上演示源程序keil工程請參考附件【LCD繪圖exa6】7數(shù)字示波器幾個參數(shù)數(shù)據(jù)采樣率與時間軸定標數(shù)據(jù)采樣率也就是每秒鐘連續(xù)采集到的數(shù)據(jù)個數(shù),或者說兩個有效數(shù)據(jù)之間的時間間隔。為了在LCD上復原波形圖,時間軸與采樣率之間要有嚴格的換算關系。為了復原波形圖,采樣率與被測量信號頻率之間有一定的關聯(lián),不同的采樣率,對應不同頻段的信號,高采樣率適合高頻信號,低采樣率適合變化緩慢的低頻信號。從顯示效果來看,為了在屏幕上再現(xiàn)信號的頻率特征,根據(jù)Nyquist頻率特征定理,一般要保證信號的每個周期內至少有2點,用LCD再現(xiàn),2點效果已經很差了。最高采樣率一般由ADC器件決定,這里用的TLC1549最快只能做到88us采集一點,按2點每周期計算的話,可以做到對5.6K(1000000/88/2)信號采樣,實際效果已經很差了,1K以內效果最好。實際在設計采樣率檔位時,最快檔按100us每點,屏幕每5點〔500us〕一格,第一檔就是0.5ms/div,這一檔位需要連續(xù)采樣,用少量延時控制采樣率為10k,第二檔就是1ms/div,第三檔2ms/div,第四檔5ms/div,第五檔10ms/div,后面四檔分別用定時器控制完成。電壓軸分檔定標由于這版沒做模擬電路,不能對信號電壓進行調理,所謂電壓檔定標是純軟件算法實現(xiàn),屏幕同樣取5點一格,共10格,當輸入信號從0到5V變化時,LCD剛好滿屏顯示,每格0.5V,另外還設計了0.1v/div,0.2v/div,1v/div,2v/div,5v/div。共6檔。交流直流切換功能完善的示波器應該從硬件上實現(xiàn)交直流切換,本版先從軟件上實現(xiàn)交流直流顯示,設計思想是根據(jù)采樣得到的數(shù)據(jù)的最大值和最小值確定交流信號幅度和中值,把直流局部減掉,顯示只顯示交流局部,這就是交流檔,直流檔就是不做去直流處理。運行停止切換該功能實現(xiàn)起來很容易,所謂停止,就是停止新的數(shù)據(jù)采集,重復顯示同一幀數(shù)據(jù),顯示的效果就是波形穩(wěn)定無抖動,便于對信號電壓和頻率進行測量。電壓測量根據(jù)當前電壓檔位〔每格表示多少伏〕,計算出兩測量線之間的電壓值,在LCD上顯示。頻率測量根據(jù)當前時間軸檔位〔每格表示多長時間〕,計算出兩測量線之間的時間,假定兩測量線之間剛好是一個周期,轉換成頻率值在LCD上顯示。波形平移用變量控制波形在LCD上顯示的相對位置,實現(xiàn)波形上下左右平移。幀同步我們使用的數(shù)字示波器,對有規(guī)律的周期信號能夠穩(wěn)定顯示,要想實現(xiàn)穩(wěn)定顯示,需要在起始點顯示信號的不同周期的同一點,如何做到這點呢?如圖7-1所示,我們比照兩幀數(shù)據(jù),波形起點不在同一點,我們沒方法保證每次數(shù)據(jù)采樣剛好在同一點〔硬件觸發(fā)的除外〕,我需要按一定的規(guī)律,在LCD上繪圖時,總是從同一點開始,例如過零點,這里我們首先用統(tǒng)計的方法找出信號的最大值和最小值,計算出信號中交流局部的中點,也就是過零點,然后逐點比擬,搜尋過零點。圖7-1
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 體育交流合同范本
- 2024年中國太平洋人壽保險股份有限公司招聘筆試真題
- 買賣物品合同范本
- 2024年內蒙古興安盟實驗高中教師招聘考試真題
- 2024年納雍縣鴿子花農業(yè)有限公司招聘考試真題
- 農夫山泉公司勞動合同范本
- 創(chuàng)業(yè)投資協(xié)議合同范本
- 2024年河南省黃河科技學院附屬醫(yī)院招聘考試真題
- 公司系統(tǒng)服務合同范本
- 全體村民土地流轉合同范本
- 國防動員建設總體規(guī)劃方案
- 教案檢查總結及整改措施
- 商業(yè)銀行經營管理課件
- 商品流通學課件
- ESD靜電管理標準課件
- 19.SL-T19-2023水利基本建設項目竣工財務決算編制規(guī)程
- 火葬場管理制度
- 《老年護理》教學教案
- 25題退役軍人事務員崗位常見面試問題含HR問題考察點及參考回答
- 駕駛服務外包投標方案(完整版)
- 全日制普通高級中學體育教學大綱
評論
0/150
提交評論