#include "12864.h"
#include "delay.h"
//#include "lcd_table.h"
/*************************************************************************************
需要实现
从数据线读数据函数(拼凑)
向数据线写数据函数(拼凑)
写命令/数据函数
点亮任意位置一个点
2015年4月14日完成
2015年4月17日修改
更换方法实现画点函数
实现一个[32][32]RAM缓冲区
格式如下
//[0]0 1 2 3 ... 31(字节)
//[1]0 1 2 3 ... 31(字节)
//[2]0 1 2 3 ... 31(字节)
//[3]0 1 2 3 ... 31(字节)
将此缓冲区直接更新到GDRAM中即可
*************************************************************************************/
/*************************************************************************************
LCD12864
LCD_RS PB1
LCD_RW PE3
LCD_EN PE4
LCD_PSB PE5
LCD_RST 接到板子RST上
LCD_D0 PE6
LCD_D1 PF6
LCD_D2 PF11
LCD_D3 PG6
LCD_D4 PG7
LCD_D5 PG8
LCD_D6 PG12
LCD_D7 PG15
LCD_BL PB0
************************************************************************************/
uint8_t xdata LCD_GRAM[32][32];
//数据格式
//D7 D6 D5 D4 D3 D2 D1 D0
uint8_t ReadByteFromLCD(void)
{
uint8_t res=0;
P0=0xFF;
res=P0;
return res;
}
void WriteByteToLCD(uint8_t byte)
{
P0=byte;
}
/*************************************************************************************
************************************************************************************/
/*************************************************************************************
LCD判忙函数
1:忙
0:不忙
************************************************************************************/
uint8_t LCD_Busy(void)
{
uint8_t res=0;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
delay_us(5);
//读数据
res=(ReadByteFromLCD()&0x80);
LCD_EN = 0;
return res;
}
//写指令/数据到LCD
void WriteToLCD(uint8_t mode,uint8_t byte)
{
if(mode==LCD_CMD)//写指令
{
while(LCD_Busy());
LCD_RS = 0;//指令
LCD_RW = 0;//写
LCD_EN = 0;
delay_us(5);
WriteByteToLCD(byte);//写
delay_us(5);
LCD_EN = 1;
delay_us(5);
LCD_EN = 0;
}else //写数据
{
while(LCD_Busy());
LCD_RS = 1;//数据
LCD_RW = 0;
LCD_EN = 0;
delay_us(5);
WriteByteToLCD(byte);//写
delay_us(5);
LCD_EN = 1;
delay_us(5);
LCD_EN = 0;
}
}
void LCD12864_Init(void)
{
LCD_PSB=1;
WriteToLCD(LCD_CMD,0x34);//扩充指令操作
delay_ms(100);
WriteToLCD(LCD_CMD,0x30);//基本指令操作
delay_ms(100);
WriteToLCD(LCD_CMD,0x0C);//显示开,关光标
delay_ms(100);
WriteToLCD(LCD_CMD,0x01);//清LCD
delay_ms(5);
}
void LCD_Clear(void)
{
WriteToLCD(LCD_CMD,0x01);//清LCD
delay_ms(5);
}
//设定显示位置
//x=0-3,y=0-7
//128*64=16*8*16*4
void LCD_SetCursor(uint8_t x,uint8_t y)
{
if (x==1)
{x=0x80;}
else if (x==2)
{x=0x90;}
else if (x==3)
{x=0x88;}
else if (x==4)
{x=0x98;}
WriteToLCD(LCD_CMD,x+y); //显示地址
}
void LCD_ShowString(uint8_t x,uint8_t y, uint8_t *s)
{
LCD_SetCursor(x,y);
while(*s!='\0')
{
WriteToLCD(LCD_DATA,*s++);
}
*s=0;
}
//画点函数
/*
GDRAM分布
256(16*16) X
|-----------------------------|-----------------------------------|
|0 | |
| 上半屏128*32 | 下半屏128*32 |
Y|32 | |
|-----------------------------|-----------------------------------|
水平x坐标每隔16个点才有一个位址,因此改变某个点需要知道该点位于这16个点的哪个位置
垂直y坐标在大于31时处于下半屏,小于31处于上半屏
*/
//x:0-127
//y:0-63
//mode:1,画点
//mode:0,清空
void LCD_DrawPoint(uint8_t x,uint8_t y,uint8_t mode)
{
//判断处于哪行哪列
uint8_t x_pos,x_bit;//x_pos用来判断处于位址,x_bit用来判断处于位址中的位置
uint8_t y_pos,y_bit;//y_pos用来判断处于上半屏还是下半屏 y_bit用来判断位于哪行
// uint8_t x_pos_temp;
// if((x>127)||(y>63)||(x<0)||(y<0))return;//去掉不合理参数
y_pos=y/32; //0:上半屏;1:下半屏
y_bit=y%32; //得到具体行位置
x_pos=x/16;
x_bit=x%16;
if(y_pos>0)//下半屏
{
if(mode)
{
if(x_bit<8)
{
LCD_GRAM[y_bit][x_pos*2+16]|=(1<<(7-x_bit));
LCD_GRAM[y_bit][x_pos*2+1+16]|=0x00;
}else
{
LCD_GRAM[y_bit][x_pos*2+16]|=0x00;
LCD_GRAM[y_bit][x_pos*2+1+16]|=(1<<(15-x_bit));
}
}
else
{
if(x_bit<8)
{
LCD_GRAM[y_bit][x_pos*2+16]&=~(1<<(7-x_bit));
LCD_GRAM[y_bit][x_pos*2+1+16]&=~0x00;
}else
{
LCD_GRAM[y_bit][x_pos*2+16]&=~0x00;
LCD_GRAM[y_bit][x_pos*2+1+16]&=~(1<<(15-x_bit));
}
}
}else//上半屏
{
if(mode)
{
if(x_bit<8)
{
LCD_GRAM[y_bit][x_pos*2]|=(1<<(7-x_bit));
LCD_GRAM[y_bit][x_pos*2+1]|=0x00;
}else
{
LCD_GRAM[y_bit][x_pos*2]|=0x00;
LCD_GRAM[y_bit][x_pos*2+1]|=(1<<(15-x_bit));
}
}
else
{
if(x_bit<8)
{
LCD_GRAM[y_bit][x_pos*2]&=~(1<<(7-x_bit));
LCD_GRAM[y_bit][x_pos*2+1]&=~0x00;
}else
{
LCD_GRAM[y_bit][x_pos*2]&=~0x00;
LCD_GRAM[y_bit][x_pos*2+1]&=~(1<<(15-x_bit));
}
}
}
// LCD_Refresh_GRAM();
}
////在指定位置显示一个字符,包括部分字符
////x:0~127
////y:0~63
////mode:0,反白显示;1,正常显示
////size:选择字体 16/12
//void LCD_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size_t,uint8_t mode)
//{
// uint8_t temp,t,t1;
// uint8_t y0=y;
// chr=chr-' ';//得到偏移后的值
// for(t=0;t
// {
// if(size_t==12)temp=lcd_asc2_1206[chr][t]; //调用1206字体
// else if(size_t==16) temp=lcd_asc2_1608[chr][t]; //调用1608字体
// else if(size_t==24)temp=lcd_asc2_2412[chr][t]; //调用2412字体
// for(t1=0;t1<8;t1++)
// {
// if(temp&0x80)LCD_DrawPoint(x,y,mode);
// else LCD_DrawPoint(x,y,!mode);
//
// temp<<=1;
// y++;
// if((y-y0)==size_t)
// {
// y=y0;
// x++;
// break;
// }
// }
// }
//// LCD_Refresh_GRAM();
//}
void LCD_Refresh_GRAM(void)
{
uint8_t i;uint16_t j;
WriteToLCD(LCD_CMD,LCD_EXTERN_SET);//扩展指令集
WriteToLCD(LCD_CMD,LCD_DRAW_OFF);//关掉绘图显示
for(i=0;i<32;i++)//遍历0-31行
{
WriteToLCD(LCD_CMD,0x80+i);//写入行地址
WriteToLCD(LCD_CMD,0x80); //写入列地址
for(j=0;j<32;j++)
{
WriteToLCD(LCD_DATA,LCD_GRAM[j]);
}
}
WriteToLCD(LCD_CMD,LCD_DRAW_ON);//开启绘图显示
WriteToLCD(LCD_CMD,LCD_BASIC_SET);//回到基本指令集
}
void LCD_Clear_DGRAM(void)
{
uint8_t i,j;
for(i=0;i<32;i++)//清屏
{
for(j=0;j<32;j++)//每行占用位置 16*16/8=32个字节
{
LCD_GRAM[j]=0x00;
}
}
// LCD_Refresh_GRAM();
}
#ifndef __12864_H
#define __12864_H
#include "reg52.h"
#include "integer.h"
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
#define DATA P0
/*****************************************************************************/
sbit LCD_PSB = P1^4; //H=并口; L=串口;
sbit LCD_RST = P3^6; //Reset Signal 低电平有效
sbit LCD_RS = P1^0; //RS=1数据 RS=0命令 串行片选CS
sbit LCD_RW = P1^1; //RW=1读取 RW=0写入 串行数据SID
sbit LCD_EN = P1^2; //使能信号 串行同步时钟CLK
sbit LCD_BL = P3^7;
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
//#define LCD_BL P3^7//点亮背光
#define LCD_CMD 0
#define LCD_DATA 1
//基本指令集
#define LCD_BASIC_SET 0x30
//扩充指令集
#define LCD_EXTERN_SET 0x34
//绘图显示开
#define LCD_DRAW_ON LCD_EXTERN_SET|0x02
//绘图显示关
#define LCD_DRAW_OFF LCD_EXTERN_SET|0x00
//暂定 反白指令在扩充指令集中
#define LCD_INVERSE_ONE 0x04|0x00
#define LCD_INVERSE_TWO 0x04|0x01
#define LCD_INVERSE_THREE 0x04|0x02
#define LCD_INVERSE_FOUR 0x04|0x03
void LCD_GPIO_Init(void);
uint8_t ReadByteFromLCD(void);
void WriteByteToLCD(uint8_t byte);
uint8_t LCD_Busy(void);
void WriteToLCD(uint8_t mode,uint8_t byte);
void LCD12864_Init(void);
void LCD_Clear(void);
void LCD_SetCursor(uint8_t x,uint8_t y);
void LCD_ShowString(uint8_t x,uint8_t y,uint8_t *s);
void LCD_SetPoint(uint8_t x,uint8_t y);
void LCD_Clear_DGRAM(void);
void LCD_Refresh_GRAM(void);
void LCD_DrawPoint(uint8_t x,uint8_t y,uint8_t mode);
void LCD_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size_t,uint8_t mode);
#endif
作为一个菜逼,干货并没有多少。唯一会的就是水,所以回帖水分大。望见谅!
#include "12864.h"
#include "delay.h"
#include
#include
//uint8_t Lcd_Con_X_Y[4][2]={{0x80,0x80},{0x80,0x90},{0x88,0x80},{0x88,0x90}}; //LCD行反白显示坐标
/******************************************************************************
*****************************基本指令集***************************************
*清显示:0x01
*地址归位:0x02 0x03
*
*/
/*****************************************************************************/
//初始化LCM
void LCD_Init(bit Mode)
{
LCD_RST=1; //RST低电平有效
LCD_PSB=Mode; //PSB=0串行模式 PSB=1并行模式
LCM_SWriteDatOrCom (0,0x30); //30---基本指令动作
LCM_SWriteDatOrCom (0,0x01); //清屏,地址指针指向00H
delay_us(100);
LCM_SWriteDatOrCom (0,0x06); //光标的移动方向
LCM_SWriteDatOrCom(0,0x0c); //开显示,关游标
LCD_BL=0;
}
//写指令或数据 (0,指令) (1,数据)串行时序
void LCM_SWriteDatOrCom(bit dat_comm,uint8_t content)
{
uint8_t a,i,j;
delay_us(50);
a=content;
LCD_RS=1;
LCD_EN=0;
LCD_RW=1;
for(i=0;i<5;i++)
{
LCD_EN=1;
LCD_EN=0;
}
LCD_RW=0;
LCD_EN=1;
LCD_EN=0;
if(dat_comm)
LCD_RW=1; //data
else
LCD_RW=0; //command
LCD_EN=1;
LCD_EN=0;
LCD_RW=0;
LCD_EN=1;
LCD_EN=0;
for(j=0;j<2;j++)
{
for(i=0;i<4;i++)
{
a=a<<1;
LCD_RW=CY;
LCD_EN=1;
LCD_EN=0;
}
LCD_RW=0;
for(i=0;i<4;i++)
{
LCD_EN=1;
LCD_EN=0;
}
}
}
/*********************************************************/
/* */
/* 设定显示位置 */
/* */
/*********************************************************/
void LCD_Pos(uint8_t X,uint8_t Y)
{
uint8_t 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_SWriteDatOrCom(0,pos); //显示地址
}
/*****************************************************************************/
void chn_disp (uint8_t code *chn)
{
uint8_t i,j;
LCM_SWriteDatOrCom (0,0x30);
LCM_SWriteDatOrCom (0,0x80);
for (j=0;j<4;j++) //4行
{
for (i=0;i<16;i++) //16列
LCM_SWriteDatOrCom (1,chn[j*16+i]);
}
}
/*****************************************************************************/
//清屏函数
void LCD_Clr(void)
{
LCM_SWriteDatOrCom (0,0x30);
LCM_SWriteDatOrCom (0,0x01);
delay_us(180);
}
/*****************************************************************************/
//向LCM发送一个字符串,长度64字符之内。
//应用:LCM_WriteString("您好!");
void LCM_WriteString(unsigned char *str)
{
while(*str != '\0')
{
LCM_SWriteDatOrCom(1,*str++);
}
*str = 0;
}
////任意行反白/取消反白
//void con_disp (uint8_t _line,uint8_t enable)
// {
// uint8_t i,j;
// for(j=0;j<16;j++) //每个中文字符占16个点
// {
// for(i=0;i<8;i++) //8个中文字符宽度,即LCD的一行
// {
// LCM_SWriteDatOrCom(0,0x36); //扩充指令集
// LCM_SWriteDatOrCom(0,Lcd_Con_X_Y[_line][1]+j);
// LCM_SWriteDatOrCom(0,Lcd_Con_X_Y[_line][0]+i);
// LCM_SWriteDatOrCom(0,0x30);
// if(enable==1) //使能指定行反白
// {
// LCM_SWriteDatOrCom(1,0xff);
// LCM_SWriteDatOrCom(1,0xff);
// }
// else //还原指定反白行
// {
// LCM_SWriteDatOrCom(1,0x00);
// LCM_SWriteDatOrCom(1,0x00);
// }
// }
// }
// LCM_SWriteDatOrCom(0,0x36);
// LCM_SWriteDatOrCom(0,0x30);
// }
//void con_disp(uint8_t data1,uint8_t data2,uint8_t x0,uint8_t y0,uint8_t xl,uint8_t yl)
// {
// u i,j;
// for(j=0;j
// {
// for(i=0;i
// {
// LCM_SWriteDatOrCom(comm,0x34);//0x34
// LCM_SWriteDatOrCom(comm,y0+j);
// LCM_SWriteDatOrCom(comm,x0+i);
// LCM_SWriteDatOrCom(comm,0x30);//0x30
// LCM_SWriteDatOrCom(dat,data1);
// LCM_SWriteDatOrCom(dat,data2);
// }
// }
// LCM_SWriteDatOrCom(comm,0x36);//0x36
// }
#ifndef __12864_H
#define __12864_H
#include "reg52.h"
#include "integer.h"
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
/*****************************************************************************/
sbit LCD_PSB = P1^3; //H=并口; L=串口;
sbit LCD_RST = P3^6; //Reset Signal 低电平有效
sbit LCD_RS = P1^0; //RS=1数据 RS=0命令 串行片选CS
sbit LCD_RW = P1^1; //RW=1读取 RW=0写入 串行数据SID
sbit LCD_EN = P1^2; //使能信号 串行同步时钟CLK
sbit LCD_BL = P3^7;
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
/*****************************************************************************/
//函数声明
void LCM_WriteString(unsigned char *str) ; //写字符 例:LCM_WriteString("您好!");
void LCM_SWriteDatOrCom(bit ,uint8_t ); //(0,指令) (1,数据)
void LCD_Init(bit Mode);
void LCD_Clr(void); //清屏
void chn_disp (uint8_t code *chn);
void LCD_Pos(uint8_t X,uint8_t Y);
//void con_disp (uint8_t _line,uint8_t enable);
/*****************************************************************************/
#endif
作为一个菜逼,干货并没有多少。唯一会的就是水,所以回帖水分大。望见谅!
串口屏好像基本是写操作,它就是方便你操作液晶,减少数据线,只要串口通信接可以。但是功能上要少一些,速度也慢一些。
我发的第二个程序是串行模式的,STC89C52RC驱动
作为一个菜逼,干货并没有多少。唯一会的就是水,所以回帖水分大。望见谅!