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。

LCD12864画点,画线,定点写入等子函数

LCD12864画点,画线,定点写入等子函数

#define LCD12864_GLOBAL#include"lcd12864.h"void delay_10us(unsigned char del){while(del--){_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}}///////////////////////////////////////读忙函数//操作方式RS>L RW>H E>低脉冲//输入://输出:忙标志1:忙0:闲/////////////////////////////////////void Lcd12864_ChkBusy(void){RS = 0;RW = 1;E = 1;L_PORT = 0XFF;while((L_PORT & 0X80) == 0X80); //忙了,则等待E = 0;}///////////////////////////////////////写指令//操作方式RS>L RW>H E>高电平//输入://输出://///////////////////////////////////void Lcd12864_WrCom(uchar com){Lcd12864_ChkBusy();RS = 0;RW = 0;E = 1;L_PORT = com;delay_10us(1);E = 0;}///////////////////////////////////////写数据//操作方式RS>L RW>H E>高电平//输入:写入数据//输出://///////////////////////////////////void Lcd12864_WrData(uchar dat){Lcd12864_ChkBusy();RS = 1;RW = 0;E = 1;L_PORT = dat;delay_10us(1);E = 0;}///////////////////////////////////////字库初始化函数//输入://输出://///////////////////////////////////void Lcd12864_WordInit(void){PSB = 1; //8位并行数据传输方式RET = 0; //复位函数delay_10us(1); //延时下RET = 1; //复位无效Lcd12864_WrCom(0x30);Lcd12864_WrCom(0x30);Lcd12864_WrCom(0x0c);Lcd12864_WrCom(0x01);Lcd12864_WrCom(0x06);}///////////////////////////////////////定位写入字符串函数//输入:参数1:行(1~4),参数2:列(0~7)参数3,字符串参数4,写入字节数//输出://///////////////////////////////////void Lcd12864_WrString(uchar x,uchar y,uchar *str,uchar num){uchar i;y = y % 7 ; //舍去大于八的数据switch(x){case 1:Lcd12864_WrCom(0x80 + y);break;case 2:Lcd12864_WrCom(0x90 + y);break;case 3:Lcd12864_WrCom(0x88 + y);break;case 4:Lcd12864_WrCom(0x98 + y);break;default:Lcd12864_WrCom(0x80 + y);}for(i = 0;i < num;i ++){Lcd12864_WrData(*str++); //写入对应点的数据}}///////////////////////////////////////图片初始化函数//输入://输出://///////////////////////////////////void Lcd12864_PhotoInit(void){PSB = 1; //8位并行数据传输方式RET = 0; //复位函数delay_10us(1); //延时下RET = 1; //复位无效Lcd12864_WrCom(0x36);Lcd12864_WrCom(0x36);Lcd12864_WrCom(0x3e);Lcd12864_WrCom(0x01);}///////////////////////////////////////图片打印函数//输入:图片数组的指针//输出://///////////////////////////////////void Lcd12864_PhotoPrint(uchar *photo){uchar i,j,k;for(i = 0;i < 2;i ++)for(j = 0;j < 32;j ++){Lcd12864_WrCom(0x80 + j); //纵坐标if(i == 0){Lcd12864_WrCom(0x80); //上半屏}else{Lcd12864_WrCom(0x88); //下半屏}for(k = 0;k < 16;k ++){Lcd12864_WrData(*photo ++ );}}}///////////////////////////////////////清楚GDRAM函数//输入://输出://///////////////////////////////////void Lcd12864_ClrGdRam(void){uchar x,y;for(y = 0;y < 64;y ++)for(x = 0;x < 16;x ++){Lcd12864_WrCom(0x34); //开指令扩充Lcd12864_WrCom(0x80 + y); //行坐标Lcd12864_WrCom(0x80 + x); //列坐标Lcd12864_WrCom(0x30); //关指令扩充Lcd12864_WrData(0x00); //高字节Lcd12864_WrData(0x00); //低字节}}///////////////////////////////////////读出数据函数//输入://输出:读出的数据/////////////////////////////////////uchar Lcd12864_ReData(void){uchar Temp;Lcd12864_ChkBusy();RS = 1;RW = 1;L_PORT = 0XFF; //准备读入数据E = 1;Temp = L_PORT; //读出数据E = 0;return Temp;}///////////////////////////////////// 0 63------------------------- 127 63//画对应点函数||//输入:参数1:列(0 ~ 127)参数2:行(0~63)参数3:改点的颜色||//输出:||///////////////////////////////////// 0 0------------------------- 127 0void Lcd12864_DrawPoint(uchar x,uchar y,uchar color){uchar Row,Tier,TierBit;uchar ReadDatH,ReadDatL;Lcd12864_WrCom(0x36);Tier = x >> 4; //取出对应层数TierBit = x & 0x0f; //取出对应层数的位if(y < 32){Row = ((~y) & 0x1f); //取32的补码Tier += 8; //下半屏}else{Row = ((~(y - 32)) & 0x1f);}//选取位置读出数据Lcd12864_WrCom(Row + 0x80); // 行Lcd12864_WrCom(Tier + 0x80); // 列Lcd12864_ReData();ReadDatH = Lcd12864_ReData(); //读取高八位ReadDatL = Lcd12864_ReData(); //读取低八位//定位位置准备写入数据Lcd12864_WrCom(Row + 0x80); // 行Lcd12864_WrCom(Tier + 0x80); // 列if(TierBit < 8){switch(color){case 0:ReadDatH &= (~(0x01 << (7 - TierBit))); //置零break;case 1:ReadDatH |= (0x01 << (7 - TierBit)); //置一break;case 2:ReadDatH ^= (0x01 << (7 - TierBit)); //异或取反break;}}else{switch(color){case 0:ReadDatL &= (~(0X01 << (15 - TierBit)));break;case 1:ReadDatL |= (0x01 << (15 - TierBit));break;case 2:ReadDatL ^= (0x01 << (15 - TierBit));}}Lcd12864_WrData(ReadDatH); //先写高位字节Lcd12864_WrData(ReadDatL);}///////////////////////////////////////画水平直线函数//输入:参数1:起始横坐标参数2:终止横坐标参数3:纵坐标参数4:显示状态//输出://///////////////////////////////////void Lcd12864_DrawLine_Level(uchar x0,uchar x1,uchar y,uchar color){uchar i,Temp;if(x0 > x1) //保证x1 > x0{Temp = x0;x0 = x1;x1 = Temp;}for(i = x0;i < x1;i ++){Lcd12864_ChkBusy();Lcd12864_DrawPoint(i,y,color);}}///////////////////////////////////////画垂直线函数///输入:参数1:定位横坐标参数2:起始纵坐标参数3:终止纵坐标参数4:显示状态//输出://///////////////////////////////////void Lcd12864_DrawLine_Vertical(uchar x,uchar y0,uchar y1,uchar color){uchar i,Temp;if(y0 > y1) //保证x1 > x0{Temp = y0;y0 = y1;y1 = Temp;}for(i = y0;i < y1;i ++){Lcd12864_ChkBusy();Lcd12864_DrawPoint(x,i,color);}}///////////////////////////////////////画垂直线函数///输入:参数1, 参数2:起始横纵坐标参数3:参数4:终止横纵坐标参数5:显示状态//输出://///////////////////////////////////void Lcd12864_DrawLine_Arbitrary(uchar x0,uchar y0,uchar x1,uchar y1,uchar color){int i,Distance;int x = 0,y = 0,DeltaX,DeltaY;char IncX,IncY; //取出斜率DeltaX = x1 - x0;DeltaY = y1 - y0;if(DeltaX > 0){IncX = 1;}else{IncX = -1;DeltaX = -DeltaX;}if(DeltaY > 0){IncY = 1;}else{IncY = -1;DeltaY = -DeltaY;}if(DeltaX > DeltaY){Distance = DeltaX;}else{Distance = DeltaY;}Lcd12864_DrawPoint(x0,y0,color);for(i = 0;i <= Distance + 1;i ++){Lcd12864_DrawPoint(x0,y0,color);x += DeltaX;y += DeltaY;if(x > Distance){x -= Distance;x0 += IncX;}if(y > Distance){y -= Distance;y0 += IncY;}}///////////////////////////////////////点位花图片函数(图片格式为横坐标32纵坐标30)///输入:参数1,图片指针,参数2,定位显示(固定)//输出://///////////////////////////////////void Lcd12864_PosDrawPhoto(uchar *photo,uchar pos){uchar Temp;uchar i,j;switch(pos){case 1: Temp = 0x80;break;case 2: Temp = 0x83;break;case 3: Temp = 0x86;break;case 4: Temp = 0x88;break;case 5: Temp = 0x8b;break;case 6: Temp = 0x8e;break;}for(i = 1;i < 31;i ++){Lcd12864_WrCom(0x80 + i); //纵坐标Lcd12864_WrCom(Temp); //横坐标for(j = 0;j < 4;j ++){Lcd12864_WrData(*photo ++);}}}。

