本帖最后由 萊鳥 于 2015-7-21 11:12 編輯
從學校的時候對器件成本不敏感,凡是顯示,基本都用12864,一來不用花錢買,二來是操作簡單,(串行模式)占用io少,顯示內容還多,
前段時間偶然從廢品站買了幾十片5110的lcd,雖然成色很爛,但是價格便宜,5塊錢一個,個個都能顯示,有點占小便宜的感覺,哈哈
之前就看到很多人玩5110的屏,屏倒是不貴,10元不到,運費卻要10元了,一直也沒買過,
剛好這兩天很閑,而且做得轉接板也到手了,就把5110的文字顯示學了一下
以前做的計價器樣機,帶字庫的12864 面積大,使用方便,
})}VESV_%M}}BMK~%FO%2%S.png (447.61 KB, 下載次數: 121)
下載附件
2015-7-21 11:07 上傳
5110價格便宜,價格便宜,價格便宜
nEO_IMG_主圖.jpg (70.82 KB, 下載次數: 132)
下載附件
2015-7-21 11:07 上傳
對于單片機來說,存儲較小,51的話,內置64k,存放3種ASCII點陣,加上 16x16和12x12的中文就基本可以滿足一般的顯示需要,比如上面diy的激光測,
標題用16的字體,其他用12的字體,感覺不算違和,
至于6x8的ASCII可以顯示不太重要的數據或者比較長的數據,
最后一行的8x12的ascii則可以用來顯示重要一點的數據,第一樣就能看到,比如測距狀態,OK還是ERROR等等
nEO_IMG_20150713_180442.jpg (210.62 KB, 下載次數: 101)
下載附件
2015-7-21 11:10 上傳
5110的lcd控制器的y地址尋址是以字節為單位的,而不是像x一樣以位為單位,這就導致了,顯示英文比較方便,可以在某一行任意地址顯示,y方向就固定6行好了,
顯示16點陣的字體也方便,因為一個漢字剛好占據兩個y地址,不過實際來看,16的字體顯得太大,和這塊小屏幕不太和諧,而且顯示內容少,所以可以選用比較秀氣的12像素字體,效果也很好,但是有個小問題,12像素字體有的筆畫會缺失,但是沒有什么太大影響,比如下圖,順序都不會影響,缺個點之類的更不用擔心啦
來看5110的控制器y地址尋址和12像素字體的關系,第0,2,4行顯示是沒問題到只不過 1 3 5行會空出來4個像素,比較常見的取模軟件都是不足8位補足8位的,所以,y1的下半部分就是0,
顯示兩行12的漢字,需要用3個y地址,把第二行的漢字上移4就可以了,
地址.png (109.31 KB, 下載次數: 120)
下載附件
2015-7-21 11:07 上傳
單獨來看y1,它包含了第一行漢字的下半部分,還包含了第二行漢字的上半部分,而且,第二行漢字的上半部分顯示在了y1的下半部分(比較繞口)看圖可以看得出來
地址 - 副本.png (107.71 KB, 下載次數: 136)
下載附件
2015-7-21 11:07 上傳
不過這樣看好像就比較清楚了,其實第二行中文的y方向起始地址還是y1,和第一行漢字的y地址重合,數據移位處理即可
地址 - 副本 (2).png (111.8 KB, 下載次數: 130)
下載附件
2015-7-21 11:07 上傳
那就可以使用單片機的xdata內存區存放交叉區的緩存數據,
顯示12像素的漢字,可以顯示4行,
我們把第一行的漢字的y1區0-83個地址都存下來,叫做y0ram,
第二行中文的y1區0-83個地址都存下來叫做 y1ram
每當顯示到這兩個地址的時候,就把這兩個ram緩存保存下來,
再顯示下一行的時候進行移位沒然后數據或運算在寫到控制器里,就可以了,
當然也可以按照控制器的地址來劃分,y1就叫y1ram,y3就叫y3ram,這樣在數據保存的時候進行移位,而且還節約了84*2字節的內存,效果是一樣的,
可以用一張圖來表示
原理.png (402.92 KB, 下載次數: 113)
下載附件
2015-7-21 11:07 上傳
在程序中
原理 - 副本.png (79.09 KB, 下載次數: 119)
下載附件
2015-7-21 11:07 上傳
然后再從主函數里調用
6ZCYTEO1{0@3@H)J[NZAFEX.png (47.4 KB, 下載次數: 114)
下載附件
2015-7-21 11:07 上傳
再說一下字庫吧,因為畢竟不是完整真正的字庫,所以顯示不知尋址來的,是查表來的,字庫呢,分為兩部分呢,一部分是索引,放在后面,一部分是點陣數據,放前面,比如我查找到"滾"是結構體中第0個元素索引中
那就調取播放圖標進行顯示,其他同理
F8ZX_SQ6N[`"3~8P~%NYU.png (63.56 KB, 下載次數: 111)
下載附件
2015-7-21 11:07 上傳
實際效果如下
nEO_IMG_WP_20150721_00_32_58_Pro.jpg (87.02 KB, 下載次數: 100)
下載附件
2015-7-21 11:07 上傳
nEO_IMG_WP_20150721_00_23_59_Pro.jpg (87.31 KB, 下載次數: 115)
下載附件
2015-7-21 11:07 上傳
nEO_IMG_WP_20150721_00_22_46_Pro.jpg (75.29 KB, 下載次數: 120)
下載附件
2015-7-21 11:07 上傳
nEO_IMG_WP_20150721_00_22_11_Pro.jpg (80.31 KB, 下載次數: 132)
下載附件
2015-7-21 11:07 上傳
代碼部分,完整版
- /*
- 顯示12*12的字體,任意地址,上下錯開也解決了
- */
- #include<reg51.h>
- #include"Nokia5110Lcd.h"
- #include "lcd5110font.c"
- #include<intrins.h>
- #define nop() _nop_()
- #define uchar unsigned char
- #define uint unsigned int
- uchar xdata Y0Ram[84]; //第0行漢字的臨時緩存
- uchar xdata Y1Ram[84];
- uchar xdata Y2Ram[84];
- uchar xdata Y3Ram[84];
- void delay(int t)
- {
- uchar i;
- while (t--)
- {
- for (i=0;i<125;i++)
- {}
- }
- }
- void Lcd5110WriteDta(uchar dat)
- {
- unsigned char i;
- sce=0;
- dc=1;
- for (i=0;i<8;i++)
- {
- if (dat&0x80)
- sdin=1;
- else
- sdin=0;
- dat=dat<<1;
- sclk=0;
- nop();
- sclk=1;
- }
- dc=1;
- sce=1;
- sdin=1;
- }
- void Lcd5110WriteCMD(uchar dat)
- {
- unsigned char i;
- sce=0;
- dc=0;
- for (i=0;i<8;i++)
- {
- if (dat&0x80)
- sdin=1;
- else
- sdin=0;
- dat=dat<<1;
- sclk=0;
- nop();
- sclk=1;
- }
- dc=1;
- sce=1;
- sdin=1;
- }
- /*---------------------------------------
- LCD_init: 3310LCD初始化
- 編寫日期:20080918
- ----------------------------------------- */
- void Lcd5110Init(void)
- {
- char i;
- // res=0;
- // delay(10);
- // res=1; //以上三句 不用也行
- Lcd5110WriteCMD(0x21 );//初始化Lcd,功能設定使用擴充指令
- Lcd5110WriteCMD(0xb2 );//設定液晶偏置電壓
- //Lcd5110WriteCMD(0xc0);//設定液晶偏置電壓 //調試用 顯示全黑
- Lcd5110WriteCMD(0x02 );//溫度校正
- Lcd5110WriteCMD(0x13 );//1:48
- Lcd5110WriteCMD(0x20 );//使用基本指令
- Lcd5110WriteCMD(0x0C );//設定顯示模式,正常顯示
- for (i=0;i<84;i++)
- {
- Y0Ram[i]=Y1Ram[i]=Y2Ram[i]=Y3Ram[i]=0;
- }
- }
- /*-------------------------------------------
- LCD_set_XY: 設置LCD坐標函數
- 輸入參數:X:0-83 Y:0-5
- 編寫日期:20080918
- ---------------------------------------------*/
- void Lcd5110SetXY(uchar X,Y)
- {
- Lcd5110WriteCMD(0x40 | Y );// 垂直方向 0-5
- Lcd5110WriteCMD(0x80 | X );// 水平方向0-83
- }
- /*------------------------------------------
- LCD_clear: LCD清屏函數
- 編寫日期:20080918
- --------------------------------------------*/
- void Lcd5110Clear(void)
- {
- unsigned char t;
- unsigned char k;
- Lcd5110SetXY(0,0);
- for (t=0;t<6;t++)
- {
- for (k=0;k<84;k++)
- Lcd5110WriteDta(0x00);
- }
- }
- /*---------------------------------------------
- LCD_write_shu: 顯示8(寬)*16(高)點陣列數字字母符號等半角類
- addr:寫入地址
- row: 第幾行 對于6*8點陣 實際5*7留有空邊,字高8個點, 屏幕一共6行 豎著48個點
- dd:字符
- -----------------------------------------------*/
- void Lcd5110Write6x8AtAddr(uchar row, addr, dat)
- {
- unsigned char i;
- dat=dat-32; //ascii轉換為字庫偏移地址
- Lcd5110SetXY(addr, row-1);// 某行的某個地址 行1-6地址0-83
- for (i=0; i<6;i++)
- {
- Lcd5110WriteDta(Ascii6x8[dat*6+i]);
- }
- }
- void Lcd5110show6x8AscWithNoAddr(uchar dat)//顯示一個6*8點陣
- {
- uchar i;
- dat-=32;
- for (i=0; i<6;i++)
- Lcd5110WriteDta(Ascii6x8[dat*6+i]);
- }
- void Lcd5110String6x8(uchar row , addr, uchar *p)
- {
- Lcd5110SetXY(addr, row);// 列,頁
- while (*p!='\0')
- {
- Lcd5110show6x8AscWithNoAddr(*p++);
- }
- }
- void Lcd5110show8x16AscAtAddr(uchar row,addr, dat)
- {
- uchar i ;
- dat-=32;
- Lcd5110SetXY(addr,row);
- for (i=0; i<8;i++)
- Lcd5110WriteDta(Ascii8x16[dat*16+i]);
- Lcd5110SetXY(addr,row+1);
- for (i=8; i<16;i++)
- Lcd5110WriteDta(Ascii8x16[dat*16+i]);
- }
- /*
- 行 范圍 1-6一共6行,但在行=6的時候會顯示不全
- */
- void Lcd5110String8x16(uchar row , addr, uchar *p)
- {
- //不再用8*16的ascii了,直接屏蔽掉,想用的時候在解除屏蔽即可
- uchar dat;
- while (*p!='\0')
- {
- dat =*p;
- Lcd5110show8x16AscAtAddr(row-1 ,addr, dat);
- *p++;
- addr+=8;
- }
- }
- void Lcd5110DisplayAscii8x12AtAddr(uchar row,addr, dat)
- {
- uchar i, LocalHalfWidth,LocalFullWidth; //半寬字體,全寬字體
- LocalHalfWidth=8;//8*12的字體,光看上面一半8字節
- LocalFullWidth=16;//8*12的字體,上下兩行就是16字節
- dat-=32;
- if (row==0)//按照4行顯示,首行為0,地址就是0-3行,不是控制器的地址
- {
- Lcd5110SetXY(addr, row);// 列,頁
- for (i=0; i<LocalHalfWidth;i++) //上半部分 12個像素
- {
- Lcd5110WriteDta(Ascii8x12[dat*LocalFullWidth+i]);
- }
- Lcd5110SetXY(addr, row+1);// 列,頁
- for (i=LocalHalfWidth; i<LocalFullWidth;i++) //下半部分 12個像素
- {
- Y0Ram[addr+i-LocalHalfWidth]=Ascii8x12[dat*LocalFullWidth+i]; //第0行的下半部分12個字節存起來
- Lcd5110WriteDta(Y0Ram[addr+i-LocalHalfWidth] | Y1Ram[addr+i-LocalHalfWidth]<<4 );
- }
- }
- if (row==1)
- {
- Lcd5110SetXY(addr, row);// 列,頁
- for (i=0; i<LocalHalfWidth;i++) //上半部分 12個像素
- {
- Y1Ram[addr+i]=Ascii8x12[dat*LocalFullWidth+i];//第1行上半部分存起來
- Lcd5110WriteDta(Y1Ram[addr+i]<<4 | Y0Ram[addr+i]);
- }
- Lcd5110SetXY(addr, row+1);// 列,頁
- for (i=LocalHalfWidth; i<LocalFullWidth;i++) //下半部分 12個像素
- {
- Lcd5110WriteDta(Ascii8x12[dat*LocalFullWidth+i]<<4 | Ascii8x12[dat*LocalFullWidth+i-LocalHalfWidth]>>4 );
- }
- }
- if (row==2)//按照4行顯示,首行為0,地址就是0-3行,不是控制器的地址
- {
- Lcd5110SetXY(addr, row+1);// 列,頁
- for (i=0; i<LocalHalfWidth;i++) //上半部分 12個像素
- {
- Lcd5110WriteDta(Ascii8x12[dat*LocalFullWidth+i]);
- }
- Lcd5110SetXY(addr, row+2);// 列,頁
- for (i=LocalHalfWidth; i<LocalFullWidth;i++) //下半部分 12個像素
- {
- Y2Ram[addr+i-LocalHalfWidth]=Ascii8x12[dat*LocalFullWidth+i]; //第0行的下半部分12個字節存起來
- Lcd5110WriteDta(Y2Ram[addr+i-LocalHalfWidth] | Y3Ram[addr+i-LocalHalfWidth]<<4 );
- }
- }
- if (row==3)//按照4行顯示的話,地址就是0-3行
- {
- Lcd5110SetXY(addr, row+1);// 列,頁
- for (i=0; i<LocalHalfWidth;i++) //上半部分 12個像素
- {
- Y3Ram[addr+i]=Ascii8x12[dat*LocalFullWidth+i];//第1行上半部分存起來
- Lcd5110WriteDta(Y3Ram[addr+i]<<4 | Y2Ram[addr+i]);
- }
- Lcd5110SetXY(addr, row+2);// 列,頁
- for (i=LocalHalfWidth; i<LocalFullWidth;i++) //下半部分 12個像素
- {
- Lcd5110WriteDta(Ascii8x12[dat*LocalFullWidth+i]<<4 | Ascii8x12[dat*LocalFullWidth+i-LocalHalfWidth]>>4);
- }
- }
- }
- void Lcd5110String8x12(uchar row,addr,uchar *p)
- {
- uchar dat;
- while (*p!='\0')
- {
- dat =*p;
- Lcd5110DisplayAscii8x12AtAddr(row ,addr, dat);
- *p++;
- addr+=8;
- //delay(6000); //調試用 慢動作
- }
- }
- /*---------------------------------------------
- 在某行某地址顯示中文字符,
- -----------------------------------------------*/
- void DispOneChs12x12(uchar row,addr,uchar *p)
- {
- uchar i, LocalHalfWidth,LocalFullWidth; //半寬字體,全寬字體
- if (row==0)//按照4行顯示,首行為0,地址就是0-3行,不是控制器的地址
- {
- Lcd5110SetXY(addr, row);// 列,頁
- for (i=0; i<12;i++) //上半部分 12個像素
- {
- Lcd5110WriteDta(p[i]);
- }
- Lcd5110SetXY(addr, row+1);
- /*字體的下半部分需要存儲起來*/
- for (i=12; i<24;i++) //下半部分 12個像素
- {
- Y0Ram[addr+i-12]=p[i]; //第0行的下半部分12個字節存起來,數組要保存文字的下半部分和這些數據在什么位置 0-83
- Lcd5110WriteDta(Y0Ram[addr+i-12] | Y1Ram[addr+i-12]<<4 );
- }
- }
- if (row==1)
- {
- Lcd5110SetXY(addr, row);// 列,頁
- for (i=0; i<12;i++) //上半部分 12個像素
- {
- Y1Ram[addr+i]=p[i];//第1行上半部分存起來
- Lcd5110WriteDta(Y1Ram[ addr+i]<<4 |Y0Ram[addr+i]);
- }
- Lcd5110SetXY(addr, row+1);// 列,頁
- for (i=12; i<24;i++) //下半部分 12個像素
- {
- Lcd5110WriteDta(p[i]<<4 | p[i-12]>>4 );
- }
- }
- if (row==2)//按照4行顯示,首行為0,地址就是0-3行,不是控制器的地址
- {
- Lcd5110SetXY(addr, row+1);// 列,頁
- for (i=0; i<12;i++) //上半部分 12個像素
- {
- Lcd5110WriteDta(p[i]);
- }
- Lcd5110SetXY(addr, row+2);
- /*字體的下半部分需要存儲起來*/
- for (i=12; i<24;i++) //下半部分 12個像素
- {
- Y2Ram[addr+i-12]=p[i]; //第0行的下半部分12個字節存起來,數組要保存文字的下半部分和這些數據在什么位置 0-83
- Lcd5110WriteDta(Y2Ram[addr+i-12] | Y3Ram[addr+i-12]<<4 );
- }
- }
- if (row==3)
- {
- Lcd5110SetXY(addr, row+1);// 列,頁
- for (i=0; i<12;i++) //上半部分 12個像素
- {
- Y3Ram[addr+i]=p[i];//第1行上半部分存起來
- Lcd5110WriteDta(Y3Ram[ addr+i]<<4 |Y2Ram[addr+i]);
- }
- Lcd5110SetXY(addr, row+2);// 列,頁
- for (i=12; i<24;i++) //下半部分 12個像素
- {
- Lcd5110WriteDta(p[i]<<4 | p[i-12]>>4 );
- }
- }
- }
- void FindHZ12fromGBK12(uchar row ,addr ,uchar *dat)
- {
- uchar i;
- for (i=0;i<LenthOfGbk12;i++) //索引
- {
- if ( (GBK12[i].Index[0] == dat[0]) && (GBK12[i].Index[1] == dat[1])) break;
- }
- DispOneChs12x12(row,addr,GBK12[i].Matrix);
- }
- void Lcd5110ChString12(uchar row,addr, uchar*dat)
- {
- while (*dat)
- {
- FindHZ12fromGBK12(row,addr,dat);
- addr+=12;//12寬的字體,寫完一個x地址加12
- dat+=2; //dat是索引數據,一個漢字的索引由兩個字節組成
- }
- }
- //顯示一個 16*16的漢字,參數是指針,指向點陣數組
- void DispOneChs16x16(uchar row,addr,uchar *dat)
- {
- uchar i,j;
- for (j=0; j<2;j++)
- {
- Lcd5110SetXY(addr, row+j);// 列,頁
- for (i=0; i<16;i++)
- Lcd5110WriteDta(dat[16*j+i]);
- }
- }
- /*從字庫里 用 漢字的指針 查找一個漢字 并顯示出來 調用上面的函數 */
- void FindHZ16fromGBK16(uchar row,addr, uchar *dat)
- {
- uchar i;
- for (i=0;i<LenthOfGbk16;i++) //索引
- {
- if ( (GBK16[i].Index[0] == dat[0]) && (GBK16[i].Index[1] == dat[1])) break;
- }
- switch (row)
- {
- case 0:
- row=0;
- break;
- case 1:
- row=2;
- break;
- case 2:
- row=4;
- break;
- default:
- break;
- }
- DispOneChs16x16(row,addr,GBK16[i].Matrix);//把這個漢字顯示出來,指向點陣區
- }
- //把數組的漢字顯示出來,傳入的參數是指針 雙引號
- void Lcd5110ChString16(uchar row,addr,uchar *dat)
- {
- while (*dat)
- {
- FindHZ16fromGBK16(row,addr,dat);
- addr+=16;//16寬的字體,寫完一個x地址加16
- dat+=2; //dat是索引數據,一個漢字的索引由兩個字節組成
- }
- }
- /*使用一個6x8的字體顯示一個3位整數*/
- void Lcd5110DispHundredIn6x8(uchar row,addr, int dat)
- {
- Lcd5110SetXY(addr,row);
- Lcd5110show6x8AscWithNoAddr(48+dat/100);
- Lcd5110show6x8AscWithNoAddr(48+dat%100/10);
- Lcd5110show6x8AscWithNoAddr(48+dat%100%10);
- }
- //row,地址,傳入
- void Lcd5110DispHundredIn12x12(uchar row,addr,int dat)
- {
- Lcd5110DisplayAscii8x12AtAddr(row,addr,48+dat/100);
- Lcd5110DisplayAscii8x12AtAddr(row,addr+8,48+dat%100/10);
- Lcd5110DisplayAscii8x12AtAddr(row,addr+16,48+dat%100%10);
- }
復制代碼
|