搜档网
当前位置:搜档网 › AVR12864驱动程序

AVR12864驱动程序

/***************************************************************************
标题: LCD12864程序
效果: 本程序在LCD12864液晶屏显示汉字及各种图形
作者: 李锐烁
******************************************************************************/
#include
#include
#include

#define uchar unsigned char
#define uint unsigned int
int time=0,time1=0,time2=0;

//12864 汉字显示模块 与MCU连接
#define CTRPORT PORTD
#define CTRDDR DDRD

#define RS PD0// 1:输入数据 ;0:输入命令
#define set_rs() CTRPORT |= (1 << RS)
#define clr_rs() CTRPORT &= ~(1 << RS)
#define RW PD1//1:读数据 0:写数据
#define set_rw() CTRPORT |= (1 << RW)
#define clr_rw() CTRPORT &= ~(1 << RW)

#define E PD2
#define set_e() CTRPORT |= (1 << E)
#define clr_e() CTRPORT &= ~(1 << E)

/*#define PSB PA7 //串并口选择 1:并口模式; 0:串口模式;
#define set_psb() CTRPORT |= (1 << PSB)
#define clr_psb() CTRPORT &= ~(1 << PSB)*/

//#define RST = P2^6;
#define BUSY PA7

#define LcdData PORTC
#define LcdPin PINC
#define LcdDdr DDRC
//void Lcd_WriteCmd1(unsigned char cmdcode);
//////////////////////////////////////////////