玩转12864液晶屏(ST7920)

玩转12864液晶屏(ST7920)
在我们常用的人机交互显示界面中,除了数码管, LED,以及我们之前已经提到的 LCD1602 之外,还有一种液晶屏用的比较多。相信接触过单片机的朋友都知道了,那就是 12864 液晶。顾名思义,12864 表示其横向可以显示 128 个点,纵向可以显示 64 个点。我们 常用的 12864 液晶模块中有带字库的, 也有不带字库的, 其控制芯片也有很多种, 如 KS0108 T6963,ST7920 等等。在这里我们以 ST7920 为主控芯片的 12864 液晶屏来学习如何去驱动 它。(液晶屏采用金鹏的 OCMJ4X8C)
SET_READ SET_INC } void v_Lcd12864SendData_f( unsigned char byData ) //发送数据 { v_Lcd12864CheckBusy_f() ; SET_DATA SET_WRITE CLR_EN io_LCD12864_DATAPORT = byData ; _nop_(); _nop_(); SET_EN _nop_(); _nop_(); CLR_EN SET_READ SET_INC } void v_DelayMs_f( unsigned int nDelay ) { unsigned int i ; for( ; nDelay > 0 ; nDelay-- ) { for( i = 125 ; i > 0 ; i-- ) ; } } void v_Lcd12864Init_f( void ) { v_Lcd12864SendCmd_f( 0x30 ) ; v_DelayMs_f( 50 ) ; v_Lcd12864SendCmd_f( 0x01 ) ; v_DelayMs_f( 50 ) ; v_Lcd12864SendCmd_f( 0x06 ) ; v_DelayMs_f( 50 ) ; v_Lcd12864SendCmd_f( 0x0c ) ; } void v_Lcd12864SetAddress_f( unsigned char x, y ) { unsigned char byAddress ; switch( y ) { //延时

LCD12864绘图之KS0108(3)

LCD12864绘图之KS0108(3)

