|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2009-1-14 09:42:19
|
显示全部楼层
问题症状:ATMEGA16芯片+ST7920 12864液晶(SYB12864J-ZK)蓝底白字,
1.显示汉字或大片(128*64)正常,
2.显示小图片(32*24)周围会有很多杂点,见图所示,即使在写图片之前,写图函数
LCD12864_opGDRAM(0x00);已经写0x00了!!!!!!并且清0了!!!!还是有杂点,换了一个旧的液晶TG12864E-03
还是一样的,不知道什么原因?
![](http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_586384.jpg)
(原文件名:ST7920 12864液晶图文菜单显示问题.jpg)
/*******************************************
文件:ST7920 12864液晶图文菜单显示.C
环境:编译为ICC AVR6.31A,仿真为AVR Studio4.14
硬件:ATMEGA16芯片
日期:2008年12月10日
** Author:ZRP QQ:978710555 E_Mail:zrp_ncu@163.com
** Time : 2009-1-4
/******************************************/
#include <iom16v.h> //包含型号头文件
#include <macros.h> //包含"位"操作头文件
#include <stdio.h> //标准输入输出头文件
#include <AVR_EB1A.H> //包含自定义常量头文件
#pragma data:code
//以下是字模工具取出的图片数组
/*========================== 菜单图片(宽度x高度=32*24)=============================*/
const uchar menu_pic[6][96]={
// 调整
{0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFE,0x40,0x00,0x00,0x02,0x40,0x00,0x00,0x02,
0x40,0x00,0x00,0x82,0x47,0xFF,0xE1,0xC2,0x47,0xFF,0xF3,0xE2,0x47,0x38,0x68,0x02,
0x46,0xDF,0x68,0x82,0x46,0xDF,0x69,0xC2,0x46,0xDE,0xE8,0x82,0x46,0xDD,0xE8,0x02,
0x46,0xDD,0xE8,0x02,0x47,0x3D,0xE8,0x02,0x47,0xFF,0xE8,0x02,0x47,0xFF,0xE9,0xC2,
0x42,0x00,0x18,0x02,0x41,0xFF,0xF3,0xE2,0x40,0x00,0x01,0xC2,0x40,0x00,0x00,0x82,
0x40,0x00,0x00,0x02,0x40,0x00,0x00,0x02,0x7F,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00
},
// 工具
{0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFE,0x40,0x00,0x00,0x02,0x40,0x00,0x03,0x82,
0x41,0xF0,0x07,0xC2,0x43,0xFF,0xCF,0xE2,0x47,0x3F,0xFE,0x02,0x47,0x3F,0xFE,0x02,
0x43,0xFF,0xCF,0xE2,0x41,0xF0,0x0F,0xC2,0x40,0x00,0x03,0x82,0x40,0x00,0x00,0x02,
0x40,0x00,0x03,0xC2,0x40,0x00,0x03,0xC2,0x41,0x80,0x01,0x82,0x43,0xFF,0xF3,0xC2,
0x47,0xFF,0xFF,0xE2,0x47,0xFF,0xFF,0xE2,0x43,0xFF,0xF3,0xC2,0x41,0x80,0x01,0x82,
0x40,0x00,0x01,0x82,0x40,0x00,0x00,0x02,0x7F,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00
},
// 设置
{0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFE,0x40,0x00,0x00,0x02,0x43,0x18,0x00,0x02,
0x44,0xA4,0x0E,0x02,0x44,0xA4,0x1F,0x02,0x43,0x24,0x3F,0x02,0x40,0x00,0x7F,0x02,
0x40,0xF0,0xFC,0x02,0x43,0xF9,0xF0,0x02,0x43,0x03,0xE0,0x02,0x46,0x77,0x80,0x02,
0x46,0x7F,0x00,0x02,0x46,0x7E,0x00,0x02,0x46,0x7C,0x00,0x02,0x47,0x3D,0x00,0x02,
0x43,0x1D,0x81,0x22,0x43,0x81,0xB2,0x42,0x41,0xC3,0x4F,0xE2,0x40,0xFE,0x4A,0x42,
0x40,0x3C,0x32,0x42,0x40,0x00,0x00,0x02,0x7F,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00
},
// 保密
{0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFE,0x40,0x00,0x00,0x02,0x40,0xFC,0x03,0x02,
0x41,0xFE,0x1F,0x02,0x43,0x87,0x03,0x82,0x43,0x03,0x03,0x02,0x43,0x03,0x03,0x02,
0x43,0x03,0x0F,0x02,0x43,0x03,0x03,0x02,0x43,0x03,0x03,0x02,0x47,0xFF,0x83,0x02,
0x47,0xFF,0x83,0x02,0x47,0xCF,0x83,0x02,0x47,0x87,0x83,0x02,0x47,0xCF,0x83,0x02,
0x47,0xCF,0x87,0x82,0x47,0xCF,0x8F,0xC2,0x47,0xCF,0x9C,0xE2,0x47,0xFF,0x8F,0xC2,
0x43,0xFF,0x07,0x82,0x40,0x00,0x00,0x02,0x7F,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00
},
// 版本
{0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFE,0x40,0x00,0x00,0x02,0x40,0x00,0x00,0x02,
0x40,0x0F,0x00,0x62,0x40,0x1D,0x80,0xF2,0x40,0x38,0x41,0xF2,0x40,0x70,0x23,0xE2,
0x40,0xE2,0x17,0xC2,0x41,0xE4,0x4F,0x82,0x41,0xF0,0x9F,0x02,0x41,0x59,0x16,0x02,
0x42,0x4C,0x1D,0x02,0x42,0x46,0x20,0x82,0x42,0x47,0x00,0x42,0x44,0x43,0x80,0xC2,
0x44,0x44,0xC1,0xC2,0x44,0xC8,0x63,0x82,0x45,0x50,0x37,0x02,0x46,0x60,0x1E,0x02,
0x40,0x40,0x0C,0x02,0x40,0x00,0x00,0x02,0x7F,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00
},
// 退出
{0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFE,0x40,0x00,0x00,0x02,0x40,0x40,0xFF,0xE2,
0x40,0x60,0x80,0x62,0x43,0xF0,0x80,0xA2,0x43,0xF0,0x81,0x22,0x40,0x60,0x82,0x22,
0x40,0x40,0x84,0x22,0x40,0x00,0x88,0x22,0x40,0x00,0x88,0x22,0x47,0xFF,0xF8,0x22,
0x47,0xFF,0xF8,0x22,0x46,0x2A,0x2A,0x22,0x46,0xE3,0x78,0x22,0x46,0x77,0x78,0x22,
0x46,0xE3,0x78,0x62,0x46,0x2A,0x38,0x82,0x47,0xFF,0xF9,0x02,0x47,0xFF,0xFA,0x02,
0x40,0x00,0x0C,0x02,0x40,0x00,0x00,0x02,0x7F,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00
}
};
#pragma data:data
uchar menu_cn[6][8]={"调 整","工 具","设 置","保 密","版 本","退 出"};
/*******************************************
函数名称: EN_Toggle
功 能: EN端产生一个高电平使能脉冲,写LCD
参 数: 无
返回值 : 无
/********************************************/
void EN_Toggle(void) //EN端产生一个高电平使能脉冲,写LCD
{
LCDb_SET_E; //拉高使能位
Delayus(50); //保持高电平一定的写时间,如果晶振频率太高,则可相应提高延时
LCDb_CLR_E;
Delayus(50);
}
/*******************************************
函数名称: LCD12864_readbyte
功 能: 从12864液晶读出一个字节数据或者指令
参 数: DatCmd--为iDat时是数据,为iCmd时是指令
返回值 : dByte--读回的数据或者指令
/********************************************/
uchar LCD12864_readbyte(uchar DatCmd)
{
uchar dByte;
if (DatCmd == iCmd) //指令操作
LCDb_CLR_RS;
else
LCDb_SET_RS;
LCDb_SET_RW; //读操作
LCDb_SET_E;
LCDb_DATA_DDR=0x00; //数据总线定义为输入
dByte=LCDb_DI; //读数据或者指令
LCDb_CLR_E;
LCDb_DATA_DDR|=0xff; //数据总线还原为输出
return dByte;
}
/*******************************************
函数名称: LCD12864_writebyte
功 能: 向12864液晶写入一个字节数据或者指令
参 数: DatCmd--为iDat时是数据,为iCmd时是指令
dByte--为写入12864的数据或者指令
返回值 : 无
/********************************************/
void LCD12864_writebyte(uchar DatCmd, uchar dByte)
{
if (DatCmd == iCmd) //指令操作
LCDb_CLR_RS;
else
LCDb_SET_RS;
LCDb_CLR_RW; //写操作
//LCDb_SET_E;
LCDb_DO = dByte; //写入数据
//LCDb_CLR_E;
EN_Toggle(); //EN端产生一个高电平使能脉冲,写LCD
}
/*******************************************
函数名称: LCD12864_sendstr
功 能: 向12864液晶写入一个字符串
参 数: ptString--字符串指针
返回值 : 无
/********************************************/
void LCD12864_sendstr(uchar *ptString)
{
while((*ptString)!='\0') //字符串未结束一直写
{
LCD12864_writebyte(iDat, *ptString++);
}
}
/*******************************************
函数名称: LCD12864_clear
功 能: 12864液晶清屏
参 数: 无
返回值 : 无
/********************************************/
void LCD12864_clear(void)
{
LCD12864_writebyte(iCmd,LCDb_CLS);
Delayms(2);// 清屏指令写入后,2ms 的延时是很必要的!!!
}
/*******************************************
函数名称: LCD12864_readBF
功 能: 12864液晶清屏
参 数: 无
返回值 : busy--为1时忙,为0时可以接收指令
/********************************************/
uchar LCD12864_readBF(void)
{
uchar busy;
busy=LCD12864_readbyte(iCmd); //读回BF标志和地址
if(busy&0x80) //读最高位PB7,为0表示空闲,如果忙返回正在忙的状态
busy=1;
else //不忙,可以写入
busy=0;
return busy;
}
/*******************************************
函数名称: LCD12864_gotoXY
功 能: 移动到指定位置
参 数: Row--指定的行
Col--指定的列
返回值 : 无
/********************************************/
void LCD12864_gotoXY(uchar Row, uchar Col)
{
switch (Row) //选择行
{
case 2:
LCD12864_writebyte(iCmd, LCDb_L2 + Col); break; //写入第2行的指定列
case 3:
LCD12864_writebyte(iCmd, LCDb_L3 + Col); break; //写入第3行的指定列
case 4:
LCD12864_writebyte(iCmd, LCDb_L4 + Col); break; //写入第4行的指定列
default:
LCD12864_writebyte(iCmd, LCDb_L1 + Col); break; //写入第1行的指定列
}
}
/*******************************************
函数名称: LCD12864_opGDRAM
功 能: 向GDRAM写入数据,并显示(完成绘图功能)
参 数: ptGDRAM--GDRAM数据指针
返回值 : 无
/********************************************/
void LCD12864_opGDRAM(const uchar *ptGDRAM)
{
uchar i,j;
uint x=0;
while(LCD12864_readBF()); //读忙标志
LCD12864_writebyte(iCmd,LCDb_EXTCMD1); //扩充指令集,并关闭绘图显示
//写入并显示上半屏幕
for(i=0;i<32;i++) //行地址计数
{
for(j=0;j<8;j++) //列地址计数
{
LCD12864_writebyte(iCmd,0x80|i);//输入行地址
LCD12864_writebyte(iCmd,0x80|j);//输入列地址
LCD12864_writebyte(iDat,ptGDRAM[x++]); //输入高位字节数据
LCD12864_writebyte(iDat,ptGDRAM[x++]); //输入低位字节数据
}
}
//写入并显示下半屏幕
for(i=0;i<32;i++)
{
for(j=8;j<16;j++)
{
LCD12864_writebyte(iCmd,0x80|i);//输入行地址
LCD12864_writebyte(iCmd,0x80|j);//输入列地址
LCD12864_writebyte(iDat,ptGDRAM[x++]); //输入高位字节数据
LCD12864_writebyte(iDat,ptGDRAM[x++]); //输入低位字节数据
}
}
Delayus(10);
LCD12864_writebyte(iCmd,LCDb_EXTCMD2); //打开绘图显示
LCD12864_writebyte(iCmd,LCDb_BASCMD); //还原回基本指令集模式
}
/*******************************************
函数名称: LCD12864_portini
功 能: 初始化12864液晶用到的IO口
参 数: 无
返回值 : 无
/********************************************/
void LCD12864_portini(void)
{
LCDb_CTRL_DDR |= BIT(LCDb_RS)|BIT(LCDb_RW)|BIT(LCDb_E)|BIT(LCDb_RST);//配置控制管脚为输出
LCDb_DATA_DDR |= 0xFF; //配置数据管脚为输出
LCDb_SET_RST; //不使能复位端
}
/*=====================================================================================
函数名称:画面构造
功能描述:界面1、2、3,图片菜单,反白,标头,16*16(32)图片
全局变量:无
参数说明:函数说明
返回说明:无
说 明:X坐标每一格每次16点
======================================================================================*/
/*反白或显示图片 参数格式:(H)8bit数据,(L)8bit数据,X0坐标(16bit),Y0坐标(1bit),X坐标(16bit),Y坐标(1bit)*/
void con_disp (uchar data1,uchar data2,uchar x0,uchar y0,uchar xl,uchar yl)
{
uchar i,j;
for(j=0;j<yl;j++)
{
for(i=0;i<xl;i++)
{
LCD12864_writebyte(iCmd,0x34); // 扩展功能
LCD12864_writebyte(iCmd,y0+j); // 写Y坐标
LCD12864_writebyte(iCmd,x0+i); // 写X坐标
LCD12864_writebyte(iCmd,0x30); // 普通功能,基本指令集
LCD12864_writebyte(iDat,data1);
LCD12864_writebyte(iDat,data2);
}
}
LCD12864_writebyte(iCmd,0x36); // 开绘图显示
}
/*显示字体 参数格式: 显示位置(0x80-0x9f),显示个数,显示内容指针*/
void display_cnasc(uchar dis_bit,uchar num,uchar *cnasc)
{
LCD12864_writebyte(iCmd,0x30); // 普通功能
LCD12864_writebyte(iCmd,dis_bit); // 写地址
while(num>0)
{
LCD12864_writebyte(iDat,*(cnasc++));
LCD12864_writebyte(iDat,*(cnasc++));
num--;
}
Delayus(10);
}
/*图片显示标头*/
void dis_title_pic(void)
{
display_cnasc(0x80,2,"〓〓");
display_cnasc(0x86,2,"〓〓");
}
/*显示菜单图片 格式:图片反显(1)或正常显示(0),显示图片的号码*/
void anti_nor_pic(uchar cpl_sign,uchar menu_num)
{
uchar i,j,x,y;
x=menu_num*3; // 计算图片显示坐标
if(x>6) x--;
if(menu_num<3) y=16; //下半屏显示
else y=8; // 上半屏显示
if(cpl_sign==1)
display_cnasc(0x82,4,menu_cn[menu_num]); //显示选择的菜单标题
for(j=0;j<24;j++)
{
for(i=0;i<2;i++)
{
LCD12864_writebyte(iCmd,0x34); // 扩充指令集,关闭绘图显示
LCD12864_writebyte(iCmd,0x80+y);
LCD12864_writebyte(iCmd,0x80+x+i); // 分两次显示16bit
LCD12864_writebyte(iCmd,0x30); // 基本指令集
if(cpl_sign==1) // 图片反选
{
con_disp(~menu_pic[menu_num][j*4+i*2]);
con_disp(~menu_pic[menu_num][j*4+i*2+1]);
}
else // 正常显示
{
con_disp(menu_pic[menu_num][j*4+i*2]);
con_disp(menu_pic[menu_num][j*4+i*2+1]);
}
}
y++;
if(y==32&&menu_num<3) {x+=8;y=0;} // 上下屏切换
}
LCD12864_writebyte(iCmd,0x36); // 扩充指令集,打开绘图显示
}
/*******************************************
函数名称: LCD12864_initial
功 能: 12864液晶初始化
参 数: 无
返回值 : 无
/********************************************/
void LCD12864_initial(void)
{
Delayms(100); // 等待内部复位
LCD12864_portini(); //端口初始化
LCD12864_writebyte(iCmd, LCDb_FUNCTION_8BIT); //功能、模式设定
while(LCD12864_readBF());
LCD12864_writebyte(iCmd, LCDb_ON); //打开显示
while(LCD12864_readBF());
LCD12864_clear(); //清屏
while(LCD12864_readBF());
LCD12864_writebyte(iCmd, LCDb_ENTRY); // 输入模式设定
//clear_dis();
LCD12864_opGDRAM(0x00);
//LCD12864_writebyte(iCmd,LCDb_CURON); // 显示光标
//LCD12864_writebyte(iCmd,LCDb_CURFLA); // 打开光标闪烁
//LCD12864_writebyte(iCmd,LCDb_C2R); //光标右移
}
/****************************************************************************
/***************************************************************************
函数名称: DIS_12864M
功 能: DIS_12864M
参 数: keynum[]--键值数组
返回值 : 无
/********************************************/
void DIS_12864M(void)
{
uchar i,j;
for(i=0;i<6;i++)
{
dis_title_pic(); //显示图片菜单
anti_nor_pic(0,i);
anti_nor_pic(1,2); //后面数字是要显示的图片位置
}
Delayms(2000);
}
/*******************************************
函数名称:main
功 能: Dis_inputkey
参 数: 无
返回值 : 无
/********************************************/
void main(void)
{
uchar i=0;
Board_init(); //初始化开发板
LCD12864_initial(); //初始化12864液晶
//调用显示程序
while (1)
{
DIS_12864M();
}
}
**********************头文件*********************************
/*******************************************
文件:AVR_EB1A.H
功能:定义一些AVR_EB1A开发板上应用程序用到的常量
/******************************************/
#include <iom16v.h> //包含型号头文件
#include <macros.h> //包含"位"操作头文件
/******************数据类型宏定义******************/
#define uchar unsigned char
#define uint unsigned int
/*******************************************
函数名称: Delayus
功 能: 延时指定微秒(8M晶振)
参 数: US--延时的微秒数(大约,不是很精确,MS越大越准确)
返回值 : 无
/********************************************/
void Delayus(uint US)
{
uint i;
US=US*5/4; //5/4是在8MHz晶振下,通过软件仿真反复实验得到的数值
for( i=0;i<US;i++);
}
/*******************************************
函数名称: Delayms
功 能: 延时指定毫秒(8M晶振)
参 数: MS--延时的毫秒数
返回值 : 无
/********************************************/
void Delayms(uint MS)
{
uint i,j;
for( i=0;i<MS;i++)
for(j=0;j<1141;j++); //1141是在8MHz晶振下,通过软件仿真反复实验得到的数值
}
/*******************************************
函数名称: Board_init
功 能: 初始化实验板,关闭全部功能
参 数: 无
返回值 : 无
/********************************************/
void Board_init(void)
{
DDRA=0xFF; //将四个IO口全部配置为输出
DDRB=0xFF;
DDRC=0xFF;
DDRD=0xFF;
}
/******************12864液晶(4-8线并行传输)常量及操作******************/
#define LCDb_CTRL PORTD //12864控制端口定义
#define LCDb_CTRL_DDR DDRD //控制端口方向寄存器定义
#define LCDb_RS PD4 //定义四个控制引脚
#define LCDb_RW PD5
#define LCDb_E PD6
#define LCDb_RST PD7
#define LCDb_L1 0x80 //第一行的地址
#define LCDb_L2 0x90 //第二行的地址
#define LCDb_L3 0x88 //第三行的地址
#define LCDb_L4 0x98 //第四行的地址
#define LCDb_CGRAM_ADDR 0x40 //CGRAM的开始地址
#define LCDb_CGMAX 64 //CGRAM存储的最大字节数
#define LCDb_SET_RS LCDb_CTRL|=BIT(LCDb_RS) //四个控制管脚的控制操作
#define LCDb_SET_RW LCDb_CTRL|=BIT(LCDb_RW)
#define LCDb_SET_E LCDb_CTRL|=BIT(LCDb_E)
#define LCDb_SET_RST LCDb_CTRL|=BIT(LCDb_RST)
#define LCDb_CLR_RS LCDb_CTRL&=~BIT(LCDb_RS)
#define LCDb_CLR_RW LCDb_CTRL&=~BIT(LCDb_RW)
#define LCDb_CLR_E LCDb_CTRL&=~BIT(LCDb_E)
#define LCDb_CLR_RST LCDb_CTRL&=~BIT(LCDb_RST)
#define LCDb_DO PORTB //输出数据总线端口定义
#define LCDb_DI PINB //输入数据总线端口定义
#define LCDb_DATA_DDR DDRB //数据总线方向寄存器定义
#define LCDb_DATA 0Xf0 //((1<<PB4)|(1<<PB5)|(1<<PB6)|(1<<PB7))
//portB4/5/6/7out,输出数据总线端口定义
#define LCDb_FUNCTION_8BIT 0x38 //液晶模式为8位
#define LCDb_FUNCTION_4BIT 0x20 //液晶模式为4位
#define LCDb_BASCMD 0x30 // 基本指令集
#define LCDb_CLS 0x01 // 清屏
#define LCDb_HOME 0x02 // 地址返回原点,不改变DDRAM内容
#define LCDb_ENTRY 0x06 // 设定输入模式,光标加,屏幕不移动
#define LCDb_CURON 0x0E // 显示光标
#define LCDb_CURFLA 0x0F // 打开光标闪烁
#define LCDb_C2L 0x10 // 光标左移
#define LCDb_C2R 0x14 // 光标右移
#define LCDb_D2L 0x18 // 屏幕左移
#define LCDb_D2R 0x1C // 屏幕又移
#define LCDb_ON 0x0C // 打开显示
#define LCDb_OFF 0x08 // 关闭显示
#define LCDb_EXTCMD1 0x34 // 扩充指令集,关闭绘图显示
#define LCDb_EXTCMD2 0x36 // 扩充指令集,打开绘图显示
#define LCDb_EXTCLS 0x01 // 清屏
#define LCDb_REVL1 0x04 // 反显第1行
#define LCDb_REVL2 0x05 // 反显第2行
#define LCDb_REVL3 0x06 // 反显第3行
#define LCDb_REVL4 0x07 // 反显第4行
本贴被 21mcuel 编辑过,最后修改时间:2009-01-14,13:13:04. |
|