/************************************************************************************************************
笔记:
1、采用串行输出
2、器件 [16 NC(PSB)]引脚需要接地, H:并口通信 L:串口通信

3、LCD_CS_Pin LCD_CS_GPIO_Port //片选控制,0,无效 1有效
LCD_SID_Pin LCD_SID_GPIO_Port //数据引脚,
LCD_SCLK_Pin LCD_SCLK_GPIO_Port //时钟引脚,0,有效,1无效

4、串口通信格式:
起始帧(1字节)--11111 R1/W0(读写) RS(数据1/指令0) 0
数据帧(2字节)--[D7 D6 D5 D4 0000] [D3 D2 D1 D0 0000]

5、指令集参考[16032液晶显示模块使用说明书.pdf--9页]

6、液晶屏掉电复位是,需要等待电源稳定后,初始化才能正常运行。
如果出现掉电重启后,液晶屏显示异常,肯定是延时得不够。
*************************************************************************************************************/
#include "LCD16032.h"
#include "string.h"
#include "cmsis_os.h"

#include "uartext.h"
//#include "stdlib.h"


#define lcd16032_cs(N) N==1?HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET):HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET)
#define lcd16032_sclk(N) N==1?HAL_GPIO_WritePin(LCD_SCLK_GPIO_Port, LCD_SCLK_Pin, GPIO_PIN_SET):HAL_GPIO_WritePin(LCD_SCLK_GPIO_Port, LCD_SCLK_Pin, GPIO_PIN_RESET)
#define lcd16032_sid(N) N==1?HAL_GPIO_WritePin(LCD_SID_GPIO_Port, LCD_SID_Pin, GPIO_PIN_SET):HAL_GPIO_WritePin(LCD_SID_GPIO_Port, LCD_SID_Pin, GPIO_PIN_RESET)
#define lcd16032_sid_input HAL_GPIO_ReadPin(LCD_SID_GPIO_Port, LCD_SID_Pin)

#define LCD16032_CMD_READ 0xFC //读命令
#define LCD16032_CMD_WRITE 0xF8 //写命令
#define LCD16032_DATA_READ 0xFE //读数据
#define LCD16032_DATA_WRITE 0xFA //写数据

#define LCD16032_BYTE_X 20 //X轴最大支持20个字符,10个汉字
#define LCD16032_BYTE_Y 2 //Y轴最大支持2行

/******************************
函数名:lcd16032_delay
功 能:实现us级(测试实际延迟 1.5us)
形 参:
返回值:
备 注:[100-40.3us] [10-4.3us] [1-0.43us]
*******************************/
void lcd16032_delay(uint8_t Nom)
{
uint8_t i = Nom * 3;
while(i--);
}
/******************************
函数名:lcd16032_send_byte
功 能:向器件发送一帧字节
形 参:byte--一帧
返回值:
备 注:看器件手册时序图
3、LCD_CS_Pin LCD_CS_GPIO_Port //片选控制,0,无效 1有效
LCD_SID_Pin LCD_SID_GPIO_Port //数据引脚,
LCD_SCLK_Pin LCD_SCLK_GPIO_Port //时钟引脚,0,有效,1无效
*******************************/
void lcd16032_send_byte(uint8_t byte)
{
uint8_t i = 0;
lcd16032_cs(1);
lcd16032_sclk(1);

//printf("ing send byte\r\n");
lcd16032_delay(1);
//printf("cs-%d,scl-%d\r\n", HAL_GPIO_ReadPin(LCD_CS_GPIO_Port, LCD_CS_Pin), HAL_GPIO_ReadPin(LCD_SCLK_GPIO_Port, LCD_SCLK_Pin));

//printf("byte-0x%x\r\n", byte);
for(i = 0; i < 8; i++)
{
lcd16032_sclk(0);
lcd16032_delay(1);
(byte & 0x80) == 0x80 ? lcd16032_sid(1) : lcd16032_sid(0); //选择数据高低电平
//printf("bit-%d,sid-%d\r\n", byte & 0x80, HAL_GPIO_ReadPin(LCD_SID_GPIO_Port, LCD_SID_Pin));
/*但sclk出现下降沿,器件接收一个位*/
lcd16032_sclk(1);
lcd16032_delay(1);

byte <<= 1; //准备下一位
//HAL_Delay(1);
}
}

/******************************
函数名:lcd16032_read_byte
功 能:从器件中读取一个字节
形 参:
返回值:一个字节
备 注:
*******************************/
uint8_t lcd16032_read_byte(void)
{
uint8_t byte = 0;
lcd16032_cs(1);
lcd16032_sclk(1);
lcd16032_delay(1);
for(uint8_t i = 0; i < 8; i++)
{
if(lcd16032_sid_input)
{
byte |= 0x01;
}
/*但sclk出现下降沿,器件发送一个位*/

byte <<= 1; //准备下一位
lcd16032_delay(1);
}
//printf("%x\r\n",byte);
return byte;
}