12864(KS0108)之绘图篇(三)常用几何图形绘制函数收集整理:杨正富(KL YZX-JDBDZZY-YZF)//画水平线: x0、x1为起始点和终点的水平坐标,y为垂直坐标void draw_Hline(uchar x0,uchar x1,uchar y,uchar color){uchar bak; //数据互换的中间变量,if(x0>x1){bak=x1;x1=x0;x0=bak;} //若x0>X1, 交换数据,使x1为大值do{draw_point(x0,y,color); //从左到右逐点显示x0++; //x0自加1}while(x1>=x0); //直到x0=x1为止}//画竖直线函数: x为起始点和终点的水平坐标,y0、y1为垂直坐标void draw_Vline(uchar x,uchar y0,uchar y1,uchar color){uchar bak; //数据互换的中间变量if(y0>y1){bak=y1;y1=y0;y0=bak;} //若y0>y1, 交换数据,使y1为大值do{draw_point(x,y0,color); //从上到下逐点显示y0++; //y0自加1}while(y1>=y0); //直到y0=y1为止}//任意两点间画直线:x0、y0为起始点坐标,x1、y1为终点坐标void draw_Rline(uchar x0,uchar y0,uchar x1,uchar y1,uchar color){int dx; //直线x轴差值变量int dy; //直线y轴差值变量char dx_sym; //x轴增长方向,为-1时减值方向,为1时增值方向char dy_sym; //y轴增长方向,为-1时减值方向,为1时增值方向int dx_x2; //dx*2值变量,用于加快运算速度int dy_x2; //dy*2值变量,用于加快运算速度int di; //决策变量/****************************画垂直线******************************/if(x0==x1) //如果水平坐标相等,则为垂直线{if(y0>y1) //若起点大于终点{dx=y0;y0=y1;y1=dx;} //交换数据(即交换起点)for(dx=y0;dx<y1+1;dx++) //从y0到y1逐点画线{draw_point(x0,dx,color); //画点}}/****************************画水平线******************************/if(y0==y1) //如果垂直坐标相等,则为水平线{if(x0>x1) //若起点横坐标大于终点{dy=x0;x0=x1;x1=dy;} //交换数据(即交换起点)for(dy=x0;dy<x1+1;dy++) //从X0到X1逐点画线{draw_point(dy,y0,color); //画点}}/****************************画斜线******************************/dx=x1-x0; //求取两点之间的差值dy=y1-y0;if(dx>0){dx_sym=1;} //判断x轴方向:dx>0,设置dx_sym=1 else if(dx<0){dx_sym=-1;} //判断x轴方向:dx<0,设置dx_sym=-1 if(dy>0){dy_sym=1;} //判断y轴方向:dy>0,设置dy_sym=1 else if(dy<0){dy_sym=-1;} //判断y轴方向:dy<0,设置dy_sym=-1 dx=dx_sym*dx; //将dx、dy取绝对值dy=dy_sym*dy;dx_x2=dx*2; //计算2倍的dx及dy值dy_x2=dy*2;/*************使用Bresenham法进行画直线**************************/if(dx>=dy) //对于dx>=dy,则使用x轴为基准{di=dy_x2-dx;while(x0!=x1){draw_point(x0,y0,color);x0+=dx_sym;if(di<0){di+=dy_x2;} //计算出下一步的决策值else{di+=dy_x2-dx_x2;y0+=dy_sym;}}draw_point(x0,y0,color); //显示最后一点}else //对于dx<dy,则使用y轴为基准{di=dx_x2-dy;while(y0!=y1){draw_point(x0,y0,color);y0+=dy_sym;if(di<0){di+=dx_x2;}else{di+=dx_x2-dy_x2;x0+=dx_sym;}}draw_point(x0,y0,color); //显示最后一点}}//画矩形rect: 矩形起左上顶点(x0,y0);右下顶点(x1,y1)void draw_rect(int x0, int y0, int x1, int y1,uchar color){int i;if(x0>x1){i=x0;x0=x1;x1=i;}if(y0>y1){i=y0;y0=y1;y1=i;}for(i=x0;i<x1+1;i++){draw_point(i,y0,color);draw_point(i,y1,color);}for(i=y0;i<y1+1;i++){draw_point(x0,i,color);draw_point(x1,i,color);}}//画实心矩形: 矩形起左上顶点(x0,y0);右下顶点(x1,y1)void draw_rectfill(int x0, int y0, int x1, int y1,uchar color){int i,j;if(x0>x1){i=x0;x0=x1;x1=i;}if(y0>y1){i=y0;y0=y1;y1=i;}for(i=y0;i<y1+1;i++){for(j=x0;j<x1+1;j++)draw_point(j,i,color);}}//画正方形函数: x0、y0为正方形左上角坐标,with正方形边长void draw_square(uchar x0,uchar y0,uchar with,uchar color){if(with == 0)return;if((x0+with)>127)return; //横轴超出液晶边界if((y0+with)>63)return;draw_rect(x0,y0,x0+with,y0+with,color);}//画填充正方形函数: x0、y0为正方形左上角坐标,with正方形边长void draw_squarefill(uchar x0,uchar y0,uchar with,uchar color){if(with==0) return;if((x0+with)>127)return; //横轴超出液晶边界if((y0+with)> 63)return;draw_rectfill(x0,y0,x0+with,y0+with,color);}//画圆函数: 圆心坐标(x1,y1),半径rvoid draw_circle(int x1,int y1,uint r,uchar color){int x=0, y=r, d=1-r; //计算初始值while(x<=y){////////绘制点(x,y)及其在八分圆中的另外7个对称点draw_point(x1+x,y1+y,color);draw_point(x1+y,y1+x,color);draw_point(x1-y,y1+x,color);draw_point(x1-x,y1+y,color);draw_point(x1-x,y1-y,color);draw_point(x1-y,y1-x,color);draw_point(x1+y,y1-x,color);draw_point(x1+x,y1-y,color);if(d<0){d+=2*x+3;} //根据误差项d的判断,决定非最大位移方向上是走还是不走else{d+=2*(x-y)+5;y--;}x++;}}//画实心圆: 圆心坐标(x1,y1),半径rvoid draw_circlefill(int x1, int y1, uint r,uchar color){int x,y,d;x=0;y=r;d=1-r; // 计算初始值while(x<=y){// 绘制点(x,y)及其在八分圆中的另外7 个对称点draw_Rline(x1+x,y1+y,x1-x,y1+y,color);draw_Rline(x1+x,y1-y,x1-x,y1-y,color);draw_Rline(x1+y,y1+x,x1-y,y1+x,color);draw_Rline(x1+y,y1-x,x1-y,y1-x,color);if(d<0)d+=2*x+3; // 根据误差项d 的判断,决定非最大位移方向上是走还是不走else{ d+=2*(x-y)+5;y--;}x++;}}//画正椭圆函数: 给定椭圆的四个点的参数,//最左、最右点的x轴坐标值为x0、x1,最上、最下点的y轴坐标为y0、y1.void draw_ellipse(char x0, char x1, char y0, char y1,uchar color){char draw_x0, draw_y0; // 刽图点坐标变量char draw_x1, draw_y1;char draw_x2, draw_y2;char draw_x3, draw_y3;char xx, yy; // 画图控制变量char center_x, center_y; // 椭圆中心点坐标变量char radius_x, radius_y; // 椭圆的半径,x轴半径和y轴半径int radius_xx, radius_yy; // 半径乘平方值int radius_xx2, radius_yy2; // 半径乘平方值的两倍char di; // 定义决策变量//参数过滤if((x0==x1)||(y0==y1)) return;//计算出椭圆中心点坐标center_x=(x0+x1)>>1;center_y=(y0+y1)>>1;//计算出椭圆的半径,x轴半径和y轴半径if(x0>x1) radius_x=(x0-x1)>>1;else radius_x=(x1-x0)>>1;if(y0>y1) radius_y=(y0-y1)>>1;else radius_y=(y1-y0)>>1;//计算半径平方值radius_xx = radius_x * radius_x;radius_yy = radius_y * radius_y;//计算半径平方值乘2值radius_xx2 = radius_xx<<1;radius_yy2 = radius_yy<<1;//初始化画图变量xx = 0;yy = radius_y;di = radius_yy2 + radius_xx - radius_xx2*radius_y ; // 初始化决策变量//计算出椭圆y轴上的两个端点坐标,作为作图起点draw_x0 = draw_x1 = draw_x2 = draw_x3 = center_x;draw_y0 = draw_y1 = center_y + radius_y;draw_y2 = draw_y3 = center_y - radius_y;draw_point(draw_x0, draw_y0, color); // 画y轴上的两个端点draw_point(draw_x2, draw_y2, color);while( (radius_yy*xx) < (radius_xx*yy) ){if(di<0)di+= radius_yy2*(2*xx+3);else{di+=radius_yy2*(2*xx+3)+4*radius_xx-4*radius_xx*yy;yy--;draw_y0--;draw_y1--;draw_y2++;draw_y3++;}xx ++; // x轴加1draw_x0++;draw_x1--;draw_x2++;draw_x3--;draw_point(draw_x0, draw_y0, color);draw_point(draw_x1, draw_y1, color);draw_point(draw_x2, draw_y2, color);draw_point(draw_x3, draw_y3, color);}di=radius_xx2*(yy-1)*(yy-1)+radius_yy2*xx*xx+radius_yy+radius_yy2*xx-radius_xx2*radius_yy; while(yy>=0){ if(di<0){ di+= radius_xx2*3 + 4*radius_yy*xx + 4*radius_yy - 2*radius_xx2*yy;xx ++; // x轴加1draw_x0++;draw_x1--;draw_x2++;draw_x3--;}else{ di += radius_xx2*3 - 2*radius_xx2*yy;}yy--;draw_y0--;draw_y1--;draw_y2++;draw_y3++;draw_point(draw_x0,draw_y0,color);draw_point(draw_x1,draw_y1,color);draw_point(draw_x2,draw_y2,color);draw_point(draw_x3,draw_y3,color);}}。

