12864画点画线算法

合集下载

12864模块ST7565R串口画点画线测试程序

12864模块ST7565R串口画点画线测试程序
ቤተ መጻሕፍቲ ባይዱ
新建文本文档 (2).txt for(z=0;z<5;z++) { DispByte(page,col+z,ASCII_5X8_12864[dat+z]); } } //---------------------------------------------------------void DispStr(Uchar page,Uchar col,Uchar *_char) //指定位 置写5*8字符串 { while(*_char!='\0') { DispChar(page,col,*_char++); col+=5; } } //---------------------------------------------------------void DispHZ(Uchar page,Uchar col,Uchar *charr) //指定位置写 16*16汉字 { Uint z,cc; for(cc=0;cc<2;cc++) { for(z=0;z<16;z++) { DispByte(page,col+z,*charr++); } page++; } } //---------------------------------------------------------//------------------1~64 com, 1~128seg---------------------//-----浮点运算和除法会降低显示速度,此处避开浮点和乘除法------void DrawLines(Uint Hx1,Uint Hy1,Uint Hx2,Uint Hy2) //指定2个坐标点 画线 { Uint temp; Uchar inc,dx,dy; if(Hx2>=Hx1) else dx=Hx2-Hx1; dx=Hx1-Hx2; //x轴方向增量

12864教程画点画线换正弦波(非常完整)有程序

12864教程画点画线换正弦波(非常完整)有程序

功能:选择 4 行中的任一行作反白显示,并可决定反白与否。第一次设定为反白显示,再次 设定时为正常显示
正常 15. 睡眠模式(15H)
0x04
0x05
0x06/0x07
功能:SL=1:脱离睡眠模式; SL=0:进入睡眠模式(外观上和清屏相同)。 16. 扩充功能设定(16H)
功能:DL=1:8-BIT 控制接口; DL=0:4-BIT 控制接口 RE=1:扩充指令集动作; RE=0:基本指令集动作 G=1:绘图显示 ON; G=0:绘图显示 OFF
10. 写资料到 RAM
功能:写入资料到内部的 RAM(DDRAM/CGRAM/GDRAM),每个 RAM 地址 都要连续写入两个字节的资料。 11. 读出 RAM 的值
功能:从内部 RAM 读取数据(DDRAM/CGRAM/GDRAM),当设定地址指令后,若需 读取数据时需先执行一次空的读数据,才会读取到正确数据,第二次读取时则不需要,除非 又下设定地址指令
//大于100uS 的延时程序
write_com(0x01); //Display Clear
delay(10);
//大于10mS 的延时程序
write_com(0x06); //Enry Mode Set,光标从右向左加1位移动
delay(100);
//大于100uS 的延时程序
}
显示图片的初始化函数:
instruction set, G=0 :graphic display OFF
delay(100);
//大于100uS 的延时程序
write_com(0x30); //Function Set
delay(37);
////大于37uS 的延时程序

电子信息工程专业毕业设计--基于51单片机的12864液晶显示器的设计和研究

电子信息工程专业毕业设计--基于51单片机的12864液晶显示器的设计和研究

目录设计总说明 (I)INTRODUCTION (II)1 绪论 (1)1.1课题背景及研究意义 (1)1.2课题研究的主要内容 (1)1.3国内外发展状况与存在问题 (1)2 总体方案设计与论述 (2)2.1 系统需求分析 (2)2.2 系统总体方案设计 (2)2.2.1 设计方案论证 (2)2.2.2总体结构框图 (3)3系统单元模块设计 (3)3.1系统硬件示意图 (3)3.2主控芯片(STC89C52模块)[5] (4)3.3 时钟控制模块[13] (6)3.3.1 DS1302简介 (6)3.3.2引脚及功能表 (7)3.3.3工作原理 (7)3.3.4 DS1302电路设计图[9] (8)3.4 温度控制模块 (8)3.5 12864接口电路模块 (9)3.6 按键电路模块 (9)3.7 电源电路模块 (10)3.8 印制电路板[9] (10)4系统整体调试与结果分析 (11)4.1 系统总体程序流程介绍 (11)4.2 按键程序设计 (13)4.3 12864驱动程序设计[15] (14)4.3.1 ST7920芯片介绍[14] (14)4.3.2 ST7920驱动程序设计 (17)4.4 12864应用程序设计 (20)4.4.1 文字显示程序设计 (20)4.4.2 点、线显示程序设计 (22)4.4.3 图形、图片显示程序设计 (23)4.5 菜单程序设计 (26)5设计调试及进一步研究 (28)5.1 系统测试 (28)5.1.1 软件调试 (28)5.1.2 硬件调试 (29)5.2 进一步研究的工作 (30)6总结 (30)鸣谢................................................................................................................................ 错误!未定义书签。

如何在LCD12864上任意画点

如何在LCD12864上任意画点

一、关于12864的画图功能。

我们知道在纸上画出一个点,我们要知道这个点在张纸上面的位置,也就是这个点在这张纸上面的坐标。

而在12864上面画点也是一样,我们要先知道这个点在液晶屏上面的坐标,然后我们该坐标点黑或是点白可以了。

而在这之前,我们要首先理解12864图形显示坐标。

12864的绘图显示坐标如图所示:需要注意的是它的水平位址并不是一个点有一个位址的,它是16个格才有一个位址。

它的垂直位址也分为上下两半部分。

当我们给出位址是X是0,Y是0的时候,其实里面包含了16个点,也就是说我们一次要操作16个点。

所有当我们要点亮一个点的时候,我们不仅要知道的位址,还要知道它在这个位址中是第几个位,也就是第几个点。