/******************************
函数名:lcd16032_read_busy
功 能:读取显示屏是否处于忙状态
形 参:
返回值:1忙 0不忙
备 注:
*******************************/
uint8_t lcd16032_read_busy(void)
{
uint16_t getd;
lcd16032_cs(1);//拉高
lcd16032_send_byte(LCD16032_CMD_READ);
getd = lcd16032_read_byte();//高字节
//printf("busy-getdh-0x%x\r\n", getd);
getd |= (lcd16032_read_byte() >> 4);//高字节+低字节
//printf("busy-getd-0x%x\r\n", getd);
return (getd & 0x80) ? 1 : 0;
}

/******************************
函数名:lcd16032_write_cmd
功 能:向器件写命令
形 参:cmd--命令
返回值:0--成功 1--失败
备 注:命令值参考器件手册
*******************************/
uint8_t lcd16032_write_cmd(uint8_t cmd)
{
uint8_t i = 0, busy = 1;
i = 5;
while(i-- && busy)
{
busy = lcd16032_read_busy();
lcd16032_delay(255);//1ms
}
if(i > 0 && busy == 0)
{
lcd16032_send_byte(LCD16032_CMD_WRITE);
}
else
{
//printf("err\r\n");
return 1;
}
lcd16032_delay(255);

i = 5;
while(i-- && busy)
{
busy = lcd16032_read_busy();
lcd16032_delay(255);//1ms
}
if(i > 0 && busy == 0)
{
lcd16032_send_byte(0xf0 & cmd); //high 4bits
lcd16032_delay(1);
lcd16032_send_byte(0xf0 & (cmd << 4)); //low 4bits
//printf("cmd-0x%x-0x%x-0x%x\r\n", cmd, 0xf0 & cmd, 0xf0 & (cmd << 4));
}
else
{
return 1;
}
return 0;
}
/******************************
函数名:lcd16032_write_data
功 能:向器件写入一个字节
形 参:byte--字节
返回值:0--成功 1--失败
备 注:
*******************************/
uint8_t lcd16032_write_data(uint8_t byte)
{
uint8_t i = 0, busy = 1;
i = 5;
while(i-- && busy)
{
busy = lcd16032_read_busy();
HAL_Delay(1);//1ms
}
if(i > 0 && busy == 0)
{
lcd16032_send_byte(LCD16032_DATA_WRITE);
}
else
{
return 1;
}
HAL_Delay(1);//1ms
i = 5;
while(i-- && busy)
{
busy = lcd16032_read_busy();
HAL_Delay(1);//1ms
}
if(i > 0 && busy == 0)
{
lcd16032_send_byte(0xf0 & byte);
lcd16032_delay(1);
lcd16032_send_byte(0xf0 & (byte << 4));
}
else
{
return 1;
}
return 0;
}

/******************************
函数名:lcd16032_set_xy
功 能:设置字符显示位置
形 参:x列,y行
返回值:0--成功 1--失败
备 注:器件 X轴:80H-89H Y轴:80H-9FH
笔 记:一个字符 占x-8位,y-16位
*******************************/
uint8_t lcd16032_set_xy(uint8_t x, uint8_t y)
{
uint8_t err;
if((x > LCD16032_BYTE_X) || (y > LCD16032_BYTE_Y+1))
{
x = 0;
y = 1;
}
y == 0 ? (err = lcd16032_write_cmd(0x80 + x)) : (err = lcd16032_write_cmd(0x90 + x)); //设置字符显示位置 至少72us
return err;
}



#define LCD_Debug(N) N==1? lcd16032_write_cmd(0x0f):lcd16032_write_cmd(0x0c)
/******************************
函数名:lcd16032_init
功 能:器件初始化
形 参:
返回值:
备 注:00110000 需要启动RTOS,才能初始化液晶屏
*******************************/
void lcd16032_init(void)
{
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); //片选拉低,使用时拉高
HAL_GPIO_WritePin(LCD_SCLK_GPIO_Port, LCD_SCLK_Pin, GPIO_PIN_SET); //时钟拉高,当拉低时有效
lcd16032_write_cmd(0x30);//功能设定设置00110000[8-BIT 控制接口][基本指令集动作]至少72us
lcd16032_delay(72);//100us
lcd16032_write_cmd(0x30);//功能设定设置00110000[8-BIT 控制接口][基本指令集动作]至少72us
lcd16032_delay(72);//100us
LCD_Debug(0); //测试模式(1测试 0出厂)能看清屏幕处理过程
lcd16032_delay(72);//100us
lcd16032_write_cmd(0x01);//显示清屏 至少1.6ms
}

