仿真時液晶的點來回跳動,請問是什么原因
#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.zg4o1577.cn/bbs/) | Powered by Discuz! X3.1 |