12864画点、画线、画圆、显示图片程序,亲测可用

12864画点、画线、画圆、显示图片程序,亲测可用

#include <reg52.h>#include <intrins.h>#define dataPort P0 //数据口sbit rs=P2^6; //寄存器选择输入sbit rw=P2^5; //液晶读/写控制sbit en=P2^7; //液晶使能控制sbit psb=P3^2; //串/并方式控制//sbit LCD_RST =P3^7; //液晶复位端口unsigned char code Photo1[] ={0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x3F,0xC0,0x80,0x42,0x04,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8A,0x1F,0xFC,0x42,0x04,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x80,0x01,0xFF,0xDE,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x2A,0x87,0xF0,0xA2,0x0A,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xBF,0x84,0x10,0xA2,0x0A,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x1F,0xFC,0xA2,0x0A,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9F,0x90,0x05,0x2F,0xCA,0xA4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x03,0xE1,0xA8,0x4A,0xA8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xBF,0xC2,0x24,0x48,0x44,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x92,0x84,0x24,0xA8,0x4A,0xA8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA6,0x58,0x3D,0x0F,0xD0,0xC4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x08,0x37,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0x08,0x40,0x00,0xFF,0x90,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x86,0x10,0x40,0x00,0x08,0x08,0x01,0x02,0x49,0x40,0x40,0x00,0x7F,0x0B, 0xFC,0x08,0x0F,0x00,0x00,0x00,0x00,0x00, 0x01,0x08,0x00,0x40,0x20,0x00,0x10,0x00, 0x10,0x49,0x0F,0x00,0x00,0x00,0x00,0x00, 0x02,0x08,0x00,0x20,0x20,0x01,0xFF,0xDD, 0x10,0x2A,0x0F,0x00,0x00,0x00,0x00,0x00, 0x04,0x31,0x83,0x20,0x20,0x00,0x20,0x04, 0x91,0xFF,0xC6,0x00,0x00,0x00,0x00,0x00, 0x04,0x52,0x44,0x90,0x20,0x00,0x7F,0x04, 0x90,0x1C,0x06,0x00,0x00,0x00,0x00,0x00, 0x09,0xA4,0x28,0x4C,0x10,0x00,0xA1,0x04, 0x10,0x2A,0x00,0x00,0x00,0x00,0x00,0x00, 0x0E,0x44,0xE9,0xC3,0x90,0x01,0x3F,0x04, 0x70,0x49,0x06,0x00,0x00,0x00,0x00,0x00, 0x00,0x82,0xC5,0x81,0x70,0x00,0x21,0x0A, 0x01,0x88,0xC6,0x00,0x00,0x00,0x00,0x00, 0x01,0x01,0x83,0x00,0x80,0x00,0x3F,0x11, 0xFC,0x08,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x0C,0x70,0x00,0x80,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x13,0x87,0x10,0x40,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x20,0x78,0xA0,0x40,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x20,0x00,0x60,0x40,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x21,0x80,0x60,0x40,0x00,0x00,0x71, 0xEE,0x3C,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x11,0x98,0x90,0x80,0x00,0x00,0x8E, 0x31,0xC6,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x08,0x18,0x80,0x80,0x00,0x01,0x24, 0x24,0x83,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x96,0x01,0x01,0x00,0x00,0x01,0x40, 0x28,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x49,0x86,0x03,0x00,0x00,0x01,0x40, 0x28,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x34,0x78,0x8C,0x00,0x00,0x01,0x00, 0x20,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x0E,0x01,0x30,0x00,0x00,0x00,0x80, 0x30,0x06,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x71,0x87,0xCE,0x00,0x00,0x00,0x40, 0x68,0x0C,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xE0,0x78,0x07,0x00,0x00,0x00,0x20,0x01,0xAF,0xFF,0xC5,0x80,0x00,0x00,0x11, 0x82,0x30,0x00,0x00,0x00,0x00,0x00,0x00, 0x03,0xA9,0xB6,0x45,0xC0,0x00,0x00,0x0B, 0x01,0x60,0x00,0x00,0x00,0x00,0x00,0x00, 0x07,0x2F,0x03,0xC4,0xE0,0x00,0x00,0x06, 0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, 0x0E,0x16,0x01,0x88,0x70,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x0F,0x08,0x00,0x10,0xF0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x0F,0x84,0x00,0x21,0xF0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };//89c51系列延时/*void delayms(unsigned int n){unsigned char i;for(;n>0;n--)for(i=0;i<100;i++);}*///12c5a系列延时void delayms(unsigned int a) //@11.0592MHz {unsigned char i, j;while(a--){_nop_();i = 11;j = 190;do{while (--j);} while (--i);}}//判断是否忙void checkBusy(void){rs=0;rw=1;en=1;dataPort=0xff;while(dataPort & 0x80);en=0;}//写指令函数void writeCommand(unsigned char cmd){checkBusy();rs=0;rw=0;en=1;dataPort=cmd;_nop_();en=0;}//写数据函数void writeData(unsigned char adata){checkBusy();rs=1;rw=0;en=1;dataPort=adata;_nop_();en=0;}//读数据函数unsigned char readData(void){unsigned char RData;dataPort=0xff;checkBusy();rs=1;rw=1;en=0;en=1;RData=dataPort;en=0;return RData;}//清除rom函数,若不清除则会出现花屏现象void ClrGDRAM(void){unsigned char x,y;for(y=0;y<64;y++)for(x=0;x<16;x++){writeCommand(0x34);writeCommand(y+0x80); //行地址writeCommand(x+0x80); //列地址writeCommand(0x30);writeData(0x00);writeData(0x00);}//writeCommand(0x30);}//lcd12864初始化函数void LcmInit(void){writeCommand(0x30);delayms(50);writeCommand(0x01);delayms(50);writeCommand(0x06);delayms(50);writeCommand(0x0c);ClrGDRAM();psb=1;}//在坐标(x,y)处显示字符串void LcmPrint(unsigned char x,unsigned char y,unsigned char *adata) {unsigned char address;unsigned char i=0;switch (y){case 0:address=0x80+x;break;case 1:address=0x90+x;break;case 2:address=0x88+x;break;case 3:address=0x98+x;break;default:break;}writeCommand(address);while(*(adata+i)){writeData(*(adata+i));i++;}}/*********************************************************** 函数名:disp_picture函数说明:显示一幅128*64的图画传入参数:图形指针*img传出参数:无返回值:无**********************************************************/ void disp_picture(unsigned char *img){unsigned char i,j;for(j=0;j<32;j++){for(i=0;i<8;i++){writeCommand(0x34);writeCommand(0x80+j);writeCommand(0x80+i);writeCommand(0x30);writeData(img[j*16+i*2]);writeData(img[j*16+i*2+1]);}}for(j=32;j<64;j++){for(i=0;i<8;i++){writeCommand(0x34);writeCommand(0x80+j-32);writeCommand(0x80+(i+8));writeCommand(0x30);writeData(img[j*16+i*2]);writeData(img[j*16+i*2+1]);}}writeCommand(0x36);}/*********************************************************** 函数名:dispU_picture函数说明:上半屏显示一幅128*32的图画传入参数:图形指针*img传出参数:无返回值:无**********************************************************/ /*void dispU_picture(unsigned char *img){unsigned char i,j;for(j=0;j<32;j++){for(i=0;i<8;i++){writeCommand(0x34);writeCommand(0x80+j);writeCommand(0x80+i);writeCommand(0x30);writeData(img[j*16+i*2]);writeData(img[j*16+i*2+1]);}}writeCommand(0x36);}*//*********************************************************** 函数名:dispD_picture函数说明:下半屏显示一幅128*32的图画传入参数:图形指针*img传出参数:无返回值:无**********************************************************/ /*void dispD_picture(unsigned char *img){unsigned char i,j;for(j=0;j<32;j++){for(i=0;i<8;i++){writeCommand(0x34);writeCommand(0x80+j);writeCommand(0x80+(i+8));writeCommand(0x30);writeData(img[j*16+i*2]);writeData(img[j*16+i*2+1]);}}writeCommand(0x36);}*//*********************************************************** 函数名:drawPoint函数说明:画点传入参数:打点位置(x0,y0);color=1,点亮;color=0,擦除传出参数:无返回值:无**********************************************************/ void drawPoint(unsigned char x,unsigned char y,unsigned char color) {unsigned char row,collum,cbite;unsigned char tempH,tempL;writeCommand(0x34);delayms(5);writeCommand(0x36);collum=x>>4;cbite=x&0x0f;if(y<32)row=y;else{row=y-32;collum+=8;}writeCommand(0x80+row);delayms(5);writeCommand(0x80+collum);readData();delayms(5);tempH=readData();tempL=readData();writeCommand(0x80+row);delayms(5);writeCommand(0x80+collum);if (color){if(cbite<8){tempH|=(1<<(7-cbite));//tempL=(1<<(7-cbite));}else{//tempH=(1<<(15-cbite));tempL|=(1<<(15-cbite));}}else{if(cbite<8){tempH&=~(1<<(7-cbite));//tempL=(1<<(7-cbite));}else{//tempH=(1<<(15-cbite));tempL&=~(1<<(15-cbite));}}writeData(tempH);writeData(tempL);writeCommand(0x30);}/***********************************************************函数名:drawRowLine函数说明:画水平线传入参数:(x0,y0),水平线的起点;(x1,y0)水平线的终点color=1,点亮;color=0,擦除传出参数:无返回值:无**********************************************************/void drawRowLine(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char color) {unsigned char temp;if(x0>x1) // 对x0、x1大小进行排列,以便画图{temp = x1;x1 = x0;x0 = temp;}do{drawPoint(x0, y0, color); // 逐点显示,描出垂直线x0++;}while(x1>=x0);}/***********************************************************函数名:drawCollumLine函数说明:画竖直线传入参数:(x0,y0),竖直线的起点;(x1,y0)竖直线的终点;color=1,点亮;color=0,擦除传出参数:无返回值:无************************************************************/void drawCollumLine(unsigned char x0,unsigned char y0,unsigned char y1,unsigned char color) {unsigned char temp;if(y0>y1){temp=y0;y0=y1;y1=temp;}while (y0<=y1){drawPoint(x0,y0,color);y0++;}}/*************************************************************函数名:drawLine函数说明:使用Bresenham法,画任意两点间的直线传入参数:(x0,y0),竖直线的起点;(x1,y1)竖直线的终点color=1,点亮;color=0,擦除传出参数:无返回值:无*************************************************************/void drawLine(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char color){int dx; // 直线x轴差值变量int dy; // 直线y轴差值变量char dx_sym; // x轴增长方向,为-1时减值方向,为1时增值方向char dy_sym; // y轴增长方向,为-1时减值方向,为1时增值方向int dx_2; // dx*2值变量,用于加快运算速度int dy_2; // dy*2值变量,用于加快运算速度int di; // 决策变量dx = x1-x0; // 求取两点之间的差值dy = y1-y0;if (dx<0) dx_sym=-1;else{if(dx>0) dx_sym=1;else{drawCollumLine(x0,y0,y1,color);return;}}if(dy>0) dy_sym=1;else{if(dy<0) dy_sym=-1;else{drawRowLine(x0,y0,x1,color);return;}}dx=dx_sym*dx;dy=dy_sym*dy;dx_2=dx*2;dy_2=dy*2;if(dx>=dy){di=dy_2-dx;while(x0!=x1){drawPoint(x0,y0,color);x0+=dx_sym;if(di<0) di+=dy_2;else {di+=dy_2-dx_2;y0+=dy_sym;}}drawPoint(x0,y0,color);}else{di=dx_2-dy;while(y0!=y1){drawPoint(x0,y0,color);y0+=dy_sym;if(di<0) di+=dx_2;else {di+=dx_2-dy_2;x0+=dx_sym;}}drawPoint(x0,y0,color);}}//画圆函数void drawRound(int x0,int y0,unsigned char r){int x=0,y=r;float d;d=1.25-r;while(x<=y){drawPoint(x0+x,y0+y,1);drawPoint(x0+x,y0-y,1);drawPoint(x0-x,y0+y,1);drawPoint(x0-x,y0-y,1);drawPoint(x0+y,y0+x,1);drawPoint(x0+y,y0-x,1);drawPoint(x0-y,y0+x,1);drawPoint(x0-y,y0-x,1);if(d<0)d+=x*2.0+3;else{d+=2.0*(x-y)+5;y--;}x++;}}//清屏函数void clr_screen(){writeCommand(0x34); //扩充指令操作delayms(5);writeCommand(0x30); //基本指令操作delayms(5);writeCommand(0x01); //清屏delayms(5);ClrGDRAM();}void main(void){delayms(500);//等待上电稳定LcmInit();while(1){drawPoint(10,20,1);delayms(1000);clr_screen();delayms(1000);drawCollumLine(20,2,50,1);delayms(1000);clr_screen();delayms(1000);drawRowLine(10,3,50,1);delayms(1000);clr_screen();delayms(1000);drawLine(1,1,30,20,1);delayms(1000);clr_screen();delayms(1000);LcmPrint(1,20,"哈哈kkkah");delayms(1000);clr_screen();delayms(1000);drawRound(64,32,20);delayms(1000);clr_screen();delayms(1000);disp_picture(Photo1);delayms(1000);clr_screen();delayms(1000);}}。

