【蓝桥杯单片机】二、独立按键和矩阵按键

1、按键的基本介绍

CT107D的按键分为独立按键和矩阵按键,跳帽 J5 接在 BTN(button)时,左边的独立按键生效,接在 KBD(keyboard)时矩阵按键生效。
在这里插入图片描述
在这里插入图片描述

2、独立按键的基本介绍

当为独立按键时候 按键按下会引起响应P3置零

按键号对应IO
S7P30
S6P31
S5P32
S4P33

如果用学校教的方式写按键有两大缺陷:
1.没有按键消抖,致命缺陷
2.不方便拓展为按下触发、松开触发、长按等等

下面提供两种方案:

2.1 方案一代码

扫描按键函数

unsigned char KeyScan(void)
{

	unsigned char keyValue;//返回值
	//速记 P3 1234 7654
	if(P30 == 0)  keyValue= 7;
	else if(P31 == 0) keyValue= 6;
	else if(P32 == 0) keyValue= 5;	
	else if(P33 == 0) keyValue= 4;	
	else keyValue= 0;
	
	return keyValue;
}

按键处理函数

void	KeyMain(void)
{
	if(keyCount) return; //当到达设定扫描时间才可以执行
	keyCount= 1; //重新计数扫描函数
	
	keyValue = KeyScan(); //获取读取的值
	//下降沿 等于 读取的值异或之前的值 与上读取的值
	keyDown = keyValue & (keyBefore ^ keyValue);
	//上升沿 =- 下降沿取反 
	keyUp = ~Key_Value & (keyBefore ^ keyValue);
	//检测电平,一直按着一直等于一个数
	keyBefore = keyValue ;

	//具体判断逻辑
}
	
	

2.1 方案二代码

void Key_scan()
{
  //把P3的值取反 ^1 表示位取反 ^0不变 
  //例当第一个按键按下时 01111 1111 -> 1000 0000
  uchar ReadDat = P3^0xff; 
  //  用于判断按键是否抬起
  //  以第一个按键按下位例
  //  Cnt在第一次按下时候等于 0000 0000 
  //  当第一个按键没有抬起时候 1000 0000 
  //  当第一个按键第一次按下时候 
  //  1000 0000 & (1000 0000 ^ 0000 0000 ) = 1000 0000 & 1000 0000 = 1000 0000
  //  当第一个按键没有抬起扫描到时候 
  //  1000 0000 &(1000 0000 ^ 1000 0000) = 1000 0000 & 0000 0000 = 0000 0000
  Trg = ReadDat & (ReadDat^Cnt); 
  Cnt = ReadDat;
  
  if(Trg & 0x01) //检测到按下S7,用(Trg==0x01)会使按键不灵敏
  {
    //S7按下要实现的逻辑
  }
  else if(Trg & 0x02) 
  {
    //S6按下要实现的逻辑
  }
  else if(Trg & 0x04) /
  {
    //S5按下要实现的逻辑
  }
  else if(Trg & 0x08) 
  {
     //S4按下要实现的逻辑
  }
  
  P2 =  //打开锁存器控制 
  P2 = 0x00; //关闭锁存器
}

2.3 独立按键练习操作

习题:S7按下点亮L7,S6按下点亮L6,S5按下点亮L5,S4按下点亮L4,

#include <STC15F2K60S2.H>

typedef unsigned char uchar;
typedef unsigned int uint;


uchar Cnt,Trg;
uchar countBotton;

void Delayms(int ms)		
{
	unsigned char i, j;
  while(ms--)
  {
    i = 12;
    j = 169;
    do
    {
      while (--j);
    } while (--i);
  }
}

void Key_scan()
{
  uchar ReadDat= P3^0xff;
  Trg=ReadDat&(ReadDat^Cnt); 
  Cnt=ReadDat;
  
  if(Trg&0x01){P0=~0x40;P2 = 0x80;  P2 = 0x00; }
  else if(Trg & 0x02) {P0=~0x20; P2 = 0x80;  P2 = 0x00; }
  else if(Trg & 0x04) {P0 = ~0x10;P2 = 0x80;  P2 = 0x00; }
  else if(Trg & 0x08) {P0 =~0x08;P2 = 0x80;  P2 = 0x00; }
  
}