#include<reg52.h>#define uint unsigned int#define uchar unsigned charsbit RS=P2^6; //这个是LCD的数据命令选择端sbit RW=P2^5; //这个是LCD的写入或是读出选择端sbit PSB=P3^2; //这个是LCD串行还是并行选择端sbit RST=P3^4; //这个是LCD的复位端口sbit LCDE=P2^7; // 这个是LCD的使能端/*延时子函数*/void delay(uint x){uint y;for(;x>0;x--)for(y=110;y>0;y--);}/*忙碌检查*/void lcd_busy(){RS=0;RW=1;P0=0XFF;LCDE=1;delay(2);while((P0&0x80)==0x80);/*如下图1,当LCD忙碌的时候BF位是为1,而我们只需要想知道这位,所有与上0x80,当它是1的时候得到0X80,当它是0的时候得到0.*/LCDE=0;}/*写入命令*/void write_com(uchar com){lcd_busy();/*每次操作LCD之前都需要检查一次LCD是否忙碌,不过一般LCD工作比单片机快,所有都不用检查。

12864液晶画点和画任意两点间直线 原理

12864液晶画点和画任意两点间直线 原理

12864液晶画点和画任意两点间直线原理、算法及程序原码12864液晶画点和画任意直线的原理和算法程序原码经验证可行12864实际上是256x64二维显示空间,整个液晶屏分上下两个半屏。

整个屏一共有256列,64行。

可以把它分成16大列,每一大列包含16列。

图形RAM的起始址址为0x80,设置读或写的地址时,要先写Y坐标,再写X坐标。

要使用画图功能,就要设置扩允指令集。

画点原理:先确定坐标->读出数据->修改数据->数据写回原处。

程序原码://画点函数void Draw_Point(uchar x,uchar y,uchar color){uchar row,tier,row_bit;uchar ReadOldH,ReadOldL;tier=x>>4; //把256列分成16大列,每大列包含16列row_bit=x&0x0f; //计算所给坐标在某一大列中的哪一列if(y<32) //分上下半屏显示row=y; //上半屏else{row=y-32; //下半屏tier+=8;}WriteCommand(0x34); //8Bit扩充指令集,即使是36H也要写两次WriteCommand(0x36); //绘图ON,基本指令集里面36H不能开绘图WriteCommand(0x80+row); // 行位置WriteCommand(0x80+tier); // 列位置ReadData();ReadOldH=ReadData();//某大列的前8列数据,低位在前,高位在后ReadOldL=ReadData();//某大列的后8列数据if( row_bit < 8 ) //修改读出的数据{switch( color){case 0 : ReadOldH &=( ~( 0x01 << ( 7 - row_bit ))) ;break ;case 1 : ReadOldH |= ( 0x01 << ( 7 - row_bit )) ;break ;case 2 : ReadOldH ^= ( 0x01 << ( 7 - row_bit )) ;break ;default : break ;}}else{switch(color){case 0 : ReadOldL &= (~( 0x01 << ( 15 - row_bit ))) ;break ;case 1 : ReadOldL |= ( 0x01 << ( 15 - row_bit )) ;break ;case 2 : ReadOldL ^= ( 0x01 << ( 15 - row_bit )) ;break ;default : break ;}}WriteCommand(0x80+row); // 行位置WriteCommand(0x80+tier); // 列位置WriteData( ReadOldH ) ;//把修改后的数据写回原地址WriteData( ReadOldL ) ;}画任意两点间直线的原理和算法:采用Bresenham画线算法。

单片机12864画线

单片机12864画线