/***************************应用类函数********************************/
/******************************
函数名:lcd16032_send_char
功 能:显示单个字符
形 参:byte--字节
返回值:0--成功 1--失败
备 注:
*******************************/
uint8_t lcd16032_send_char(uint8_t byte)
{
return lcd16032_write_data(byte);
}
/******************************
函数名:lcd16032_show_char
功 能:显示单个字符
形 参:x,y byte--字节
返回值:0--成功 1--失败
备 注:
*******************************/
uint8_t lcd16032_show_char(uint8_t x, uint8_t y, uint8_t byte)
{
lcd16032_set_xy(x, y);
return lcd16032_write_data(byte);
}

/******************************
函数名:lcd16032_send_string
功 能:显示多个字符
形 参:str--字符串
返回值:0--成功 >1--失败
备 注:
*******************************/
uint8_t lcd16032_send_string(uint8_t *str)
{
uint8_t i, len, err = 0;
len = strlen((const char*) str);
for(i = 0; i < len; i++)
{
err |= lcd16032_write_data(str[i]);
}
return err;
}

/******************************
函数名:lcd16032_show_string
功 能:显示多个字符,并指定显示位置
形 参:col,row str
返回值:0--成功 >1--失败
备 注:一个汉字两个字节,液晶屏一个地址只能存放一个汉字或者两个字符.
*******************************/
uint8_t lcd16032_show_string(uint8_t col, uint8_t row, uint8_t *str)
{
uint8_t err, game_x, game_y, i = 0, len, flag = 0;
// uint8_t TxBuffer[32];
err = lcd16032_set_xy(col, row);
//HAL_Delay(1);
osDelay(1);
game_x = col;
game_y = row;
len = strlen((const char *)str);

//printf("TextLen-%d\r\n", len);

while(*str != '\r' && i < len)
{

if(*str > 127)//汉字
{
if(flag == 1) //判断上个字节,是否占满一个地址。没有占满补位 ! = 0
{
game_x++;
flag = 0;
lcd16032_send_char(' ');//补位,使汉字正常显示
//lcd16032_set_xy(game_x, game_y);

}
osDelay(1);
//HAL_Delay(1);
lcd16032_send_char(*str++);
osDelay(1);
//HAL_Delay(1);
lcd16032_send_char(*str++);
game_x ++; //记录光标位置
i += 2; //记录字符串目标位
}
else //字母
{
if(flag == 1)
{
game_x++;
flag = 0;

}
else
{
flag++;
}
i++;
err |= lcd16032_send_char(*str++);
osDelay(1);
//HAL_Delay(1);
}

if(*str == '&' && game_y < 2) //如果有换行符,就切换到下一行
{
if(game_y == 1)
{
lcd16032_set_xy(game_x, 1);
lcd16032_delay(72);
game_y = 1;
i++;
flag = 0;
}
else
{
lcd16032_set_xy(0, 1);
//HAL_Delay(1);
lcd16032_delay(72);
game_x = 0;
game_y = 1;
flag = 0;

}
//printf("game_y-%d\r\n", game_y);
*str++;

continue;
}
else if((col + game_x > (LCD16032_BYTE_X/2) - 1) && game_y == 0) //第一行过长,自动切换到第二行
{
lcd16032_set_xy(0, 1);
//HAL_Delay(1);
lcd16032_delay(72);
game_x = 0;
game_y = 1;
flag = 0;
//printf("game_y2-%d\r\n", game_y);
continue;
}
}
return err;
}
#ifndef _LCD16032_H
#define _LCD16032_H
#include "main.h"
void lcd16032_delay(uint8_t Nom);
void lcd16032_send_byte(uint8_t byte);
uint8_t lcd16032_read_byte(void);
uint8_t lcd16032_read_busy(void);
uint8_t lcd16032_write_cmd(uint8_t cmd);
uint8_t lcd16032_write_data(uint8_t byte);
void lcd16032_init(void);

uint8_t lcd16032_send_char(uint8_t byte);
uint8_t lcd16032_show_char(uint8_t x, uint8_t y, uint8_t byte);
uint8_t lcd16032_send_string(uint8_t *str);
uint8_t lcd16032_set_xy(uint8_t x, uint8_t y);

uint8_t lcd16032_show_string(uint8_t x, uint8_t y, uint8_t *str);

char* split(char * p, char * str);
#endif

​16032液晶显示模块使用说明书.pdf​