DSP28335的3X3矩阵键盘扫描,用LCD1602显示
1、LCD1602 使用
要使用 LCD1602, 首先需要对其初始化, 即通过写入一些特定的指令实现。然后选择要在 LCD1602 的哪个位置显示并将所要显示的数据发送到 LCD 的DDRAM。 使用 LCD1602 通常都是用于写数据进去, 很少使用读功能。 LCD1602 操作步骤如下所示: 1) 初始化(2) 写命令(RS=L) , 设置显示坐标(3) 写数据(RS=H)
在此, 不需要读出它的数据的状态或者数据本身。 所以只需要看两个写时序:① 当要写指令字, 设置 LCD1602 的工作方式时: 需要把 RS 置为低电平, RW置为低电平, 然后将数据送到数据口 D0~D7, 最后 E 引脚一个高脉冲将数据写入。② 当要写入数据字, 在 1602 上实现显示时: 需要把 RS 置为高电平, RW 置为低电平, 然后将数据送到数据口 D0~D7, 最后 E 引脚一个高脉冲将数据写入。RW为低电平, 然后将数据送到数据口 D0~D7, 最后 E 引脚一个高脉冲将数据写入。
写指令和写数据, 差别仅仅在于 RS 的电平不一样而已。 以下是 LCD1602 的时序图:
LCD1602只能显示字符,,需要把按键值对应的数字量转成字符量来显示,否则显示错误
/***************************************************
使用GPIO0-GPIO11,液晶与其对应的引脚如下所示:
//
// RS–GPIO0引脚,
R/W–GND,
EN–GPIO1引脚,
D0–GPIO2引脚
// D1–GPIO3引脚,
* D2–GPIO4引脚,
* D3–GPIO5引脚,
* D4–GPIO6引脚
// D5–GPIO7引脚,
* D6–GPIO8引脚,
* D7–GPIO9引脚;
*
*按键扫描,,三行接的是GPIO12 13 14
三列接的是GPIO48 49 50
按键扫描原理: 1、3列对应的IO设置为输出,3行对应的IO设置为输入。其实
2、若无按键按下,3行输入IO,均为高电平(因为有外部上拉电阻)
3、若按键按下,对应行IO被拉低(假设为第X行),检测为低电平。按键所在行(X行),被鉴别出来。
4、此时,依次改变3列的输出为高,当遇到按键所在列时,第X行电平重新变为高。按键所在列。被鉴别出来。
观测变量Key的值来判断哪个按键按下了;
* ****************************************************/
#include “DSP2833x_Device.h”
#include “DSP2833x_Examples.h”
/***************************************************
宏定义
*************************************************/
//1602部分宏定义
#define uchar unsigned char
#define LCD_RS GpioDataRegs.GPADAT.bit.GPIO0
#define LCD_EN GpioDataRegs.GPADAT.bit.GPIO1
#define LCD_DB GpioDataRegs.GPADAT.all
//key部分宏定义
#define SET_KY1 GpioDataRegs.GPBSET.bit.GPIO48 = 1
#define SET_KY2 GpioDataRegs.GPBSET.bit.GPIO49 = 1
#define SET_KY3 GpioDataRegs.GPBSET.bit.GPIO50 = 1
#define RST_KY1 GpioDataRegs.GPBCLEAR.bit.GPIO48 = 1
#define RST_KY2 GpioDataRegs.GPBCLEAR.bit.GPIO49 = 1
#define RST_KY3 GpioDataRegs.GPBCLEAR.bit.GPIO50 = 1
#define KX1_STATUS GpioDataRegs.GPADAT.bit.GPIO12
#define KX2_STATUS GpioDataRegs.GPADAT.bit.GPIO13
#define KX3_STATUS GpioDataRegs.GPADAT.bit.GPIO14
/**************************************************
函数声明
*****************************************************/
//1602部分函数
void Init_Port(void);//初始化1602使用的GPIO端口
void LCD_init(void);//初始化Lcd1602
void LCD_write_command(uchar command);//LCDD写命令函数
void LCD_write_data(uchar dat);//LCD写数据函数
void show(char *cont);//LCD显示函数
//key部分函数
void Init_KeyGpio(void);//初始化3X3矩阵键盘对应的GPIO端口
void delay(Uint32 t);//软件延时函数
void ResetAllKY(void);//用于复位所有列端口的函数
void KX_AllStatus(void);//用于读取所有行端口的电平状态的函数
void Read_KX(Uint16 x);//读取按键行值的函数
void Read_KY(Uint16 x);//读取按键列值的函数
void Set_KY(Uint16 x);//用于将某一列对应端口置高的函数
void Rst_KY(Uint16 x);//用于将某一列对应端口置低的函数
/*********************************************************
变量设定
*******************************************************/
Uint16 Keys[3][3] = {1,2,3,4,5,6,7,8,9};
Uint16 Key = 0;
uchar p;
Uint16 KX_On = 0;
Uint16 KX_Tim[5] = {0};
Uint16 KX_Status[5]={0};
Uint16 KY_On = 0;
void main(void)
{
InitSysCtrl();
Init_Port();
Init_KeyGpio();
DINT;
InitPieCtrl();
IER = 0x00000000;
IFR = 0x00000000;
InitPieVectTable();
for(;;)
{
LCD_init();
LCD_write_command(0x80);
show(“Key number: “);
while(1)
{
Read_KX(1);
Read_KX(2);
Read_KX(3);
Read_KY(1);
Read_KY(2);
Read_KY(3);
}
}
}
//LCD1602部分函数
void Init_Port(void)
{
EALLOW;
GpioCtrlRegs.GPAMUX1.all = 0x00000000;
GpioCtrlRegs.GPADIR.all = 0x00000FFF;
GpioDataRegs.GPADAT.bit.GPIO0 = 0;
GpioDataRegs.GPADAT.bit.GPIO1 = 0;
EDIS;
}
//LCD初始化函数,,严格按照初始化顺序来进行,延时,写指令
void LCD_init(void)
{
DELAY_US(15000);
LCD_write_command(0x38);
DELAY_US(5000);
LCD_write_command(0x38);
DELAY_US(5000);
LCD_write_command(0x38);
LCD_write_command(0x38);
LCD_write_command(0x08);
LCD_write_command(0x01);
LCD_write_command(0x06);
LCD_write_command(0x0c);
}
void LCD_write_command(uchar command)
{
LCD_EN = 0;
LCD_RS = 0;
LCD_DB = (command << 2) | 0x0000;//这个地方0x0000,,为了保证在或运算时候,LCD_EN=0,LCD_RS=0保持不变
DELAY_US(500);
LCD_EN = 1;
DELAY_US(1000);
LCD_EN = 0;//最后三行制造了一个1ms的高脉冲
}
void show(char *cont)
{
while(*cont != 0)
{
LCD_write_data(*cont);
DELAY_US(500);
cont++;
}
}
void LCD_write_data(uchar dat)
{
LCD_EN = 0;
LCD_RS = 1;
LCD_DB = (dat << 2) | 0x0001;//这个地方。0x0001,,为了保证在或运算过程中,LCD_EN=0,LCD_RS=1保持不变,注意与上面LCD_write_command函数中的区别
DELAY_US(500);
LCD_EN = 1;
DELAY_US(1000);
LCD_EN = 0;//最后三行制造了一个1ms的高脉冲
}
//Key部分函数
void Init_KeyGpio(void)
{
EALLOW;
//GPIO48初始化,输出,低电平
GpioCtrlRegs.GPBMUX2.bit.GPIO48 = 0;
GpioCtrlRegs.GPBDIR.bit.GPIO48 = 1;
GpioDataRegs.GPBCLEAR.bit.GPIO48 = 1;
GpioCtrlRegs.GPBPUD.bit.GPIO48 = 0;
//GPIO49初始化,输出,低电平
GpioCtrlRegs.GPBMUX2.bit.GPIO49 = 0;
GpioCtrlRegs.GPBDIR.bit.GPIO49 = 1;
GpioDataRegs.GPBCLEAR.bit.GPIO49 = 1;
GpioCtrlRegs.GPBPUD.bit.GPIO49 = 0;
//GPIO50初始化,输出,低电平
GpioCtrlRegs.GPBMUX2.bit.GPIO50 = 0;
GpioCtrlRegs.GPBDIR.bit.GPIO50 = 1;
GpioDataRegs.GPBCLEAR.bit.GPIO50 = 1;
GpioCtrlRegs.GPBPUD.bit.GPIO50 = 0;
//GPIO12 初始化 输入
GpioCtrlRegs.GPAMUX1.bit.GPIO12 = 0;
GpioCtrlRegs.GPADIR.bit.GPIO12 = 0;
GpioCtrlRegs.GPAPUD.bit.GPIO12 = 0;
//GPIO13初始化 输入
GpioCtrlRegs.GPAMUX1.bit.GPIO13 = 0;
GpioCtrlRegs.GPADIR.bit.GPIO13 = 0;
GpioCtrlRegs.GPAPUD.bit.GPIO13 = 0;
//GPIO14初始化 输入
GpioCtrlRegs.GPAMUX1.bit.GPIO14 = 0;
GpioCtrlRegs.GPADIR.bit.GPIO14 = 0;
GpioCtrlRegs.GPAPUD.bit.GPIO14 = 0;
EDIS;
ResetAllKY();
}
void ResetAllKY(void)
{
RST_KY1;
RST_KY2;
RST_KY3;
}
void Read_KX(Uint16 x)
{
KX_AllStatus();
if(KX_Status[x] == 0)
{
KX_Tim[x]++;
if(KX_Tim[x] >= 6000)//个人理解,,这个判断类似延时消抖,,,但是这个地方换成DELAY_US函数,延时消抖,,并不太好使,,会出现按键值错误的情况
{
KX_On = x;
KX_Tim[1] = 0;
KX_Tim[2] = 0;
KX_Tim[3] = 0;
}
}
}
void KX_AllStatus(void)
{
KX_Status[1] = KX1_STATUS;
KX_Status[2] = KX2_STATUS;
KX_Status[3] = KX3_STATUS;
}
void Read_KY(Uint16 x)
{
if((!KX_Status[KX_On]) && (KX_On))
{
Set_KY(x);
DELAY_US(200);
KX_AllStatus();
if(KX_Status[KX_On])
{
KY_On = x;
Key = Keys[KX_On – 1][KY_On – 1];
p = Key + 0x30;//LCD1602只能显示字符,,Key+0x30是把按键值的数字值转成字符值
LCD_write_command(0x8d);
LCD_write_data(p);
DELAY_US(500);
KX_On = 0;
KY_On = 0;
}
Rst_KY(x);
}
}
void Set_KY(Uint16 x)
{
if(x == 1){SET_KY1;}
if(x == 2){SET_KY2;}
if(x == 3){SET_KY3;}
}
void Rst_KY(Uint16 x)
{
if(x == 1){RST_KY1;}
if(x == 2){RST_KY2;}
if(x == 3){RST_KY3;}
}