
/此程序适用于FYD12864-0402B/
#include <REG932H>
#define uchar unsigned char
#define uint unsigned int
//uchar data CMD;
//uchar data DATA;
uchar idata busy,Line,Col;
sbit RS= P2^0;
sbit RW= P2^1;
sbit E= P1^7;
sbit LCD_LIGHT= P2^7;
sbit LCD_RST= P2^6;
code char STR1[]= "成都飞宇达";
code char STR2[]= "欢迎您";
code char STR3[]= "谢谢";
code char STR4[]= "SCCDCYB";
void Read_Busy();
void Delay100us(volatile uint n);
void Clear_LCD();
void Write_Single_CMD(uchar cmd);
void Write_Single_Data(uchar a);
void Init_LCD();
void Display(uchar ptr,uchar ddram) ;
void Init_IO(void);
void Reset_St7920(void);
void DispSetCursor(uchar LineNum,uchar ColumnNum);
void main(void)
{
uchar i,j;
Init_IO();
Reset_St7920();
// LCD_LIGHT=1;
Clear_LCD();
Init_LCD();
Write_Single_CMD(0X01);
Display(STR1,0X80);
Display(STR2,0X90);
Display(STR3,0X88);
Display(STR4,0X98);
Delay100us(200);
Write_Single_CMD(0x80);
j=0;
for (i=0;i<32;i++)
{
Write_Single_Data(0xb4);
Write_Single_Data(0xde+j);
// Write_Single_CMD(0x01); //将光标移到0x9C
j++;
}
// Write_Single_CMD(0x01); //将光标移到0x9C
Write_Single_CMD(0x01); //光标移到0x9C
Write_Single_CMD(0x34); //将光标移到0x9C
Write_Single_CMD(0x36); //将光标移到0x9C
for (i=0;i<32;i++)
{
Write_Single_CMD(0x80+i);
Write_Single_CMD(0x80);
// Write_Single_CMD(0x01); //将光标移到0x9C
for (j=0;j<8;j++)
{
Write_Single_Data(0x00);
Write_Single_Data(0x00);
}
}
for (i=0;i<32;i++)
{
Write_Single_CMD(0x80+i);
Write_Single_CMD(0x88);
// Write_Single_CMD(0x01); //将光标移到0x9C
for (j=0;j<8;j++)
{
Write_Single_Data(0x00);
Write_Single_Data(0x00);
}
}
for (i=0;i<32;i++)
{
Write_Single_CMD(0x80+i);
Write_Single_CMD(0x80);
// Write_Single_CMD(0x01); //将光标移到0x9C
for (j=0;j<8;j++)
{
Write_Single_Data(0xFF);
Write_Single_Data(0xFF);
}
}
for (i=0;i<32;i++)
{
Write_Single_CMD(0x80+i);
Write_Single_CMD(0x88);
// Write_Single_CMD(0x01); //将光标移到0x9C
for (j=0;j<8;j++)
{
Write_Single_Data(0xFF);
Write_Single_Data(0xFF);
}
}
// DispSetCursor(1,3);
// for (i=0;i<64;i++)
// {
// for (j=0;j<16;j++)
// {
// Write_Single_Data(0x3f);
// Write_Single_Data(0xff);
// }
// }
while(1)
{
}
}
void Init_IO(void)
{
P0M1=0X00;
P0M2=0X00; //P0=I/O
P1M1=0X00; //P14:输入(DR)
P1M2=0X00; //P1=P16为推挽,其它为I/O
P2M1=0X00; //P26、P27:输入(AM、CD)
P2M2=0X00; //P2=I/O
P3M1=0X00;
P3M2=0X00; //P3=I
}
void Read_Busy(void) //读忙 *** 作
{
P0=0x0ff;
RS=0;
RW=1;
do{
E=1;
busy=P0;
E=0;
}while(busy>0x7f);
}
void Reset_St7920(void)
{
LCD_RST=0;
Delay100us(100);
LCD_RST=1;
Delay100us(200);
}
void Delay100us(volatile uint n)
{
uchar i;
while(n--)
for(i=0;i<40;i++)
;
}
void Write_Single_CMD(uchar cmd) //写单字节命令字
{
Read_Busy();
RS=0;
RW=0;
E=1;
P0=cmd;
E=0;
P0=0xff;
}
void Write_Single_Data(uchar a) //写单字节数据
{
Read_Busy();
RS=1;
RW=0;
E=1;
P0=a;
E=0;
P0=0xff;
}
void Init_LCD(void) //初始化LCD模块
{
Write_Single_CMD(0x30); //功能设置--8BIT控制界面,基本指令集
Delay100us(10);
Write_Single_CMD(0x30); //功能设置--8BIT控制界面,基本指令集
Delay100us(5);
Write_Single_CMD(0X0C);
Delay100us(5);
Write_Single_CMD(0x01); //清除屏幕显示,将DDRAM的地址计数器清零
Delay100us(2);
Write_Single_CMD(0x06); //DDRAM的地址计数器(AC)加1
Delay100us(1);
}
void DispSetCursor(uchar LineNum,uchar ColumnNum)
{
uchar i=0x00;
switch(LineNum&0x0f) //确定行号
{
case 0x00: i=0x80; break;
case 0x01: i=0xa0; break;
case 0x02: i=0x88; break;
case 0x03: i=0xa8; break;
default : break;
}
i = (ColumnNum&0x0f)|i; //确定列号
Write_Single_CMD(i);
}
void Clear_LCD(void)
{
Read_Busy();
RS=0;
RW=0;
P0=0x01;
E=1;
E=0;
}
/
void ExpandFucntionEnable(void)
Function:
/
void ExpandFunctionEnable(void)
{
Write_Single_CMD(0x34);
}
/
void ExpandFunctionDisable(void)
Function:
/
void ExpandFunctionDisable(void)
{
Write_Single_CMD(0x30);
}
/
void ClearScreen(void)
Function:
/
void ClearScreen(void)
{
Write_Single_CMD(0x01);
Delay100us(100);
}
/
void CursorGoHome(void)
Funtion:
Cursor go home,DDRAM's address counter 'AC=0x00'
/
void CursorGoHome(void)
{
Write_Single_CMD(0x02);
}
/
void DisplayOn(void)
Function:
/
void DisplayOn(void)
{
Write_Single_CMD(0x0d); //整体显示开,游标开,游标位置反白禁止
}
/
void DisplayOff(void)
Function:
/
void DisplayOff(void)
{
Write_Single_CMD(0x09);
}
/
void IdleMode(void)
Function:
Expand instruction
/
void IdleMode(void)
{
Write_Single_CMD(0x01);
}
/
void RollInstructionEnable(void)
Function:
Expand instruction
/
void RollInstructionEnable(void)
{
Write_Single_CMD(0x03);
}
/
void RollInstructionDisable(void)
Function:
Expand instruction
/
void RollInstructionDisable(void)
{
Write_Single_CMD(0x02);
}
/
void SetRollAddress(unsigned char WhichLine)
Function:
Expand instruction
/
void SetRollAddress(uchar WhichLine)
{
ExpandFunctionEnable();
RollInstructionEnable();
Write_Single_CMD(WhichLine|0x40);
ExpandFunctionDisable();
}
/
void Sleep(void)
Function:
Expand instruction
/
void Sleep(void)
{
Write_Single_CMD(0x08);
}
/
void Waken(void)
Function:
Expand instruction
/
void Waken(void)
{
Write_Single_CMD(0x0c);
}
/
void NegativeDisplay(uchar WhichLine)
Function:
Expand instruction
WhichLine=1,2,3,4
/
void NegativeDisplay(uchar WhichLine)
{
if(WhichLine>4)return;
if(WhichLine==0)return;
Write_Single_CMD((WhichLine-1)|0x04);
}
void Display(uchar ptr,uchar ddram)
{
uchar i,l,x;
l=0;
if(ddram<0x88)
{ Line=0; } //定位行地址:第一行
else if(ddram<0xA0)
{ Line=2; } //定位行地址:第三行
else if(ddram<0xA8)
{ Line=1; } //定位行地址:第二行
else
{ Line=3; } //定位行地址:第四行
Col=0x0f&ddram; //定位列地址
if(Col>0x07)
{ Col=Col-0x08;}
x=Col2;
Write_Single_CMD(ddram); // 定位显示起始地址
while ((ptr[l])!='\0')
{l++;}
for (i=0;i<l;i++)
{
Write_Single_Data(ptr[i]); //输出单个字符
x++;
if (x ==0x10)
{
x=0;
Line++;
switch (Line)
{
case 0:Write_Single_CMD(0x80);
break;
case 1:Write_Single_CMD(0xA0);
break;
case 2:Write_Single_CMD(0x88);
break;
case 3:Write_Single_CMD(0xA8);
}
if (Line>3)
{
Write_Single_CMD(0x80);
Line=0;
}
}
}
}
顶层文件 万年历C #include<reg51h> #include "LCD1602h" #include "DS1302h" #define uchar unsigned char #define uint unsigned int sbit speaker=P2^4; bit key_flag1=0,key_flag2=0; SYSTEMTIME adjusted; uchar sec_add=0,min_add=0,hou_add=0,day_add=0,mon_add=0,yea_add=0; uchar data_alarm[7]={0}; /键盘控制/ int key_scan() //扫描是否有键按下 { int i=0; uint temp; P1=0xf0; temp=P1; if(temp!=0xf0) i=1; else i=0; return i; } uchar key_value() //确定按键的值 { uint m=0,n=0,temp; uchar value; uchar v[4][3]={'2','1','0','5','4','3','8','7','6','b','a','9'} ; P1=0xfe; temp=P1; if(temp!=0xfe)m=0; P1=0xfd;temp=P1 ;if(temp!=0xfd)m=1; P1=0xfb;temp=P1 ;if(temp!=0xfb)m=2; P1=0xf7;temp=P1 ;if(temp!=0xf7)m=3; P1=0xef;temp=P1 ;if(temp!=0xef)n=0; P1=0xdf;temp=P1 ;if(temp!=0xdf)n=1; P1=0xbf;temp=P1 ;if(temp!=0xbf)n=2; value=v[m][n]; return value; } /设置闹铃函数/ void naoling(void) { uchar i=0,l=0,j; init1602(); while(key_flag2&&i<12) if(key_scan()){j=key_value();write_data(j);if(i%2==0)data_alarm[l]=(j-'0')10;else {data_alarm[l]+=(j-'0');l++;}i++;delay(600);} write_com(0x01); } uchar according(void) { uchar k; if(data_alarm[0]==adjustedYear&&data_alarm[1]==adjustedMonth&&data_alarm[2]==adjustedDay&&data_alarm[3]==adjustedHour&&data_alarm[4]==adjustedMinute&&data_alarm[5]==adjustedSecond) k=1; else k=0; return k; } void speak(void) {uint i=50; while(i) {speaker=0; delay(1); speaker=1; delay(1); i--; } } void alarm(void) {uint i=10; while(i) { speak(); delay(10); i--; } } /修改时间 *** 作/ void reset(void) { sec_add=0; min_add=0; hou_add=0; day_add=0; mon_add=0; yea_add=0 ; } void adjust(void) { if(key_scan()&&key_flag1) switch(key_value()) {case '0':sec_add++;break; case '1':min_add++;break; case '2':hou_add++;break; case '3':day_add++;break; case '4':mon_add++;break; case '5':yea_add++;break; case 'b':reset();break; default: break; } adjustedSecond+=sec_add; adjustedMinute+=min_add; adjustedHour+=hou_add; adjustedDay+=day_add; adjustedMonth+=mon_add; adjustedYear+=yea_add; if(adjustedSecond>59) adjustedSecond=adjustedSecond%60; if(adjustedMinute>59) adjustedMinute=adjustedMinute%60; if(adjustedHour>23) adjustedHour=adjustedHour%24; if(adjustedDay>31) adjustedDay=adjustedDay%31; if(adjustedMonth>12) adjustedMonth=adjustedMonth%12; if(adjustedYear>100) adjustedYear=adjustedYear%100; } /中断处理函数/ void changing(void) interrupt 0 using 0 //需要修改时间和日期,或者停止修改 { if(key_flag1)key_flag1=0; else key_flag1=1; } void alarming(void) interrupt 3 using 0 //需要设置闹铃或者停止设置 { if(key_flag2)key_flag2=0; else key_flag2=1; } /主函数/ main() {uint i; uchar l; uchar p1[]="D:",p2[]="T:"; SYSTEMTIME T; EA=1; EX0=1; IT0=1; EA=1; EX1=1; IT1=1; init1602(); Initial_DS1302() ; while(1) { write_com(0x80); write_string(p1,2); write_com(0xc0); write_string(p2,2); DS1302_GetTime(&T) ; adjustedSecond=TSecond; adjustedMinute=TMinute; adjustedHour=THour; adjustedWeek=TWeek; adjustedDay=TDay; adjustedMonth=TMonth; adjustedYear=TYear; for(i=0;i<9;i++) { adjustedDateString[i]=TDateString[i]; adjustedTimeString[i]=TTimeString[i]; } adjust(); if(key_flag2)naoling(); if(according())alarm(); DateToStr(&adjusted); TimeToStr(&adjusted); write_com(0x82); write_string(adjustedDateString,8); write_com(0xc2); write_string(adjustedTimeString,8); delay(10); } (二)头文件1 显示模块 LCD1602H #ifndef LCD_CHAR_1602_2009_5_9 #define LCD_CHAR_1602_2009_5_9 #define uchar unsigned char #define uint unsigned int sbit lcdrs = P2^0; sbit lcdrw = P2^1; sbit lcden = P2^2; void delay(uint z) // 延时 { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } void write_com(uchar com) // 写入指令数据到 lcd { lcdrw=0; lcdrs=0; P0=com; delay(5); lcden=1; delay(5); lcden=0; } void write_data(uchar date) // 写入字符显示数据到 lcd { lcdrw=0; lcdrs=1; P0=date; delay(5); lcden=1; delay(5); lcden=0; } void init1602() // 初始化设定 { lcdrw=0; lcden=0; write_com(0x3C); write_com(0x0c); write_com(0x06); write_com(0x01); write_com(0x80); } void write_string(uchar pp,uint n) { int i; for(i=0;i<n;i++) write_data(pp[i]); } #endif (三)头文件2 时钟模块 DS1302H #ifndef _REAL_TIMER_DS1302_2009_5_20_ #define _REAL_TIMER_DS1302_2003_5_20_ sbit DS1302_CLK = P2^6; //实时时钟时钟线引脚 sbit DS1302_IO = P2^7; //实时时钟数据线引脚 sbit DS1302_RST = P2^5; //实时时钟复位线引脚 sbit ACC0 = ACC^0; sbit ACC7 = ACC^7; typedef struct SYSTEM_TIME { unsigned char Second; unsigned char Minute; unsigned char Hour; unsigned char Week; unsigned char Day; unsigned char Month; unsigned char Year; unsigned char DateString[9]; //用这两个字符串来放置读取的时间 unsigned char TimeString[9]; }SYSTEMTIME; //定义的时间类型 #define AM(X) X #define PM(X) (X+12) // 转成24小时制 #define DS1302_SECOND 0x80 #define DS1302_MINUTE 0x82 #define DS1302_HOUR 0x84 #define DS1302_WEEK 0x8A #define DS1302_DAY 0x86 #define DS1302_MONTH 0x88 #define DS1302_YEAR 0x8C #define DS1302_RAM(X) (0xC0+(X)2) //用于计算 DS1302_RAM 地址的宏 /内部指令/ void DS1302InputByte(unsigned char d) //实时时钟写入一字节(内部函数) { unsigned char i; ACC = d; for(i=8; i>0; i--) { DS1302_IO = ACC0; DS1302_CLK = 1; DS1302_CLK = 0; ACC = ACC >> 1; //因为在前面已经定义了ACC0 = ACC^0;以便再次利用DS1302_IO = ACC0; } } unsigned char DS1302OutputByte(void) //实时时钟读取一字节(内部函数) { unsigned char i; for(i=8; i>0; i--) { ACC = ACC >>1; ACC7 = DS1302_IO; DS1302_CLK = 1; DS1302_CLK = 0; } return(ACC); } // void Write1302(unsigned char ucAddr, unsigned char ucDa) //ucAddr: DS1302地址, ucData: 要写的数据 { DS1302_RST = 0; DS1302_CLK = 0; DS1302_RST = 1; DS1302InputByte(ucAddr); // 地址,命令 DS1302InputByte(ucDa); // 写1Byte数据 DS1302_CLK = 1; DS1302_RST = 0; } unsigned char Read1302(unsigned char ucAddr) //读取DS1302某地址的数据 { unsigned char ucData; DS1302_RST = 0; DS1302_CLK = 0; DS1302_RST = 1; DS1302InputByte(ucAddr|0x01); // 地址,命令 ucData = DS1302OutputByte(); // 读1Byte数据 DS1302_CLK = 1; DS1302_RST = 0; return(ucData); } void DS1302_SetProtect(bit flag) //是否写保护 { if(flag) Write1302(0x8E,0x10); else Write1302(0x8E,0x00); } void DS1302_SetTime(unsigned char Address, unsigned char Value) // 设置时间函数 { DS1302_SetProtect(0); Write1302(Address, ((Value/10)<<4 | (Value%10))); //将十进制数转换为BCD码 } //在DS1302中的与日历、时钟相关的寄存器存放的数据必须为BCD码形式 void DS1302_GetTime(SYSTEMTIME Time) { unsigned char ReadValue; ReadValue = Read1302(DS1302_SECOND); Time->Second = ((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); //将BCD码转换为十进制数 ReadValue = Read1302(DS1302_MINUTE); Time->Minute = ((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); ReadValue = Read1302(DS1302_HOUR); Time->Hour = ((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); ReadValue = Read1302(DS1302_DAY); Time->Day = ((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); ReadValue = Read1302(DS1302_WEEK); Time->Week = ((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); ReadValue = Read1302(DS1302_MONTH); Time->Month = ((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); ReadValue = Read1302(DS1302_YEAR); Time->Year = ((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); } unsigned char DataToBCD(SYSTEMTIME Time) { unsigned char D[8]; D[0]=Time->Second/10<<4+Time->Second%10; D[1]=Time->Minute/10<<4+Time->Minute%10; D[2]=Time->Hour/10<<4+Time->Hour%10; D[3]=Time->Day/10<<4+Time->Day%10; D[4]=Time->Month/10<<4+Time->Month%10; D[5]=Time->Week/10<<4+Time->Week%10; D[6]=Time->Year/10<<4+Time->Year%10; return D; } void DateToStr(SYSTEMTIME Time) { //将十进制数转换为液晶显示的ASCII值 Time->DateString[0] = Time->Year/10 + '0'; Time->DateString[1] = Time->Year%10 + '0'; Time->DateString[2] = '-'; Time->DateString[3] = Time->Month/10 + '0'; Time->DateString[4] = Time->Month%10 + '0'; Time->DateString[5] = '-'; Time->DateString[6] = Time->Day/10 + '0'; Time->DateString[7] = Time->Day%10 + '0'; Time->DateString[8] = '\0'; } void TimeToStr(SYSTEMTIME Time) { //将十进制数转换为液晶显示的ASCII值 Time->TimeString[0] = Time->Hour/10 + '0'; Time->TimeString[1] = Time->Hour%10 + '0'; Time->TimeString[2] = ':'; Time->TimeString[3] = Time->Minute/10 + '0'; Time->TimeString[4] = Time->Minute%10 + '0'; Time->TimeString[5] = ':'; Time->TimeString[6] = Time->Second/10 + '0'; Time->TimeString[7] = Time->Second%10 + '0'; Time->DateString[8] = '\0'; } void Initial_DS1302(void) { unsigned char Second; Second=Read1302(DS1302_SECOND); if(Second&0x80) //初始化时间 DS1302_SetTime(DS1302_SECOND,0); } void DS1302_TimeStop(bit flag) // 是否将时钟停止 { unsigned char Data; Data=Read1302(DS1302_SECOND); DS1302_SetProtect(0); if(flag) Write1302(DS1302_SECOND, Data|0x80); else Write1302(DS1302_SECOND, Data&0x7F); } #endifzftzbpujjj1134358763,jaiezwwysu6517560870,2012-2-15 11:08:28
1指令0x38的作用是设定使用8位总线、2行显示、使用5X7字符。要多次重复执行的目的是为了LCD的可靠初始化。
2在单片机中char和int的定义和在计算机上是一样的,char是8位的,int是16位的。char可以成为8位整型或者字符型数据,因为我们平时使用的ASCII码就是char型的,并且包含了可以显示的字符(比如数字、字母和符号),比如0x41就是代表可以显示的字母A。所以char型可以称为字符型。
3既然已经知道char是8位的,而IO端口也是8位的,所以使用char在对端口赋值时,就是把char型字符中每一个位的状态(0或者1)复制到端口的对应位上了。
你这个液晶屏不是一般开发板能带有的。大致读了一下:
#include <avr/ioh> #include "boardh" #include "manageh"//调用头文件 #include "scanh" #include "timerh" #include "lcdh"
void sys_init(void);
void bus_reset(void);
int main(void) //主程序
{ uint8_t i = 0; //这里定义了一个计数器,用于指示灯闪烁计时用
sys_init(); //系统初始化,具体程序在下面
int_init(); //又初始化了一个什么东西,先不管
// timer0_init(); //没有用到time0
timer1_init(); //time1初始化,但是就现有程序而言还无法知道计时周期
// timer2_init();
// adc_init();
wdt_disable(); //先禁用看门狗
wdt_enable(WDTO_250MS); //设置看门狗250ms为一周期
wdt_reset(); //复位看门狗
sei(); //禁用中断
// 初始化LCD
lcd_init(); //调用液晶屏初始化程序
while(1) //主程序循环
{ manage(); //应该是处理液晶显示内容用的子程序
if (i & 0x10)
LED_ON(); //0x10个周期后LED闪烁
else
LED_OFF();
i++;
delay_ms(10);
wdt_reset(); //复位看门狗
}
}
// 系统初始化
void sys_init(void) //系统初始化子程序的详细内容(看来只定义了IO口还真不知道这个系统内单片机的定时器如何初始化的)
{
PORTA = 0xf2; //定义IO口
DDRA = 0; // PA7~PA4 键盘输入,PA3: LCD_A0复用电池测量时,输出1
// PA2: 输入,测电池电压, PA1:LCD_CS, PA0:输入,测总线电压?
PORTB = 0xff;
DDRB = 0x00; // PB输出,LCD_DB,PB0~PB4 KEY SCAN
PORTC = 0x80;
DDRC = 0xc0; // PC输出,PC7:LCD_RST,PC6:LCD_LED+,
PORTD = 0x03;
DDRD = 0xf3; // PD7:PWM,PD6:ZL,PD5:ZH,PD4:LED
// PD3返回,PD2开关, PD1:LCD_RD, PD0:LCD_WR
}
void lcd_init(void) //LCD的初始化
{
uint8_t i;
LCD_RST_L(); //应该是复位LCD
delay_ms(2); //延时
LCD_RST_H(); //复位完毕,该复位引脚拉高
for (i=0; i<8; i++) //复位8次看门狗?
{
delay_ms(20);
wdt_reset();
}
write_cmd(0xe2);//system reset 24 //写一个复位命令?
delay_ms(10);
write_cmd(0xeb);//set bias RATIO=1/12 27 =E8 FOR LOW POWER //设置液晶屏偏压
write_cmd(0x81);//set refence voltage ;pm 11 DOUBLE command //设置参考电压
write_cmd(0x83);//set RGB D1 21 //设置RGB方式?
write_cmd(0x2f);//set color mode,65K 22 D4 FOR 256 COLOR 3r-3g-2b//设置彩色显示深度
write_cmd(0x2b);//set line rate,358kps 15 A3//设置啥?不是很明白
write_cmd(0x24);//set n-line 5,TempCompensation 00//设置某种补偿?
write_cmd(0xa2); // 15 set line rate 296k
write_cmd(0xd0);//set partial display 21 D0 BGR//设置一个副屏幕?或许这个彩屏还附带一个小屏幕?
write_cmd(0xd6);//set cen 22 d6 64k color 5-6-5//不明白
write_cmd(0xc0); // 19 LC[2:0]
write_cmd(0xaf); //set display on 18, DC[4:2]=111//仍然不明白
delay_ms(10);
wdt_reset();//重启看门狗
}
void write_cmd(uint8_t cmd)//“写命令”子程序
{
LCD_A0_L();//应该是拉低“命令\数据”引脚的电平
LCD_CS_L(); //片选引脚
PORTB = cmd; //PORTB的8个引脚作为并行口向液晶屏输出数据
DDRB = 0xff; //PORTB的方向定义为输出
LCD_WR_L(); //写LCD引脚电平拉低,看来这程序可能是为了防止被中断或者别的情况打乱,特地发送了两遍
LCD_WR_L();
LCD_WR_H();
LCD_CS_H();
DDRB = 0; //改PORTB为高阻态
//个人觉得后面应该还需要两个语句:LCD_CS_H();和LCD_A0_H();已完成一个“写命令”周期
}
总之,你这块液晶屏应该在市场上不常见。要用这个玩意,你必须有对应这块液晶屏的详细文档、数据手册,否则光这么一个程序很难把这个液晶屏玩转了。
51单片机对lcd1602一些基础程序
#include <intrinsh>
#define dataport P1
sbit RS=P2^ 6;
sbit RW=P2^5;
sbit EN=P2^4;
//========================
//=========================
void waitfor() //检测忙信号函数
{
dataport=0xff;
RS=0;RW=1;_nop_(); //选择指令寄存器 读 *** 作
EN=1;_nop_(); //使能 *** 作
while(dataport&0x80); //如果最高位是1 表示1602正忙 原地踏步 忙完后芯片会将高位拉低
EN=0;
}
//======================
void writedata(unsigned char dataw) //写数据到lcm
{
waitfor(); //测忙
RS=1;RW=0;_nop_(); //选择数据寄存器 写 *** 作
dataport=dataw;_nop_(); //将数据送到数据口
EN=1;_nop_();_nop_();EN=0; //使能
}
//==========================
void writecmd(unsigned char cmd) //写命令到lcm
{
waitfor();
RS=0;RW=0;_nop_();
dataport=cmd;_nop_();
EN=1;_nop_();_nop_();EN=0;
}
//===========================
void init(void) // 初始化函数
{
writecmd(0x38); //功能设定 8位数据传输 双行显示
writecmd(0x0c);//显示器开关
writecmd(0x01);//清屏
writecmd(0x06);//字符进入模式 每进入一个字符光标向右移动一格 原有字符不动
//我在刚开始学的时候不知道下一个字符显示在哪 是和AC值有关还是和光标位置有关
//最后摸索出来是只和光标定位有关 现在还是不知道Ac值有什么用
}
//=========================
void location(unsigned char x,unsigned char y) //确实坐标函数
{
unsigned char temp;
temp=x&0x0f; //只要x数据的后四位
if(y){temp=temp|0x40;} //第一行为0 第二行为1 如果y=1则地址加0x40
temp|=0x80; //DDRAM地址的命令DB7为一
writecmd(temp);
}
//==============================
void displyonechar(unsigned char x,unsigned char y,unsigned char dataw) //显示一个字符函数
{
location(x,y);
writedata(dataw);
}
//=======================================
void displylistchar(unsigned char x,unsigned char y,unsigned char p) //显示字符串
{
while(p) //当一个字符型数组读完时P指的为零
{
displyonechar(x,y,(p++));
x++;
}
}
//=====================================================
void writecgram(unsigned char address,unsigned char p) //写CGRAM的数据
{
unsigned char i=8;
writecmd(address); //CGRAM里的地址 初始值0x40 每次加0x80
while(i--)
{
writedata(p);
p++;
}
}
//=====================================================
void displyonecharacter(unsigned char x,unsigned char y,unsigned char address,unsigned char p) //显示一个自定义字符
{
unsigned char i=8;
writecmd(address); //CGRAM里的地址 初始值0x40 每次加0x08
while(i--)
{
writedata(p);
p++;
}
//============================================================
location(x,y); //设定要显示的位置
writedata((address&=0x3f)/0x08); //要从CGRAM中读出数据在1602上显示 搞了半天发现CGRAM里的地址
} //和DDRAM里的地址有上面的转换关系
//========================================================
void displynumber(unsigned char x,unsigned char y,unsigned long num) //显示一个整数
{
unsigned int number[8];
int k,gh;
for(k=0;;k++)
{
(number+k)=(unsigned int)(num%10);//强制类型转换
num=num/10;
if(num==0)break;
}
for(gh=k;gh>=0;gh--)
{
displyonechar(x,y,((number+gh)+48));
x++;
}
}
//字型码
uchar code nin[]={0x08,0x0f,0x12,0x0f,0,0x1f,0x02,0x02};// "年"
uchar code yue[]={0x0f,0x09,0x0f,0x09,0x0f,0x09,0x0b,0x11};// "月"
uchar code ri[]={0x1f,0x11,0x11,0x1f,0x11,0x11,0x11,0x1f};// "日"
显示汉字
displyonecharacter(0,0,0x40,nin);
displyonecharacter(1,0,0x80,yue);
displyonecharacter(1,0,0xc0,ri);
1602LCD显示原理
通过电压来改变填充在两块平行板之间的液晶材料内部分子的排列状况,以达到遮光和透光的目的来显示深浅不一,错落有致的图象,而且只要在两块平板间再加上三元色的滤光层,就可实现显示彩色图象。液晶是具有流动特性的物质,所以只需外加很微小的力量即可使液晶分子运动,以最常见普遍的向列型液晶为例,液晶分子可轻易的借着电场作用使得液晶分子转向,由于液晶的光轴与其分子轴相当一致,故可借此产生光学效果,而当加于液晶的电场移除消失时,液晶将借着其本身的d性及黏性,液晶分子将十分迅速的回撤消来未加电场前的状态。
1602液晶资料详解
1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如下表所示:
编号 符号 引脚说明 编号 符号 引脚说明
1 VSS 电源地 9 D2 数据
2 VDD 电源正极 10 D3 数据
3 VL 液晶显示偏压 11 D4 数据
4 RS 数据/命令选择 12 D5 数据
5 R/W 读/写选择 13 D6 数据
6 E 使能信号 14 D7 数据
7 D0 数据 15 BLA 背光源正极
8 D1 数据 16 BLK 背光源负极
1602液晶模块引脚说明:
第1脚:VSS为地电源。
第2脚:VDD接5V正电源。
第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。
第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:R/W为读写信号线,高电平时进行读 *** 作,低电平时进行写 *** 作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:D0~D7为8位双向数据线。
第15脚:背光源正极。
第16脚:背光源负极。
1602LCD的指令说明及时序
1602液晶模块内部的控制器共有11条控制指令,如下表所示:
序号 指令 RS R/W D7 D6 D5 D4 D3 D2 D1 D0
1 清显示 0 0 0 0 0 0 0 0 0 1
2 光标返回 0 0 0 0 0 0 0 0 1
3 置输入模式 0 0 0 0 0 0 0 1 I/D S
4 显示开/关控制 0 0 0 0 0 0 1 D C B
5 光标或字符移位 0 0 0 0 0 1 S/C R/L
6 置功能 0 0 0 0 1 DL N F
7 置字符发生存贮器地址 0 0 0 1 字符发生存贮器地址
8 置数据存贮器地址 0 0 1 显示数据存贮器地址
9 读忙标志或地址 0 1 BF 计数器地址
10 写数到CGRAM或DDRAM) 1 0 要写的数据内容
11 从CGRAM或DDRAM读数 1 1 读出的数据内容
602液晶模块的读写 *** 作、屏幕和光标的 *** 作都是通过指令编程来实现的。(说明:1为高电平、0为低电平)
指令1:清显示,指令码01H,光标复位到地址00H位置。
指令2:光标复位,光标返回到地址00H。
指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。
指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。
指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。
指令7:字符发生器RAM地址设置。
指令8:DDRAM地址设置。
指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:写数据。
指令11:读数据。
读状态 输入 RS=L,R/W=H,E=H 输出 D0—D7=状态字
写指令 输入 RS=L,R/W=L,D0—D7=指令码,E=高脉冲 输出 无
读数据 输入 RS=H,R/W=H,E=H 输出 D0—D7=数据
写数据 输入 RS=H,R/W=L,D0—D7=数据,E=高脉冲 输出 无
602LCD的RAM地址映射及标准字库表
液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,下图是1602的内部显示地址。
在这里插入描述
例如第二行第一个字符的地址是40H,那么是否直接写入40H就可以将光标定位在第二行第一个字符的位置呢?这样不行,因为写入显示地址时要求最高位D7恒定为高电平1所以实际写入的数据应该是01000000B(40H)+10000000B(80H)=11000000B(C0H)。
在对液晶模块的初始化中要先设置其显示模式,在液晶模块显示字符时光标是自动右移的,无需人工干预。每次输入指令前都要判断液晶模块是否处于忙的状态。
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如图所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”
在这里插入描述
显示字符编码
根据1602LCD的文档说明,可根据文档的要求进行编程,显示需要显示的字符,通过程序代码的实现,能够更清楚1602LCD的使用。
#include<reg52h> //包含头文件,这个嘛,就不用多说了~~
#define uint unsigned int //预定义一下
#define uchar unsigned char
sbit rs=P3^5; //1602的数据/指令选择控制线
sbit rw=P3^6; //1602的读写控制线
sbit en=P3^7; //1602的使能控制线
/P2口接1602的D0~D7,注意不要接错了顺序,我以前可在这上面吃过亏~/
uchar code table[]="LCD1602 check ok"; //要显示的内容1放入数组tablel
uchar code table1[]="study up"; //要显示的内容2放入数组table1
void delay(uint n) //延时函数
{
uint x,y;
for(x=n;x>0;x--)
for(y=110;y>0;y--);
}
void lcd_wcom(uchar com) //1602写命令函数
{
rs=0; //选择指令寄存器
rw=0; //选择写
P2=com; //把命令字送入P2
delay(5); //延时一小会儿,让1602准备接收数据
en=1; //使能线电平变化,命令送入1602的8位数据口
en=0;
}
void lcd_wdat(uchar dat) //1602写数据函数
{
rs=1; //选择数据寄存器
rw=0; //选择写
P2=dat; //把要显示的数据送入P2
delay(5); //延时一小会儿,让1602准备接收数据
en=1; //使能线电平变化,数据送入1602的8位数据口
en=0;
}
void lcd_init() //1602初始化函数
{
lcd_wcom(0x38); //8位数据,双列,57字形
lcd_wcom(0x0c); //开启显示屏,关光标,光标不闪烁
lcd_wcom(0x06); //显示地址递增,即写一个数据后,显示位置右移一位
lcd_wcom(0x01); //清屏
}
void main() //主函数
{
uchar n,m=0;
lcd_init(); //液晶初始化
lcd_wcom(0x80); //显示地址设为80H(即00H,)上排第一位
for(m=0;m<16;m++) //将table[]中的数据依次写入1602显示
{
lcd_wdat(table[m]);
delay(200);
}
lcd_wcom(0x80+0x44); //重新设定显示地址为0xc4,即下排第5位
for(n=0;n<8;n++) //将table1[]中的数据依次写入1602显示
{
lcd_wdat(table1[n]);
delay(200);
}
while(1); //动态停机
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2MOV LCD,#0FFH是将P2口置为输入模式。
3E端口是高电平有效。
其他的“清屏并光标复位”这段命令不是很清楚,请参考程序:>
以上就是关于FYD12864-0402B液晶显示模块C语言程序全部的内容,包括:FYD12864-0402B液晶显示模块C语言程序、跪求:液晶LCD1602显示时钟的C程序!、单片机Lcd指令问题等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)