void Time0_init(void)  //1毫秒 @11.0592MHz
{
    AUXR |= 0x80; 
    TMOD &= 0xF0; 
    TL0 =0xCD;    
    TH0 = 0xD4;
    TR0=1;        
    ET0=1;        
    EA= 1; 
}

void Time0_isr() interrupt 1
{
  ++countBotton; 
}
void main()
{
  P0=0xff;
  P2=0x80;
  P2=0x00;
  
  P0=0x00;
  P2=0xa0;
  P2=0x00;
  
  Time0_init();
  while(1)
  {
    if(countBotton > 9)
    {
      countBotton = 0;
      Key_scan();
    }
  }
}

3、矩阵按键的基本介绍

在这里插入图片描述

3.1、方案一:

选择一列扫描行,有点麻烦

unsigned char Keys_Scan(void)
{
	unsigned int Key_New;//0x0000 存放每一列的结果
	unsigned char Key_Value;//对应的按键编号
	//第一次扫描时候直接取P3的第四位,其他的左移4位再取P3的低四位或上之前的值
	//0在哪扫描哪
	P44 = 0; P42 = 1; P35 = 1; P34 = 1;  // 0111
	Key_New = P3 & 0X0F;  //P3高四位清0 低四位赋值给 Key_New 000a
	P44 = 1; P42 = 0; P35 = 1; P34 = 1;  // 1011
	Key_New = (Key_New << 4) | (P3 & 0X0F); //  00ab
	P44 = 1; P42 = 1; P35 = 0; P34 = 1;  // 1101
	Key_New = (Key_New << 4) | (P3 & 0X0F); // 0abc
	P44 = 1; P42 = 1; P35 = 1; P34 = 0;  // 1110
	Key_New = (Key_New << 4) | (P3 & 0X0F); // acbd

	switch(~Key_New)//Key_Value的数值对应按键的编号 记得取反
	{
		//每一列8421 一直加 没不是结果为0
		case 0x8000: Key_Value = 4; break;
		case 0x4000: Key_Value = 5; break;
		case 0x2000: Key_Value = 6; break;
		case 0x1000: Key_Value = 7; break;		
	
		case 0x0800: Key_Value = 8; break;
		case 0x0400: Key_Value = 9; break;
		case 0x0200: Key_Value = 10; break;
		case 0x0100: Key_Value = 11; break;		
	
		case 0x0080: Key_Value = 12; break;
		case 0x0040: Key_Value = 13; break;
		case 0x0020: Key_Value = 14; break;
		case 0x0010: Key_Value = 15; break;			
	
		case 0x0008: Key_Value = 16; break;
		case 0x0004: Key_Value = 17; break;
		case 0x0002: Key_Value = 18; break;
		case 0x0001: Key_Value = 19; break;			
	
		default : Key_Value = 0;
	}
	
	return Key_Value;
}

3.2、方案二:

**扫描行扫描列 **

void scan_key()
{
  static uchar key_state=0;
  uchar key_val=0, key_x=0, key_y=0;
  //行扫描 
  P3=0x0f; P4=0x00;
  if(!P30)      key_x=3;
  else if(!P31) key_x=2;
  else if(!P32) key_x=1;
  else if(!P33) key_x=0;
  //X=3210 Y=4321 特别易记
  //列扫描 对行扫描取反
  P3=0xf0; P4=0xff; 
  if(!P34)     key_y=4;
  else if(!P35) key_y=3;
  else if(!P42)  key_y=2;
  else if(!P44) key_y=1;
  key_val=key_x+ key_y*4;//综合行、列扫描的结果,判断具体位置
  
  switch(key_state)
  {
    case 0:
      if(key_val!=0) key_state = 1; //第一次检测到有按键按下,状态为1
      break;  
    case 1:
      if(key_val==0) key_state=0;//第二次(10ms后)若检测到无按键按下,返回状态0
      else 
      {
        key_state = 2; //第二次(10ms 后)再次检测到有按键按下状态为2
        value = key_val; ///将按键值传给需要显示的变量
        switch(key_val)
        {
          case 4: P0=~0x04;P2=0x80;P2=0; break;//按下S4
          case 5: P0=~0x05;P2=0x80;P2=0; break;//按下S5
          case 6: P0=~0x06;P2=0x80;P2=0; break; //按下S6
          case 7: P0=~0x07;P2=0x80;P2=0; break; //按下S7
          case 8: P0=~0x08;P2=0x80;P2=0; break;//按下S8
          case 9: P0=~0x09;P2=0x80;P2=0; break;//按下S9
          case 10: P0=~0x0a;P2=0x80;P2=0; break;//按下S10
          case 11: P0=~0x0b;P2=0x80;P2=0; break; //按下S11
          case 12: P0=~0x0c;P2=0x80;P2=0; break;//按下S12
          case 13: P0=~0x0d;P2=0x80;P2=0; break; //按下S13
          case 14: P0=~0x0e;P2=0x80;P2=0; break;//按下S14
          case 15: P0=~0x0f;P2=0x80;P2=0; break;//按下S15
          case 16: P0=~0x10;P2=0x80;P2=0; break;//按下S16
          case 17: P0=~0x11;P2=0x80;P2=0; break;//按下S17
          case 18: P0=~0x12;P2=0x80;P2=0; break;//按下S18
          case 19: P0=~0x13;P2=0x80;P2=0; break;//按下S19
        }
      }
    case 2:if(key_val==0) key_state = 0;//第三次若检测到无按键按下,返回状态0。
  }
}