12864画点教程(保留)

12864画点教程(保留)

基于ST7920控制的12864液晶用于字符显示很方便的,但网友说用它显示图形并不合适,原因就是它绘图时先要关闭显示,绘完后又要打开,速度会较慢。

我没有用过别的液晶,手中只有这一款,摆弄了几天,掌握了一点东西,写出来共享。

首先,我们知道,图形都是由像素点组成的,绘图的基础其实就是画点。

只要我们能点亮液晶的任意一个像素点,那么绘图就不是什么难事了。

万丈高楼平地起嘛,先要做的,当然是要打好基础。

ST7920提供了用于绘图的GDRAM(graph display RAM)。

共64×32个字节的空间(由扩充指令设定绘图 R AM 地址),最多可以控制256×64点阵的二维绘图缓冲空间。

在它的Datasheet给出了GDRAM的坐标地址对照表:(原文件名:图片1.png)引用图片用坐标表示,就是这样:(原文件名:图片2.png)引用图片它的横坐标每一个地址都是16 位的。

共16个地址,256位。

很明显,它能控制256*64像素的液晶屏,而我们的只是128*64像素液晶屏,显然只用到它的一部分。

我刚开始以为它对应屏幕的绘图RAM是这样分布的(如红色部分):(原文件名:图片3.png)引用图片结果栽了大根头,后来终于弄明白,原来它对应屏幕的GDRAM是这样分布的:汗,发了一半不小心提交了,继续(原文件名:图片4.png)引用图片只要我们清楚了它的GDRAM和屏幕上像素点的映射(对应)关系,点亮对应的像素点就容易多了。

