STM32串行通信模式驱动LCD12864,结合手册从原理让你理解显示过程

常见的人机交互界面,除了数码管、LED、LCD1206,OLED,Nokia5110以外,比较常用的还有LCD12864。

LCD12864从字面意思就是横向可以显示128个像素点,纵向可以显示64个像素点。常见的LCD12864液晶模块分为带字库版本和不带字库版本,一般为了使用方便,直接选用带中文字库版本即可。

引脚定义

本文使用的是串行通信模式,下面仅介绍跟串行通信相关的引脚:

本次实例选用的LCD12864背部如下所示,显示的型号为:12864J-3 V1

原理图

具体连接情况:

引脚1 VSS 电源负极,接地

引脚2 VDD 电源正极,接3.3V(注意自己所选的LCD12864是否支持3.3V)

引脚3 VO 调节屏幕对比度(模组背部自带可调电位器VR1),JP40与18脚VOUT相连

引脚4[PA8] CS 片选引脚,高电平时可接受数据,低电平锁存数据

引脚5[PC9] SID 串行数据输入端

引脚6[PC8]  CLK 串行同步时钟

引脚15 PSB 低电平时为串行模式(在有的液晶屏背部,可以通过焊锡短接设置为默认模式为串行模式),跳线与GND相连

引脚17 RESET 复位引脚,低电平可使LCD复位

引脚19 A LCD背光源的电源

引脚20 K LCD背光源的地

串行模式时序图分析

串行模式下传输一个字节数据过程

  1. 数据传输过程中,片选CS引脚置高,此期间LCD可接受数据或指令;

  2. 随后,单片机端(STM32)要给出同步位串:'11111',5个连续的“1”作数据起始位;

  3. 接下来一位为:RW,用于选择数据的传输方向,1是读数据,0是写数据,H 表示数据从 LCD 到 MCU,L 表示数据从 MCU 到 LCD;

  4. 接下来一位为:RS,用于选择内部数据寄存器或指令寄存器,0是命令寄存器,1是数据寄存器;

  5. 第一字节的最后位(第8位)固定为“0”;

  6. 第一个字节传输完成之后,开始正式传输指令或者数据,在传输过程中会进行拆分处理,该字节指令或者数据将被分为2个字节来传输;

  7. 第二个字节的高4位为待传输数据的高4位(D7-D4),低4位用0填充;

  8. 第三个字节的高4位为待传输数据的低4位(D3-D0),低4位用0填充;

  9. 经过上面几步,完成了一个字节(D7-D0)指令或数据的传送。  

比如你想发送的数据为“0”,对应16进制为0x30,对应二进制为0011 0000,那么发送的顺序就是:

  1. 因为是数据,所以先发送0xFA (11111 010) ==> 五个1,RW=0,RS=1
  2. 发送0011 0000 ==> 高四位为数据“0”的高四位,低4位补0
  3. 发送0000‬ 0000 ==> 高四位为数据“0”的低四位,低4位补0到此一个字节发送完成。所以写指令之前,必须先发送 11111 000 (即0xF8);写数据之前,必须先发送 11111 010 (即0xFA)。

综上所述,发送命令和数据的函数封装如下:

void WriteCommand(uchar Cbyte )   
{     
  GPIO_SetBits(LCD_CS);      
  delay_ms(1);
  
  SendByte(0xF8);              //11111,RW(0),RS(0),0   
  SendByte(0xF0&Cbyte);       //高四位          
  SendByte(0xF0&Cbyte<<4);    //低四位(先执行<<)
  
  GPIO_ResetBits(LCD_CS); 
  delay_ms(2);
}

void WriteData(uchar Dbyte )   
{ 
  GPIO_SetBits(LCD_CS);  
  delay_ms(1);  
  
  SendByte(0xFA);            //11111,RW(0),RS(1),0  
  SendByte(0xF0&Dbyte);        
  SendByte(0xF0&Dbyte<<4);
  
  GPIO_ResetBits(LCD_CS);   
  delay_ms(2);
}
  1. 完成一个字节数据的发送需要24个时钟周期(CLK引脚发送24个同步时钟信号),发送一个字节的有效数据实际上发送了3个字节;

  2. 只有在时钟线SCLK拉低时,数据线SID上的数据才允许变化,在时钟线SCLK高电平时,SID上的数据必须保持稳定(不能变化)。即在低电平的时候改变数据,上升沿的时候模块读取SID数据。

LCD内部资源及显示原理

  • 设置命令为基本指令集

LCD的控制芯片为ST7920,每次执行新的命令之前,一般需要先发送一个0x30。

WriteCommand(0x30);

对应手册中下面位置:

由上我们知道0x30对应着基本指令集。

  • 设定显示地址
WriteCommand(TABLE[8*row+col]);

其中TABLE内容如下:

uchar const TABLE[]=
{   
   0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,  //第一行
   0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,  //第二行       
   0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,   //第三行     
   0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,   //第四行    
};

此表格中的数值来自于手册中如下位置:

由上面的分析之后,封装显示字符或者汉字的函数如下:

/*! 
 *  @brief      显示字符或汉字
 *  @param  row: row(0~3)
 *  @param  col: line(0~7) 
 *  @param   str: 要显示的字符或汉字
 */
void LCD_Display_Words(uchar row,uchar col,uchar *str)   
{   
  WriteCommand(0x30);       
  WriteCommand(TABLE[8*row+col]);      
  while(*str != '\0')     
  {   
     if(col==8)             
     {              
       col=0;   
       row++;   
     }   
     if(row==4) row=0;       
     WriteCommand(TABLE[8*row+col]);   
     WriteData(*str);      
     str++;   
     WriteData(*str);   
     str++;   
     col++;   
  }   
}

我们使用上面的函数打印输出一个汉字进行测试:

LCD_Display_Words(0,0,(u8 *)"哈");

将WriteData的数据通过串口打印输出:

我们可以在串口助手中看到打印的数据为:“B9 FE”,具体的结果如下:

对应手册中字库,可以发现“哈”的编码即是“B9 FE”,由上我们知道了,为什么直接使用LCD_Display_Words函数输出汉字,就能够在LCD12864上显示出对应的汉字。

结果展示

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 1
收藏 2
关注 62
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