0
点赞
收藏
分享

微信扫一扫

51单片机矩阵键盘控制LCD屏幕

陆佃 2022-03-30 阅读 63

课程资源

B站矩阵键盘课程

实现代码

Delay.c

void Delay(unsigned int xms)		
{	//延迟x毫秒
	while(xms--)
	{
		unsigned char i, j;

		i = 12;
		j = 169;
		do
		{
			while (--j);
		} while (--i);
	}
}

MatrixKey.c

#include <REGX52.H>
#include "Delay.h"
#define KEY_SCAN P1

void MatrixKey(unsigned char* keyValue)
{
	KEY_SCAN = 0X0F;
	if(KEY_SCAN!=0X0F)
	{	//判断是否按下
		Delay(10);	//消除抖动
		
		KEY_SCAN = 0X0F;	//列扫描
		switch(KEY_SCAN)
		{
			case 0X07:*keyValue = 0;break;
			case 0X0B:*keyValue = 1;break;
			case 0X0D:*keyValue = 2;break;
			case 0X0E:*keyValue = 3;break;
		}
		
		KEY_SCAN = 0XF0; //行扫描
		switch(KEY_SCAN)
		{
			case 0X70:*keyValue = *keyValue;break;
			case 0XB0:*keyValue += 4;break;
			case 0XD0:*keyValue += 8;break;
			case 0XE0:*keyValue += 12;break;
		}
		while(KEY_SCAN!=0XF0)
		{	//检测按键是否松开,松开时返回键值
			Delay(10);
		}
	}	
}

LCD1602.C

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;	//选择操作控制字
	LCD_RW=0;	//写操作
	LCD_DataPort=Command;	//输入写入控制字的数据
	LCD_EN=1;	//使能信号,LCD选中
	LCD_Delay();	
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;	//选择数据寄存器
	LCD_RW=0;	//写操作
	LCD_DataPort=Data;	//需要写入的数据
	LCD_EN=1;	
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

main.c

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey.h"
//从左到右从上到下4x4矩阵按键对应字符
unsigned char KeyValueTbl[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
unsigned char value;	//按键键值

void main()
{
	LCD_Init();	//初始化LCD1602屏幕
	LCD_ShowString(1,5,"Welcome!");	//在第1行第5列开始显示字符串
	while(1)
	{	//检测矩阵键盘
		MatrixKey(&value);	//返回键值给value
		LCD_ShowChar(2,8,KeyValueTbl[value]);	//在LCD屏幕的2行8列位置输出对应按键字符
	}
}

出现的错误

MatrixKey函数与main函数之间逻辑关系错误
错误代码——MatrixKey()

unsigned char MatrixKey(void)
{
	unsigned char keyValue = 0;
	KEY_SCAN = 0X0F;
	if(KEY_SCAN!=0X0F)
	{
		Delay(10);
		
		KEY_SCAN = 0X0F;	//¼ì²âÁÐ
		switch(KEY_SCAN)
		{
			case 0X07:*keyValue = 0;break;
			case 0X0B:*keyValue = 1;break;
			case 0X0D:*keyValue = 2;break;
			case 0X0E:*keyValue = 3;break;
		}
		
		KEY_SCAN = 0XF0; //¼ì²âÐÐ
		switch(KEY_SCAN)
		{
			case 0X70:*keyValue = *keyValue;break;
			case 0XB0:*keyValue += 4;break;
			case 0XD0:*keyValue += 8;break;
			case 0XE0:*keyValue += 12;break;
		}
		while(KEY_SCAN!=0XF0)
		{
			Delay(10);
		}
	}	
	
	return keyValue;
}

错误原因:

  1. 当按下按键松手后,返回keyValue值给value,然后接着将value值对应KeyValueTbl中的值在LCD输出
  2. 很快,再一次进入MatrixKey(),keyValue值重新赋值为0,此时没有按键按下,keyValue值返回值0赋值给value,将0在LCD屏幕输出
  3. 因为51单片机频率为12KHZ,运行程序速度很快,前两步骤间时间间隔很短,所以肉眼看上去屏幕输出永远为0(没有键值输入的情况)
  4. 所以,最根本的原因是给LCD屏幕输入的值没有保持到下一次按下按键就清零处理了,导致无法观察到每个按键的键值

改进方案

  1. 在main.c文件中设置全局变量value
  2. unsigned char MatrixKey(void)改为void MatrixKey(unsigned char* keyValue)
  3. main函数中调用MatrixKey(&value);使每次keyValue的值能返回到value中,有按键时输出按键值;没有按键时输出上一次按键值

注意

void MatrixKey(unsigned char keyValue){...}

//main.c中
int main()
{
	...
	MatrixKey(value);
}

这种修改方式并不能使keyValue的值返回到value中,因为实际参数(value)只是把值复制给了形式参数(keyValue),在函数中对于形式参数的修改都不会影响到实际参数,即返回后value的值始终为0

小结

单片机编程过程中,while(1){…}循环体内的逻辑结构要考虑到单片机执行速度带来的问题,要充分考虑一次while循环对下一次循环带来的影响

举报

相关推荐

0 条评论