#include <reg52.h>#include <MA TH.H>#define uchar unsigned chartypedef unsigned int uint;#define BASIC_SET 0x30 //基本指令集#define EXTEND_SET 0x34 //扩展指令集#define DRAW_ON 0x36 //绘图显示开#define DRAW_OFF 0x34sbit RS = P2^4;sbit RW = P2^5;sbit E = P2^6;sbit RES= P2^3;sbit PSB= P2^1;#define DataPort P0/*****************************大致7us*****************************/void DelayUs2x(uchar t){while(--t);}/****************************大致1ms*****************************/void DelayMs(unsigned char t){while(t--){DelayUs2x(245);DelayUs2x(245);}}void Check_Busy(){DataPort=0xff;RS=0;RW=1;E=1;while((DataPort&0x80)==0x80); //忙则等待E=0;}void Write_Cmd(uchar Cmd){Check_Busy();RS=0;RW=0;DataPort=Cmd;E=1;E=0;}void Write_Data(uchar Data){Check_Busy();RS=1;RW=0;DataPort=Data;E=1;E=0;}uchar Read_Data(){uchar LCD_DATA;Check_Busy();DataPort=0xff;RS=1;RW=1;E=1;LCD_DATA=DataPort;DelayUs2x(5);E=0;DelayUs2x(5);return LCD_DATA;}/*------------------------------------------------显示字符串x:横坐标值,范围0~8y:纵坐标值,范围1~4------------------------------------------------*/void LCD_PutString(unsigned char x,unsigned char y,unsigned char *s) {switch(y){case 1: Write_Cmd(0x80+x);break;case 2: Write_Cmd(0x90+x);break;case 3: Write_Cmd(0x88+x);break;case 4: Write_Cmd(0x98+x);break;default:break;}while(*s>0){Write_Data(*s);s++;}}void Init_ST7920(){DelayMs(40); //大于40MS的延时程序PSB=1; //设置为8BIT并口工作模式DelayMs(1); //延时RES=0; //复位DelayMs(1); //延时RES=1; //复位置高DelayMs(10);//Write_Cmd(0x30); //选择基本指令集//DelayUs2x(50); //延时大于100usWrite_Cmd(0x30); //选择8bit数据流DelayUs2x(20); //延时大于37usWrite_Cmd(0x0c); //开显示(无游标、不反白)DelayUs2x(50); //延时大于100usWrite_Cmd(0x01); //清除显示,并且设定地址指针为00HDelayMs(15); //延时大于10msWrite_Cmd(0x06); //指定在资料的读取及写入时,设定游标的移动方向及指定显示的移位,光标从右向左加1位移动DelayUs2x(50); //延时大于100us}void LCD_Clear(){Write_Cmd(0x01);DelayMs(15);}/*清绘图*/void LCD_Clear_GDRAM(void){uchar i,j;for(j=0;j<32;j++){Write_Cmd(EXTEND_SET);Write_Cmd(0x80+j);Write_Cmd(0x80);Write_Cmd(0x30); //基本指令集,绘图关for(i=0;i<32;i++)Write_Data(0x00); // 写入0x00}Write_Cmd(DRAW_ON);Write_Cmd(BASIC_SET);}/*------------------------------------------------打点x:横坐标值,范围0~127y:纵坐标值,范围0~63------------------------------------------------*/void LCD_SET_Dot(uchar x,uchar y,bit Mode){uchar x_byte,x_bit;uchar y_byte,y_bit;uchar LCD_H,LCD_L;x&=0x7f;//防止x坐标超过127y&=0x3f;//防止y坐标超过63x_byte=x/16;//那一个地址x_bit=x%16;y_byte=y/32;y_bit=y%32;Write_Cmd(EXTEND_SET);Write_Cmd(DRAW_OFF);Write_Cmd(0x80+y_bit);//垂直Write_Cmd(0x80+x_byte+8*y_byte);//水平Read_Data();LCD_H=Read_Data();LCD_L=Read_Data();Write_Cmd(0x80+y_bit);//垂直Write_Cmd(0x80+x_byte+8*y_byte);//水平if(x_bit<8){if(Mode){Write_Data(LCD_H|(0x01<<(7-x_bit)));Write_Data(LCD_L);}else{Write_Data(LCD_H&(~(0x01<<(7-x_bit))));Write_Data(LCD_L);}}else{if(Mode){Write_Data(LCD_H);Write_Data(LCD_L|(0x01<<(15-x_bit)));}else{Write_Data(LCD_H);Write_Data(LCD_L&(~(0x01<<(15-x_bit))));}}Write_Cmd(DRAW_ON);}//画水平线void v_Lcd12864DrawLineX_f( unsigned char X0, unsigned char X1, unsigned char Y, unsigned char Color ){ unsigned char Temp ;if( X0 > X1 ){Temp = X1 ;X1 = X0 ;X0 = Temp ;}for( ; X0 <= X1 ; X0++ )LCD_SET_Dot( X0, Y, Color ) ;}//画垂直线:void v_Lcd12864DrawLineY_f( unsigned char X, unsigned char Y0, unsigned char Y1, unsigned char Color ){unsigned char Temp ;if( Y0 > Y1 ){Temp = Y1 ;Y1 = Y0 ;Y0 = Temp ;}for(; Y0 <= Y1 ; Y0++)LCD_SET_Dot( X, Y0, Color) ;}/*------------------------------------------------画直线x:横坐标值,范围0~127y:纵坐标值,范围0~63------------------------------------------------*/void LCD_SET_Line(uchar x1,uchar y1,uchar x2,uchar y2,bit Mode) {uchar x_add,y_add,y_temp,Line_K;x1&=0x7f;x2&=0x7f;y1&=0x3f;y2&=0x3f;if(x2>x1){if(y2>y1||y2==y1){Line_K=(y2-y1)/(x2-x1);for(x_add=0;x_add<=(x2-x1);x_add++){y_temp=y1+(Line_K*(x_add+x1));LCD_SET_Dot(x_add+x1,y_temp,Mode);}}else{Line_K=(y1-y2)/(x2-x1);for(x_add=0;x_add<=(x2-x1);x_add++){y_temp=y1-(Line_K*(x_add+x1));LCD_SET_Dot(x_add+x1,y_temp,Mode);}}}else if(x2==x1){for(y_add=0;y_add<=(y2-y1);y_add++){LCD_SET_Dot(x1,y1+y_add,Mode);}}{}}void v_Lcd12864DrawLine_f( unsigned char StartX, unsigned char StartY, unsigned char EndX, unsigned char EndY, unsigned char Color ){int t, distance; /*根据屏幕大小改变变量类型(如改为int型)*/int x = 0 , y = 0 , delta_x, delta_y ;char incx, incy ;delta_x = EndX - StartX ;delta_y = EndY - StartY ;if( delta_x > 0 ){incx = 1;}else if( delta_x == 0 ){v_Lcd12864DrawLineY_f( StartX, StartY, EndY, Color ) ;return ;}else{incx = -1 ;}if( delta_y > 0 ){incy = 1 ;}else if(delta_y == 0 ){v_Lcd12864DrawLineX_f( StartX, EndX, StartY, Color ) ;return ;}else{incy = -1 ;}delta_x = abs( delta_x );delta_y = abs( delta_y );if( delta_x > delta_y )distance = delta_x ;}else{distance = delta_y ;}LCD_SET_Dot( StartX, StartY, Color ) ;/* Draw Line*/for( t = 0 ; t <= distance+1 ; t++ ){LCD_SET_Dot( StartX, StartY, Color ) ;x += delta_x ;y += delta_y ;if( x > distance ){x -= distance ;StartX += incx ;}if( y > distance ){y -= distance ;StartY += incy ;}}}/*------------------------------------------------画矩形x:横坐标值,范围0~127y:纵坐标值,范围0~63------------------------------------------------*/void LCD_SET_Box(uchar x1,uchar y1,uchar x2,uchar y2,bit Mode) {LCD_SET_Line(x1,y1,x2,y1,Mode);LCD_SET_Line(x1,y2,x2,y2,Mode);LCD_SET_Line(x1,y1,x1,y2,Mode);LCD_SET_Line(x2,y1,x2,y2,Mode);}/*画正弦曲线*/void fsin(){float x,y;uchar x1,y1;for(x=0;x<(4*3.1415);x+=0.1) //4*3.1415)=125.6<127 {y=sin(x);x1=10*x;y1=31-(10*y+0.5);LCD_SET_Dot(x1,y1,1);}}//y1=31-(10*y+0.5);这条语句是对y值进行四舍五入!void main(){Init_ST7920();LCD_Clear_GDRAM();v_Lcd12864DrawLine_f( 0, 0, 127, 63, 1 ) ;v_Lcd12864DrawLine_f( 0, 63, 127, 0 , 1 ) ;v_Lcd12864DrawLine_f( 12, 0, 127, 63, 1 ) ;v_Lcd12864DrawLine_f( 52, 63, 127, 0 , 1 ) ;v_Lcd12864DrawLine_f( 32, 63, 98, 0, 1 ) ;v_Lcd12864DrawLine_f( 67, 0, 127, 63 , 1 ) ; DelayMs(10000);LCD_Clear_GDRAM();LCD_SET_Line( 0,0,127,0,1 ) ;DelayUs2x(5);LCD_SET_Line( 0,7,127,7,1 ) ;DelayUs2x(5);LCD_SET_Line( 0,15,127,15,1 ) ;DelayUs2x(5);LCD_SET_Line( 0,23,127,23,1 ) ;DelayUs2x(5);LCD_SET_Line( 0,31,127,31,1 ) ;DelayUs2x(5);LCD_SET_Line( 0,39,127,39,1 ) ;DelayUs2x(5);LCD_SET_Line( 0,47,127,47,1 ) ;DelayUs2x(5);LCD_SET_Line( 0,55,127,55,1 ) ;DelayUs2x(5);LCD_SET_Line( 0,63,127,63,1 ) ;DelayUs2x(5);LCD_SET_Line( 0,0,0,63,1 ) ;DelayUs2x(5);LCD_SET_Line( 15,0,15,63,1 ) ;DelayUs2x(5);LCD_SET_Line( 31,0,31,63,1 ) ;DelayUs2x(5);LCD_SET_Line( 47,0,47,63,1 ) ;DelayUs2x(5);LCD_SET_Line( 63,0,63,63,1 ) ;DelayUs2x(5);LCD_SET_Line( 79,0,79,63,1 ) ;DelayUs2x(5);LCD_SET_Line( 95,0,95,63,1 ) ;DelayUs2x(5);LCD_SET_Line( 111,0,111,63,1 ) ;DelayUs2x(5);LCD_SET_Line( 127,0,127,63,1 ) ;DelayMs(10000);LCD_Clear_GDRAM();fsin();while(1){}}以前看到Bresenham画线算法,直接拿来用,没有去推导它,近日,参考一些资料,特整理其算法推导过程如下。

