LCD1602使用4线方式驱动
先介绍硬件环境:
MCU:STM32F030F4,主频16Mhz
显示器:LCD1602A,黄绿屏
软件环境:STM32CUBE_MX
编译器:keil MDK;
不多说了,直接上代码:
头文件
/**
硬件连接:
DB4--PA0
DB5--PA1
DB6--PA2
DB7--PA3
E----PA4
RW---PA5
RS---PA6
**/
/**
读状态。输入RS=0,RW=1,E=高脉冲。输出:D0—D7为状态字。
读数据。输入RS=1,RW=1,E=高脉冲。输出:D0—D7为数据。
写命令。输入RS=0,RW=0,E=高脉冲。输出:无。
写数据。输入RS=1,RW=0,E=高脉冲。输出:无。
**/
#ifndef __LCD_1602_H
#define __LCD_1602_H
#include "main.h"
#define COM 0
#define DAT 1
#define LCD_RS_H() HAL_GPIO_WritePin(LCD_RS_GPIO_Port,LCD_RS_Pin,GPIO_PIN_SET)
#define LCD_RS_L() HAL_GPIO_WritePin(LCD_RS_GPIO_Port,LCD_RS_Pin,GPIO_PIN_RESET)
#define LCD_RW_H() HAL_GPIO_WritePin(LCD_RW_GPIO_Port,LCD_RW_Pin,GPIO_PIN_SET)
#define LCD_RW_L() HAL_GPIO_WritePin(LCD_RW_GPIO_Port,LCD_RW_Pin,GPIO_PIN_RESET)
#define LCD_E_H() HAL_GPIO_WritePin(LCD_E_GPIO_Port,LCD_E_Pin,GPIO_PIN_SET)
#define LCD_E_L() HAL_GPIO_WritePin(LCD_E_GPIO_Port,LCD_E_Pin,GPIO_PIN_RESET)
void LCD1602_Init(void);
void LCD1602_ClearScreen(void);
void LCD1602_ShowStr(uint8_t x, uint8_t y, char *str);
void LCD1602_ShowNum(uint8_t x,uint8_t y, uint16_t num,uint8_t lenth,uint8_t mode);
#endif
//
//
C文件
#include "lcd1602.h"
void LCD1602_Set_Cursor(uint8_t x, uint8_t y);
///4线LCD1602
//函数名: delay
//函数功能:LCD1602延时
//注释:
void delay(unsigned char z)
{
unsigned char x,y,j;
for(j=0; j<4; j++)
for(x=z; x>0; x--)
for(y=110; y>0; y--);
}
//
void Send2Lcd(uint8_t data,uint8_t rs)
{
uint8_t i;
if(rs) LCD_RS_H();
else LCD_RS_L();
LCD_RW_L();
for(i=0; i<2; i++)
{
GPIOA->ODR = (GPIOA->ODR & 0xfff0) | ((data>>4) & 0x0f);
LCD_E_H();
delay(50);
LCD_E_L();
data <<= 4;
}
}
//void LCD_CheckBusy(void)
//{
//
// uint16_t portValue;
// portValue = GPIOA->ODR;
// GPIOA->ODR= portValue | 0X000F;
//
// LCD_RS_L();
// LCD_RW_H();
// LCD_E_H();
//
// while(LCD_BusySta());
// LCD_E_L();
//}
/*向1602写入一字节命令,cmd-待写入命令 */
//写入指令PA4-7 RS-0 RW-0
void LCD1602_Write_Cmd(uint8_t cmd)
{
// LCD_CheckBusy();
Send2Lcd(cmd,COM);
}
/* 向1602写入一字节数据*/
void LCD1602_Write_Dat(uint8_t dat)
{
// LCD_CheckBusy();
Send2Lcd(dat,DAT);
}
/*清屏*/
void LCD1602_ClearScreen(void)
{
LCD1602_Write_Cmd(0x01);
HAL_Delay(2);
}
/* 设置RAM其实地址,即光标位置,(X,Y)对应屏幕上的字符坐标 */
void LCD1602_Set_Cursor(uint8_t x, uint8_t y)
{
switch(y)
{
case 0:
x|=0x80;
break;
case 1:
x|=0xc0;
break;
}
LCD1602_Write_Cmd(x);
}
/* 在液晶上显示字符串,(X,Y)-对应屏幕上的其实坐标,str-字符串指针 */
void LCD1602_ShowStr(uint8_t x, uint8_t y, char *str)
{
LCD1602_Set_Cursor(x, y);
while(*str != '\0')
{
LCD1602_Write_Dat(*str++);
}
}
void LCD1602_ShowChar(uint8_t x,uint8_t y,char dat)
{
LCD1602_Set_Cursor(x, y);
LCD1602_Write_Dat(dat);
}
/*
********************************************
* 说明:返回M的N次幂
********************************************
*/
uint32_t LCD_Pow(uint8_t m,uint8_t n)
{
uint32_t result=1;
while(n--)result*=m;
return result;
}
/*
********************************************
* 说明:显示数字
* mode:0=前导零不显示,1=前导零显示
********************************************
*/
void LCD1602_ShowNum(uint8_t x,uint8_t y, uint16_t num,uint8_t lenth,uint8_t mode)
{
uint8_t t,temp;
uint8_t enshow = 0;
for(t=0;t<lenth;t++)
{
temp=(num/LCD_Pow(10,lenth-t-1))%10;
if(enshow == 0 && t < (lenth-1))
{
if(temp == 0)
{
if(mode)
{
LCD1602_ShowChar(x+t,y,temp+0x30);
}
else
{
LCD1602_ShowChar(x+t,y,0X20);
}
continue;
}
else
{
enshow = 1;
}
}
LCD1602_ShowChar(x+t,y,temp+0x30);
}
}
/* 初始化液晶 */
void LCD1602_Init(void)
{
HAL_Delay(50);
LCD1602_Write_Cmd(0x33);
HAL_Delay(5);
LCD1602_Write_Cmd(0x32);
HAL_Delay(1);
LCD1602_Write_Cmd(0x28); //16*2显示,5*7点阵,4位数据口
HAL_Delay(1);
LCD1602_Write_Cmd(0x01); //清屏
HAL_Delay(1);
LCD1602_Write_Cmd(0x06); //文字不动,地址自动+1
HAL_Delay(1);
LCD1602_Write_Cmd(0x0c);
}
//
//
注意项点:
1、在发送数据的时候,因为硬件是直接在PA低四位,所以采用了寄存器直接输出,如果不是,请调整数据发送。
2、初始化命令要按上面程序的来,我之前用其他初始化程序,在debug完成后,能正常显示,但是直接上电就总是显示不正常。
最后来个图片验证一下吧。