要点亮某一个像素点,就是将这个像素点在GDRAM中对应的位置1,这个相信没人会不知道吧?我们先讨论一下思路,再一步步写代码。

我觉得,思路要比代码重要的多,只要你的思路通了,正确了,那么写出代码肯定会很容易。

首先,给你x,y的坐标,要你点亮一个点,要怎么做呢?从上面的图我们知道,它是分为两个半屏的,首先,我们要确定这个点是在上半屏还是下半屏,然后确定它是在那一行(纵坐标Y),再确定它是在哪一个字节的哪一个位(也就是确定它在那一列,即横坐标X)。

12864画图

12864画图

1、打点部分/********************************************************名称:GUI_Point(打点)说明:X:横坐标(代表列的位置,0~127) Y:纵坐标(代表行的位置,0~63) 根据Datesheet需先把数据写到GDRAM,读取当前位置的数据,经过或和移位后再把数据重新写入GDRAM每行有16个位元,共64行,每个位元有两个8位(高低8位) 计算出在那个位元,在该位元的哪一位易出现的问题:1、打点位置的定位2、读取当前显示的数据3、或和移位,即重新写人的新数据********************************************************/void GUI_Point(uchar x,uchar y,uchar flag){uchar x_Dyte,x_byte; //定义列地址的字节位,及在字节中的哪1位uchar y_Dyte,y_byte; //定义为上下两个屏(取值为0,1),行地址(取值为0~31)Write_command(0x36); //绘图模式命令/***X,Y坐标互换,即普通的X,Y坐标***/x_Dyte=x/16; //计算在16个字节中的哪一个x_byte=x&0x0f; //计算在该字节中的哪一位y_Dyte=y/32; //0为上半屏,1为下半屏y_byte=y&0x1f; //计算在0~31当中的哪一行Write_command(0x80+y_byte); //设定行地址(y坐标)Write_command(0x80+x_Dyte+8*y_Dyte); //设定列地址(x坐标),并通过8*y_D yte选定上下屏Read_data();GDRAM_hbit=Read_data(); //读取当前显示高8位数据GDRAM_lbit=Read_data(); //读取当前显示低8位数据delay_us(5);if(flag==1){Write_command(0x80+y_byte); //设定行地址(y坐标)Write_command(0x80+x_Dyte+8*y_Dyte); //设定列地址(x坐标),并通过8*y _Dyte选定上下屏delay_us(5);if(x_byte<8) //判断其在高8位,还是在低8位{Write_data(GDRAM_hbit|(0X01<<(7-x_byte))); //显示GDRAM区高8位数据 Write_data(GDRAM_lbit); //显示GDRAM区低8位数据}else{Write_data(GDRAM_hbit);Write_data(GDRAM_lbit|(0x01<<(15-x_byte)));}}else{Write_data(0x00); //清除GDRAM区高8位数据Write_data(0x00); //清除GDRAM区低8位数据}}2、画线部分先看程序/********************************************************* 名称:GUI_Line()采用布兰森汉姆(Bresenham)算法画线* 功能:任意两点间的直线。

lcd12864画点线程序

lcd12864画点线程序

LCD.H#ifndef __LCD_H__#define __LCD_H__#include <reg51.h>#include <intrins.h>#include"def.h"#include<math.h>#define LCD_data P0 //数据口sbit LCD_RS = P1^0; //寄存器选择输入sbit LCD_RW = P1^1; //液晶读/写控制sbit LCD_EN = P1^2; //液晶使能控制sbit LCD_PSB = P1^6; //串/并方式控制#define BASIC_SET 0x30#define EXTEND_SET 0x34#define DRAW_ON 0x36#define DRAW_OFF 0x34//void delay1ms(uchar z);void delay70us(uchar z);voidlcd_write_cmd(ucharcmd);voidlcd_write_data(uchardat);voidlcd_pos(ucharX,uchar Y);voidlcd_init();ucharlcd_read_data();voidlcd_set_dot(ucharx,uchar y);voidlcd_clc_GDROM();voidGUI_XLine(uchar x0,uchar y0,uchar x1,uchar y1); voidGUI_YLine(uchar x0,uchar y0,uchar x1,uchar y1); void GUI_Line8(uchar x0,uchar y0,uchar x1,uchar y1); #endifdef.h#ifndef __DEF_H_#define __DEF_H_#define uchar unsigned char#define uint unsignedint#endifLcd画点线.c#include"lcd.h"void delay70us(uchar z){uchari,j;for(i=0;i<z;i++){for(j=0;j<10;j++){_nop_();}}}/********************************************************** *********//**//*写指令数据到LCD *//*RS=L,RW=L,E=高脉冲,D0-D7=指令码。

12864多功能程序实现

12864多功能程序实现

/*以下程序是自己在做天津市TI电设时调试的12864程序,每一部分都亲自调试过,功能都可以实现,建议使用者先花一点时间把程序看懂,不是很难。

程序里有许多注释掉的函数,都是相关的一些测试函数,使用者可根据需要,解冻相关测试函数,来调试一下功能。

当然,前提还是你要先熟悉一下全部的程序结构,不然很可能改动出现错误。

实现功能:画点,画线(水平线、垂直线、任意指定首尾坐标的斜线、折线)、画圆,键盘控制上下左右来画任意图形,以及指定一初始点后按使用者指定的路径自动完成一副图形(譬如矩形、三角形,更复杂的可由使用者继续优化算法。

)*/#include <stdio.h>#include <math.h>#include <reg52.h>#include <string.h>/******************************************************************//* 定义接口信息*//******************************************************************/sbit RS =P2^4; // 并行:指令(H)/数据(L)选择;串行:片选信号(CS)sbit WRD=P2^5; //并行:读写选择;串行:数据口(SID)sbit E= P2^6; // 并行:使能信号;串行:时钟信号(SLK)sbit PSB=P2^1; // 选择并口或者串口工作模式sbit RES=P2^3; // 复位信号,低电平有效sbit key1=P3^0; //定义按键位置sbit key2=P3^1;sbit key3=P3^2;sbit key4=P3^3;/******************************************************************//* 定义数组*//******************************************************************/unsigned char code pic2[];void TransferData(char data1,bit DI);void display(void);void delayms(unsigned int n);void delay(unsigned int m);/******************************************************************//* 液晶初始化-图形*//******************************************************************/void initina2(void) //LCD显示图片(扩展)初始化程序{delay(40); //大于40mS的延时程序PSB=1; //设置为8BIT并口工作模式delay(1); //延时RES=0; //复位delay(1); //延时RES=1; //复位置高delay(10);TransferData(0x36,0); //Extended Function Set RE=1: extended instructiondelay(100); //大于100uS的延时程序TransferData(0x36,0); //Extended Function Set:RE=1: extended instruction setdelay(37); ////大于37uS的延时程序TransferData(0x3E,0); //EXFUNCTION(DL=8BITS,RE=1,G=1)delay(100); //大于100uS的延时程序TransferData(0x01,0); //CLEAR SCREENdelay(100); //大于100uS的延时程序}/****************************************************************************** **///图形区清RAM函数/****************************************************************************** */void LCD_ClearBMP( void ){unsigned char i,j;TransferData(0x34,0); //8Bit扩充指令集,即使是36H也要写两次TransferData (0x36,0); //绘图ON,基本指令集里面36H不能开绘图for(i=0;i<32;i++) //12864实际为256x32{TransferData(0x80|i,0); //行位置TransferData(0x80,0); //列位置for(j=0;j<32;j++) //256/8=32 byteTransferData(0,1);}}/******************************************************************//******************************************************************/ void v_Lcd12864CheckBusy_f( void ) //忙检测函数{unsigned int nTimeOut = 0;P0 = 0x80 ;//P0=0x80WRD= 1 ; //io_LCD12864_RW= 1,读RS=0; //io_LCD12864_RS=0,指令E=0 ; //io_LCD12864_EN=0,E=1 ; //io_LCD12864_EN=1,使能while((P0==0x80)&&(++nTimeOut!=0));//在P0==0x80时,等待E=0; //io_LCD12864_EN=0,}// 读取一个字节unsigned char u8_Lcd12864ReadByte_f( void ){unsigned char byReturnV alue ;v_Lcd12864CheckBusy_f();P0 = 0xff ;//P0=0xffRS=1; //RS=1,指令WRD=1; //RW=1,读E=0; //EN=0E=1; //EN=1byReturnV alue = P0 ;//byReturnV alue=P0delay(1);E=0; //EN=0;return byReturnV alue;}/******************************************************************//******************************************************************/void TransferData(char data1,bit DI) //传送数据或者命令,当DI=0是,传送命令,当DI=1,传送数据.{//char buffer;WRD=0;RS=DI;delay(1);//buffer = data1;//P0 = buffer;P0 = data1;/*count++;if(count == 14){P0= 0x00;count=0;} */E=1;delay(1);E=0;}/****************************************************************************** ********/// 延时函数/****************************************************************************** ********/void delayms(unsigned int n) //延时10×n毫秒程序{unsigned int i,j;for(i=0;i<n;i++)for(j=0;j<2000;j++);}void delay(unsigned int m) //延时程序{unsigned int i,j;for(i=0;i<m;i++)for(j=0;j<10;j++);}/******************************************************************/// 画点函数/******************************************************************/ void v_Lcd12864DrawPoint_f( unsigned char X, unsigned char Y, unsigned char Color ) {unsigned char Row,Tier,Tier_bit;//Tier_bit的作用:确定该位置是低八位,还是高八位unsigned char ReadOldH, ReadOldL ;TransferData( 0x34,0 ) ; //使用扩充指令集delay(1);TransferData( 0x36,0 ) ; //使用扩充指令集,图像显示开?delay(1);Tier = X >> 4 ;//X的范围是0-127,即0x7f.Tier 除以16,获取它的字。

12864 点,线,圆,图

12864 点,线,圆,图
sbit lcd_en =P2^7; // EN使能
sbit lcd_psb=P2^2; //PSB并行串行选择
void LCD_graphic_display(uchar,uchar,uchar code *addre_gra); //图形显示函数
void LCD_DDA_line(uchar,uchar,uchar,uchar,uchar); //DDA算法画直线函数
void LCD_draw_dot(uchar,uchar,uchar); //画点函数
void LCD_clear_CGRAM(); //绘图清零
uchar LCD_read(); //读数据函数
void LCD_BF(); //忙标志位检测函数
void LCD_init(); //12864的初始化函数
函 数 名:LCD_init
函数功能:12864的初始化
进入参数:无
返回************************************************************************/
void LCD_init() //LCD的字符初始化程序
LCD_write(0x30,0); //功能设定 8位数据操作
delay(10);
LCD_write(0x30,0); //功能设定 8位数据操作
{
_nop_();
_nop_();
_nop_();
}
/*************************************************************************
函 数 名:delay
  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 ; }
相关文档
最新文档