|
发表于 2005-5-12 10:16:17
|
显示全部楼层
下面是WINAVR上的改动后程序,调试通过!
要注意的问题:在读ROM区字节时候:用pgm_read_byte(lib) 与pgm_read_byte(lib + i)的结果是不同的,虽然在语法上是一样的.
/*写汉字液晶子程 液晶屏分为4行*12列汉字,全部使用模拟接口方式。
CKW19264A接口程序(模拟方式)
液晶模块供应商:上海市HENGFANG电子有限公司 HTTP://WWW.HENGFANG.COM.CN
;************************************************************************
;连线图:
;*LCM----S8515* *LCM----S8515* *LCM-----S8515* *LCM-----S8515* *
;*DB0-----PA0* *DB4-----PA4* *D/I------PC6* *CS1------PC4* *
;*DB1-----PA1* *DB5-----PA5* *R/W------PC7* *CS2------PC5* *
;*DB2-----PA2* *DB6-----PA6* *RST------VCC* *CS3------PD2* *
;*DB3-----PA3* *DB7-----PA7* *E--------PC3* *
;注:Mega16的晶振频率为4MHz *
;************************************************************************/
#include <avr\io.h>
#include <avr\pgmspace.h>
#include <avr\delay.h>
#include "worddot.h" // 自定义字符点阵码文件,存于include目录下
//#include <math.h> // 数学_运算定义,没有使用
#define CRYSTAL 4 //4M crystal
typedef unsigned char uchar;
/***********液晶显示器接口引脚定义***************/
#define LCD_E (1 << 3) // PC3----E
#define LCD_DI (1 << 6) // PC6----D/I
#define LCD_RW (1 << 7) // PC7----R/W
#define LCD_CS1 (1 << 4) // PC4----CS1
#define LCD_CS2 (1 << 5) // PC5----CS2
#define LCD_CS3 (1 << 2) // PD2----CS3
#define lcd_set_e() (PORTC |= LCD_E) // 位置位,输出1
#define lcd_set_di() (PORTC |= LCD_DI)
#define lcd_set_rw() (PORTC |= LCD_RW)
#define lcd_clear_e() (PORTC &= ~LCD_E) // 位清零,输出0
#define lcd_clear_di() (PORTC &= ~LCD_DI)
#define lcd_clear_rw() (PORTC &= ~LCD_RW)
#define lcd_set_cs1() (PORTC |= LCD_CS1) // 片选
#define lcd_set_cs2() (PORTC |= LCD_CS2)
#define lcd_set_cs3() (PORTD |= LCD_CS3)
#define lcd_clear_cs1() (PORTC &= ~LCD_CS1)
#define lcd_clear_cs2() (PORTC &= ~LCD_CS2)
#define lcd_clear_cs3() (PORTD &= ~LCD_CS3)
#define LCD_BUSY 0x80 //LCM忙判断位
#define lcd_read_status() (PINA & LCD_BUSY) //LCM忙判断
#define Datalcm PORTA //数据口
/***********常用操作命令和参数定义***************/
#define DISPON 0x3f /*显示on */
#define DISPOFF 0x3e /*显示off */
#define DISPFIRST 0xc0 /*显示起始行定义 */
#define SETX 0x40 /*X定位设定指令(页) */
#define SETY 0xb8 /*Y定位设定指令(列) */
/**************显示分区边界位置*****************/
#define MODL 0x00 /*左区 */
#define MODM 0x40 /*左区和中区分界 */
#define MODR 0x80 /*中区和右区分界 */
#define LCMLIMIT 0xC0 /*显示区的右边界 */
/****************全局变量定义*******************/
uchar col, row, cbyte, timer1, timer2, statusm; /*列x,行(页)y,输出数据 */
unsigned int speed = 0x7fff;
/*****************函数列表**********************/
void Lcminit(void); //液晶模块初始化
void Delay(uchar); //延时,入口数为Ms
void lcdbusyL(void); //busy判断、等待(左区)
void lcdbusyM(void); //busy判断、等待(中区)
void lcdbusyR(void); //busy判断、等待(右区)
void Putedot(uchar x, uchar y, const prog_uchar *Lib, uchar Order, uchar widthw);
void Wrdata(uchar); //数据输出给LCM
void Lcmcls( void ); //LCM全屏幕清零(填充0)
void wtcom(void); //公用busy等待
void Locatexy(void); //光标定位
void WrcmdL(uchar); //左区命令输出
void WrcmdM(uchar); //中区命令输出
void WrcmdR(uchar); //右区命令输出
void Putstr(uchar x, uchar y, const prog_uchar *puts, uchar i);//字符串输出
void Rollscreen(uchar x); //屏幕向上滚动演示
void Rddata(void); //从液晶片上读数据
void point(void); //打点 */
void Linexy(uchar x0, uchar y0, uchar xt, uchar yt);
void main_init(void);
void timer(void);
void circle(uchar Ox, uchar Oy, uchar Rx);
/******************数组列表*********************/
//const prog_uchar Ezk[]; /*ASCII常规字符点阵码表 */
//const prog_uchar Hzk[]; /*自用汉字点阵码表 */
//const prog_uchar STR1[]; /*自定义字符串 */
//const prog_uchar STR2[]; //const prog_uchar "=" code(keil c51)
//const prog_uchar STR3[]; //
//const prog_uchar STR4[]; //
/********************************/
//定义字符串数组 */
/********************************/
const prog_uchar STR1[]=
{
0x80,0x81,0x82,0x83,0x84,0x85,
0x86,0x87,0x88,0x89,0x8a,0x8B
};
const prog_uchar STR2[] = "http://www.xiao-qi.com/ ";
const prog_uchar STR3[] = "Program by ICCAVR V6.23B";
const prog_uchar STR4[] = "Thank you __@ 1234567890";
/********************************/
/* 演示主程序 */
/********************************/
int main(void)
{
uchar x=0;
DDRD = 0xFF; //|= LCD_CS3; /*定义输出位
DDRC = 0xFF; /*定义为输出口 */
statusm&=~(1<<7);
//main_init();
Delay(5); /*延时,等待外设准备好 */
Lcminit(); /*液晶模块初始化,包括全屏幕清屏*/
//Putstr(0,0,STR3,24); /*第一行字符输出,24字节 */
Putstr(0,2,STR1,12); /*第二行字符输出,12字节(汉字)*/
//Putstr(0,4,STR3,24); /*第三行字符输出,24字节 */
//Putstr(0,6,STR4,24); /*第四行字符输出,12字节 */
//Linexy(0,0,191,0); /*line (0,0)-(191,0) */
//Linexy(191,0,191,32); /*line (191,0)-(191,32) */
//Linexy(191,32,0,32); /*line (191,32)-(0,32) */
//Linexy(0,32,0,0); /*line (0,32)-(0,0) */
//Linexy(1,15,191,15); /*line (1,15)-(191,15) */
//Linexy(0,63,44,33); /*line (0,63)-(44,33) */
//Linexy(44,33,191,63); /*line (44,33)-(191,63) */
//circle(46,49,12); //画一个圆
//circle(46,49,11);
while(1)
{
// Rollscreen(x); /*定位新的显示起始行 */
x++;
Delay(20); /*延时,控制滚动速度 */
};
}
/***************************
初始化8515定时寄存器
***************************/
void main_init(void)
{
TCCR1A = 0x00;
TCCR1B = 0x00; /* 停止定时器1 */
TCNT1H = 0x00; /* 清除定时器1 */
TCNT1L = 0x00;
TIMSK = 0x80; /* 开放定时器1溢出中断 */
SREG |= 0x80;
TCCR1B = 0x01; /* 启动定时器1,预分频比例1 */
}
/*************************************
在定时器中断中做多个分级定时
*************************************/
void timer()
{
timer1--;
if (timer2 < 0x80)
speed += 0x100;
else
speed -= 0x200;
if (statusm & 0x80)
{
timer2++;
col = (speed >> 8) | timer1;
row = (timer2 & 0x1f) + 32;
point();
}
}
/************************************************/
/*画圆。数学方程(X-Ox)^2+(Y-Oy)^2=Rx^2 */
/************************************************/
void circle(uchar Ox, uchar Oy, uchar Rx)
{
unsigned int xx, rr, xt, yt, rs;
yt = Rx;
rr = Rx * Rx + 1; //补偿 1 修正方形
rs = (yt + (yt >> 1)) >> 1; //(*0.75)分开1/8圆弧来画
for (xt = 0; xt <= rs; xt++)
{
xx = xt * xt;
while ((yt * yt) > (rr - xx))
yt--;
col = Ox + xt; //第一象限
row=Oy-yt;
point();
col = Ox - xt; //第二象限
point();
row = Oy + yt; //第三象限
point();
col = Ox + xt; //第四象限
point();
/***************45度镜象画另一半***************/
col = Ox + yt; //第一象限
row = Oy - xt;
point();
col = Ox - yt; //第二象限
point();
row = Oy + xt; //第三象限
point();
col = Ox + yt; //第四象限
point();
}
}
/************************************************/
/*画线。任意方向的斜线,直线数学方程 aX+bY=1 */
/************************************************/
void Linexy(uchar x0,uchar y0,uchar xt,uchar yt)
{
register uchar t;
int xerr = 0, yerr = 0, delta_x, delta_y, distance;
int incx, incy;
delta_x = xt - x0; /*计算坐标增量 */
delta_y = yt - y0;
col = x0;
row = y0;
if (delta_x > 0)
{
incx = 1; /*设置单步方向 */
}
else if (delta_x == 0 )
incx = 0; /*垂直线 */
else
{
incx =- 1;
delta_x =- delta_x;
}
if (delta_y > 0)
{
incy = 1;
}
else if (delta_y == 0 ) incy = 0; /*水平线 */
else {incy =- 1; delta_y =- delta_y;}
if ( delta_x > delta_y )
distance = delta_x; /*选取基本增量坐标轴*/
else
distance = delta_y;
for (t = 0; t <= distance + 1; t++)
{ /*画线输出 */
point(); /*画点 */
xerr += delta_x;
yerr += delta_y;
if (xerr > distance)
{
xerr -= distance;
col += incx;
}
if( yerr > distance )
{
yerr -= distance;
row += incy;
}
}
}
/****************************************/
/* 画点 */
/****************************************/
void point(void)
{
uchar x1, y1, y;
x1 = col;
y1 = row;
row = y1 >> 3; /*取Y方向分页地址 */
Rddata();
y = y1 & 0x07; /*字节内位置计算 */
Wrdata(cbyte | (1 << y)); /*画上屏幕 */
col = x1; /*恢复xy坐标 */
row = y1;
}
/****************************************/
/* 屏幕滚动定位 */
/****************************************/
void Rollscreen(uchar x)
{
cbyte = DISPFIRST | x; /*定义显示起始行为x?*/
WrcmdL(cbyte);
WrcmdM(cbyte);
WrcmdR(cbyte);
}
/****************************************/
/* 一个字串的输出 */
/****************************************/
void Putstr(uchar x, uchar y, const prog_uchar *puts, uchar i)
{
uchar j, wordx;
for (j = 0; j < i; j++)
{
//wordx = puts[j];
wordx = pgm_read_byte(puts + j); //从ROM中取数据
Delay(2);
if (wordx & 0x80)
{
Putedot(x, y, Hzk, wordx & 0x7f, 16); /*只保留低7位 */
}
else
{
Putedot(x, y, Ezk, wordx - 0x20, 8); /*ascii码表从0x20开始*/
}
x = col;
y = row;
}
}
/****************************************/
/* 字符点阵码数据输出 */
/****************************************/
void Putedot(uchar x, uchar y, const prog_uchar *Lib, uchar Order, uchar widthw)
{
uchar i;
unsigned int xi; /*偏移量,字符量少的可以定义为Uchar */
col = x; /*暂存x,y坐标,已备下半个字符使用 */
row = y;
xi = Order * (widthw << 1); // 每个字符widthw列
/****************上半个字符输出**************/
for (i = 0; i < widthw; i++)
{
//cbyte = Lib[xi]; // 取点阵码,rom数组
cbyte = pgm_read_byte(Lib + xi);
Wrdata(cbyte); // 写输出一字节
xi++;
col++;
if (col == LCMLIMIT)
{
col = 0;
row += 2;
} /*下一列,如果列越界换行*/
if (row > 7)
{
row = 0; /*如果行越界,返回首行 */
}
} /*上半个字符输出结束 */
col = x; /*列对齐 */
row = y + 1; /*指向下半个字符行 */
/****************下半个字符输出****************/
for (i = 0; i < widthw; i++)
{
//cbyte = Lib[xi]; /*取点阵码 */
cbyte = pgm_read_byte(Lib + xi);
Wrdata(cbyte); /*写输出一字节 */
xi++;
col++;
if (col == LCMLIMIT)
{
col = 0;
row += 2;
}; /*下一列,如果列越界换行*/
if (row > 7)
{
row = 1; /*如果行越界,返回首行 */
}
} /*下半个字符输出结束 */
row = y;
} /*整个字符输出结束 */
/****************************************/
/* 清屏,全屏幕清零 */
/****************************************/
void Lcmcls( void )
{
for (row = 0; row < 8; row++)
{
for (col = 0; col < LCMLIMIT; col++)
{
Wrdata(0);
}
}
}
/****************************************/
/* 从液晶片上读数据,保留在全局变量中 */
/****************************************/
void Rddata(void)
{
Locatexy(); /*坐标定位,返回时保留分区状态不变 */
DDRA = 0; /*改变PA口的状态,作为输入口 */
Datalcm = 0xFF;
lcd_set_di(); /*数据 */
lcd_set_rw(); /*读数据 */
lcd_set_e();
asm("NOP"); /*读入到LCM */
cbyte = PINA; /*虚读一次 */
lcd_clear_e();
Locatexy(); /*坐标定位,返回时保留分区状态不变 */
DDRA = 0;
Datalcm = 0xFF;
lcd_set_di(); /*数据 */
lcd_set_rw(); /*读数据 */
lcd_set_e();
asm("NOP"); /*读入到LCM */
cbyte = PINA; /*从数据口读数据,真读 */
lcd_clear_e();
asm("NOP");
DDRA = 0xFF; /*改变PA口的状态,作为输出口 */
}
/****************************************/
/* 数据写输出 */
/****************************************/
void Wrdata(uchar X)
{
Locatexy(); /*坐标定位,保留分区状态不变 */
wtcom();
lcd_set_di(); /*数据输出*/
lcd_clear_rw();
asm("NOP"); /*写输出 */
Datalcm = X; /*数据输出到数据口 */
lcd_set_e(); /*LCM读入*/
asm("NOP");
lcd_clear_e();
}
/********************************/
/* 命令输出到左区控制口 */
/********************************/
void WrcmdL(uchar X)
{
lcdbusyL(); /*确定分区,返回时保留分区状态不变*/
lcd_clear_di(); /*命令操作 */
lcd_clear_rw();
asm("NOP"); /*写输出 */
Datalcm = X; /*数据写到数据口 */
lcd_set_e();
asm("NOP");
lcd_clear_e(); /*LCM读入*/
}
/********************************/
/* 命令输出到中区控制口 */
/********************************/
void WrcmdM(uchar X)
{
lcdbusyM(); /*确定分区,保留分区状态不变*/
lcd_clear_di(); /*命令操作 */
lcd_clear_rw();
asm("NOP"); /*写输出 */
Datalcm = X; /*命令写到数据口*/
lcd_set_e();
asm("NOP");
lcd_clear_e(); /*LCM读入*/
}
/********************************/
/* 命令输出到右区控制口 */
/********************************/
void WrcmdR(uchar X)
{
lcdbusyR(); /*确定分区,保留分区状态不变 */
lcd_clear_di(); /*命令操作 */
lcd_clear_rw();
asm("NOP"); /*写输出 */
Datalcm = X; /*命令输出到数据口 */
lcd_set_e();
asm("NOP");
lcd_clear_e(); /*读入到LCM */
}
/********************************************************/
/* 分区操作允许等待,返回时保留分区选择状态 */
/********************************************************/
void lcdbusyL(void)
{
lcd_clear_cs1(); /*CLR CS1 */
lcd_set_cs2(); /*SETB CS2 */
lcd_set_cs3(); /*SETB CS3 */
wtcom(); /* waitting for enable */
}
void lcdbusyM(void)
{
lcd_set_cs1(); /*SETB CS1 */
lcd_clear_cs2(); /*CLR CS2 */
lcd_set_cs3(); /*SETB CS3 */
wtcom(); /* waitting for enable */
}
void lcdbusyR(void)
{
lcd_set_cs1(); /*SETB CS1 */
lcd_set_cs2(); /*SETB CS2 */
lcd_clear_cs3(); /*CLR CS3 */
wtcom(); /* waitting for enable */
}
void wtcom(void)
{
DDRA = 0;
lcd_clear_di(); /*CLR DI */
lcd_set_rw(); /*SETB RW */
Datalcm = 0xFF; /*MOV DATA_LCM,#0FFH */
lcd_set_e();
asm("NOP");
while(lcd_read_status());
lcd_clear_e();
DDRA = 0xFF;
}
/********************************************************/
/*根据设定的坐标数据,定位LCM上的下一个操作单元位置 */
/********************************************************/
void Locatexy(void)
{
uchar x,y;
switch (col & 0xc0) /* col.and.0xC0 */
{ /*条件分支执行 */
case 0:
lcdbusyL();
break; /*左区 */
case 0x40:
lcdbusyM();
break; /*中区 */
case 0x80:
lcdbusyR();
break; /*右区 */
default:
break;
}
x = (col & 0x3F) | SETX; /* col.and.0x3f.or.setx */
y = (row & 0x07) | SETY; /* row.and.0x07.or.sety */
wtcom(); /* waitting for enable */
lcd_clear_di(); /*CLR DI */
lcd_clear_rw(); /*CLR RW */
asm("NOP");
Datalcm = y; /*MOV P0,Y */
lcd_set_e();
asm("NOP");
lcd_clear_e();
wtcom(); /* waitting for enable */
lcd_clear_di(); /*CLR DI */
lcd_clear_rw(); /*CLR RW */
asm("NOP");
Datalcm = x; /*MOV P0,X */
lcd_set_e();
asm("NOP");
lcd_clear_e();
}
/********************************/
/*液晶屏初始化 */
/********************************/
void Lcminit(void)
{
cbyte = DISPOFF; /*关闭显示屏 */
WrcmdL(cbyte);
WrcmdM(cbyte);
WrcmdR(cbyte);
cbyte = DISPON; /*打开显示屏 */
WrcmdL(cbyte);
WrcmdM(cbyte);
WrcmdR(cbyte);
cbyte = DISPFIRST; /*定义显示起始行为零 */
WrcmdL(cbyte);
WrcmdM(cbyte);
WrcmdR(cbyte);
Lcmcls(); /*清屏 */
}
/********************************/
/* 延时 */
/********************************/
void Delay(uchar MS)
{
uchar i;
for (i = 0; i < MS; i++)
{
_delay_loop_2(CRYSTAL * 25);
}
} |
|