学习笔记:LCD12864的画点功能

学习笔记:LCD12864的画点功能

学习笔记:LCD12864的画点功能本人学习的LCD12864的驱动控制器是ST7920,本文档主要记述了本人学习LCD12864画点原理的一些心得及细节。

但只限于画点功能,其他功能将在其他文档中记述。

首先,先介绍与画点功能有关的存储器:GDRAM:(Graphic Display RAM):图形显示RAM,这一块区域用于绘图,往里面写啥,屏幕就会显示啥,它与DDRAM的区别在于,往DDRAM中写的数据是字符的编码,字符的显示先是在CGROM中找到字模,然后映射到屏幕上,而往GDRAM中写的数据是图形的点阵信息,每个点用1bit来保存其显示与否。

GDRAM的空间结构图如下图所示。

可以看出,它可以看作是32行*256列的屏幕,只不过分成上下半屏来显示,所以GDRAM 的地址是上下半屏连续循环的,例如点亮上半屏的第0行的第0列像素点,之后点亮第0行第2列、第0行第2列、第0行第4列......一直到第0行第127列,此时上半屏第0行像素已经全部点亮,当点亮第0行第128列时,点亮的像素点会是下半屏的第0行第0列,点亮第0行第129列会是下半屏的第0行第1列像素点亮,但要注意地址只是在当前行循环。

比如上面讲的例子,地址始终是在第0行循环的。

另外重要的是,在对GDRAM进行数据读/写时,当读/写完毕后,在当前的行上地址自动增加一个单位,这一个单位的大小为十六个格子,也就是16bit,一个字。

而读/写数据的最小单位也是一个字。

每一个方格代表一个像素点,在GDRAM空间结构中,以十六个方格为一个数据单位,即字(两个字节)。

在对GDRAM读写操作中,也是以字为单位的。

而又以16列*32行为一个单位,共分为16个单位。

分别为图中的0~15,为了方便叙述下面我将这些单位称之为模块(16列*32行,即32字)。

这些模块在存储中是有地址的,0~15分别对应地址80H~8FH。

上半屏为80H~87H,下半屏为88H~8FH。

ATmega128的_LCD12864_绘图(画点_画线_画矩形等)

ATmega128的_LCD12864_绘图(画点_画线_画矩形等)

