完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本帖最后由 3010203109 于 2013-1-14 19:29 编辑 LCD12864是一种常用的图形液晶显示模块,顾名思义,就是可以在水平方向显示128个点,在竖直方向显示64个点。通过对控制芯片写入数据,可以控制点的亮灭,从而显示字符、数字、汉字或者自定义的图形。尽管LCD12864有各个不同厂家生产的产品,控制芯片和引脚定义也不尽相同,但是控制原理都大同小异。本文是对我个人使用LCD12864的经验做一个总结,希望能对入门者起到抛砖引玉的作用。 就以深圳市亚晶达电子有限公司生产的YJD12864C-1为例,我不想深究显示屏的内部结构,单讲讲各个引脚的作用以及数据读写时的时序。 上图是YJD12864C-1的实物图,从右往左,1脚到20脚的定义如下: 1:VSS,接地端 2:VDD,电源正,接+5V 3:VO,对比度调整,一般接+5V就行了 4:D/I(CS*),片选,也叫使能,接+5V 5:R/W(SID*),数据输入端 6:E(SCLK*),时钟输入端 7~14:DB0 ~ DB7,并行数据总线 15:PSB,串并模式选择,串行模式下接地,并行模式下接+5V 16:NC,空引脚,不需要连接 17:RSTB,复位端,低电平有效,一般接+5V就行了 18:VEE,空引脚,不需要连接 19:BLA,背光正极,接+5V 20: BLK,背光负极,接地 在实际编程时,有串行、并行两种模式可以选择。个人觉得,并行模式占用单片机引脚多(11个),优点是速度快(一次传8位数据,速度自然快),串行模式占用引脚少(2个),速度慢点。我喜欢使用串行模式,AVR单片机的时钟频率最快可达20MHZ(不用除以12),经过实测,从头到尾刷一次屏大约只需0.1s,这在很多场合已经够用了。由于并行模式用的少,不熟悉,下面只讲串行模式。 在串行模式下,硬件的连接为:1、15、20接地,2、3、4、17、19接+5V,5接单片机SPI输出(下图第6脚),6接单片机SPI时钟信号输出(下图第8脚)。 ATMEGA324引脚图 下面介绍程序: 1、底层数据通信程序:包括SPI设置,SPI发送单字节,LCD写数据,LCD初始化 ////////////////////////////////////////////////////////////////////////////////////////// #define F_CPU 8//时钟频率8MHZ #include #include"delay.h" ////////////////////////////////////////////////////////////////////////////////////////// 上面是开头部分,其中delay.h内容如下: #ifndef __IAR_DELAY_H #define __IAR_DELAY_H #include #define delay_us(x) __delay_cycles((unsigned long)(x * F_CPU)) #define delay_ms(x) __delay_cycles((unsigned long)(x * F_CPU*1000UL)) #define delay_s(x) __delay_cycles((unsigned long)(x * F_CPU*1000000UL)) #endif ////////////////////////////////////////////////////////////////////////////////////////// SPI设置: void SPI_MasterInit(void) { DDRB=(1<<7)|(1<<5)|(1<<4);//(1<<5)|(1<<7);//设置MOSI和SCK 为输出 SPCR = (1<<6)|(1<<4);// 1< SPSR = 1<<0;// 1< } ////////////////////////////////////////////////////////////////////////////////////////// SPI发送单字节: void SPI_MasterTransmit(char cData) { SPDR = cData; while(!(SPSR & (1<<7)));//1<
} LCD写数据: void LCD_Write (char RS,char content)//RS=1发数据RS=0发命令 { charStart,High4,Low4; Start=0xf8|(RS<<1); High4=content&0xf0; Low4=(content<<4)&0xf0; SPI_MasterTransmit(Start);//发送开始字节,前面5个1,倒数第二位RS SPI_MasterTransmit(High4);//发送数据高4位 SPI_MasterTransmit(Low4);//发送数据低4位 delay_us(300); } ////////////////////////////////////////////////////////////////////////////////////////// LCD初始化 void LCD_INIT() { LCD_Write(0,0x30); /*30---基本指令动作*/ LCD_Write(0,0x01); /*清屏,地址指针指向00H*/ LCD_Write(0,0x06); /*光标的移动方向*/ LCD_Write(0,0x0c); /*开显示,关游标*/ } ////////////////////////////////////////////////////////////////////////////////////////// 2、应用层程序,包括汉字显示,字符显示,图形显示等等 汉字显示: 分4行,一行可显示8个汉字,每个汉字占16*16个格 void Show_Chinese(char x0,char y0,chark,char *chn) //x0,y0为显示位置x0: 0~3, y0: 0~7, k为汉字个数, chn为汉字数组 { charadr,i; switch(x0) { case0: adr = 0x80 + y0;break; //在第1行y列显示 case1: adr = 0x90 + y0;break; //在第2行y列显示 case 2: adr = 0x88 + y0;break; //在第3行y列显示 case3: adr = 0x98 + y0;break; //在第4行y列显示 default:; } LCD_Write(0,adr); for(i=0;i<2*k;i++) LCD_Write(1,chn); } ////////////////////////////////////////////////////////////////////////////////////////// 显示字符串: 分4行,一行可显示16个汉字,每个汉字占8*16个格 void Show_String(char x0,char y0,chark,char *chn) //x0,y0为显示位置x0: 0~8, y0:0~3, k为字符串个数, chn为字符串 { charadr,i; switch(x0) { case0: adr = 0x80 + y0;break; //在第1行y列显示 case1: adr = 0x90 + y0;break; //在第2行y列显示 case2: adr = 0x88 + y0;break; //在第3行y列显示 case3: adr = 0x98 + y0;break; //在第4行y列显示 default:; } LCD_Write(0,0x30); LCD_Write(0,adr); for(i=0;i LCD_Write(1,chn); } ////////////////////////////////////////////////////////////////////////////////////////// 显示数字: void Show_Number(char x0,char y0,charnum)//显示两位数字 //x0,y0为显示位置x0: 0~8, y0:0~3,显示数字位数可调 { charadr; switch(x0) { case0: adr = 0x80 + y0;break; //在第1行y列显示 case1: adr = 0x90 + y0;break; //在第2行y列显示 case2: adr = 0x88 + y0;break; //在第3行y列显示 case3: adr = 0x98 + y0;break; //在第4行y列显示 default:; } LCD_Write(0,0x30); LCD_Write(0,adr); //LCD_Write(1,num/100%10+'0'); //上句不注释则显示3位数字,要显示更多位可以此类推,不过要注意num的字长 LCD_Write (1,num/10%10+'0'); LCD_Write(1,num%10+'0'); } ////////////////////////////////////////////////////////////////////////////////////////// 显示图片: char lcd_x,lcd_y; void Show_Image(char *p) //水平扫描 //P含128*64/8=1024字节 //可用字模软件获得任意图片的水平扫描码 { chari,j,k; lcd_x=0x9f; lcd_y=0x80; LCD_Write(0,0x34); for(i=0;i<2;i++)//分为上下两屏 { for(j=0;j<32;j++) { LCD_Write(0,lcd_y+j); LCD_Write (0,lcd_x); for(k=0;k<16;k++)//写入显示数据 { LCD_Write (1,*p++); } } lcd_x=0x87; } LCD_Write(0,0x36); LCD_Write(0,0x30); } 图片模式下清屏: void Clear_Gcrom() { chari,j,k; lcd_x=0x80; lcd_y=0x80; LCD_Write (0,0x34); for(i=0;i<2;i++) { for(j=0;j<32;j++) { LCD_Write(0,lcd_y+j); LCD_Write (0,lcd_x); for(k=0;k<16;k++){ LCD_Write (1,0x00); } } lcd_x=0x88; } LCD_Write(0,0x36); LCD_Write(0,0x30); } 显示两字节,LCD12864每次至少刷新16格: void Show_2Byte(char x,char y,chardat1,char dat2)// x:0~7 y:0~63 { if(y<32)//下屏 { x+=8; y=31-y; } else//上屏 { y=63-y; } LCD_Write (0,0x34); LCD_Write (0,0x80+y);//y:0~31 LCD_Write (0,0x80+x);//x:0~15 LCD_Write (1,dat1); LCD_Write (1,dat2); LCD_Write (0,0x36); LCD_Write (0,0x30); } 刷新1行: void Show_Hang(char y,char p[64][16]) //显示一行 y:0~63 { chark,y0=y; lcd_y=0x80; LCD_Write(0,0x34); if(y<32) { lcd_x=0x80+8;//下屏 y=31-y; } else { lcd_x=0x80;//上屏 y=63-y; } //LCD_Write(0,0x80+0);//y1:0~31 //LCD_Write (0,0x80+0);//x1:0~15 LCD_Write (0,lcd_y+y); LCD_Write (0,lcd_x); for(k=0;k<16;k++)//写入显示数据 { LCD_Write (1,p[y0][k]); } LCD_Write(0,0x36); LCD_Write(0,0x30); } 有了以上函数就可以轻松玩转LCD12864了,注意在main函数中应先执行初始化程序: void main(){ SPI_MasterInit(); LCD_INti (); while(1) { } } 最后是我用ATMEGA324PA单片机和LCD12864做的一个贪吃蛇游戏,见开头视频。 有兴趣的可以看下 全部程序如下:/*********************************************************************** LCD12864贪吃蛇 贪吃蛇游戏(不死版) 单片机:ATMEGA324PA 编程软件:IAR 编程语言:C++ 屏幕:LCD12864 按键:上下左右 ***********************************************************************/ #define F_CPU 8 #include"delay.h" #include #include #include #include "function.h" #define K0 PINA_Bit0 #define K1 PINA_Bit1 #define K2 PINA_Bit2 #define K3 PINA_Bit3 #define K4 PINA_Bit4 #define K5 PINA_Bit5 class Point{ public: char x;//x:0~127 char y;//y:0~63 Point(){}; Point(char m,char n){x=m;y=n;} bool operator==(Point &a) { if(x==a.x&&y==a.y)return true; else return false; } //char Get_x(){return x;} //char Get_y(){return y;} }; class Snake{ public: char length; Point body[64];//头:body[0]尾:body[length-1] 其余:空 Point food; Snake() { length=3; for(char i=0;i<64;i++)body=Point(0,0); body[0]=Point(64,33); body[1]=Point(64,32); body[2]=Point(64,31); } void Go_ahead(); //void Go_back(); void Turn_left(); void Turn_right(); void Turn_up(); void Turn_down(); void Generate_food(); void Eat(); void Restart(); bool Near_food(); char Get_direction(); void Refresh(Point p); }; void Snake::Go_ahead() { Point temp=body[0],temp1=body[length-1]; char v=Get_direction(); switch(v) { case 0: if(body[0].y==63)Restart(); else body[0].y++;break; case 1: if(body[0].y==0)Restart(); else body[0].y--;break; case 2: if(body[0].x==0)Restart(); else body[0].x--;break; case 3: if(body[0].x==127)Restart(); else body[0].x++;break; default:break; } if(body[0].x==food.x&&body[0].y==food.y) { length++; for(char i=length-1;i>1;i--) { body=body[i-1]; } body[1]=temp; Generate_food(); } else { for(char i=length-1;i>1;i--) { body=body[i-1]; } body[1]=temp; } Refresh(body[0]); Refresh(temp1); } void Snake::Turn_left() { Point temp1=body[length-1]; for(char i=length-1;i>0;i--) { body=body[i-1]; } if(body[0].x==0)Restart(); else body[0].x--; Refresh(body[0]); Refresh(temp1); } void Snake::Turn_right() { Point temp1=body[length-1]; for(char i=length-1;i>0;i--) { body=body[i-1]; } if(body[0].x==127)Restart(); else body[0].x++; Refresh(body[0]); Refresh(temp1); } void Snake::Turn_up() { Point temp1=body[length-1]; for(char i=length-1;i>0;i--) { body=body[i-1]; } if(body[0].y==63)Restart(); else body[0].y++; Refresh(body[0]); Refresh(temp1); } void Snake::Turn_down() { Point temp1=body[length-1]; for(char i=length-1;i>0;i--) { body=body[i-1]; } if(body[0].y==0)Restart(); else body[0].y--; Refresh(body[0]); Refresh(temp1); } void Snake::Generate_food() { char x,y,i=0; while(i!=length) { x=rand()%128; y=rand()%64; food=Point(x,y); for(i=0;i if(food==body)break; } } Refresh(food); } bool Snake::Near_food() { bool k; if(body[0].x==food.x&&body[0].y==food.y) k=true; else k=false; return k; } void Snake::Eat() { for(char i=length;i>0;i--) { body=body[i-1]; } body[0]=food; length++; Generate_food(); } //enum direction{up,down,left,right} char Snake::Get_direction() { char i; if(body[0].x==body[1].x) { if(body[0].y>body[1].y){i=0;} else i=1; } else { if(body[0].x>body[1].x){i=3;} else i=2; } return i; } void Snake::Refresh(Point p) { char temp1=0,temp2=0,a,b,c; for(char i=0;i<2;i++) { a=p.x-p.x%8; if((p.x/8)%2==0) { b=a+8; c=b+8; } else { b=a; a-=8; c=b+8; } for(char i=0;i if(body.y==p.y) { if(body.x>=a&&body.x.x%8); if(body.x>=b&&body.x } if(food.y==p.y) { if(food.x>=a&&food.x if(food.x>=b&&food.x } Show_2Byte(p.x/16,p.y,temp1,temp2); } } void WDT_off(void) { __disable_interrupt(); __watchdog_reset(); /* Clear WDRF in MCUSR */ MCUSR &= ~(1< /* Keep old prescaler setting to prevent unintentional time-out */ WDTCSR |= (1< WDTCSR = 0x00; __enable_interrupt(); } void WDT_Prescaler_Change(void) { __disable_interrupt(); __watchdog_reset(); /* Start timed equence */ WDTCSR |= (1< WDTCSR = (1< } void Snake::Restart() { //WDT_Prescaler_Change(); } void main() { WDT_off(); Snake Snake1; DDRB=0xff; PORTA=0x00; DDRA=0x00; SPI_MasterInit(); LCD_INIT(); Clear_Gcrom(); Snake1.Generate_food(); while(1) { { delay_ms(50); Snake1.Go_ahead(); if(!K2) { Snake1.Turn_left(); } if(!K3) { Snake1.Turn_up(); } if(!K4) { Snake1.Turn_right(); } if(!K5) { Snake1.Turn_down(); } //if(Snake1.body[0].x<0||Snake1.body[0].x>127||Snake1.body[0].y<0|| Snake1.body[0].y>63) //Snake1.Die(); } } } /////////////////////////////////////////////////////////////////////////// #define F_CPU 8 #include #include"delay.h" void SPI_MasterInit(void) { /* Set MOSI and SCK output, all others input */ //DDRB =(1<<7)|(1<<5)|(1<<4);//(1<<5)|(1<<7); /* Enable SPI, Master, set clock rate fck/16 */ SPCR = (1<<6)|(1<<4);//|(1<<1)|0x01;//1< } void SPI_MasterTransmit(char cData) { /* Start transmission */ SPDR = cData; /* Wait for transmission complete */ while(!(SPSR & (1<<7)));//1< void LCD_Write (char RS,char content) { char Start,High4,Low4; Start=0xf8|(RS<<1); High4=content&0xf0; Low4=(content<<4)&0xf0; //SS=1; SPI_MasterTransmit(Start); SPI_MasterTransmit(High4); SPI_MasterTransmit(Low4); //SS=0; delay_us(300); } /*-----------------------------------*/ void LCD_INIT(void) { LCD_Write (0,0x30); /*30---基本指令动作*/ LCD_Write (0,0x01); /*清屏,地址指针指向00H*/ LCD_Write (0,0x06); /*光标的移动方向*/ LCD_Write (0,0x0c); /*开显示,关游标*/ } /*--------------清DDRAM------------------*/ void ClearRam(void) { LCD_Write (0,0x30); LCD_Write (0,0x01); } char lcd_x,lcd_y; void Clear_Gcrom() { char i,j,k; lcd_x=0x80; lcd_y=0x80; LCD_Write (0,0x34); for(i=0;i<2;i++) { for(j=0;j<32;j++) { LCD_Write (0,lcd_y+j); LCD_Write (0,lcd_x); for(k=0;k<16;k++) { LCD_Write (1,0x00); } } lcd_x=0x88; } LCD_Write (0,0x36); LCD_Write (0,0x30); } void Show_2Byte(char x,char y,char dat1,char dat2)// x:0~7 y:0~63 { if(y<32)//下屏 { x+=8; y=31-y; } else//上屏 { y=63-y; } LCD_Write (0,0x34); LCD_Write (0,0x80+y);//y:0~31 LCD_Write (0,0x80+x);//x:0~15 LCD_Write (1,dat1); LCD_Write (1,dat2); LCD_Write (0,0x36); LCD_Write (0,0x30); } void Show_Hang(char y,char p[64][16]) //显示一行 y:0~63 { char k,y0=y; lcd_y=0x80; LCD_Write (0,0x34); if(y<32) { lcd_x=0x80+8;//下屏 y=31-y; } else { lcd_x=0x80;//上屏 y=63-y; } //LCD_Write (0,0x80+0);//y1:0~31 //LCD_Write (0,0x80+0);//x1:0~15 LCD_Write (0,lcd_y+y); LCD_Write (0,lcd_x); for(k=0;k<16;k++) //写入显示数据 { LCD_Write (1,p[y0][k]); } LCD_Write (0,0x36); LCD_Write (0,0x30); } ////////////////////////////////////////////////////////////////////////////// #ifndef __IAR_DELAY_H #define __IAR_DELAY_H #include #define delay_us(x) __delay_cycles ((unsigned long)(x * F_CPU)) #define delay_ms(x) __delay_cycles ((unsigned long)(x * F_CPU*1000UL)) #define delay_s(x) __delay_cycles ((unsigned long)(x * F_CPU*1000000UL)) #endif ////////////////////////////////////////////////////////////////////////////// #ifndef _FUNCTION_INCLUDED #define _FUNCTION_INCLUDED extern void Show_Hang(char y,char p[64][16]); //显示一行 y:0~63 extern void LCD_INIT(void); extern void Clear_Gcrom(); extern void ClearRam(void); extern void SPI_MasterInit(void); extern void Show_2Byte(char x,char y,char dat1,char dat2);// x:0~7 y:0~63 #endif |
|
相关推荐
68 个讨论
|
|
不错
|
|
|
|
|
|
好东西,顶一下!
|
|
|
|
|
|
也不弄个备注!
|
|
|
|
|
|
|
|
|
|
楼主,能帮我看看程序吗?lcd12864的
|
|
|
|
|
|
|
|
|
|
mark一下,留下一次看看
|
|
|
|
|
|
好东西啊,学习了,非常有用的东西
|
|
|
|
|
|
那个用C++编写的看不懂,没学过C++,还得自己想,不过前面那几个很好很好!
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
852个成员聚集在这个小组
加入小组AVR Atmega16 Bootloader程序与上位机LabView程序
5104 浏览 6 评论
#include <ioavr.h>这个头文件我应该下什么编译器
7749 浏览 0 评论
3015 浏览 2 评论
3098 浏览 1 评论
10039 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-10 16:00 , Processed in 0.997722 second(s), Total 79, Slave 69 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号