一、了解LCD12864引脚功能
本次使用串行
1、初始化LCD所需引脚
(正常背光灯为硬件给合适的电压就可以点亮,但在本硬件电路设计中,由MOS管进行控制,所以需要单片机给高电平,使MOS管导通,LCD屏幕被点亮。)
#define CS GPIO_Pin_6//片选
#define A0 GPIO_Pin_0//选择数据还是命令
#define SCL GPIO_Pin_14//串行时钟
#define SI GPIO_Pin_15//串行数据
#define RS GPIO_Pin_7//硬件复位
void lcd_gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//GPIO开时钟使能 GPIOA GPIOB
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//GPIOA
//背光PA5 CS片选PA6 RS复位PA7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|CS|RS;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//GPIOB
//A0命令数据选择PB0 SCL串行时钟PB14 SI串行数据PB15
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = A0|SCL|SI;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,CS);//片选拉高
GPIO_SetBits(GPIOB,SCL);//时钟拉高
GPIO_SetBits(GPIOB,SI);//数据拉高
}
2、了解初始化LCD流程
3、发送字节,按照时序要求进行拉高拉低对应引脚
对应的引脚按照时序要求分别进行拉高拉低,因为使用串行,所以在发送字节类型数据时需要一位一位发送,先发高位所以采用移位后与0x80,来判断该位为1或0。
1、发送前,先拉低片选引脚,CS使能;
判断输出为数据或命令,拉高拉低A0,A0可以一直保持此状态。
2、传输每位bit前,拉低时钟引脚,SCL使能。
4、传输每位bit,根据传输1或0,拉高拉低SI。
5、传输后,将SCL拉高,失能。
6、传输一位bit后,片选端拉高,失能。
注意延时先后顺序以及时间,要保证满足最小需求。
因为将CMD与DATA封装为两个函数,在写函数时明确自己应该拉高或拉低A0,所以拉低片选引脚后就可以使A0一直保持对应状态。(A0与SI均为可高可低,看使用时的需求)
也可以将发送封装为一个函数(因为函数整体相同,只需要修改A0的拉高拉低,来改变发送数据或命令,两个函数看起来更清晰,不易调用出错),在函数传参时,通过参数判断需要发送数据或命令。
//两个函数 (仅作参考)
//写命令
void lcd_writecmd(u8 cmd)
{
u8 i;
GPIO_ResetBits(GPIOA,CS);//CS片选拉低
GPIO_ResetBits(GPIOB,A0);//A0拉低 指令
for(i=0;i<8;i++)
{
GPIO_ResetBits(GPIOB,SCL);//时钟拉低
if(cmd&0x80)
{
GPIO_SetBits(GPIOB,SI);//写命令1
}
else
{
GPIO_ResetBits(GPIOB,SI);//写命令0
}
GPIO_SetBits(GPIOB,SCL);//时钟拉高
delay_us(10);
cmd=(cmd<<1);
}
GPIO_SetBits(GPIOA,CS);//片选拉高失效
}
//写数据
void lcd_writedata(u8 data)
{
u8 i;
GPIO_ResetBits(GPIOA,CS);//CS片选拉低
GPIO_SetBits(GPIOB,A0);//A0拉高 数据
for(i=0;i<8;i++)
{
GPIO_ResetBits(GPIOB,SCL);//时钟拉低
if(data&0x80)
{
GPIO_SetBits(GPIOB,SI);//写数据1
}
else
{
GPIO_ResetBits(GPIOB,SI);//写数据0
}
GPIO_SetBits(GPIOB,SCL);//时钟拉高
delay_us(10);
data=(data<<1);
}
GPIO_SetBits(GPIOA,CS);//片选拉高失效
}
//一个函数
//type为DATA或CMD 为1时传数据 为0时传命令
void lcd_write_CorD(u8 type,u8 data)
{
u8 i;
GPIO_ResetBits(GPIOA,CS);//CS片选拉低
GPIO_WriteBit(GPIOB,A0,type);//A0
for(i=0;i<8;i++)
{
GPIO_ResetBits(GPIOB,SCL);//时钟拉低
if(data&0x80)
{
GPIO_SetBits(GPIOB,SI);//写数据1
}
else
{
GPIO_ResetBits(GPIOB,SI);//写数据0
}
GPIO_SetBits(GPIOB,SCL);//时钟拉高
delay_us(10);
data=(data<<1);
}
GPIO_SetBits(GPIOA,CS);//片选拉高失效
}
4、发送对应指令进行初始化并点亮屏幕
//背光开 PA5 1开 0关
//BitAction 即Bit_SET and Bit_RESET enumeration
void lcd_bkon(u8 i)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)i);
}
发送命令对LCD进行初始化操作(具体流程参考2)
注意命令中的扫描顺序,影响显示效果。
//屏幕初始化
void lcd_init(void)
{
GPIO_ResetBits(GPIOA,RS);//硬件复位拉低
delay_us(10);
GPIO_SetBits(GPIOA,RS);//硬件复位拉高
delay_us(10);
lcd_writecmd(0xE2);//软件复位
delay_us(20);
lcd_writecmd(0x2C);//升压
delay_us(20);
lcd_writecmd(0x2E);//升压
delay_us(20);
lcd_writecmd(0x2F);//升压
delay_us(20);
lcd_writecmd(0x22);//调整对比度,设置范围0x20~0x27
lcd_writecmd(0x81);//微调对比度
lcd_writecmd(0x3B);//微调对比度的值
lcd_writecmd(0xA2);//偏压比 0xA2 1/9 0xA3 1=1/7
lcd_writecmd(0xA6);//正常显示
lcd_writecmd(0xA4);//全部点阵打开
lcd_writecmd(0xC8);//行扫描顺序 从下到上
lcd_writecmd(0xA0);//列扫描顺序 从右到左
lcd_writecmd(0x40);//起始行 第一行开始
lcd_writecmd(0xAF);//开显示
systick_delay(20);
lcd_clearscreen();//清除屏幕
lcd_bkon(1);//背光灯开
}
5、屏幕显示对应字符
12864即长128宽64,按4行显示,即64/4=16,竖16个像素点为一个字符的高,8为一个字符的宽,128/8=16,所以12864按照16*8显示,可以显示4行,每行16个字符。
//指明写数据地址
void lcd_addr(u8 page,u8 column)
{
page = page - 1;//页数从1开始计数
lcd_writecmd(0xb0+page);//传行地址
column = column ;//偏移至中心
lcd_writecmd(((column>>4)&0x0f)+0x10);//传列地址的高4位
lcd_writecmd(column&0x0f);//传列地址的低4位
}
//清除屏幕内容
void lcd_clearscreen()
{
lcd_fillscreen(0x00);
}
//全屏幕指定地方写数据
void lcd_fillscreen(u8 data)
{
u16 i,j;
for(i=1;i<9;i++)//8页 循环8次 页从1起始 列从0起始
{
lcd_addr(i,0);
for(j=0;j<129;j++)//128列 循环
{
lcd_writedata(data);
}
}
}
//显示一行字符
void lcd_string(u16 page,u16 column,char *text)
{
u16 i=0,j,k,n;
while(text[i]>0x00)
{
if((text[i]>=0x20)&&(text[i]<=0x7e))
{
j=text[i]-0x20;
for(n=0;n<2;n++)//16行 分两页
{
lcd_addr(page+n,column+1);
for(k=0;k<8;k++)
{
lcd_writedata(ASCII_8X16[j][k+8*n]);//显示ASCII 字到 LCD 上
}
}
i++;
column+=8;//一个字符 8列
}
else
i++;
}
}
ASCII字库
unsigned char ASCII_8X16[95][16]={
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/
{0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00},/*"!",1*/
{0x00,0x10,0x0C,0x02,0x10,0x0C,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*""",2*/
{0x00,0x40,0xC0,0x78,0x40,0xC0,0x78,0x00,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x00},/*"#",3*/
{0x00,0x70,0x88,0x88,0xFC,0x08,0x30,0x00,0x00,0x18,0x20,0x20,0xFF,0x21,0x1E,0x00},/*"$",4*/
//{0x00,0x1C,0x14,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"°",*/
//加一个 ° 取模 替换 $ 位置字符 显示时用$代替°(如果注释掉$打开° 这样写$实际显示°)
{0xF0,0x08,0xF0,0x80,0x60,0x18,0x00,0x00,0x00,0x31,0x0C,0x03,0x1E,0x21,0x1E,0x00},/*"%",5*/
{0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x2C,0x19,0x27,0x21,0x10},/*"&",6*/
{0x00,0x12,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/
{0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00},/*"(",8*/
{0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00},/*")",9*/
{0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00},/*"*",10*/
{0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x0F,0x01,0x01,0x01},/*"+",11*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x70,0x00,0x00,0x00,0x00,0x00},/*",",12*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x00},/*"-",13*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00},/*".",14*/
{0x00,0x00,0x00,0x00,0xC0,0x38,0x04,0x00,0x00,0x60,0x18,0x07,0x00,0x00,0x00,0x00},/*"/",15*/
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00},/*"0",16*/
{0x00,0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00},/*"1",17*/
{0x00,0x70,0x08,0x08,0x08,0x08,0xF0,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00},/*"2",18*/
{0x00,0x30,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x18,0x20,0x21,0x21,0x22,0x1C,0x00},/*"3",19*/
{0x00,0x00,0x80,0x40,0x30,0xF8,0x00,0x00,0x00,0x06,0x05,0x24,0x24,0x3F,0x24,0x24},/*"4",20*/
{0x00,0xF8,0x88,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x20,0x20,0x20,0x11,0x0E,0x00},/*"5",21*/
{0x00,0xE0,0x10,0x88,0x88,0x90,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x20,0x1F,0x00},/*"6",22*/
{0x00,0x18,0x08,0x08,0x88,0x68,0x18,0x00,0x00,0x00,0x00,0x3E,0x01,0x00,0x00,0x00},/*"7",23*/
{0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00},/*"8",24*/
{0x00,0xF0,0x08,0x08,0x08,0x10,0xE0,0x00,0x00,0x01,0x12,0x22,0x22,0x11,0x0F,0x00},/*"9",25*/
{0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00},/*":",26*/
{0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00},/*";",27*/
{0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00},/*"<",28*/
{0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x00},/*"=",29*/
{0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00},/*">",30*/
{0x00,0x70,0x48,0x08,0x08,0x88,0x70,0x00,0x00,0x00,0x00,0x30,0x37,0x00,0x00,0x00},/*"?",31*/
{0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x28,0x2F,0x28,0x17,0x00},/*"@",32*/
{0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20},/*"A",33*/
{0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00},/*"B",34*/
{0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00},/*"C",35*/
{0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00},/*"D",36*/
{0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00},/*"E",37*/
{0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00},/*"F",38*/
{0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00},/*"G",39*/
{0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20},/*"H",40*/
{0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},/*"I",41*/
{0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00},/*"J",42*/
{0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00},/*"K",43*/
{0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00},/*"L",44*/
{0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x01,0x3E,0x01,0x3F,0x20,0x00},/*"M",45*/
{0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00},/*"N",46*/
{0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00},/*"O",47*/
{0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00},/*"P",48*/
{0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x28,0x28,0x30,0x50,0x4F,0x00},/*"Q",49*/
{0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20},/*"R",50*/
{0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00},/*"S",51*/
{0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00},/*"T",52*/
{0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00},/*"U",53*/
{0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00},/*"V",54*/
{0x08,0xF8,0x00,0xF8,0x00,0xF8,0x08,0x00,0x00,0x03,0x3E,0x01,0x3E,0x03,0x00,0x00},/*"W",55*/
{0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20},/*"X",56*/
{0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00},/*"Y",57*/
{0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00},/*"Z",58*/
{0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00},/*"[",59*/
{0x00,0x04,0x38,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00},/*"\",60*/
{0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00},/*"]",61*/
{0x00,0x00,0x04,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"^",62*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80},/*"_",63*/
{0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/
{0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x19,0x24,0x24,0x12,0x3F,0x20,0x00},/*"a",65*/
{0x10,0xF0,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00},/*"b",66*/
{0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00},/*"c",67*/
{0x00,0x00,0x80,0x80,0x80,0x90,0xF0,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20},/*"d",68*/
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x24,0x24,0x24,0x24,0x17,0x00},/*"e",69*/
{0x00,0x80,0x80,0xE0,0x90,0x90,0x20,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},/*"f",70*/
{0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00},/*"g",71*/
{0x10,0xF0,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20},/*"h",72*/
{0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},/*"i",73*/
{0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00},/*"j",74*/
{0x10,0xF0,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x06,0x29,0x30,0x20,0x00},/*"k",75*/
{0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},/*"l",76*/
{0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F},/*"m",77*/
{0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20},/*"n",78*/
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00},/*"o",79*/
{0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0x91,0x20,0x20,0x11,0x0E,0x00},/*"p",80*/
{0x00,0x00,0x00,0x80,0x80,0x00,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0x91,0xFF,0x80},/*"q",81*/
{0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00},/*"r",82*/
{0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00},/*"s",83*/
{0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x10,0x00},/*"t",84*/
{0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20},/*"u",85*/
{0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x03,0x0C,0x30,0x0C,0x03,0x00,0x00},/*"v",86*/
{0x80,0x80,0x00,0x80,0x80,0x00,0x80,0x80,0x01,0x0E,0x30,0x0C,0x07,0x38,0x06,0x01},/*"w",87*/
{0x00,0x80,0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x20,0x31,0x0E,0x2E,0x31,0x20,0x00},/*"x",88*/
{0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x81,0x86,0x78,0x18,0x06,0x01,0x00},/*"y",89*/
{0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00},/*"z",90*/
{0x00,0x00,0x00,0x00,0x00,0xFC,0x02,0x02,0x00,0x00,0x00,0x00,0x01,0x3E,0x40,0x40},/*"{",91*/
{0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00},/*"|",92*/
{0x02,0x02,0xFC,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x3E,0x01,0x00,0x00,0x00,0x00},/*"}",93*/
{0x00,0x02,0x01,0x02,0x02,0x04,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"~",94*/
};
6、屏幕通过按键切换页面
初始化按键
#define sw1 GPIO_Pin_4
#define sw2 GPIO_Pin_3
#define sw3 GPIO_Pin_0
#define sw4 GPIO_Pin_2
#define sw5 GPIO_Pin_1
static void sw_gpio_init()
{
//GPIOA
//按键sw1~sw5 PA0~PA4 对应面板 1 sw5 目录 2 sw4 确定 3 sw3 下一个 4 sw2 返回
//sw1 PA0 目录键
//sw2 PA1 确定键
//sw3
//sw4 PA3 选中下一行
//sw5 PA4 返回键
//GPIO开时钟使能 GPIOA
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = sw1|sw2|sw3|sw4|sw5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
按键检测,是否有按键被按下(如果增加窗口看门狗喂狗时,注意时长)
//检测按键被按下
u8 mid_sw_scan(u16 GPIO_Pin)
{
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin) == 0)
{
mid_systick_delay(40); //软件消抖 40ms
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin) == 0)
{
WWDG_ReloadCounter();
return 1;
}
}
return 0;
}
定义结构体,存储需要保存的按键以及需要切换到界面
Menu_table 结构体中,每个索引为序列号(页面编号)对应本次需要显示的内容。sw_xxxx为按下对应按键后,跳转到的新索引行。current_operation为对应执行的函数指针。
typedef struct (部分代码展示)
{
u8 current;//当前状态索引号
u8 sw_menu; //目录
u8 sw_enter; //确定
//u8 sw_null; //空
u8 sw_next; //向下一个
u8 sw_back; //返回
void (*current_operation)(void); //当前状态应该执行的操作
} Menu_table;
Menu_table table[32]=
{
//索引值 按键值1-5 调用界面
// 2确定键5返回键 //未添加sw3
// 1 2 4 5//sw5432
{ 0, 1, 0, 0, 0,(*lcd_display_welcome)},//首页
{ 1, 1, 5, 2, 0,(*lcd_display_menu1)},//目录第一行
{ 2, 1,10, 3, 0,(*lcd_display_menu2)},//目录第二行
{ 3, 1,27, 4, 0,(*lcd_display_menu3)},//目录第三行
{ 4, 1,28, 1, 0,(*lcd_display_menu4)},//目录第四行
{ 5, 1, 5, 6, 1,(*lcd_display_Analog_Info11)},//目录第一行里的第一行 没有子内容
{ 6, 1, 6, 7, 1,(*lcd_display_Analog_Info12)},//目录第一行里的第二行 没有子内容
{ 7, 1,13, 8, 1,(*lcd_display_Analog_Info13)},//目录第一行里的第三行
{ 8, 1,16, 9, 1,(*lcd_display_Analog_Info14)},//目录第一行里的第四行
{ 9, 1,21, 5, 1,(*lcd_display_Analog_Info21)},//目录第一行里的第五行
}
//清除显示缓存区
void lcd_clear()
{
memset(txt_buf[0],' ',len);
memset(txt_buf[1],' ',len);
memset(txt_buf[2],' ',len);
memset(txt_buf[3],' ',len);
}
//txt_buf 为二维数组 4行n列,对应屏幕显示
//屏幕显示
void lcd_display()
{
mid_lcd_string(1,0,txt_buf[0]);
mid_lcd_string(3,0,txt_buf[1]);
mid_lcd_string(5,0,txt_buf[2]);
mid_lcd_string(7,0,txt_buf[3]);
}
void lcd_display_welcome(void)
{
lcd_clear();
sprintf(txt_buf[0]," Welcome To Use ");
sprintf(txt_buf[1]," Smart DEV ");
sprintf(txt_buf[2],"----------------");
sprintf(txt_buf[3]," Press MENU KEY ");
lcd_display();
}
void lcd_display_menu1(void)
{
lcd_clear();
sprintf(txt_buf[0],">>Analog Info>>");
sprintf(txt_buf[1],"--DEV Status>>");
sprintf(txt_buf[2],"--Para Setting>>");
sprintf(txt_buf[3],"--Sys Setting>>");
lcd_display();
}
void lcd_display_menu2(void)
{
lcd_clear();
sprintf(txt_buf[0],"--Analog Info>>");
sprintf(txt_buf[1],">>DEV Status>>");
sprintf(txt_buf[2],"--Para Setting>>");
sprintf(txt_buf[3],"--Sys Setting>>");
lcd_display();
}
void lcd_display_menu3(void)
{
lcd_clear();
sprintf(txt_buf[0],"--Analog Info>>");
sprintf(txt_buf[1],"--DEV Status>>");
sprintf(txt_buf[2],">>Para Setting>>");
sprintf(txt_buf[3],"--Sys Setting>>");
lcd_display();
}
void lcd_display_menu4(void)
{
lcd_clear();
sprintf(txt_buf[0],"--Analog Info>>");
sprintf(txt_buf[1],"--CEV Status>>");
sprintf(txt_buf[2],"--Para Setting>>");
sprintf(txt_buf[3],">>Sys Setting>>");
lcd_display();
}
按键是否执行对应的显示
void Menu_key_set(void)
{
key1 = mid_sw_scan(sw1);
key2 = mid_sw_scan(sw2);
//key3 = mid_sw_scan(sw3);
key4 = mid_sw_scan(sw4);
key5 = mid_sw_scan(sw5);
//按键功能判断
if(key1 == 1)
{
func_index=table[func_index].sw_menu;//按键menu按下后的索引号
}
if(key2 == 1)
{
func_index=table[func_index].sw_enter;//按键enter按下后的索引号
}
// if(key3 == 1)//未使用
// {
// func_index=table[func_index].sw_null;
// }
if(key4 == 1)
{
func_index=table[func_index].sw_next;//按键next按下后的索引号
}
if(key5 == 1)
{
func_index=table[func_index].sw_back;//按键back按下后的索引号
}
//函数执行//执行当前索引号所对应的功能函数
current_operation_index=table[func_index].current_operation;
(*current_operation_index)(void);//执行当前操作函数
}
使用sprintf的好处,结合使用标准化输出,可以将字符与数值拼接,再在ASCII字库中找到出显示时对应的十六进制即可,不用直接输出显示所需的十六进制。显示整型数、浮点数、字符、字符串等都极其方便。
void lcd_display_Sys_Setting(All_Data* all_msg)
{
lcd_clear();
sprintf(txt_buf[0],"--Baud rate:%4d",all_msg->baudrate);
sprintf(txt_buf[1],"--PackV:%7.2fV",all_msg->packv/100.0);
sprintf(txt_buf[2],"--Status:%s ",all_msg->status);
sprintf(txt_buf[3]," ");
lcd_display();
}
遇到的问题
1、屏幕初期使用时,功能正常,突然只能点亮屏幕,不能正常显示字符。
原因:根据电路设计,已知屏幕点亮为供电即可实现,正常点亮即说明单片机发送高电平控制MOS管正常导通,说明芯片已经正常工作,且供电线路应该正常。此时可以通过万用表量通断或者电压来检查电路。使用keil软件进debug调试,单步调试,进入函数后,使用万用表量对应引脚电压(或前边的电阻),发现片选引脚无法正常拉高拉低电平,导致初始化操作未完成,所以LCD未工作并不会显示字符。(应注意,在 lcd_init 函数中,屏幕点亮在函数体最后,此时屏幕能正常点亮说明已经执行到了最后一句,但之前的初始化设置命令执行了可能并没有生效,后续显示字符可能就不正常,所以不能通过屏幕是否能点亮来判断在此之前的初始化操作是否完成。另,屏幕之前可以正常显示,说明代码逻辑应该没问题,突然不能使用,应考虑硬件是否磕碰有影响或者虚焊或者电阻等掉落等问题。)