本帖最后由 学电子 于 2013-3-18 09:43 编辑
以下是我的程序。其中遇到了一点问题,请高手帮帮忙,指点指点。
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define LCD_data P0
sbit wela=P2^7;
sbit dula=P2^6;
sbit LCD_EN=P3^4;
sbit LCD_RS=P3^5;
sbit LCD_RW=P3^6;
sbit LCD_PSB=P3^7;
uchar code num1[]={0x00,0x00,0x00,0x38,0x00,0x78,0x00,0xF8,0x01,0xF8,0x01,0xF8,0x00,0x78,0x00,0x78,
0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,
0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,
0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x00};
/***************************************************************
以下是关于12864的子程序
***************************************************************/
void delay(uint z) //延时函数
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void check_lcd_busy() //忙检测
{
LCD_RS=0;
LCD_RW=1;
LCD_EN=1;
LCD_data=0xff;
while((LCD_data&0x80)==0x80);
LCD_EN=0;
}
void write_cmd(uchar cmd) //12864写指令
{
check_lcd_busy();
LCD_RS=0;
LCD_RW=0;
LCD_EN=0;
P0=cmd;
delay(5);
LCD_EN=1;
delay(5);
LCD_EN=0;
}
void write_dat(uchar dat) //12864写数据
{
check_lcd_busy();
LCD_RS=1;
LCD_RW=0;
LCD_EN=0;
P0=dat;
delay(5);
LCD_EN=1;
delay(5);
LCD_EN=0;
}
void clear_GDRAM() //清除GDRAM,防止花屏
{
uchar i,j;
write_cmd(0x34);
write_cmd(0x30);
write_cmd(0x0c);
write_cmd(0x06);
write_cmd(0x34);
for(j=0;j<32;j++)
{
write_cmd(0x80+j);
write_cmd(0x80);
for(i=0;i<16;i++)
{
write_dat(0x00);
write_dat(0x00);
}
}
}
void display_bmp(uchar x,uchar *bmp) //显示16*32的数字
{
uchar i,j,X;
X=0x80+x;
write_cmd(0x36);
for(i=0;i<16;i++)
{
write_cmd(0x90+i);
write_cmd(X);
for(j=0;j<2;j++)
write_dat(*bmp++);
}
for(i=0;i<16;i++)
{
write_cmd(0x80+i);
write_cmd(X+8);
for(j=0;j<2;j++)
write_dat(*bmp++);
}
write_cmd(0x36);
}
void lcd_init() //12864初始化
{
LCD_PSB=1;
write_cmd(0x30);
write_cmd(0x0c);
write_cmd(0x01);
write_cmd(0x06);
}
/***************************************************************
以下是主函数
***************************************************************/
void main()
{
wela=0;
dula=0;
delay(10);
lcd_init();
clear_GDRAM(); //如果把这句代码取消,屏幕显示花屏。但是如果加上这句,显示的特别慢。why????
while(1)
{
display_bmp(0,num1);
display_bmp(1,num1);
display_bmp(2,num1);
display_bmp(3,num1);
display_bmp(4,num1);
display_bmp(5,num1);
display_bmp(6,num1);
display_bmp(7,num1);
}
}
刚才试过了,一下子就快了,原来是延时时间太长了。
不愧是高手!!!一针见血!!!感谢感谢!!!
液晶采用串口通讯方式
*********************************************************/
#ifndef __LCD12864_H__
#define __LCD12864_H__
#define uchar unsigned char
#define uint unsigned int
#include "zk.h"
#include "shengming.h"
/*========================定义12864液晶屏数据线=====================================*/
sbit LCM_PSB = P1^3; //
/*========================定义12864液晶屏数据线=====================================*/
sbit cs2=P1^4 ;
sbit LCM_cs = P2^3;
sbit LCM_std = P2^4;
sbit LCM_sclk = P2^5;/*==========================12864液晶显示屏并口驱动程序=============================*/
//===========检查忙位
void Delay123(int num)//延时函数
{
while(num--);
}
void LCM_WriteDatOrCom(bit dat_comm,uchar content)
{
uchar a,i,j;
Delay123(10);
a=content ;
LCM_cs=1;
LCM_sclk=0;
LCM_std=1;
for(i=0;i<5;i++)
{
LCM_sclk=1;
LCM_sclk=0;
}
LCM_std=0;
LCM_sclk=1;
LCM_sclk=0;
if(dat_comm)
LCM_std=1; //data
else
LCM_std=0; //command
LCM_sclk=1;
LCM_sclk=0;
LCM_std=0;
LCM_sclk=1;
LCM_sclk=0;
for(j=0;j<2;j++)
{
for(i=0;i<4;i++)
{
a=a<<1;
LCM_std=CY;
LCM_sclk=1;
LCM_sclk=0;
}
LCM_std=0;
for(i=0;i<4;i++)
{
LCM_sclk=1;
LCM_sclk=0;
}
}
}
void lcd_pos(uchar X,uchar Y)//设定显示位置
{
uchar pos;
if (X==1)
{X=0x80;}
else if (X==2)
{X=0x90;}
else if (X==3)
{X=0x88;}
else if (X==4)
{X=0x98;}
pos = X+Y ;
LCM_WriteDatOrCom(0,pos); //显示地址
}
//================写指令到LCD=============================
void write_com(uchar cmdcode)
{
LCM_WriteDatOrCom(0,cmdcode);
}
//=================写数据到LCD==============================
void write_data(uchar Dispdata)
{ LCM_WriteDatOrCom(1,Dispdata);
}
//==========向LCM发送一个字符串,长度64字符之内============
void lcm_w_word(uchar *s)
{
while(*s>0) { write_data(*s); s++; } //应用:lcm_w_word("您好!");
}
/**************在X(行)Y(列)显示字符串********************/
void LCD_Display_String( uchar x,uchar y,uchar *str )
{
lcd_pos(x,y); //先确定起始行和列
while (*str!=' ')
{
write_data(*str);
str++;
}
}
void LCD_Display_Array( uchar x,uchar y,uchar *Array,uchar Lenth )
{
lcd_pos(x,y); //先确定起始行和列
while(Lenth--)
{
write_data(*Array);
Array++;
}
}
/******************************************************************************/
void lcm_w_test(bit i,unsigned char word){//写指令或数据(被调用层)
if(i == 0){
write_com(word);//写指令(0,指令)
}else{
write_data(word);//写数据(1,数据)
}
}
//===========清屏函数=====================================
void lcm_clr(void)
{
write_com(0x30);
write_com(0x01);
delayms(5);
}
//=========================================================
void lcm_clr2(void){//清屏上面3行(用空格填满要清显示的地方,因为液晶屏是静态显示的,所以这办法常用)
lcm_w_test(0,0x80);//第一行
lcm_w_word(" ");
//标尺("1234567812345678"应该能够显示满一行)
lcm_w_test(0,0x90);//第二行
lcm_w_word(" ");
//标尺("1234567812345678"应该能够显示满一行)
lcm_w_test(0,0x88);//第一行
lcm_w_word(" ");
//标尺("1234567812345678"应该能够显示满一行)
}
//==================初始化LCD屏===============================
void lcm_init()
{
write_com(0x30); //选择8bit数据流
write_com(0x0c); //开显示(无游标、不反白)
lcm_clr(); //清除显示,并且设定地址指针为00H
write_com(0x06); //光标右移,DDRAM位址计数器(AC)加1,不整屏移动
lcm_clr2();
}
/*-------------------使用绘图的方法让一个16*16的汉字符反白---------------------------
形式参数:uchar x,uchar y,uchar wide,uchar bkcor
行参说明:坐标水平位置,坐标垂直位置,反白行数,要反白还是清除(1:反白,0:清除)
-----------------------------------------------------------------------------------*/
void write1616GDRAM(uchar x,uchar y,uchar sign,uchar *bmp)
{
uchar i,j,basex;
write_com(0x36); //扩展指令,绘图模式命令,开显示也可以绘.(关图片显示0x34)
if(y==1||y==2) //第一第二行
{
basex=0x80; //上半屏
y=(y-1)*16; //垂直位址从0X80开始.
}
if(y==3||y==4) //第三第四行
{
basex=0x88; //下半屏
y=(y-3)*16; //垂直位址都是从0X80开始的,不管上下半屏。
}
for(i=0;i<16;i++) //
{
write_com(0x80+y+i); //写入垂直位址。
write_com(basex+x-1); //再写入水平位址(上半屏第一字为0X80,……第七字为0X87)
//下半屏第一字为0X88,……第七字为0X8F;
for(j=0;j<2;j++) //再写入两个8位元的数据,AC会自动增一,接着写数据
{
if(sign==1)
write_data(~(*bmp++));
else
write_data(*bmp++);
}
}
write_com(0x36); //写完数据,开图片显示
}
/**********************************************************
//函数功能:使用绘图的方法让一行反白
//形式参数:uchar row,uchar bkcor
//行参说明:反白行数,要反白还是清除(1:反白,0:清除反白)
//返回参数:无
//使用说明:无
//**********************************************************/
void setrowbkcolor(uchar row,uchar bkcor)
{
uchar i,j,basex,basey,color;
if(bkcor==1) color=0xff; //全写入0XFF,反白。
if(bkcor==0) color=0x00; //全写入0X00,消白。
write_com(0x36); //扩展指令,写图片时,关图片显示
if(row==1||row==2) //第一第二行
{
basex=0x80; //上半屏
}
if(row==3||row==4) //第三第四行
{
basex=0x88; //下半屏
row=row-2; //垂直位址都是从0X80开始的,不管上下半屏。
}
basey=0x80+(row-1)*16; //从哪一行的首行点阵开始
for(i=0;i<16;i++) //一行有16行点阵
{
write_com(basey+i); //写入垂直位址。
write_com(basex); //水平位址(上半屏第一字为0X80)//下半屏第一字为0X88;
for(j=0;j<16;j++) //再写入两个8位元的数据,AC会自动增一,接着写数据
write_data(color);
}
write_com(0x36); //写完数据,开图片显示
}
/*=====================================================================================
函数功能:显示16X32图形,适用于st7920型液晶
形式参数:uchar x,uchar y,uchar *bmp
行参说明:横坐标X列,纵坐标Y行,要显示的图形BMP
=====================================================================================*/
void write1632GDRAM(uchar x,uchar y,uchar *bmp)
{
uchar i,j,basex,basey;
switch(y) //由y纵坐标定是上半屏还是下半屏
{
case 1: basex=0x80; break; //上半屏
case 2: basex=0x80; break; //先上半屏,下面再下半屏。
case 3: basex=0x88; break; //下半屏
default: return; //别的则返回
}
basey=basex+x-1;
write_com(0x36);
if(y==1||y==3) //如为第一第三行,则直接是在同一半屏,直接绘完32行点陈数据。
{
for(i=0;i<32;i++) //写入32行点阵
{
write_com(0x80+i); //先写入垂直位址,选上下32行的哪一行,
//不管上下半屏,首行都为0X80
write_com(basey); //再写入水平位址(选上下半屏)
for(j=0;j<2;j++) //2个8位元的数据,即16BIT宽度
write_data(*bmp++);
}
}
if(y==2) //从第二行开始则画图将上下半屏都有,所以先画完上半屏16行,再画下半屏16行。
{
for(i=0;i<16;i++) //写入上半屏16行点阵
{
write_com(0x90+i); //先写入垂直位址,选上下32行的哪一行,不管上下半屏,
//首行都为0X80,第二行为0X90。
write_com(basey); //(选上半屏)再写入水平位址
for(j=0;j<2;j++) //2个8位元的数据,即16BIT宽度
write_data(*bmp++);
}
for(i=0;i<16;i++) //写入下半屏16行点阵
{
write_com(0x80+i); //先写入垂直位址,选上下32行的哪一行,不管上下半屏,首行都为0X80
write_com(basey+8); //(选下半屏)再写入水平位址
for(j=0;j<2;j++) //2个8位元的数据,即16BIT宽度
write_data(*bmp++);
}
}
write_com(0x36); //写完数据,开图片显示
}
/*=====================================================================================
函数名称: init_12864_GDRAM()
功能描述: 在程写GDRAM时序初始化12864
=====================================================================================*/
void init_12864_GDRAM()
{
write_com(0x30); //基本指令操作(扩充指令操作为:0x34)
write_com(0x0C); //整体显示ON,游标OFF,游标位置OFF
write_com(0x06); //光标右移,DDRAM位址计数器(AC)加1,不整屏移动
lcm_clr(); //清屏 (清DDRAM)
}
/*======================================================================================
函数名称:Clean_12864_GDRAM(void)
函数功能:清屏函数
使用说明:GDRAM填满0
=======================================================================================*/
void Clean_12864_GDRAM(void)
{
uchar x,y;
write_com(0x36);
init_12864_GDRAM(); //设置扩展指令集,按手册说明,仅设置了绘图位,
write_com(0x36); //需要两次,本次设置扩展指令集。
for (y=0;y<32;y++)
{
write_com(0x80+y); //设置y=1000+00xx,y+1则往下一行
write_com(0x80); //设置x=1000 0000
for (x=0;x<16;x++)
{
write_data(0x00); //高字节数据
write_data(0x00); //低字节数据
}
}
}
/*------------------显示图片------------------------*/
void Disp_Img(unsigned char code *img)
{ unsigned int j=0;
unsigned char x,y,i;
for(i=0;i<9;i+=8)
for(y=0;y<32;y++)//原来 为 y<26 ,上下两个半屏不能正常对接显示,导致显示的图片中间有空隙
for(x=0;x<8;x++)
{ write_com(0x36);//功能设置---8BIT控制界面,扩充指令集
write_com(y+0x80); //行地址
write_com(x+0x80+i); //列地址
write_com(0x30);
write_data(img[j++]); //写数据还要回到基本指令集
write_data(img[j++]);
}
}
/*=======================================================================================*/
#endif
慢慢找吧。
Clean_12864_GDRAM(); //清屏
write1632GDRAM(地址,地址,字符(第几个));
我用串口的都不慢
一周热门 更多>