基于ATmega128的LCD12864画图(画点,画线,画矩形等) 先上图:程序:文件结构:---------------- _main.c --------------- /** 基于ATmega128 的LCD12864 画图显示实验* 16MHz* 编译器: ICCAVR* 已测试通过* by Qin Zhengye* 2011-08-07*//** 硬件接口: LCD_DATA -> PE* RS -> PB0* RW -> PB1* EN -> PB2*/#include "my_include.h"#include "LCD12864_graphics.h"void main(){Port_init(); // 端口初始化LCD12864_init();_delay_ms( 5 ); // 要等待液晶初始化完毕LCD12864_string( 0, 0, "液晶" ); // 写入容LCD12864_string( 1, 0, "被屏蔽的" ); //LCD12864_string( 0, 6, "画点");LCD12864_clear(); // 图形模式的清屏LCD12864_dot( 36, 0, 8, 1 ); // 在( 36, 8 ) 处画点( 0无用, 看定义函数前的说明)LCD12864_line( 90, 8, 39, 8, 1 ); // 箭头的形状LCD12864_dot( 40, 0, 7, 1 );LCD12864_dot( 40, 0, 9, 1 );LCD12864_dot( 41, 0, 6, 1 );LCD12864_dot( 41, 0, 10, 1 );LCD12864_line( 30, 60, 116, 20, 1 );LCD12864_bar( 90, 45, 110, 60, 1 );LCD12864_rectangle( 9, 34, 40, 62, 1 );}------------ LCD12864_basic.h -------------/** LCD12864驱动程序----basic* 此头文件有LCD12864的基本的写指令数据* for ATmega128* 16MHz* 编译器: ICCAVR* 已测试通过* by Qin Zhengye*//* 宏定义要用到的函数( 没用到可以注释掉, 以减小目标程序的大小)*///#define __KEY_scanf#define __LCD12864_string/** define functions*/void LCD12864_init( void );void LCD12864_cmd ( unsigned char cmd );void LCD12864_dat ( unsigned char dat );void LCD12864_string( unsigned char Y, unsigned char X, unsigned char *table ); void check_busy( void );unsigned char KEY_scanf( void );/** 定义硬件接口( 只接8数据+ 3控制+ 2电源根线) * RS 0-command; 1-data* RW 0-write ; 1-read* EN 1-input ; 1->0 action*/#define LCD_IN PINE#define LCD_DDR DDRE#define LCD_OUT PORTE#define KEY_IN PIND#define KEY_OUT PORTD#define KEY_DDR DDRD#define BUSY ((LCD_IN & 0x80) != 0)#define RS_COMD ( PORTB &= ~(0x01 << 0) )#define RS_DATA ( PORTB |= (0x01 << 0) )#define RW_WRITE ( PORTB &= ~(0x01 << 1) )#define RW_READ ( PORTB |= (0x01 << 1) )#define EN_SET ( PORTB |= (0x01 << 2) )#define EN_CLR ( PORTB &= ~(0x01 << 2) )/* 键盘扫描* 电路无需电阻,高效行列版** 键盘布局:** D3 D2 D1 D0* | | | |* D4-- 0 1 2 3* D5-- 4 5 6 7* D6-- 8 9 A B* D7-- C D E F** 说明: 键盘没有按下则返回0, 按下返回对应键值*/#ifdef __KEY_scanfunsigned char KEY_scanf( void ){uchar temp;KEY_DDR = 0x0F;KEY_OUT = 0xF0;_delay_ms( 4 );if( (temp = KEY_IN) != 0xF0 ){KEY_DDR = 0xF0;KEY_OUT = 0x0F;_delay_ms( 1 );temp = temp | KEY_IN;switch( temp ){case 0xE7: return '0';case 0xEB: return '1';case 0xED: return '2';case 0xEE: return '3'; // 第一行case 0xD7: return '4';case 0xDB: return '5';case 0xDD: return '6';case 0xDE: return '7'; // 第二行case 0xB7: return '8';case 0xBB: return '9';case 0xBD: return 'A';case 0xBE: return 'B'; // 第三行case 0x77: return 'C';case 0x7B: return 'D';case 0x7D: return 'E';case 0x7E: return 'F'; // 第四行}}return 0;}#endif/* LCD12864初始化*/void LCD12864_init( void ){LCD12864_cmd( 0x30 ); // 基本指令, 字符模式LCD12864_cmd( 0x06 );LCD12864_cmd( 0x0C ); //LCD12864_cmd( 0x01 ); // 清屏LCD12864_cmd( 0x80 );}/* 写8位的命令*/void LCD12864_cmd( unsigned char cmd ){check_busy();RW_WRITE;LCD_OUT = cmd;_delay_us( 1 ); // 出现乱码请加长延时时间EN_CLR;}/* 写8位的数据*/void LCD12864_dat( unsigned char dat ){check_busy();RS_DATA;RW_WRITE;LCD_OUT = dat;_delay_us( 1 ); // 出现乱码请加长延时时间EN_CLR;}/** 写字符串* Y 取值( 0 ~ 3 )* X 取值( 0 ~ 7 )* table: 要显示的字符串的指针*/#ifdef __LCD12864_stringvoid LCD12864_string( unsigned char Y, unsigned char X, unsigned char *table ) {unsigned char i;switch( Y ){case 0: LCD12864_cmd( 0x80 + X ); break;case 1: LCD12864_cmd( 0x90 + X ); break;case 2: LCD12864_cmd( 0x88 + X ); break;case 3: LCD12864_cmd( 0x98 + X ); break;default: return ;}for( i = 0; table[i] != '\0'; i++ )LCD12864_dat( table[i] );}#endif/* 检查忙*/void check_busy( void ){uchar n = 200; // 控制时间, 时间过长强制退出LCD_OUT = 0xFF;RS_COMD;RW_READ;EN_SET;//_delay_us( 10 );while( BUSY == 1 && --n > 0 );}----------- LCD12864_graphics.h ------------- /** LCD12864驱动程序----graphics* 此头文件有LCD12864的图形模式下的* 清屏, 画320 * 240 的图画,* 读指定位置的容, 画点, 画线, 画矩形框,* 填充矩形* for ATmega128* 16MHz* 编译器: ICCAVR* 已测试通过* by Qin Zhengye*//* 注意: 本人用ICCAVR作编译器, 发现下面的"LCD12864_dot" 函数的参数有问题* 定义成"LCD12864_dot ( unsigned char X, unsigned char Y, unsigned char color )"* 当第一个实参"X" 是浮点数时, 发现传给第二个参数"Y" 的值会跟传给"X" 的数值一样* 所以下面在两者之间插入一个参数, 调用时多写一个数就没事了. 如果你知道解决办法麻烦QQ通知一声:)*//** 宏定义要用到的函数( 没用到可以注释掉, 以减小目标程序的大小)* 函数具体容看下面*/#define __LCD12864_clear#define __LCD12864_next#define __LCD12864_read_8#define __LCD12864_read_16#define __LCD12864_dot#define __LCD12864_line#define __LCD12864_bar#define __LCD12864_rectangle#define __LCD12864_whole_line//#define __LCD12864_BMP/** 声明函数*/void LCD12864_clear( void );void LCD12864_next ( void );void LCD12864_dot ( unsigned char X, unsigned char DB_X, unsigned char Y, unsigned char color );void LCD12864_line( unsigned char X0, unsigned char Y0, unsigned char X1, unsigned char Y1, unsigned char color );void LCD12864_bar ( unsigned char left, unsigned char up, unsigned char right, unsigned char down, unsigned char color );void LCD12864_rectangle ( unsigned char left, unsigned char up, unsigned char right, unsigned char down, unsigned char color );void LCD12864_whole_line( unsigned char Y, unsigned char color );void LCD12864_BMP( unsigned char *table );unsigned char LCD12864_read_8( void );unsigned int LCD12864_read_16( void );/* 包含基本的函数*/#include "LCD12864_basic.h"/* 图形模式的清屏*/#ifdef __LCD12864_clearvoid LCD12864_clear( void ){unsigned char i,j;LCD12864_cmd( 0x34 ); // 关图形模式的显示for( i = 0; i < 32; i++ ){LCD12864_cmd( 0x80 + i );LCD12864_cmd( 0x80 );for( j = 0; j < 32; j++ )LCD12864_dat( 0x00 );}LCD12864_cmd( 0x36 ); // 开图形模式的显示}#endif/* 编辑位置移到下一个8位* 可以移到低8位单独编辑容*/#ifdef __LCD12864_nextvoid LCD12864_next( void ){uchar n = 100;RS_COMD;RW_READ;EN_SET;while( BUSY == 1 && --n > 0 );RS_DATA;EN_CLR;}#endif/* 从LCD12864读数据* 注意: LCD12864的读操作, 第一次读到的是地址* 第二次读到的才是该地址对应的数据*/#ifdef __LCD12864_read_8unsigned char LCD12864_read( void ){unsigned char temp;check_busy();LCD_OUT = 0xFF;RS_DATA;RW_READ;EN_SET;LCD_DDR = 0x00;_delay_us(1);temp = LCD_IN;EN_CLR;LCD_DDR = 0xFF;return ( temp );}/* 读LCD12864的一个字节*/unsigned char LCD12864_read_8( void ){LCD12864_read(); // 注意: 读两次才读到数据return LCD12864_read();}#endif/* 读LCD12864的16位数据*/#ifdef __LCD12864_read_16unsigned int LCD12864_read_16( void ){unsigned int _16_data;unsigned char L_dat;_16_data = LCD12864_read_8();L_dat = LCD12864_read();return (_16_data << 8) | L_dat;}#endif/** 向LCD12864在( X, Y )出写一个点** 0 <= X <= 127* 0 <= Y <= 63* color: 0 -> 擦点, 非0 -> 画点* ( 传来的DB_X没用看文件前面的注意)*/#ifdef __LCD12864_dotvoid LCD12864_dot( unsigned char X, unsigned char DB_X, unsigned char Y, unsigned char color ){unsigned char temp, temp2 = 0;if( (0x01 & (X >> 3)) != 0 )temp2 = 1;DB_X = X >> 4;X = X & 0x07; // X = X % 8;if( Y >= 32 ){DB_X += 8;Y -= 32;}LCD12864_cmd( 0x80 + Y ); LCD12864_cmd( 0x80 + DB_X ); if( temp2 )LCD12864_next();temp = LCD12864_read_8();if( color != 0 )temp |= (0x80 >> X ); elsetemp &= ~(0x80 >> X ); LCD12864_cmd( 0x80 + Y ); LCD12864_cmd( 0x80 + DB_X ); if( temp2 )LCD12864_next();LCD12864_dat( temp );}#endif/** 向LCD12864画一条线* 起点( X0, Y0 ), 终点( X1, Y1 )* 0 <= X <= 127* 0 <= Y <= 63*/#ifdef __LCD12864_linevoid LCD12864_line( unsigned char X0, unsigned char Y0, unsigned char X1, unsigned char Y1, uchar color ) {LCD12864_cmd( 0x34 ); // 关闭显示if( X0 == X1 ) // K = 1{if( Y0 > Y1){X1 = Y0;Y0 = Y1;Y1 = X1;}while( Y0 <= Y1)LCD12864_dot( X0, 0, Y0++, color );LCD12864_cmd( 0x36 ); // 打开显示return;}if( Y0 == Y1 ) // K = 0{if( X0 > X1 ){Y1 = X0;X0 = X1;X1 = Y1;}while( X0 <= X1 )LCD12864_dot( X0++, 0, Y0, color );LCD12864_cmd( 0x36 ); // 打开显示return;}else // K != 0 && K != 1{float _K;char temp1 = ( X1 < X0 )?( X0 - X1 ):( X1 - X0 );char temp2 = ( Y1 < Y0 )?( Y0 - Y1 ):( Y1 - Y0 );if( temp1 < temp2 ) // Y{_K = (float)temp1 / temp2;temp2 = ( Y0 > Y1 )?( -1 ):( 1 );if( X0 > X1 )_K = -_K;temp1 = 1;LCD12864_dot( X0, 0, Y0, color );do{Y0 += temp2;LCD12864_dot( X0 + _K * temp1 ,0 , Y0, color );temp1++;}while( Y0 != Y1 );}else // X{_K = (float)temp2 / temp1;temp2 = ( X0 > X1 )?( -1 ):( 1 );if( Y0 > Y1 )_K = -_K;temp1 = 1;LCD12864_dot( X0, 0,Y0, color );do{X0 += temp2;LCD12864_dot( X0, 0, Y0 + _K * temp1, color );temp1++;}while( X0 != X1 );}}LCD12864_cmd( 0x36 ); // 打开显示}#endif/** 向LCD12864画一个填充矩形** left : 左, X 坐标* up : 上, Y 坐标* right: 右, X 坐标* down : 下, Y 坐标** 0 <= (left & right) <= 127* 0 <= (up & down) <= 63*/#ifdef __LCD12864_barvoid LCD12864_bar( unsigned char left, unsigned char up, unsigned char right, unsigned char down, uchar color ) {unsigned char temp;LCD12864_cmd( 0x34 );if( left > right ){temp = left;left = right;right = temp;}if( up > down ){temp = up;up = down;down = temp;}for( ; up <= down; up++ )for( temp = left; temp <= right; temp++ ) LCD12864_dot( temp, 0, up, color );LCD12864_cmd( 0x36 );}#endif/** 向LCD12864画一个矩形框** left : 左, X 坐标* up : 上, Y 坐标* right: 右, X 坐标* down : 下, Y 坐标** 0 <= (left & right) <= 127* 0 <= (up & down) <= 63*/#ifdef __LCD12864_rectanglevoid LCD12864_rectangle( unsigned char left, unsigned char up,unsigned char right, unsigned char down, uchar color ) {LCD12864_line( left, up, right, up, color );LCD12864_line( right, up, right, down, color );LCD12864_line( right, down, left, down, color );LCD12864_line( left, down, left, up, color );}#endif/* 画一整行* Y: 行数( 0 ~ 63 )*/#ifdef __LCD12864_whole_linevoid LCD12864_whole_line( unsigned char Y, unsigned char color ) {unsigned char temp = 0x80;if( Y >= 32 ){temp += 8;Y -= 32;}LCD12864_cmd( Y + 0x80);LCD12864_cmd( temp );for( temp = 0; temp < 16; temp++ )LCD12864_dat( color );}#endif/* 画一幅128*64的图画*/#ifdef __LCD12864_BMPvoid LCD12864_BMP( unsigned char *table ) {uchar i,j;uint n = 0;LCD12864_cmd( 0x34 );for( i = 0; i < 64; i++ ){if( i >= 32 ){LCD12864_cmd( 0x80 + i - 32 );LCD12864_cmd( 0x88 );}else{LCD12864_cmd( 0x80 + i );LCD12864_cmd( 0x80 );}for( j = 0; j < 16; j++ )LCD12864_dat( table[n++] );}LCD12864_cmd( 0x36 );}#endif--------------- my_include.h --------------- /** ATmega128的头文件* 晶振16MHz* by Qin Zhengye* 2011-08-07*//* 宏定义要用到的函数*/#define __Port_init#define ___delay_ms#define ___delay_us/* 包含头文件; <macros.h>中有"NOP()" */ #include <iom128v.h>#ifdef ___delay_us#include <macros.h>#endif#ifdef ___delay_ms#include <macros.h>#endif/* defines */#define uchar unsigned char#define uint u nsigned int#define ulong unsigned long/* 定义位操作 */#define SETBIT( x, y ) ( x |= (0x01 << y) ) #define CLRBIT( x, y ) ( x &= ~(0x01 << y) ) #define CHKBIT( x, y ) ( x & (0x01 << y) )/* I/O口初始化* 全部配置为输出高电平*/#ifdef __Port_initvoid Port_init( void ){DDRA = 0xFF;DDRB = 0xFF;DDRC = 0xFF;DDRD = 0xFF;DDRE = 0xFF;DDRF = 0xFF;DDRG = 0x1F;PORTA = 0xFF;PORTB = 0xFF;PORTC = 0xFF;PORTD = 0xFF;PORTE = 0xFF;PORTF = 0xFF;PORTG = 0x1F;}#endif/* 延时N毫秒(已仿真,稍有偏差16MHz) */#ifdef ___delay_msvoid _delay_ms( unsigned int _ms ){unsigned int _temp;for( ; _ms > 0; _ms-- )for( _temp = 2290; _temp > 0; _temp-- ) NOP();}#endif/* 延时N微秒(已仿真16MHz) */ #ifdef ___delay_usvoid _delay_us( unsigned int _us ){while( -- _us ){NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();}}#endif。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

