仿真时液晶的点来回跳动,请问是什么原因
#include <reg51.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define DATA P0 //LCD12864数据线
sbit RS=P2^2; // 数据\指令 选择
sbit RW=P2^1; // 读\写 选择
sbit EN=P2^0; // 读\写使能
sbit cs1=P2^4; // 片选1
sbit cs2=P2^3; // 片选2
/*状态检查,LCD是否忙*/
void CheckState()
{
uchar dat;//状态信息(判断是否忙)
RS=0; // 数据\指令选择,D/I(RS)=“L” ,表示 DB7∽DB0 为显示指令数据
RW=1; //R/W=“H” ,E=“H”数据被读到DB7∽DB0
do{
DATA=0x00;
EN=1; //EN下降源
_nop_(); //一个时钟延时
dat=DATA;
EN=0;
dat=0x80 & dat; //仅当第7位为0时才可操作(判别busy信号)
}while(!(dat==0x00));
}
/*写命令到LCD中*/
void SendCommandToLCD(uchar com)
{
CheckState();//状态检查,LCD是否忙
RS=0; //向LCD发送命令。RS=0写指令,RS=1写数据
RW=0;//R/W=“L” ,E=“H→L”数据被写到 IR 或 DR
DATA=com; //com :命令
EN=1;//EN下降源
_nop_();
_nop_();
EN=0;
}
/*设置页 0xb8是页的首地址*/
void SetLine(uchar page)
{
page=0xb8|page; //1011 1xxx 0<=page<=7 设定页地址--X 0-7,8行为一页64/8=8,共8页
SendCommandToLCD(page);
}
/*设定显示开始行,0xc0是行的首地址*/
void SetStartLine(uchar startline)
{
startline=0xc0|startline; //1100 0000
SendCommandToLCD(startline); //设置从哪行开始:0--63,一般从0 行开始显示
}
/*设定列地址--Y 0-63 ,0x40是列的首地址*/
void SetColumn(uchar column)
{
column=column &0x3f; //column最大值为64,越出 0=<column<=63
column= 0x40|column; //01xx xxxx
SendCommandToLCD(column);
}
/*开关显示,0x3f是开显示,0x3e是关显示*/
void SetOnOff(uchar onoff)
{
onoff=0x3e|onoff; //0011 111x,onoff只能为0或者1
SendCommandToLCD(onoff);
}
/*写显示数据 */
void WriteByte(uchar dat)
{
CheckState();//状态检查,LCD是否忙
RS=1; //RS=0写指令,RS=1写数据
RW=0;////R/W=“L” ,E=“H→L”数据被写到 IR 或 DR
DATA=dat;//dat:显示数据
EN=1; //EN下降源
_nop_();
_nop_();
EN=0;
}
/*选择屏幕screen: 0-全屏,1-左屏,2-右屏*/
void SelectScreen(uchar screen)
{
switch(screen)
{ case 0: cs1=0;//全屏
_nop_(); _nop_(); _nop_();
cs2=0;
_nop_(); _nop_(); _nop_();
break;
case 1: cs1=0;//左屏
_nop_(); _nop_(); _nop_();
cs2=1;
_nop_(); _nop_(); _nop_();
break;
case 2: cs1=1;//右屏
_nop_(); _nop_(); _nop_();
cs2=0;
_nop_(); _nop_(); _nop_();
break;
}
}
/*清屏screen: 0-全屏,1-左屏,2-右*/
void ClearScreen(uchar screen)
{
uchar i,j;
SelectScreen(screen);
for(i=0;i<8;i++) //控制页数0-7,共8页
{
SetLine(i);
SetColumn(0);
for(j=0;j<64;j++) //控制列数0-63,共64列
{
WriteByte(0x00); //写点内容,列地址自动加1
}
}
}
/*延时程序*/
void delay(uint z)
{
uint i,j;
for(i=0; i<z; i++)
for(j = 0; j < 110; j++);
}
/*初始化LCD*/
void InitLCD()
{
CheckState();
SelectScreen(0);
SetOnOff(0); //关显示
SelectScreen(0);
SetOnOff(1); //开显示
SelectScreen(0);
ClearScreen(0);//清屏
SetStartLine(0); //开始行:0
}
void GUI_Point(uchar x,uchar y,uchar flag)
{
uchar x_Dyte,x_byte; //定义列地址的字节位,及在字节中的哪1位
uchar y_Dyte,y_byte; //定义为上下两个屏(取值为0,1),行地址(取值为0~31)
uchar GDRAM_hbit;
uchar GDRAM_lbit;
uchar shuju;
/***X,Y坐标互换,即普通的X,Y坐标***/
x_Dyte=y/16; //计算在16个字节中的哪一个
x_byte=y&0x0f; //计算在该字节中的哪一位
y_Dyte=x/32; //0为上半屏,1为下半屏
y_byte=x&0x1f; //计算在0~31当中的哪一行
GDRAM_hbit=shuju&0xF0; //读取当前显示高8位数据
GDRAM_lbit=shuju&0x0F; //读取当前显示低8位数据
_nop_();
_nop_();
_nop_();
if(flag==1)
{
SetStartLine(0x80+y_byte); //设定行地址(y坐标)
SetColumn(0x80+x_Dyte); //设定列地址(x坐标)
if(y_Dyte<32)
{
SelectScreen(2);
}
else
{
SelectScreen(0);
}
if(x_byte<8) //判断其在高8位,还是在低8位
{
WriteByte(GDRAM_hbit|(0X01<<(7-x_byte))); //显示GDRAM区高8位数据
WriteByte(GDRAM_lbit); //显示GDRAM区低8位数据
}
else
{
WriteByte(GDRAM_hbit);
WriteByte(GDRAM_lbit|(0x01<<(15-x_byte)));
}
}
else
{
WriteByte(0x00); //清除GDRAM区高8位数据
WriteByte(0x00); //清除GDRAM区低8位数据
}
}
/**********读取当前地址的LCD显示数据**********/
void Read_data()
{
uchar shuju;
RS=1; // D/I=1,代表数据
RW=1; // R/W=1.读取
delay(10);
EN=1;
delay(100);
shuju=DATA; //读取当前显示的数据
_nop_();
EN=0;
return;
}
void hualinex(uchar x0,uchar x1,uchar y,uchar flag)
{
uchar temp;
if(x0>x1)
{
temp=x1;
x1=x0;
x0=temp;
}
for(;x0<=x1;x0++)
GUI_Point(x0, y,flag);
}
/*主函数*/
void main()
{
InitLCD();//初始12864
ClearScreen(0);
SetStartLine(0);//显示开始行
while(1)
{
hualinex(0,127,0,1);
}
}
大虾,请问有没有Proteus中的硬件电路图,
LCD_DATA EQU P0 ;液晶并行数据口
LCD_RS EQU P2.0 ;液晶指令数据选择:H=数据 L=指令
LCD_RW EQU P2.1 ;液晶读写信号控制: H=读 L=写
LCD_E EQU P2.2 ;液晶数据锁存信号: 下降沿锁存
LCD_SPB EQU P2.3 ;液晶通信格式: H=并行 L=串行
LCD_RES EQU P2.4 ;液晶复位信号: 低电平复位
POW_EN EQU P2.6
TX_EN EQU P2.5
DISP_ON EQU 20H.0
SCAN_BIT EQU 20H.1
;液晶显示区首地址:第一行:30H~3FH,第二行:40H~4FH,第三行:50H~5FH,第四行:60H~6FH
ORG 0000H
JMP MAIN
ORG 0023H
JMP RS_232
主程序:
MAIN:CLR DISP_ON
CLR SCAN_BIT
SETB POW_EN
CLR TX_EN
MOV R1,#30H ;指向存储区首地址
MOV R5,#0
MOV R4,#0
CALL LCD_INIT
CALL RS232_INIT
CALL DELY2
CALL DELY2
CALL DELY2
MAIN_LOOP:JNB DISP_ON,$
CALL DISP_RAM
CLR DISP_ON
JMP MAIN_LOOP
RET
串口初始化程序:
RS232_INIT:MOV TMOD,#20H
MOV SCON,#50H
MOV TL1,#0FAH
MOV TH1,#0FAH
SETB TR1
SETB ES
SETB EA
RET
显示RAM区程序:
DISP_RAM:MOV A,#80H
CALL WRITE_COM
MOV R0,#30H
DISP_RAM_JMP1:MOV A,@R0
CALL WRITE_DATA
INC R0
CJNE R0,#40H,DISP_RAM_JMP1
MOV A,#90H
CALL WRITE_COM
DISP_RAM_JMP2:MOV A,@R0
CALL WRITE_DATA
INC R0
CJNE R0,#50H,DISP_RAM_JMP2
MOV A,#88H
CALL WRITE_COM
DISP_RAM_JMP3:MOV A,@R0
CALL WRITE_DATA
INC R0
CJNE R0,#60H,DISP_RAM_JMP3
MOV A,#98H
CALL WRITE_COM
DISP_RAM_JMP4:MOV A,@R0
CALL WRITE_DATA
INC R0
CJNE R0,#70H,DISP_RAM_JMP4
RET
液晶初始化程序:
LCD_INIT: CLR LCD_RES ;复位
CALL DELY2 ;复位延时
CALL DELY2 ;复位延时
SETB LCD_RES ;复位结束
CALL DELY2 ;复位延时
CALL DELY2 ;复位延时
SETB LCD_SPB ;并行通信方式
MOV A,#30H
CALL WRITE_COM
CALL DELY1
MOV A,#03H
CALL WRITE_COM
CALL DELY1
MOV A,#0CH
CALL WRITE_COM
CALL DELY1
MOV A,#01H
CALL WRITE_COM
CALL DELY1
MOV A,#06H
CALL WRITE_COM
CALL DELY1
RET
液晶写指令,入口地址A
WRITE_COM:CLR LCD_RS
CLR LCD_RW
SETB LCD_E
MOV LCD_DATA,A
NOP
NOP
CLR LCD_E
CALL DELY1
RET
液晶写数据,入口地址A
WRITE_DATA:SETB LCD_RS
CLR LCD_RW
SETB LCD_E
MOV LCD_DATA,A
NOP
NOP
CLR LCD_E
CALL DELY1
RET
延时程序1
DELY1:MOV R7,#255
DJNZ R7,$
RET
延时程序2
DELY2:MOV R6,#255
DELY2_JMP1:CALL DELY1
DJNZ R6,DELY2_JMP1
RET
串口中断程序
RS_232:PUSH A
MOV A,SBUF
JB SCAN_BIT,RS_232_JMP1
CJNE A,#99H,RS_232_JMP0
INC R5
CJNE R5,#2,RS_232_EXIT
MOV R1,#30H
MOV R4,#0
SETB SCAN_BIT
RS_232_JMP0:MOV R5,#0
JMP RS_232_EXIT
RS_232_JMP1:CJNE A,#0AAH,RS_232_JMP2
INC R4
CJNE R4,#3,RS_232_JMP3
MOV R5,#0
CLR SCAN_BIT
SETB DISP_ON
JMP RS_232_EXIT
RS_232_JMP2:MOV R4,#0
RS_232_JMP3:CJNE R1,#70H,RS_232_JMP4
JMP RS_232_EXIT
RS_232_JMP4:MOV @R1,A
INC RRS_232_EXIT:POP A
CLR RI
RETI
要么就是电压不稳,要么就是CS1、CS2问题,因为它们两个不能够联在一起一个是显示左半,一个是显示右半的吗
欢迎光临 (http://www.51hei.com/bbs/) | Powered by Discuz! X3.1 |