3.3、矩阵按键的练习操作

习题:用L1到L8显示矩阵按键对应的二进制

#include <STC15F2K60S2.H>

typedef unsigned char uchar;
typedef unsigned int uint;

uchar countkey;

void Time0_init(void) 
{
    AUXR |= 0x80; 
    TMOD &= 0xF0; 
    TL0 =0xCD;    
    TH0 = 0xD4;
    TR0=1;        
    ET0=1;        
    EA= 1; 
}

void Time0_isr() interrupt 1
{ 
  countkey++;
}

void scan_key()
{
  static uchar key_state=0;
  uchar key_val=0, key_x=0, key_y=0;
  //行扫描 
  P3=0x0f; P4=0x00;
  if(!P30)      key_x=3;
  else if(!P31) key_x=2;
  else if(!P32) key_x=1;
  else if(!P33) key_x=0;
  //X=3210 Y=4321 特别易记
  //列扫描 
  P3=0xf0; P4=0xff;
  if(!P34)     key_y=4;
  else if(!P35) key_y=3;
  else if(!P42)  key_y=2;
  else if(!P44) key_y=1;
  key_val=key_x+ key_y*4;//综合行、列扫描的结果,判断具体位置
  
  switch(key_state)
  {
    case 0:
      if(key_val!=0) key_state = 1; //第一次检测到有按键按下,状态为1
      break;  
    case 1:
      if(key_val==0) key_state=0;//第二次(10ms后)若检测到无按键按下,返回状态0
      else 
      {
        key_state = 2; //第二次(10ms 后)再次检测到有按键按下状态为2
        switch(key_val)
        {
          case 4: P0=~0x04;P2=0x80;P2=0; break;//按下S4
          case 5: P0=~0x05;P2=0x80;P2=0; break;//按下S5
          case 6: P0=~0x06;P2=0x80;P2=0; break; //按下S6
          case 7: P0=~0x07;P2=0x80;P2=0; break; //按下S7
          case 8: P0=~0x08;P2=0x80;P2=0; break;//按下S8
          case 9: P0=~0x09;P2=0x80;P2=0; break;//按下S9
          case 10: P0=~0x0a;P2=0x80;P2=0; break;//按下S10
          case 11: P0=~0x0b;P2=0x80;P2=0; break; //按下S11
          case 12: P0=~0x0c;P2=0x80;P2=0; break;//按下S12
          case 13: P0=~0x0d;P2=0x80;P2=0; break; //按下S13
          case 14: P0=~0x0e;P2=0x80;P2=0; break;//按下S14
          case 15: P0=~0x0f;P2=0x80;P2=0; break;//按下S15
          case 16: P0=~0x10;P2=0x80;P2=0; break;//按下S16
          case 17: P0=~0x11;P2=0x80;P2=0; break;//按下S17
          case 18: P0=~0x12;P2=0x80;P2=0; break;//按下S18
          case 19: P0=~0x13;P2=0x80;P2=0; break;//按下S19
        }
      }
    case 2:if(key_val==0) key_state = 0;//第三次若检测到无按键按下,返回状态0。
  }
}
void main()
{
  P0=0xff;P2=0x80;P2=0x00;
  P0=0x00;P2=0xa0;P2=0x00;
  Time0_init();
  
  while(1)
  {
    if(countkey>9)
    {
      countkey=0;
      scan_key();
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值