/*==============================
*LCD_1264液晶显示驱动(并行)*
* CPU:-------AVR系列 *
*端口连接:X={A,B,C,D}
* RESET ______________ PX7 *
* PSB ________________ PX6 *
* E ________________ PX5 *
* R/W ________________ PX4 *
* RS ________________ PX3 *
* DATA _____________ PORTC*
==============================*/
#include<avr/io.h>
#include<avr/delay.h>
#include <math.h>
#define uchar unsigned char
#define uint unsigned int
//LCD数据端口
#define DDR_data DDRC
#define PIN_data PINC
#define lcd_data PORTC //暂时用PORTC,实际使用时因情况而定
//LCD控制端口
#define lcd_kz PORTA //暂时用PORTA,实际使用时因情况而定
//LCD片选端
#define RS 3
#define set_lcd_RS lcd_kz |= (1<<RS) //置高
#define clr_lcd_RS lcd_kz &= (~(1<<RS))//清0
//LCD串行数据输入端
#define RW 4
#define set_lcd_RW lcd_kz |= (1<<RW) //置高
#define clr_lcd_RW lcd_kz &= (~(1<<RW))//清0
//LCD时钟输入端
#define E 5
#define set_lcd_E lcd_kz |= (1<<E) //置高
#define clr_lcd_E lcd_kz &= (~(1<<E))//清0
//8/4位选择控制PSB操作:PD6输出
#define PSB 6
#define clr_lcd_PSB lcd_kz &= (~(1<<PSB)) //清0:4位
#define set_lcd_PSB lcd_kz |= (1<<PSB) //置位:8位
//复位端RST操作:PD7输出
#define RST 7
#define clr_lcd_RST lcd_kz &= (~(1<<RST)) //清0
#define set_lcd_RST lcd_kz |= (1<<RST) //置位
/*======================================
*串口调试模块
*由于读取内部数据
*当程序调试完成,应注释掉
======================================*/
//串口初始化
void USART_Init(void)
{
UBRRH = 0x00;
UBRRL = 47; //设置波特率9600
UCSRB = (1<<TXEN);//发送使能
}
//串口发送子程序*
void USART_Transmit( unsigned char _data )
{
while ( !( UCSRA & (1<<UDRE)) );
UDR = _data;
}
/******************************
*读忙标志BF
******************************/
void BF_busy(void)
{ uchar BF;
DDR_data=0x00; //定义输入方式
_delay_us(10);
do{
clr_lcd_RW;
clr_lcd_RS; //读指令
set_lcd_RW;
set_lcd_E;
BF=PIN_data;
BF=PIN_data;
clr_lcd_E;
clr_lcd_RW;
BF&=0X80; //屏蔽地址位
}
while(BF!=0);//BF=0x80表示忙
DDR_data=0xff; //定义输出方式
_delay_us(10);
}
/*-----------------------------------
*执行写命令
*RS=0 写指令
*RS=1 写数据
-----------------------------------*/
void wr_12864(uchar _RS,uchar a_data)
{
BF_busy(); //检查忙否?
set_lcd_RW;
if(_RS==1)
set_lcd_RS; //写数据
else
clr_lcd_RS; //写指令
clr_lcd_RW; //写命令
set_lcd_E; //置使能
_delay_us(1);
lcd_data=a_data;
DDR_data=0xff; //定义输出方式
clr_lcd_E;
_delay_us(1);
set_lcd_RW;
BF_busy();
}
/*-----------------------------------
*读绘图RAM数据
----------------------------------*/
uchar rd_12864(void)
{ uchar data_temp;
BF_busy();
DDR_data=0x00; //定义输入方式
clr_lcd_RW;
set_lcd_RS; //读数据
set_lcd_RW; //数据
set_lcd_E; //使能
_delay_us(2);
data_temp=PIN_data;
clr_lcd_E;
_delay_us(1);
clr_lcd_RW;
return data_temp;
}
/*****************************************
* LCD12864初始化函数 *
*****************************************/
void lcd12864_init(void)
{
set_lcd_PSB; //并行工作方式
_delay_ms(50);
clr_lcd_RST; //复位
_delay_ms(100);
set_lcd_RST;
_delay_ms(200);
//说明:wr_12864(a,b)
// a=0时写指令a=1时写数据
wr_12864(0,0x30); //功能设置:扩充指令集(0X34),基本指令集(0X30)
BF_busy();
wr_12864(0,0x30); //绘图显示开
BF_busy();
wr_12864(0,0x0C); //显示状态:0X0C整体显示,D=1
BF_busy();
wr_12864(0,0x40); //开显示
BF_busy();
wr_12864(0,0x01); //清屏
BF_busy();
}
/************************************
* LCD12864显示字符串函数 *
*入口:待显示的字符串
************************************/
void lcd_xs(char *s)
{
while(*s)
{
wr_12864(1,*s);
s++;
}
}
/************************************
* LCD12864显示汉字定位函数 *
* 入 口:hang定位的行数,lie列数 *
************************************/
void hang_l(uchar hang,uchar lie)
{
switch(hang)
{
case 1: wr_12864(0,(0x80+lie)); //写第一行V列地址
break;
case 2: wr_12864(0,(0x90+lie)); //写第二行V列地址
break;
case 3: wr_12864(0,(0x88+lie)); //写第三行V列地址
break;
case 4: wr_12864(0,(0x98+lie)); //写第四行V列地址
break;
default:break;
}
}
/************************************
* LCD12864显示清屏函数 *
************************************/
void cls(void)
{
BF_busy();
wr_12864(0,0x30);
BF_busy();
wr_12864(0,0x01); //清屏
}
/**********************************
*绘图显示开关
*ON=1,绘图显示开
*ON=0,绘图显示关
*********************************/
void hui_tu(uchar ON)
{
if(ON==1)
{
BF_busy();
wr_12864(0,0x36);
}
else
{
BF_busy();
wr_12864(0,0x34);
}
}
/**********************************
*绘图坐标
*说明:hang,lie分别是实际的行和列
**********************************/
void xy_line(uchar hang,uchar lie)
{
wr_12864(0,(0x80+lie)); //先写y坐标地址
wr_12864(0,(0x80+hang)); //后写x坐标地址
BF_busy();
}
/*=============================
*X—Y坐标 画线 y=f(x)
*实际的列 lie
*实际的行 hang
============================*/
void x_y_line(uchar x,uchar y)
{ uchar lie ,hang, lie_bit;
uchar i,j;
uchar data_h,data_l;
i=x/16; //
j=y/32;
lie_bit=x%16; //要写的位
hang=31-y%32; //实际的行 y
if(j==0)
lie=i+8;
else
lie=i; //要写的列x
for(i=0;i<=4;i++) //读RAM数据
{
xy_line(lie,hang); //给地址
data_h=rd_12864(); //虚拟读数据(因ST7920所至)
data_h=rd_12864(); //
data_l=rd_12864();
}
/*
//串口测试
USART_Transmit(data_h);
USART_Transmit(data_l);
USART_Transmit(0xff);
*/
if(lie_bit > 7)
{
data_l |= (0x80>>(lie_bit-8));
}
else
{
data_h |= (0x80>>(lie_bit));
}
/*
//串口测试
USART_Transmit(data_h);
USART_Transmit(data_l);
USART_Transmit(0xff);
*/
hui_tu(0); //关绘图
xy_line(lie,hang);
wr_12864(1,data_h);
wr_12864(1,data_l);
hui_tu(1); //开绘图
}
/*====================================
*Bresenham画线算法的推导
*说明:(x1,y1)起点坐标;
*说明:(x2,y2)终点坐标;
=====================================*/
void ks_Line(uchar x1, uchar y1, uchar x2, uchar y2)
{
int x,y,dx,dy,Dx,Dy,e,i; //中间变量
Dx=x2-x1; //x增量
Dy=y2-y1; //y增量
dx=fabs(x2-x1); //x绝对增量
dy=fabs(y2-y1); //y绝对增量
x=x1;
y=y1;
if(dy>dx) //斜率大于1
{
e=-dy; //
for(i=0;i<dy;i++)
{
x_y_line(x,y);
if(Dy>=0)
y++;
else
y--;
e+=2*dx;
if(e>=0)
{
if(Dx>=0)
x++;
else
x--;
e-=2*dy;
}
}
}
else //斜率小于1
{
e=-dx;
for(i=0;i<dx;i++)
{
x_y_line(x,y);
if(Dx>=0)
x++;
else
x--;
e+=2*dy;
if(e>=0)
{
if(Dy>=0)
y++;
else
y--;