前言
字符型液晶显示模块是一种专门用于显示字母、数字、符号等点阵式 LCD,目前常用 161,162,202 和 402 行等的模块。
上面指的是以字符为单位,如161,也就是1行16列,最多能显示16个字符。其中,每个字符都是有几行乘几列的像素点组成,如168的像素点构成一个字符。本次介绍的液晶是12864。
正文
如上图所示,就是我要讲的液晶显示。CS1,CS2用于片选操作,也就是选择左半屏和右半屏,其中每一屏是64位,也就是说每一屏都是64x64dots,这里的液晶显示是4行16列,也就是说,一个字符,高是16dots,宽是8dots(一共128x64dots)。
引脚定义:
- VSS 为接地
- VDD 接 5V 正电源
- RS 为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器
R/W 为读写信号线,高电平时进行读操作,低电平时进行写操作。当 RS 和 R/W
共同为低电平时可以写入指令或者显示地址,当 RS 为低电平 R/W 为高电平时可以读忙信
号,当 RS 为高电平 R/W 为低电平时可以写入数据 - E 端为使能端,当 E 端由高电平跳变成低电平时,液晶模块执行命令。
- D0~D7 为 8 位双向数据线
下面说说指令集:
1602 液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明: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:读数据。
关于如何写数据
1.让引脚RW置高电平
2.让引脚RS置高电平
3.如果是片选一,则让CS1置高电平,否则让CS2置高电平
4.让引脚RW置低电平 (RS高,RW低表示可以写入数据)
5.将数据写入引脚中(STM32每个GPIO口16个引脚)
6.让引脚E置高电平
7.延时1us
8.让引脚E置低电平
9.延时1us
10.让引脚RW置高电平
11.如果是片选一,则让CS1置低电平,否则让CS2置低电平
代码理解
LCD_PRINT(0,0,lcd_show,"Input Card pwd:");
调用LCD_PRINT函数,对应4个参数
#define LCD_PRINT(row, colum, buf, fmt, args...) do{\
memset(buf, 0, sizeof(buf));\
sprintf(buf, fmt,##args);\
lcd_clr_row(row);\
lcd_write(row, colum, buf, strlen(buf));}while(0)
发现,该函数是一个宏定义的函数,args表示参数缺省,首先先将将数组buf清空
int sprintf(char *str, const char *format, …) 发送格式化输出到 str 所指向的字符串
也就是让buf的值 = fmt的值 = Input Card pwd:
接着调用函数lcd_clr_row(row),看这名字,应该是lcd显示清空,row为行号
接着往lcd里面开始写入数据,我们先来看函数lcd_clr_row(row),如下
lcd_clr_row
void lcd_clr_row(unsigned char row)
{
unsigned char i;
//CHAR_ROW_PIXEL = 16,LCD_PAGE_ROW_NUM = 8
lcd_set_dsp_position(row*(CHAR_ROW_PIXEL/LCD_PAGE_ROW_NUM), 0); //选中左屏
//LCD_COLUMN_PIXEL_SUM = 128
for(i = 0; i < LCD_COLUMN_PIXEL_SUM/2; i++){ //一行两页,一次清除一页,其中一次只能清除8像素行,需要循环64次,清除
lcd_write_data(0, CONCTROLLER_CS1); //也就是清除row的内容.
}
lcd_set_dsp_position(row*(CHAR_ROW_PIXEL/LCD_PAGE_ROW_NUM) + 1, 0);
for(i = 0; i < LCD_COLUMN_PIXEL_SUM/2; i++){
lcd_write_data(0, CONCTROLLER_CS1);
}
lcd_set_dsp_position(row*(CHAR_ROW_PIXEL/LCD_PAGE_ROW_NUM), 64); //选中右屏
for(i = 0; i < LCD_COLUMN_PIXEL_SUM/2; i++){
lcd_write_data(0, CONCTROLLER_CS2);
}
lcd_set_dsp_position(row*(CHAR_ROW_PIXEL/LCD_PAGE_ROW_NUM) + 1, 64);
for(i = 0; i < LCD_COLUMN_PIXEL_SUM/2; i++){
lcd_write_data(0, CONCTROLLER_CS2);
}
}
首先,根据上面传递的参数,row的值为0,表示选中左屏,那么一开始lcd_set_dsp_position(0,0),进入for循环,重复64次写入数据1,其中,CONCTROLLER_CS1 为1,CONCTROLLER_CS2为2。第二次的是lcd_set_dsp_position(1, 0),重复64次写入数据1。接着就是lcd_set_dsp_position(0, 64)和lcd_set_dsp_position(1, 64);这里我们有必要看看函数lcd_set_dsp_position,如下
lcd_set_dsp_position
/* set display position
page: page num(0~7), column:column pixel num(0~127)*/
void lcd_set_dsp_position(unsigned char page, unsigned char column)
{
unsigned char controller_cs;
if( column >= LCD_COLUMN_PIXEL_SUM/2 )
controller_cs = CONCTROLLER_CS2;
else
controller_cs = CONCTROLLER_CS1;
lcd_write_cmd(0xC0, controller_cs); //row
lcd_write_cmd(0x40 + (column & 0x3F), controller_cs); //col
lcd_write_cmd(0xB8 + (page & 0x07), controller_cs); //page
}
根据前面,我们知道page的范围是0-7,column像素的范围是0-127 (16行8个像素),首先往0xC0这个地址写入片选数据1,接着往0x40写入数据1,往0xB8 写入数据1,这里,我们研究左屏。0xC0表示设备起始行的地址,0x40表示设备的列地址,0xB8表示页地址。现在我们不难理解,这段函数的功能,那就是选中对应的显示位置。
lcd_write_data(0,1),数据为0表示清除该数据。
这里,这个函数的功能是清除第row行,那么如果我们要清除全部行(4行)怎么写呢?
lcd_clr
void lcd_clr(void)
{
unsigned char i, x=0;
for(x=0; x<8; x++)
{
lcd_set_dsp_position(x, 0); //选中左屏
//clean all lcd
//8 times = 8 page left 64bit right 64bit
// one page 8 pixel row 64 column
for(i=0; i<64; i++)
{
//clean one column 8 pixel row
lcd_write_data(0, CONCTROLLER_CS1);
}
lcd_set_dsp_position(x, 64); //选中右屏
for(i=0; i<64; i++)
{
lcd_write_data(0, CONCTROLLER_CS2);
}
}
}
这里,一次lcd_wirte_data,只能清除1列,8像素行(1页),所以x循环8次8页,循环128次128列。
lcd_write
/*row num(0~3), column num(0~15), lcd can display 4*16 chars*/
int lcd_write(unsigned char row, unsigned char column, char* data, unsigned char len)
{
unsigned char controller_cs;
unsigned char page_addr_cmd;
unsigned char column_addr_cmd;
unsigned char i,j,page_index,column_index;
unsigned char code_idx1,code_idx2;
if((row > LCD_ROW_NUM -1 ) || (column > LCD_COLUMN_NUM - 1) || (data == NULL)){
return -1;
}
if((len + column) > LCD_COLUMN_NUM){
len = LCD_COLUMN_NUM - column; //超出范围,那么超出的部分不显示
}//128*64
//for (page_index=0;page_index<2;page_index++)
for(page_index = 0; page_index < (CHAR_ROW_PIXEL/LCD_PAGE_ROW_NUM); page_index++){
//for (column_index = 0,i=0;column_index<(3);column_index++,i++)
for(column_index = column, i = 0; column_index < (column + len); column_index++, i++){
//if (column_index>=16/2=8)
if(column_index >= (LCD_COLUMN_NUM / 2)){
controller_cs = CONCTROLLER_CS2; //2
}else{
controller_cs = CONCTROLLER_CS1; //1
}
lcd_write_cmd(0xC0, controller_cs); //行地址
page_addr_cmd = 0xB8 | row*(CHAR_ROW_PIXEL/LCD_PAGE_ROW_NUM) + page_index; //页地址
lcd_write_cmd(page_addr_cmd, controller_cs); //写入页地址
column_addr_cmd = 0x40 | ((column_index * CHAR_COLUMN_PIXEL) & 0x3f); //列地址
lcd_write_cmd(column_addr_cmd, controller_cs);
//send data to lcd
if(data[i] & 0x80){
//chinese
printf("not support display chinese\r\n");
}else{
//CHAR_COLUMN_PIXEL = 8
for(j = 0; j < CHAR_COLUMN_PIXEL; j++){
code_idx1 = data[i]-ASCILL_TO_CODE_INDEX; //32
code_idx2 = j+LCD_PAGE_ROW_NUM*page_index;//j + 8 x page_index
lcd_write_data(char_code_8x16[code_idx1][code_idx2], controller_cs);
}
}
}
}
return 0;
}
这段代码的意思就是,每一次写数据,假设data[] = “input”,前面说过,一个字符是宽8x高16个像素点,高16个像素点,就占两页,也就是外循环需要两次,内循环是字符串的长度列,其中每一列占8个像素点,就是最内层的j循环8次,j循环结束后,也就是1页 8x8个像素点。lcd_write_data是数据写入。
除了以上数据写入之外,我们还需要对液晶的初始化,如下
lcd_init
void lcd_init (void)
{
lcd_gpio_init(); //引脚的初始化
//打开背光
GPIO_ResetBits(GPIOD, LCD_BL); //BL = 0
//reset
GPIO_ResetBits(GPIOD, LCD_RST); //RST = 0,复位
delay_ms(100);
GPIO_SetBits(GPIOD, LCD_RST); //RST = 1
delay_ms(100);
GPIO_ResetBits(GPIOE, LCD_E); //E = 0 使能
delay_us(1);
lcd_write_cmd(0xC0, CONCTROLLER_CS1); //设置显示起始行(左)
lcd_write_cmd(0x3F, CONCTROLLER_CS1); //显示打开
lcd_write_cmd(0xC0, CONCTROLLER_CS2); //设置显示起始行(右)
lcd_write_cmd(0x3F, CONCTROLLER_CS2); //显示打开
lcd_clr(); //清屏
}
STM32液晶显示完整代码
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include "systick.h"
#include "LCD12864.h"
#define CONCTROLLER_CS1 1
#define CONCTROLLER_CS2 2
int main( void )
{
lcd_init(); //lcd_init
show_logo(); //显示logo
}
void lcd_init (void)
{
lcd_gpio_init();
//打开背光
GPIO_ResetBits(GPIOD, LCD_BL);
//reset
GPIO_ResetBits(GPIOD, LCD_RST);
delay_ms(100);
GPIO_SetBits(GPIOD, LCD_RST);
delay_ms(100);
GPIO_ResetBits(GPIOE, LCD_E);
delay_us(1);
lcd_write_cmd(0xC0, CONCTROLLER_CS1); //set first row adr left
lcd_write_cmd(0x3F, CONCTROLLER_CS1); //show open
lcd_write_cmd(0xC0, CONCTROLLER_CS2); //set first row adr right
lcd_write_cmd(0x3F, CONCTROLLER_CS2); //show open
lcd_clr(); //clear lcd
}
void show_logo(void)
{
lcd_disp_full_img(newLandEduLogo); //myname是一维字符数组,大小是16 * 64
delay_ms(1000); //延时1000ms
lcd_clr(); //清除lcd内容
}
void lcd_disp_full_img(unsigned char *img)
{
//img一维数组,需要自己使用字摸工具,使用。
unsigned char i=0,j=0;
for(i=0;i<8;i++)
{
lcd_set_dsp_position(i, 0);
//一次性一页,一共八页
for(j=0;j<128;j++)
{
if( j == 64 )
{
lcd_set_dsp_position(i, j); //选中右屏
}
if(j < 64)
lcd_write_data(*img, CONCTROLLER_CS1); //一次一页,因为数据引脚8位
else
lcd_write_data(*img, CONCTROLLER_CS2);
img++; //img++,指向下一个位置
}
}
}
void lcd_set_dsp_position(unsigned char page, unsigned char column)
{
unsigned char controller_cs;
if( column >= LCD_COLUMN_PIXEL_SUM/2 )
controller_cs = CONCTROLLER_CS2; //2
else
controller_cs = CONCTROLLER_CS1; //1
lcd_write_cmd(0xC0, controller_cs); //0x40 + 0x80 = 0xc0 row
//µÚÒ»ÐеĵØÖ·ÊÇ80H = 0x80
lcd_write_cmd(0x40 + (column & 0x3F), controller_cs); //col
lcd_write_cmd(0xB8 + (page & 0x07), controller_cs); //page
}
void lcd_write_cmd(unsigned char cmd, unsigned char controller_cs)
{
uint16_t data;
if(controller_cs != CONCTROLLER_CS1 && controller_cs != CONCTROLLER_CS2) {
printf("controller_cs(%d)error...\r\n", controller_cs);
return;
}
//while(is_lcd_busy(controller_cs));
GPIO_SetBits(GPIOD, LCD_RW); // RW= 1
set_lcd_data_gpio_to_output();//init lcd_rw output
GPIO_ResetBits(GPIOD, LCD_RS); //RS = 1
if(controller_cs == CONCTROLLER_CS1)
GPIO_SetBits(GPIOD, LCD_CS1);
else
GPIO_SetBits(GPIOD, LCD_CS2);
GPIO_ResetBits(GPIOD, LCD_RW); //RW = 0
data = GPIO_ReadInputData(GPIOE);
data &= 0x00ff;
data |= (cmd << 8);
GPIO_Write(GPIOE, data);
GPIO_SetBits(GPIOE, LCD_E);
delay_us(1);
GPIO_ResetBits(GPIOE, LCD_E);
delay_us(1);
GPIO_SetBits(GPIOD, LCD_RW);
if(controller_cs == CONCTROLLER_CS1)
GPIO_ResetBits(GPIOD, LCD_CS1);
else if(controller_cs == CONCTROLLER_CS2)
GPIO_ResetBits(GPIOD, LCD_CS2);
}
/* send lcd data to show */
void lcd_write_data(unsigned char wdata, unsigned char controller_cs)
{
uint16_t data;
if(controller_cs != CONCTROLLER_CS1 && controller_cs != CONCTROLLER_CS2) {
printf("controller_cs(%d)error...\r\n", controller_cs);
return;
}
//while(is_lcd_busy(controller_cs));
GPIO_SetBits(GPIOD, LCD_RW);
set_lcd_data_gpio_to_output(); //É豸Êý¾ÝÒý½Å
GPIO_SetBits(GPIOD, LCD_RS);
if(controller_cs == CONCTROLLER_CS1)
GPIO_SetBits(GPIOD, LCD_CS1);
else
GPIO_SetBits(GPIOD, LCD_CS2);
GPIO_ResetBits(GPIOD, LCD_RW);
data = GPIO_ReadInputData(GPIOE); //读取数据
data &= 0x00ff; //取低8位
data |= (wdata << 8); //wadata = 0x40
GPIO_Write(GPIOE, data); //写入数据
GPIO_SetBits(GPIOE, LCD_E);
delay_us(1);
GPIO_ResetBits(GPIOE, LCD_E);
delay_us(1);
GPIO_SetBits(GPIOD, LCD_RW);
if(controller_cs == CONCTROLLER_CS1)
GPIO_ResetBits(GPIOD, LCD_CS1);
else
GPIO_ResetBits(GPIOD, LCD_CS2);
}
unsigned char newLandEduLogo[]=
{//New land edu logo,128*64
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,
0xFE,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x60,0xE0,0xE0,0x78,0x78,0xE0,0xE0,0x60,0x60,0xE0,0xE0,0x60,0x60,0x60,
0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xE0,0xE0,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xC0,0xC0,
0xC0,0xC0,0xE0,0xE0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0xF0,0xF0,
0xF0,0xE0,0xC0,0xE0,0x20,0xE0,0xF0,0xF0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,
0x60,0x60,0x60,0xE0,0xE0,0xE0,0xE0,0x70,0x70,0x70,0x60,0xE0,0xE0,0x60,0x60,0x60,
0x00,0xC0,0xE0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xF8,0xF8,0xE0,0xE0,0x80,0x80,
0x00,0x00,0xFA,0xFA,0xFB,0xFF,0xFE,0xFF,0xFB,0x9A,0x9A,0xFF,0xFF,0x02,0xFE,0xFE,
0xFE,0x02,0x00,0x00,0x00,0x03,0x03,0x03,0x03,0x83,0xE3,0xFB,0xFF,0xFF,0xFF,0x83,
0x83,0x03,0x03,0x03,0x03,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xBF,0xFF,0xE0,0xE6,0xE6,
0xE6,0x06,0xFF,0xFF,0x06,0xE6,0xE6,0x06,0x00,0x00,0x00,0x00,0xBA,0x9A,0x9F,0xDF,
0xFF,0xFF,0xBB,0xBB,0x03,0x1F,0x7F,0xF8,0xF0,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,
0x00,0xFB,0xFB,0xFB,0x6B,0x6B,0x6B,0x6B,0x6B,0x6B,0x6B,0x6B,0xFB,0xFB,0x02,0x00,
0x00,0x00,0x01,0x03,0x87,0x8F,0xCF,0xEF,0x33,0xBB,0xCC,0xEE,0x31,0xBB,0xC7,0xEF,
0x1F,0xBF,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0xBF,0x9F,0x0F,0x07,0x03,0x01,0x00,
0x00,0x00,0x0F,0x07,0x03,0x0F,0x0F,0x0F,0x01,0x03,0x07,0x07,0x03,0x00,0x0F,0x0F,
0x0F,0x00,0x00,0x00,0x00,0x0C,0x0E,0x06,0x07,0x03,0x03,0x01,0x00,0x00,0x03,0x03,
0x07,0x06,0x06,0x0E,0x0C,0x00,0x00,0x00,0x0F,0x0F,0x0F,0x01,0x01,0x01,0x07,0x0F,
0x0F,0x0C,0x0F,0x0F,0x0C,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x01,0x0D,0x0D,0x0F,
0x0F,0x07,0x00,0x0C,0x0E,0x06,0x03,0x03,0x03,0x07,0x06,0x0E,0x00,0x00,0x00,0x00,
0x00,0x0F,0x0F,0x0F,0x03,0x03,0x03,0x03,0x03,0x03,0x0B,0x0F,0x0F,0x0F,0x00,0x00,
0x00,0x0C,0x0E,0x37,0x3B,0xDB,0xEC,0xEE,0x33,0xFB,0xCC,0xEE,0x33,0xBB,0xCC,0xEE,
0x33,0xBB,0xCC,0xEF,0x33,0xBB,0xCC,0xEE,0x33,0xBB,0xCC,0xEE,0x26,0x3A,0x18,0x00,
0x00,0x00,0xFE,0xFE,0x3E,0x78,0xF0,0xC0,0xFE,0xFE,0xFE,0xE0,0xF8,0xB8,0x98,0xD8,
0xF8,0x78,0xB8,0x28,0xF8,0xF0,0x80,0xE0,0xF8,0xF8,0xE0,0xC0,0xF8,0x38,0xFE,0xFE,
0xFE,0xE0,0xF8,0x38,0x38,0x18,0x18,0x38,0xF8,0xE0,0xE0,0xF0,0xF8,0x38,0x18,0x38,
0xF8,0xE0,0xE0,0xF0,0xF8,0x38,0x18,0x18,0x38,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xFE,0xFE,0x66,0x66,0x66,0x66,0x66,0x06,0x00,0xE0,0xF8,0x38,0x18,
0x18,0x38,0x00,0xFE,0xFE,0x00,0xF8,0xF8,0x00,0x00,0x00,0xF8,0xF8,0xF8,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x03,0x0B,0x0C,0x2E,0x33,0xBB,0xCC,0xEE,
0x33,0xBB,0xCC,0xEE,0x33,0x3B,0x0C,0x0E,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0F,0x0F,0x00,0x00,0x01,0x03,0x0F,0x0F,0x0F,0x01,0x07,0x07,0x0F,0x0C,
0x0E,0x06,0x07,0x00,0x00,0x03,0x0F,0x07,0x01,0x03,0x0F,0x0F,0x03,0x00,0x0F,0x0F,
0x0F,0x01,0x07,0x07,0x0E,0x0E,0x0E,0x06,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0x00,0x00,
0x0F,0x0F,0x03,0x03,0x0F,0x0E,0x0E,0x0E,0x0F,0x07,0x03,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x0F,0x0F,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x00,0x03,0x07,0x0E,0x0E,
0x0E,0x0E,0x07,0x03,0x00,0x00,0x03,0x0F,0x0E,0x0E,0x0E,0x0F,0x07,0x03,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,
0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
总结
通过以上,我们掌握了基本的LCD使用方法。但这里,我们把LCD封装成函数,那么我们只要关心如何调用就好,如下:
- show_logo() 显示logo,使用字摸工具128*64
- LCD_PRINT(0,0,lcd_show,“Connect to sever”); 第0行0列,字符数组,显示的内容
- lcd_clr_row(row) 清除第row行的内容(0-3)
- lcd_clr(); //清除lcd所有内容
疑惑
每个GOIP口都有16个引脚,那么上述中的
data = GPIO_ReadInputData(GPIOE);
data &= 0x00ff;
data |= (cmd << 8);
其中cmd假设是0x40,无符号字符型,首先读取GPIOE的数据,存储到data,而data是两个字节的数据,接着跟0x00ff按位与,那么必然舍弃高8位,假设读取到的数据是0101 0101 1110 1110,那么按位与之后就是0000 0000 1110 1110,接着
data = data | (cmd<<8),疑惑就是cmd是8位的数据,往左移8位,按C语言语法来看,左移8位,低位自动补0,那么需要数据cmd的作用是什么?
这里,我猜测可能是编译器问题,当cmd的精度不够,它会自动转换成精度更高的数据类型,这里是uint16_t