Proteus-32单片机与LCD1602屏幕实现按键值显示功能详解
0、LCD1602屏幕介绍
LCD1602 是一种常见的字符型液晶显示屏,广泛应用于各种电子设备中,用于显示文本信息。它通常具有16个字符宽和2行的显示能力,因此得名“LCD1602”。以下是关于LCD1602的详细介绍,包括其特点、引脚定义、工作原理以及如何与微控制器(如51单片机或STM32)连接和控制。
LCD1602的特点
显示能力:16个字符宽,2行显示,共32个字符。
字符集:内置5×8点阵字符集,支持ASCII字符和部分扩展字符。
接口类型:并行数据接口,支持4位或8位数据传输。
背光:部分型号带有背光功能,可在低光环境下使用。
低功耗:工作电压通常为4.5V至5.5V,功耗低。
易于控制:通过简单的指令集控制显示内容。
引脚定义
LCD1602通常有16个引脚,具体定义如下:
引脚号 引脚名称 功能描述 1 VSS 地(GND) 2 VDD 电源正极(+5V) 3 V0 对比度调整(通过电位器调节) 4 RS 寄存器选择(0=指令寄存器,1=数据寄存器) 5 RW 读写选择(0=写,1=读) 6 E 使能信号(上升沿触发) 7-14 D0-D7 数据线(8位数据传输) 15 A 背光正极(部分型号) 16 K 背光负极(部分型号)
.工作原理 LCD1602通过并行数据接口与微控制器通信,支持4位和8位数据传输模式。以下是其基本工作原理:
(1)指令和数据传输
指令寄存器:用于接收控制指令(如清屏、设置光标位置等)。
数据寄存器:用于接收要显示的字符数据。
RS引脚:用于选择当前操作是写入指令还是数据。
RW引脚:用于选择当前操作是写入还是读取。
E引脚:使能信号,上升沿触发数据或指令的读取。
(2)显示控制
清屏指令:清除显示内容。
光标控制:设置光标位置。
字符显示:将字符数据写入指定位置。
初始化和控制
以下是使用51单片机控制LCD1602的初始化和控制代码示例:
(1)硬件连接
数据线(D0-D7)连接到51单片机的P0口。
控制线:
RS:连接到P2^0。
RW:连接到P2^1。
E:连接到P2^2。
电源和地:连接到51单片机的电源和地。
1、开发环境
proteus8.17 :制作stm32f103c8t6 和lcd1602连接电路图 keil mdk 编写stm32工程实现代码
2、LCD1602.h代码
#ifndef __LCD1602_H
#define __LCD1602_H
#include"stm32f10x.h"
//lcd1602引脚定义
#define LCD1602_Timer_GPIOA RCC_APB2Periph_GPIOA
#define LCD1602_Timer_GPIOB RCC_APB2Periph_GPIOB
#define LCD1602_GPIOA GPIOA
#define LCD1602_GPIOB GPIOB
#define LCD1602_RS GPIO_Pin_8
#define LCD1602_RW GPIO_Pin_6
#define LCD1602_E GPIO_Pin_7
#define LCD1602_IO GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15
#define LCD1602_I0_SET() GPIO_SetBits(GPIOB, LCD1602_IO)
#define LCD1602_RS_SET() GPIO_SetBits(GPIOA,LCD1602_RS)
#define LCD1602_RS_RESET() GPIO_ResetBits(GPIOA,LCD1602_RS)
#define LCD1602_RW_SET() GPIO_SetBits(GPIOB,LCD1602_RW)
#define LCD1602_RW_RESET() GPIO_ResetBits(GPIOB,LCD1602_RW)
#define LCD1602_E_SET() GPIO_SetBits(GPIOB,LCD1602_E)
#define LCD1602_E_RESET() GPIO_ResetBits(GPIOB,LCD1602_E)
//初始化函数
void LCD1602_Init(void);
//显示数字
void LCD1602_ShowNum(unsigned char x,unsigned char y,unsigned char *str,unsigned char i);
/*显示字符串函数
x:0,1两行
y:0到15个列
str:显示字符串
*/
void LCD1602_ShowStr(unsigned char x,unsigned char y,unsigned char *str);
//清屏函数
void LCD1602_Clear(void);
#endif
3、LCD1602.c代码
#include"lcd1602.h"
void LCD1602_GPIO_Init_Out()//LCD1602端口初始化,配置为输出
{
GPIO_InitTypeDef GPIO_InitStructrue;
RCC_APB2PeriphClockCmd(LCD1602_Timer_GPIOA | LCD1602_Timer_GPIOB, ENABLE);//使能端口时钟
GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出
GPIO_InitStructrue.GPIO_Pin = LCD1602_RS;
GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_10MHz;//低速输出
GPIO_Init(LCD1602_GPIOA, &GPIO_InitStructrue);//初始化
GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出
GPIO_InitStructrue.GPIO_Pin = LCD1602_RW | LCD1602_E | LCD1602_IO ;
GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_10MHz;// 低速输出
GPIO_Init(LCD1602_GPIOB, &GPIO_InitStructrue);//初始化
}
void LCD1602_GPIO_Init_Inupt()//LCD1602端口初始化,配置为输入
{
GPIO_InitTypeDef GPIO_InitStructrue;
RCC_APB2PeriphClockCmd(LCD1602_Timer_GPIOB, ENABLE);//使能端口时钟
GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_15;
GPIO_Init(LCD1602_GPIOB, &GPIO_InitStructrue);//初始化
}
void LCD1602_WaitReady(void)//用于LCD忙检测
{
u8 sta = 0;
LCD1602_GPIO_Init_Out();//LCD1602端口初始化,配置为输出
GPIOB->ODR =0xff00;
LCD1602_RS_RESET();
LCD1602_RW_SET();//读状态
LCD1602_GPIO_Init_Inupt();//LCD1602端口初始化,配置为输入
do{
LCD1602_E_SET();
sta = GPIO_ReadInputDataBit(LCD1602_GPIOB, GPIO_Pin_15);
LCD1602_E_RESET();
}
while(sta);
LCD1602_GPIO_Init_Out();//LCD1602端口初始化,配置为输出
}
void LCD1602_WriteCmd(u16 cmd)//用于写指令
{
LCD1602_WaitReady();//等待液晶准备好
LCD1602_RS_RESET();
LCD1602_RW_RESET();//写指令
GPIOB->ODR &=((cmd<< 8)|0x0000);
LCD1602_E_SET();
LCD1602_E_RESET();//高脉冲
}
void LCD1602_WriteDate(u16 date)//用于写数据
{
LCD1602_WaitReady();//等待液晶准备好
LCD1602_RS_SET();
LCD1602_RW_RESET();//写数据
GPIOB->ODR &=((date << 8)|0x0000);
LCD1602_E_SET();
LCD1602_E_RESET();//高脉冲
}
void LCD1620_SetAddress(unsigned char x,unsigned char y)
{
if(y == 0)
LCD1602_WriteCmd(0x80 | x);//从第一行开始显示
else
LCD1602_WriteCmd(0x80 | 0x40 | x);//从第二行开始显示
}
void LCD1602_ShowStr(unsigned char x,unsigned char y,unsigned char *str)//LCD1602显示字符串
{
LCD1620_SetAddress(x,y);//设置数据地址指针
while(*str != '\0')
LCD1602_WriteDate(*str++);//写数据
}
void LCD1602_ShowChar(unsigned char x,unsigned char y,unsigned char date)//LCD1602显示字符
{
LCD1620_SetAddress(x,y);//设置数据地址指针
LCD1602_WriteDate(date);//写数据
}
void LCD1602_ShowNum(unsigned char x,unsigned char y,unsigned char *str,unsigned char i)//LCD1602显示数字
{
LCD1620_SetAddress(x,y);//设置数据地址指针
str = str+ i;
LCD1602_WriteDate(*str);//写数据
}
void LCD1602_Init(void)//液晶初始化函数
{
LCD1602_GPIO_Init_Out();
LCD1602_WriteCmd(0x38);//设置16*2显示,5*7点阵,8位数据接口
LCD1602_WriteCmd(0x0c);//开显示,显示光标,光标不闪烁
LCD1602_WriteCmd(0x06);//光标加1,屏幕显示不移动
LCD1602_WriteCmd(0x01);//清屏
}
void LCD1602_Clear(void)
{
LCD1602_WriteCmd(0x01);//清屏
}
4、key.c key.h按键代码
#include "stm32f10x.h" // Device header
#include "delay.h"
/**
* 函 数:按键初始化
* 参 数:无
* 返 回 值:无
*/
void Key_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOB的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 |GPIO_Pin_14 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PB1和PB11引脚初始化为上拉输入
}
/**
* 函 数:按键获取键码
* 参 数:无
* 返 回 值:按下按键的键码值,范围:0~2,返回0代表没有按键按下
* 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手
*/
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0; //定义变量,默认键码值为0
//按键1 检测
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_13) == 0) //读PB1输入寄存器的状态,如果为0,则代表按键1按下
{
Delay_ms(100); //延时消抖
while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_13) == 0); //等待按键松手
//Delay_ms(2); //延时消抖
KeyNum = 1; //置键码为1
}
//按键2 检测
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_14) == 0) //读PB11输入寄存器的状态,如果为0,则代表按键2按下
{
Delay_ms(100); //延时消抖
while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_14) == 0); //等待按键松手
//Delay_ms(2); //延时消抖
KeyNum = 2; //置键码为2
}
return KeyNum; //返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0
}
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h" // Device header
void Key_Init(void);
uint8_t Key_GetNum(void);
#endif
5、主函数代码
#include "stm32f10x.h" // Device header
#include "lcd1602.h"
#include "stdio.h"
#include "Key.h"
char time=30;
void Buzzer_delay(u32 ms)
{
while(ms--);
}
//蜂鸣器
void Buzzer_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_WriteBit(GPIOA,GPIO_Pin_10,(BitAction)0); //输出高电平 GPIO_SetBits(GPIOA, GPIO_Pin_0)
}
//蜂鸣器驱动
void Buzzer_run(uint16_t xms)
{
uint16_t i;
for(i=0;i<xms;i++)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_10,(BitAction)1);
Buzzer_delay(2);
GPIO_WriteBit(GPIOA,GPIO_Pin_10,(BitAction)1);
Buzzer_delay(2);
}
}
//主函数
int main(void)
{
unsigned char getKey,count=0;
char buff5[16];
LCD1602_Init();//lcd1602初始化
Key_Init();//按键初始化
//Buzzer_Init();//蜂鸣器初始化
LCD1602_ShowStr(0,0,"Hello Everyone!");
LCD1602_ShowStr(0,1,"Testing:");
count=2;
while (1)
{
getKey=Key_GetNum();
if(getKey ==1)
{
count=count+1;
if(count>10)
{
count=0;
}
}
if(getKey ==2)
{
count=count-1;
if(count<0)
{
count=10;
}
}
// if(count>5)
// {
// Buzzer_run(20);
// }
//显示数字
sprintf(buff5,"%d",count);
LCD1602_ShowStr(9,1,(unsigned char *)buff5);
Buzzer_delay(4000);
}//while line
}
6、proteus 电路连接图
7、实现效果:左按键+数值,右按键-数值
作者:瓢儿菜2018