基于STM32的12864液晶理解

前言

字符型液晶显示模块是一种专门用于显示字母、数字、符号等点阵式 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

猜你喜欢

转载自blog.csdn.net/qq_40318498/article/details/95621876
今日推荐