for( ; X0 <= X1 ; X0++ ) v_Lcd12864DrawPoint_f( X0, Y, Color ) ; } 画垂直线: void v_Lcd12864DrawLineY_f( unsigned char X, unsigned char Y0, unsigned char Y1, unsigned char Color ) { unsigned char Temp ; if( Y0 > Y1 ) { Temp = Y1 ; Y1 = Y0 ; Y0 = Temp ; } for(; Y0 <= Y1 ; Y0++) v_Lcd12864DrawPoint_f( X, Y0, Color) ; } 下面我们就用以上两个画线函数,在液晶屏上面画一个表格出来 v_Lcd12864DrawLineX_f( 0, 127 , 0, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 7, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 15, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 23, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 31, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 39, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 47, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 55, 1 ) ; v_Lcd12864DrawLineX_f( 0, 127 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 0, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 15, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 31, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 47, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 63, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 79, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 95, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 111, 0 , 63, 1 ) ; v_Lcd12864DrawLineY_f( 127, 0 , 63, 1 ) ; 看看显示效果
从图中可以看出,X 方向共有 8 个字(16 个字节)Y 方向共有 0~31 行 分为上下两个屏。 弄懂了之后我们就可以依照此坐标来显示一整屏的图片了。 随便用一个图片的提取转换软件,讲一副 128X64 大小的图片转换成字节数据,总共字节大 小为 128*64/8 = 1024 个字节。 下面我们来看看这个显示整屏图像的函数 void v_Lcd12864DrawPicture_f( unsigned char code *pPicture ) { unsigned char i, j, k ; for( i = 0 ; i < 2 ; i++ )//分上下两屏写 {
| | 0,63----------------------------------127,63 0,0 代表屏幕的左上角,127,63 代表屏幕的右下角。 对于屏幕上面任意一个点, 如果我们想要点亮它, 必须先读出此点的状态, 然后再修改该点 , 最后送出去,即 读----修改----写。按照这个步骤,然后再运用 C 语言中的位操作运算符 可 以很方便的完成画点的函数。 由于画点函数涉及到读 ST7920 内部 RAM 的操作,因此,我们必须先要完成这个读数据的 函数 具体实现过程如下: unsigned char u8_Lcd12864ReadByte_f( void ) { unsigned char byReturnValue ; v_Lcd12864CheckBusy_f() ; io_LCD12864_DATAPORT = 0xff ; SET_DATA SET_READ CLR_EN SET_EN byReturnValue = io_LCD12864_DATAPORT ; CLR_EN return byReturnValue ; } 然后是画点的函数,其实现过程如下: void v_Lcd12864DrawPoint_f( unsigned char X, unsigned char Y, unsigned char Color ) { unsigned char Row , Tier , Tier_bit ; unsigned char ReadOldH, ReadOldL ; v_Lcd12864SendCmd_f( 0x34 ) ; v_Lcd12864SendCmd_f( 0x36 ) ; Tier = X >> 4 ; Tier_bit = X & 0x0f ; if( Y < 32 ) { Row = Y ; } else { Row = Y - 32 ; Tier += 8 ; } v_Lcd12864SendCmd_f( Row + 0x80 ) ;
下面来看看如何在任意一个位置显示或者是擦除一个点 对于 12864 这种二值显示屏来说,其显示状态无外乎显示和不显示一个点这两种状态。而 在任意位置画点,是我们随心所欲的画线,画圆,画矩形的等 GUI 函数的基础。 为了让这个位置有一个参考点,我们有必要定பைடு நூலகம்一个坐标系 在这里,我定义的坐标系如下 0,0------------------------------------127,0 | | | | | |
} else if(delta_y == 0 ) { v_Lcd12864DrawLineX_f( StartX, EndX, StartY, Color ) ; return ; } else { incy = -1 ; } delta_x = ABS( delta_x ); delta_y = ABS( delta_y ); if( delta_x > delta_y ) { distance = delta_x ; } else { distance = delta_y ; } v_Lcd12864DrawPoint_f( StartX, StartY, Color ) ; /* Draw Line*/ for( t = 0 ; t <= distance+1 ; t++ ) { v_Lcd12864DrawPoint_f( StartX, StartY, Color ) ; x += delta_x ; y += delta_y ; if( x > distance ) { x -= distance ; StartX += incx ; } if( y > distance ) { y -= distance ; StartY += incy ; } } } 老规矩,我们用这个函数随便画任意斜率的几条直线看看。 v_Lcd12864DrawLine_f( 0, 0, 127, 63, 1 ) ; v_Lcd12864DrawLine_f( 0, 63, 127, 0 , 1 ) ; v_Lcd12864DrawLine_f( 12, 0, 127, 63, 1 ) ;
通过上一篇的实验,相信大家都掌握了显示字符的基本用法。 下面我们来看一下 12864 液晶更高级的用法。 首先是它的绘图功能。 让我们先来显示一整副的图片吧,也就是 128x64 大小。 在使用绘图功能时,先要打开扩充指令集,然后再打开绘图功能。接着就是送数据显示了。 这里我们首先要弄明白 ST7920 的显示坐标关系。其显示坐标如下。
v_Lcd12864SendCmd_f( Tier + 0x80 ) ; u8_Lcd12864ReadByte_f() ; ReadOldH = u8_Lcd12864ReadByte_f() ; ReadOldL = u8_Lcd12864ReadByte_f() ; v_Lcd12864SendCmd_f( Row + 0x80 ) ; v_Lcd12864SendCmd_f( Tier + 0x80 ) ; if( Tier_bit < 8 ) { switch( Color) { case 0 : ReadOldH &=( ~( 0x01 << ( 7 - Tier_bit ))) ; break ; case 1 : ReadOldH |= ( 0x01 << ( 7 - Tier_bit )) ; break ; case 2 : ReadOldH ^= ( 0x01 << ( 7 - Tier_bit )) ; break ; default : break ; } v_Lcd12864SendData_f( ReadOldH ) ; v_Lcd12864SendData_f( ReadOldL ) ; } else { switch(Color) { case 0 : ReadOldL &= (~( 0x01 << ( 15 - Tier_bit ))) ; break ; case 1 : ReadOldL |= ( 0x01 << ( 15 - Tier_bit )) ; break ; case 2 : ReadOldL ^= ( 0x01 << ( 15 - Tier_bit )) ; break ; default : break ; } v_Lcd12864SendData_f( ReadOldH ) ; v_Lcd12864SendData_f( ReadOldL ) ; } v_Lcd12864SendCmd_f( 0x30 ) ; } 有了画点的函数之后, 一切似乎都变得简单了, 因为点是一切复杂图形的最基本的组成单位 。 下面我们就在这个画点函数的基础上,实现画水平线和垂直线的两个函数。 画水平线: void v_Lcd12864DrawLineX_f( unsigned char X0, unsigned char X1, unsigned char Y, unsigned char Color ) { unsigned char Temp ; if( X0 > X1 ) { Temp = X1 ; X1 = X0 ; X0 = Temp ; }
相关文档
最新文档