|||
/***************************************************/
//屏大小配置
#define lcd_x_size 240
#define lcd_y_size 128
#define lcdxdev8 (lcd_x_size/8)
/****************************************************/
#include"reg51.h"
#define uchar unsigned char
#define uint unsigned short
#define port P3
sbit cd=P2^0;
sbit rd=P2^1;
sbit wr=P2^2;
sbit ce=P2^3;
void lcd_writecom_two(uchar onedat,uchar twodat,uchar com);
void lcd_writedat_onebyte(uchar onedat,uchar com);
uchar lcd_readdat_onebyte(uchar com);
void lcd_writedat_nbyte(uchar *dat,uchar len);
void lcd_readdat_nbyte(uchar *dat ,uchar len);
void clear_point(uchar x,uchar y);
void sel_point(uchar x,uchar y);
void sel_rmiddling(uchar x,uchar y);
void clr_rmiddling(uchar x,uchar y);
void sel_rbig(uchar x,uchar y);
void clr_rbig(uchar x,uchar y);
void graph_mode_writeword(uchar x,uchar y,uchar *dat);
void graph_mode_write_letter(uchar x,uchar y,uchar *dat);
void rhorizontal(uchar x0,uchar x1,uchar y);
void erect(uchar y0,uchar y1,uchar x);
void Draw_line(uchar x0,uchar y0,uchar x1,uchar y1);
void draw_circle(int x, int y, int r);
void lcd_init();
/*****************************************************
驱动名:T6963驱动 (液晶)
设计者:阿飞
修正:全面优化 画点 划线 数据处理等(采用读修改些方式)
版本: v4
*****************************************************/
/**********************************
读取lcd状态
**********************************/
#include "lcd.h"
uchar lcd_readcom()
{
uchar temp;
port=0xff;
cd=1;
ce=0;
rd=0;
wr=1;
temp=port;
rd=1;
return temp;
}
/*********************************
判断指令/数据读写忙碌状态
*********************************/
void check_busy()
{
uchar temp;
do{
temp=lcd_readcom();
}while((temp&0x03)!=0x03);
}
/*********************************
判断数据自动写忙碌状态
*********************************/
void check_auto_write_busy()
{
uchar temp;
do{
temp=lcd_readcom();
}while((temp&0x08)!=0x08);
}
/*********************************
判断数据自动读忙碌状态
*********************************/
void check_auto_read_busy()
{
uchar temp;
do{
temp=lcd_readcom();
}while((temp&0x04)!=0x04);
}
/*********************************
向lcd写命令
*********************************/
void lcd_writecom(uchar dat)
{
check_busy();
cd=1;
ce=0;
port=dat;
wr=0;
rd=1;
wr=1;
}
/************************************
向lcd写数据
************************************/
void lcd_writedat(uchar dat)
{
check_busy();
port=0xff;
cd=0;
ce=0;
wr=0;
rd=1;
port=dat;
wr=1;
}
/********************************
从lcd读数据
*********************************/
uchar lcd_readdat()
{
uchar temp;
cd=0;
port=0xff;
wr=1;
ce=0;
rd=0;
temp=port;
rd=1;
cd=1;
return temp;
}
/************************************************
发出命令控制 参数 低onedat 高twodat 命令com
*************************************************/
void lcd_writecom_two(uchar onedat,uchar twodat,uchar com)
{
lcd_writedat(onedat);
lcd_writedat(twodat);
lcd_writecom(com);
}
/**********************************************
一次写一个数据 对应地址指针位置
**********************************************/
void lcd_writedat_onebyte(uchar onedat,uchar com)
{
lcd_writedat(onedat);
lcd_writecom(com);
}
/**********************************************
一次读一个数据 对应地址指针位置
**********************************************/
uchar lcd_readdat_onebyte(uchar com)
{
uchar dat;
lcd_writecom(com);
dat=lcd_readdat();
return dat;
}
/****************************************
一次写n个数据 对应地址指针位置
****************************************/
void lcd_writedat_nbyte(uchar *dat,uchar len)
{
lcd_writecom(0xb0);
check_auto_write_busy();
while(len)
{
lcd_writedat(*dat);
dat++;
len--;
}
lcd_writecom(0xb2);
}
/****************************************
一次读n个数据 对应地址指针位置
****************************************/
void lcd_readdat_nbyte(uchar *dat ,uchar len)
{
lcd_writecom(0xb1);
check_auto_read_busy();
while(len)
{
*dat=lcd_readdat();
dat++;
len--;
}
lcd_writecom(0xb2);
}
/************************************************
清除一个点坐标 X,Y 左上角第一个点为0,0
************************************************/
void clear_point(uchar x,uchar y)
{
uint addr;
uchar temp1,temp2;
addr=y*lcdxdev8+(x>>3);//32+8
temp1=addr;//&0x00ff;
temp2=addr>>8;
lcd_writecom_two(temp1,temp2,0x24);
lcd_writecom(0xf7-(x&0x07));
}
/************************************************
点亮一个点 坐标 X,Y 左上角第一个点为0,0
************************************************/
void sel_point(uchar x,uchar y)
{
uint addr;
uchar temp1,temp2;
addr=y*lcdxdev8+(x>>3);//32+8
temp1=addr;//&0x00ff;
temp2=addr>>8;
lcd_writecom_two(temp1,temp2,0x24);
lcd_writecom(0xff-(x&0x07));
}
/*************************************************
画中等大小的点 4*4(用画点方法 效率低)
*************************************************/
/*sel_middling(uchar x,uchar y)
{
uint addr;
uchar temp1,temp2,n;
addr=y*lcdxdev8*4+(x>>1);//x/8*4;
for(n=0;n<4;n++)
{
temp1=addr%256;
temp2=addr>>8;
lcd_writecom_two(temp1,temp2,0x24);
if(x%2)
{
lcd_writecom(0xfb);
lcd_writecom(0xfa);
lcd_writecom(0xf9);
lcd_writecom(0xf8);
}
else
{
lcd_writecom(0xff);
lcd_writecom(0xfe);
lcd_writecom(0xfd);
lcd_writecom(0xfc);
}
addr+=40;
}
}*/
/*************************************************
画中等大小的点 4*4(用读修改写 效率高)
*************************************************/
void sel_rmiddling(uchar x,uchar y)
{
uint addr;
uchar temp1,temp2,n,dat;
addr=y*lcdxdev8*4+(x>>1);//x/8*4;//128+32
for(n=0;n<4;n++)
{
temp1=addr;//&0x0ff;
temp2=addr>>8;
lcd_writecom_two(temp1,temp2,0x24);
if(x&0x01)//x%2
{
dat=(lcd_readdat_onebyte(0xc5))|0x0f;
lcd_writedat_onebyte(dat,0xc4);
}
else
{
dat=(lcd_readdat_onebyte(0xc5))|0xf0;
lcd_writedat_onebyte(dat,0xc4);
}
addr+=lcdxdev8;
}
}
/*************************************************
清楚中等大小的点 4*4(用清点方式 效率底)
*************************************************/
/*clr_middling(uchar x,uchar y)
{
uint addr;
uchar temp1,temp2,n;
addr=y*lcdxdev8*4+(x>>1);//x/8*4;
for(n=0;n<4;n++)
{
temp1=addr%256;
temp2=addr>>8;
lcd_writecom_two(temp1,temp2,0x24);
if(x%2)
{
lcd_writecom(0xf3);
lcd_writecom(0xf2);
lcd_writecom(0xf1);
lcd_writecom(0xf0);
}
else
{
lcd_writecom(0xf7);
lcd_writecom(0xf6);
lcd_writecom(0xf5);
lcd_writecom(0xf4);
}
addr+=lcdxdev8;
}
}*/
/*************************************************
清楚中等大小的点 4*4(用读修改写 效率高)
*************************************************/
void clr_rmiddling(uchar x,uchar y)
{
uint addr;
uchar temp1,temp2,n,dat;
addr=y*lcdxdev8*4+(x>>1);//x/8*4;//128+32
for(n=0;n<4;n++)
{
temp1=addr;//&0xff;
temp2=addr>>8;
lcd_writecom_two(temp1,temp2,0x24);
if(x&0x01)
{
dat=(lcd_readdat_onebyte(0xc5))&0xf0;
lcd_writedat_onebyte(dat,0xc4);
}
else
{
dat=(lcd_readdat_onebyte(0xc5))&0x0f;
lcd_writedat_onebyte(dat,0xc4);
}
addr+=lcdxdev8;
}
}
/*********************************************************
画8*8的大点(用画点方式 速度慢)
*********************************************************/
/*void sel_big(uchar x,uchar y)
{
uint addr;
uchar temp1,temp2,n;
addr=lcdxdev8*8+(x);//x/8*4;y*320=y*(256+64)=(y<<8)+(y<<6)
for(n=0;n<8;n++)
{
temp1=addr&0x00ff;//addr%256
temp2=addr>>8;
lcd_writecom_two(temp1,temp2,0x24);
lcd_writecom(0xfb);
lcd_writecom(0xfa);
lcd_writecom(0xf9);
lcd_writecom(0xf8);
lcd_writecom(0xff);
lcd_writecom(0xfe);
lcd_writecom(0xfd);
lcd_writecom(0xfc);
addr+=lcdxdev8;
}
}
*/
/*********************************************************
画8*8的大点(用读改写方式 速度快)
*********************************************************/
void sel_rbig(uchar x,uchar y)
{
uint addr;
uchar temp1,temp2,n,dat;
addr=y*lcdxdev8*8+(x);//x/8*4;y*320=y*(256+64)=(y<<8)+(y<<6)
for(n=0;n<8;n++)
{
temp1=addr;//&0x00ff;//addr%256
temp2=addr>>8;
lcd_writecom_two(temp1,temp2,0x24);
//dat=(lcd_readdat_onebyte(0xc5))|0xff;
dat=0xff;
lcd_writedat_onebyte(dat,0xc4);
addr+=lcdxdev8;
}
}
/*********************************************************
清楚8*8的大点(用画点方式 速度慢)
*********************************************************/
/*void clr_big(uchar x,uchar y)
{
uint addr;
uchar temp1,temp2,n;
addr=lcdxdev8*8+(x);//x/8*4;y*320=y*(256+64)=(y<<8)+(y<<6)
for(n=0;n<8;n++)
{
temp1=addr&0x00ff;//addr%256
temp2=addr>>8;
lcd_writecom_two(temp1,temp2,0x24);
lcd_writecom(0xf3);
lcd_writecom(0xf2);
lcd_writecom(0xf1);
lcd_writecom(0xf0);
lcd_writecom(0xf7);
lcd_writecom(0xf6);
lcd_writecom(0xf5);
lcd_writecom(0xf4);
addr+=lcdxdev8;
}
}
*/
/*********************************************************
清除8*8的大点(用读修改写方式 速度快)
*********************************************************/
void clr_rbig(uchar x,uchar y)
{
uint addr;
uchar temp1,temp2,n,dat;
addr=y*lcdxdev8*8+(x);//x/8*4;y*320=y*(256+64)=(y<<8)+(y<<6)
for(n=0;n<8;n++)
{
temp1=addr;//&0x00ff;//addr%256
temp2=addr>>8;
lcd_writecom_two(temp1,temp2,0x24);
//dat=(lcd_readdat_onebyte(0xc5))|0x00;
dat=0x00;
lcd_writedat_onebyte(dat,0xc4);
addr+=lcdxdev8;
}
}
/*************************************************************
图形方式 屏上写汉字 16*16
************************************************************/
void graph_mode_writeword(uchar x,uchar y,uchar *dat)
{
uint addr;
uint temp1;
uchar n;
temp1=y;temp1=lcdxdev8*16;//30*16
addr=temp1+(x<<1);
for(n=0;n<16;n++)
{
lcd_writecom_two((addr&0x00ff),(addr>>8),0x24);
lcd_writedat_onebyte(*dat,0xc0);
dat++;
lcd_writedat_onebyte(*dat,0xc4);
dat++;
addr=addr+lcdxdev8;
}
}
/*************************************************************
图形方式 屏上写字母,数字 8*16
************************************************************/
void graph_mode_write_letter(uchar x,uchar y,uchar *dat)
{
uint addr;
uint temp1;
uchar n;
temp1=y;temp1=lcdxdev8*16;//512+128//lcdxdev8 40*16
addr=temp1+(x<<1);
for(n=0;n<16;n++)
{
lcd_writecom_two((addr&0x00ff),(addr>>8),0x24);
lcd_writedat_onebyte(*dat,0xc0);
dat++;
addr=addr+lcdxdev8;
}
}
/******************************************************
用画点的方式划横线 (可以用读改写的方式)
******************************************************/
/*void horizontal(uchar x0,uchar x1,uchar y)
{
uchar temp,n;
if(x0>x1)
{
temp=x0;
x0=x1;
x1=temp;
}
n=x1-x0;
for(;n>0;n--)
{
sel_point(x0+n,y);
}
}*/
/*************************************
划横线 (用读改写的方式)
***************************************/
uchar get_num(uchar x0)
{
uchar dat;
switch(x0)
{
case 0: dat=0xff;break;
case 1: dat=0x7f;break;
case 2: dat=0x3f;break;
case 3: dat=0x1f;break;
case 4: dat=0x0f;break;
case 5: dat=0x07;break;
case 6: dat=0x03;break;
case 7: dat=0x01;break;
}
return dat;
}
uchar get_num_n(uchar x1)
{
uchar dat;
switch(x1)
{
case 0: dat=0x80;break;
case 1: dat=0xc0;break;
case 2: dat=0xe0;break;
case 3: dat=0xf0;break;
case 4: dat=0xf8;break;
case 5: dat=0xfc;break;
case 6: dat=0xfe;break;
case 7: dat=0xff;break;
}
return dat;
}
void rhorizontal(uchar x0,uchar x1,uchar y)
{
uint addr;
uchar temp,n,temp1,temp2,dat,dat1;
if(x0>x1)
{
temp=x0;
x0=x1;
x1=temp;
}
addr=y*lcdxdev8+(x0>>3);
temp1=addr;//&0xff;
temp2=addr>>8;
lcd_writecom_two(temp1,temp2,0x24);
lcd_writecom_two(temp1,temp2,0x24);
n=x1-x0;
dat1=lcd_readdat_onebyte(0xc5);
if((x0>>3)!=(x1>>3))
{
lcd_writedat_onebyte((get_num(x0&0x3)|dat1),0xc0);
temp1=x0>>3;
temp2=x1>>3;
temp=temp2-temp1-1;
lcd_writecom(0xb0);
check_auto_write_busy();
while(temp)
{
lcd_writedat(0xff);
temp--;
}
lcd_writecom(0xb2);
dat1=lcd_readdat_onebyte(0xc5);
lcd_writedat_onebyte((get_num_n(x1&0x03)|dat1),0xc4);
}
else
{
x0=x0&0x07;
x1=x1%0x07;
dat =~(get_num(x0)^get_num_n(x1));
lcd_writedat_onebyte((dat|dat1),0xc4);
}
}
/*****************************************
用画点的方式画竖线
*****************************************/
void erect(uchar y0,uchar y1,uchar x)
{
uchar temp,n;
if(y0>y1)
{
temp=y0;
y0=y1;
y1=temp;
}
n=y1-y0;
for(;n>0;n--)
{
sel_point(x,y0+n);
}
}
/*******************************************************
布兰森汉姆(Bresenham)算法画线 两端点(x0,y0) (x1,y1)
*******************************************************/
void Draw_line(uchar x0,uchar y0,uchar x1,uchar y1)
{
int dx,dy; //定义X.Y轴上增加的变量值
int sub;
int temp; //起点、终点大小比较,交换数据时的中间变量
uchar flag;
if(x0>x1) //X轴上,起点大于终点,交换数据
{
temp=x1;
x1=x0;
x0=temp;
temp=y1;
y1=y0;
y0=temp;
}
dx=x1-x0; //X轴方向上的增量
dy=y1-y0; //Y轴方向上的增量
if(dx==0)
erect(y0,y1,x0);
if(dy==0)
rhorizontal(x0,x1,y0);
if(dy>0)
flag=1;
else
flag=0;
if((dx!=0)&&(dy!=0))
{
// 布兰森汉姆(Bresenham)算法画线 /
if(flag==1)
{
if(dx>=dy) //靠近X轴
{
sub=2*dy-dx; //计算下个点的位置
while(x0!=x1)
{
sel_point(x0,y0); //画起点
x0++; // X轴上加1
if(sub>0) // 判断下下个点的位置
{
y0++; // 为右上相邻点,即(x0+1,y0+1)
sub+=2*dy-2*dx;
}
else
sub+=2*dy; // 判断下下个点的位置
}
sel_point(x0,y0);
}
else
{
sub=2*dy-dx; //靠近Y轴
while(y0!=y1)
{
sel_point(x0,y0); //画起点
y0++;
if(sub>0) //判断下下个点的位置
{
x0++;
sub+=2*dx-2*dy;
}
else
sub+=2*dx;
}
sel_point(x0,y0);
}
}
else
{
dy=y0-y1;
if(dx>=dy) //靠近X轴
{
sub=2*dy-dx; //计算下个点的位置
while(x0!=x1)
{
sel_point(x0,y0); //画起点
x0++; // X轴上加1
if(sub>0) // 判断下下个点的位置
{
y0--; // 为右上相邻点,即(x0+1,y0+1)
sub+=2*dy-2*dx;
}
else
sub+=2*dy; // 判断下下个点的位置
}
sel_point(x0,y0);
}
else
{
sub=2*dx-dy; //靠近Y轴
while(y0!=y1)
{
sel_point(x0,y0); //画起点
y0--;
if(sub>0) //判断下下个点的位置
{
x0++;
sub+=2*dx-2*dy;
}
else
sub+=2*dx;
}
sel_point(x0,y0);
}
}
}
}
/****************************************************
画圆 圆点(x,y) 半径 r
****************************************************/
void draw_circle(int x, int y, int r)
{
int a, b, num;
a = 0;
b = r;
while(2 * b * b >= r * r) // 1/8圆即可
{
sel_point(x + a, y - b); // 0~1
sel_point(x - a, y - b); // 0~7
sel_point(x - a, y + b); // 4~5
sel_point(x + a, y + b); // 4~3
sel_point(x + b, y + a); // 2~3
sel_point(x + b, y - a); // 2~1
sel_point(x - b, y - a); // 6~7
sel_point(x - b, y + a); // 6~5
a++;
num = (a * a + b * b) - r*r;
if(num > 0)
{
b--;
a--;
}
}
}
void lcd_init()
{
lcd_writecom_two(0x00,0x00,0x24);
lcd_writecom_two(0x00,0x00,0x21);
lcd_writecom_two(0x00,0x00,0x42);
lcd_writecom_two(lcdxdev8,0x00,0x43);//28
lcd_writecom_two(0x00,0x00,0x40);
lcd_writecom_two(lcdxdev8,0x00,0x41);//1e
lcd_writecom(0xa0);
lcd_writecom(0x98);
lcd_writecom(0x80);
}
#include "lcd.h"
int main()
{
lcd_init();
sel_point(239,5);
clear_point(239,5);
sel_rmiddling(1,1);
clr_rmiddling(1,1);
sel_rbig(3,3);
//void graph_mode_writeword(uchar x,uchar y,uchar *dat);
//void graph_mode_write_letter(uchar x,uchar y,uchar *dat);
rhorizontal(0,128,20);
erect(0,100,100);
draw_circle(80, 64, 60);
//clr_rbig(3,3);
/* Draw_line(0,0,127,127);
Draw_line(0,127,239,0);
Draw_line(0,0,239,0);
Draw_line(0,127,239,127);
Draw_line(0,0,0,127);
Draw_line(239,0,239,127); */
while(1);
}