//*****************延时子程序********************//
void delay(unsigned int t)
{ unsigned int i,j;
for(i=0;ifor(j=0;j<10;j++);

}

void delay_ms(unsigned int t)
{ unsigned int i,j;
for(i=0;ifor(j=0;j<120;j++);

}
//**********************************************//

//&&&&&&&&&&&&&&& LCD基本函数 &&&&&&&&&&&&&&&&&&&//
//测试LCD忙
char Check_Busy()
{
char b;
clr_rs();
set_rw();
asm("NOP"); asm("NOP");
LcdData |= (1 << BUSY);
set_e();
asm("NOP"); asm("NOP");

LcdDdr = 0;
asm("NOP"); asm("NOP");
b = LcdPin & (1 << BUSY);
LcdDdr = 0xff;

asm("NOP"); asm("NOP");
clr_e();
return b;
}

//等待LCD到空闲
void wait()
{
while(Check_Busy());
}

//写数据
void Lcd_Writedata(unsigned char dispdata)
{ wait();
set_rs();
clr_e();
asm("NOP"); asm("NOP");
clr_rw();
asm("NOP"); asm("NOP");
set_e();
asm("NOP"); asm("NOP");
LcdData=dispdata;
asm("NOP"); asm("NOP");
clr_e();
asm("NOP"); asm("NOP");
set_rw();

}

//写指令代码
void Lcd_WriteCmd(unsigned char cmdcode)
{ wait();
clr_rs();
clr_e();
asm("NOP"); asm("NOP");
clr_rw();
asm("NOP"); asm("NOP");
set_e();
asm("NOP"); asm("NOP");
LcdData=cmdcode;
asm("NOP"); asm("NOP");
clr_e();
asm("NOP"); asm("NOP");
set_rw();
}

//读数据
uchar LCD_ReadDate()
{
uchar ReadValue;
wait();
LcdDdr=0x00; //改为输入模式
set_rs(); // RS=1;
set_rw(); // RW=1;
clr_e(); // EN=0;
set_e(); // EN=1;
delay(5);
ReadValue= LcdPin; //Store the Value
clr_e(); // EN=0;
LcdDdr=0xff; //改输出模式
r

eturn ReadValue;
}
//初始化LCD
void Lcd_Init()
{
CTRDDR |= (1 << RS)|(1 << RW)|(1 << E);
LcdDdr = 0xff;

/*RST=0;
delay(50);
RST=1;*/ //复位
// set_psb(); //选择并行方式
Lcd_WriteCmd(0x30); //选择基本指令集
delay(50);
Lcd_WriteCmd(0x30);
delay(50);
Lcd_WriteCmd(0x0c); //开显示(无游标、不反白)
delay(50);
Lcd_WriteCmd(0x01); //清除显示,并且设定地址指针为00H
delay(50);
Lcd_WriteCmd(0x06); //指定在资料的读取及写入时,设定游标的移动方向及指定显示的移位
delay(50);
}

//清屏
void LCDclean()
{
Lcd_WriteCmd(0x01);
delay(5);
Lcd_WriteCmd(0x34);
delay(5);
Lcd_WriteCmd(0x30);
delay(5);
}

//清除DDRAM:文字层清零
void LCD_ClearDDRAM(void)
{
Lcd_WriteCmd(0x01);
delay(10);
Lcd_WriteCmd(0x34);
delay(10);
Lcd_WriteCmd(0x30);
delay(10);
}

//清除CGRAM:图像层清零
void LCD_ClearCGRAM(void)
{
char x,y;
Lcd_WriteCmd(0x34);
for(x=0;x<32;x++)
{
Lcd_WriteCmd(0x80+x);
delay(2);
Lcd_WriteCmd(0x80);
for(y=0;y<16;y++)
Lcd_Writedata(0x00);
}
for(x=0;x<32;x++)
{
Lcd_WriteCmd(0x80+x);
delay(2);
Lcd_WriteCmd(0x88);
for(y=0;y<16;y++)
Lcd_Writedata(0x00);
}

}
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//

/************************************************************
函数名: WriteStr()
作用: 写汉字
备注: (X,Y)为所要显示字符的坐标,speed为显示速度
**************************************************************/
void WriteStr(int X,int Y,int speed,char *msg)
{
if(X==1)
{
X=0x80;
}
else if(X==2)
{
X=0x90;
}
else if(X==3)
{
X=0x88;
}
else if(X==4)
{
X=0x98;
}
Y=X+Y;
Lcd_WriteCmd(Y);
while(*msg)
{
Lcd_Writedata(*msg++);
wait();
delay_ms(speed);
}
}

/************************************************************
函数名: Dis_Picture()
作用: 显示图像
备注: *DData为图像数组的指针
**************************************************************/

void Dis_Picture(uchar *DData) //显示图像
{
uchar x,y,i;
uint temp;
for(i=0;i<9;)
{
for(x=0;x<32;x++)
{
Lcd_WriteCmd(0x34); //开图像显示
Lcd_WriteCmd(0x80+x);
Lcd_WriteCmd(0x80+i);
Lcd_WriteCmd(0x30);
for(y=0;y<16;y++)
Lcd_Writedata(DData[temp+y]);
temp+=16;
}
i+=8;
}
Lcd_WriteCmd(0x36);
Lcd_WriteCmd(0x30);
}


/*绘图显示的步骤
1 关闭绘图显示功能
2 先将垂直的坐标(Y)写入绘图RAM地址
3 再将水平的位元组坐标(X)写入绘图RAM地址
4 将D15-D8写入RAM中
5 将D7-D0写入到RAM中
6 打开绘图显示功能*/
//整屏显示竖条
//当ii=0时显示上面128×32,当ii=8时显示下面128×3

2
void LcdFill_Vertical()
{ unsigned char x,y,ii;
for(ii=0;ii<9;ii+=8)
for(y=0;y<0x20;y++)
for(x=0;x<8;x++)
{
Lcd_WriteCmd(0x36);//扩充指令 绘图显示
Lcd_WriteCmd(y+0x80); //行地址
Lcd_WriteCmd(x+0x80+ii); //列地址

Lcd_Writedata(0x55); //写数据 D15-D8
Lcd_Writedata(0x55); //写数据 D7-D0
Lcd_WriteCmd(0x30);
}
}
//当ii=0时显示上面128×32,当ii=8时显示下面128×32

//整屏显示横条线
void LcdFill_Level()
{ unsigned char x,y,ii;
unsigned char k;
for(ii=0;ii<9;ii+=8)
for(y=0;y<0x20;y++)
{ if((y%2)==1)
k=0xff;
else
k=0;
for(x=0;x<8;x++)
{ Lcd_WriteCmd(0x36); //扩充指令 绘图显示
Lcd_WriteCmd(y+0x80); //行地址
Lcd_WriteCmd(x+0x80+ii); //列地址
Lcd_Writedata(k);
Lcd_Writedata(k);
Lcd_WriteCmd(0x30);
}
}
}


/************************************************************
函数名: LCD_DrawPoint() 作用:画点
函数名: LCD_DrawLine () 作用:画线
作用: 通过调用这两个函数可以画出各种图型
**************************************************************/
//画点
void LCD_DrawPoint(uchar x,uchar y)
{
int Y_add,XH,XL,VL,VH;
Lcd_WriteCmd(0x34);
if(y<32)
Y_add=0x80;
else
{Y_add=0x88;y=y-32;}
XH=x/16;
XL=x%16;

Lcd_WriteCmd(0x80+y);
Lcd_WriteCmd(Y_add+XH);
LCD_ReadDate(); //预读
VL=LCD_ReadDate();
VH=LCD_ReadDate();

Lcd_WriteCmd(0x80+y);
Lcd_WriteCmd(Y_add+XH);
if(XL>=8)
{
Lcd_Writedata(VL);
Lcd_Writedata(VH|(0x01<<(15-XL)));
}
else
{
Lcd_Writedata(VL|(0X01<<(7-XL)));
Lcd_Writedata(VH);
}
}


//画线
//画线--参考https://www.sodocs.net/doc/5016867869.html,/read-htm-tid-11317.html
// --参考https://www.sodocs.net/doc/5016867869.html,/cugThird/CGOL_NET/CLASS/course/2-1-2-a.htm
void LCD_DrawLine(uchar x0,uchar y0,uchar x1,uchar y1)
{
int temp;
int dx,dy; //定义起点到终点的横、纵坐标增加值
int s1,s2,status,i;
int Dx,Dy,sub;

dx=x1-x0;
if(dx>=0) //X的方向是增加的
s1=1;
else //X的方向是降低的
s1=-1;
dy=y1-y0; //判断Y的方向是增加还是降到的
if(dy>=0)
s2=1;
else
s2=-1;

Dx=fabs(x1-x0); //计算横、纵标志增加值的绝对值
Dy=fabs(y1-y0);
if(Dy>Dx) //
{ //以45度角为分界线,靠进Y轴是status=1,靠近X轴是status=0
temp=Dx;
Dx=Dy;
Dy=temp;
status=1;
}
else
status=0;
/********判断垂直线和水平线********/
if(dx==0) //横向上没有增量,画一

条水平线
{ if(y0<=y1)
for(;y0<=y1;y0++)
LCD_DrawPoint(x0,y0);
else
for(;y1LCD_DrawPoint(x0,y1);
}
else if(dy==0) //纵向上没有增量,画一条垂直线
{
if(x0<=x1)
for(;x0<=x1;x0++)
LCD_DrawPoint(x0,y0);
else
for(;x1LCD_DrawPoint(x1,y1);
}
/*********Bresenham算法画任意两点间的直线********/
else
{
sub=2*Dy-Dx; //第1次判断下个点的位置
for(i=0;i{
LCD_DrawPoint(x0,y0); //画点
if(sub>=0)
{
if(status==1) //在靠近Y轴区,x值加1
x0+=s1;
else //在靠近X轴区,y值加1
y0+=s2;
sub-=2*Dx; //判断下下个点的位置
}
if(status==1)
y0+=s2;
else
x0+=s1;
sub+=2*Dy;

}
}
}
/*******************************************/
/*****************************************
名称:LCD_DrawSquare()
作用:在任意位置画矩形
备注:(x0,y0)为矩形左上点,(x1,y1)为矩形右下点

(x0,y0) ..............
. .
. .
. .
.............. (x1,y1)
*****************************************/
void LCD_DrawSquare(uchar x0,uchar y0,uchar x1,uchar y1)
{
LCD_DrawLine(x0,y0,x1,y0);
LCD_DrawLine(x0,y1,x1,y1);
LCD_DrawLine(x0,y0,x0,y1);
LCD_DrawLine(x1,y0,x1,y1);
}


/*****************************************
名称:LCD_DrawCircle()
作用:在任意位置画圆
备注:(x0,y0)为圆点坐标,r为半径
说明:使用Bresenham法画1/8个圆,在用对称性画出其他的7/8个圆

按下图把圆分为8份
0
7 1
6 2
5 3
4
*****************************************/
void LCD_DrawCircle(uchar x0,uchar y0,uchar r)
{
int a,b;
int di;
a=0;
b=r;
di=3-2*r; //判断下个点位置的标志
while(a<=b)
{
LCD_DrawPoint(x0-b,y0-a); //3
LCD_DrawPoint(x0+b,y0-a); //0
LCD_DrawPoint(x0-a,y0+b); //1
LCD_DrawPoint(x0-b,y0-a); //7
LCD_DrawPoint(x0-a,y0-b); //2
LCD_DrawPoint(x0+b,y0+a); //4
LCD_DrawPoint(x0+a,y0-b); //5
LCD_DrawPoint(x0+a,y0+b); //6
LCD_DrawPoint(x0-b,y0+a);
a++;
/***使用Bresenham算法画圆**/
if(di<0)
di +=4*a+6;
else
{
di +=10+4*(a-b);
b--;
}
LCD_DrawPoint(x0+a,y0+b);
}
}


///////////////////////////////////////////////////////////////
void Time0_init()
{
TCNT0=0; //定时/计数器0初始值
TCCR0=1; //0:时钟不工作;1:没有分频;2:8分频;3:64分频;4:256分频;5:1024分频
TIMSK=(1<

IE0);//使能定时器0的溢出中断
sei(); //开启总中断,这个是使用signal中断宏封装的方法,也可以直接使用寄存器打开总中断使能
}

int main()
{
DDRA |= (1 << 7);
PORTA &= ~(1 << 7);
// Time0_init();
Lcd_Init(); //初始化LCD屏
while(1)
{
LCDclean();
LCD_ClearCGRAM();
LCD_ClearDDRAM();
LcdFill_Vertical(); //显示竖条
delay_ms(100);

LCDclean();
LcdFill_Level(); //显示横条
delay_ms(100);


LCDclean();
//显示汉字
WriteStr(1,0,50,"黄河远上白云间,");
WriteStr(2,0,50,"一片孤城万仞山。");
WriteStr(3,0,50,"羌笛何须怨杨柳?");
WriteStr(4,0,50,"春风不度玉门关。");
delay_ms(1000);
LCDclean();
LCD_ClearCGRAM();
LCD_ClearDDRAM();

LCD_DrawLine(63,31,63,60);//秒针

LCD_DrawLine(63,31,83,34);
LCD_DrawLine(83,34,85,31);
LCD_DrawLine(63,31,85,31);
LCD_DrawLine(83,28,85,31);
LCD_DrawLine(63,31,83,28);//分针

LCD_DrawLine(63,31,53,34);
LCD_DrawLine(83,34,51,31);
LCD_DrawLine(63,31,51,31);
LCD_DrawLine(83,28,51,31);
LCD_DrawLine(63,31,53,28);//时针

LCD_DrawCircle(63,31,31);
LCD_DrawCircle(63,31,30);
LCD_DrawCircle(63,31,29);

Lcd_WriteCmd(0x36);
Lcd_WriteCmd(0x30);
delay_ms(2000);
while(1);
}
}


SIGNAL(SIG_OVERFLOW0) //中断函数设置,来自GCC宏SIGNAL,SIG_OVERFLOW0参数是定时器0的溢出中断,可参考中断表
{
TCNT0=0;
time1++; //30ms太短,闪烁频率太快
if(time1>=20) //用变量 count 延长到300ms,根据自己的需要,调整参数或者定时器初始值来改成时间量
time++;
}




相关主题