矩阵键盘扫描程序实例

16 篇文章 0 订阅

使用芯片STM8S003

所用端口:PD2~PD6, PA1~PA3

其中,PD3~PD6为输出,PA1~PA3 / PD2为输入(默认上拉)

/*
    PortCom BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0
                  PD6  PD5  PD4  PD3  PD2  PA3  PA2  PA1
  */

程序如下:

/*    添加包含芯片的头文件    */
#include<iostm8s103f3.h>



volatile unsigned char CF[4];     //按键触发标志(表示4列,每一列同一行的
                                  //值是一样的但列标不一样来区分不同列的键)
volatile unsigned char Cont[4];
unsigned char KeyVal;     //键值
//unsigned char KeyOut[4] = {0xef,0xdf,0xbf,0x7f};    //4X4按输出端控制
//unsigned char KeyOut[4] = {0x7f,0xbf,0xdf,0xef};
unsigned char KeyOut[4] = {0x3f,0x5f,0x6f,0x77};      //两个端口组合4x4端口输出控制
unsigned char PortCom;    //两个端口组合的端口
unsigned char cIn0,cIn1,cIn2,cIn3;


/*******************************************************************************
**函数名称:void delay(unsigned int ms)     Name: void delay(unsigned int ms)
**功能描述:大概延时
**入口参数:unsigned int ms   输入大概延时数值
**输出:无
*******************************************************************************/
void delay(unsigned int ms)
{
  unsigned int x , y;
  for(x = ms; x > 0; x--)
    for(y = 1000 ; y > 0 ; y--);
}

/*
**描述:新型4X4按键扫描程序 放在1ms-10ms中断内使用(十分稳定不需要再写消抖程序)
**备注:按键弹起时 keyVal = 0 单键按下 keyVal 有16个值,你自己程序可以针对不同值
**进行不同程序操作 keyVal单键值分别为 
**0x01,0x02,0x04,0x08,
**0x11,0x12,0x14,0x18,
**0x21,0x22,0x24,0x28,
**0x31,0x32,0x34,0x38,
*/ 
void Key_Head() 
{
  unsigned char ReadData[4];
  static unsigned char i;
  /*
    PortCom BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0
            PD6  PD5  PD4  PD3  PD2  PA3  PA2  PA1
  */
  cIn0 = 0;
  cIn1 = 0;
  cIn2 = 0;
  cIn3 = 0;
  if(++i>=4)i=0;

//  PortCom = KeyOut[i]|0x0f;                     //忽略低4位
  //输出扫描
  PD_ODR = KeyOut[i];
  //输入侦测
  cIn0 = PA_IDR_bit.IDR1;
  cIn1 = PA_IDR_bit.IDR2;
  cIn2 = PA_IDR_bit.IDR3;
  cIn3 = PD_IDR_bit.IDR2;
  PortCom = (cIn3<<3) | (cIn2<<2) | (cIn1<<1) | cIn0; 
  
  ReadData[i] = (PortCom|0xf0)^0xff;            //忽略高4位 取反 
  CF[i] = ReadData[i] & (ReadData[i] ^ Cont[i]); 
  Cont[i] = ReadData[i]; 
  //输出键值
  switch(CF[i])//第i列
  {
    case 0x08: KeyVal = ((i<<4)+8);break;
    case 0x04: KeyVal = ((i<<4)+4);break;
    case 0x02: KeyVal = ((i<<4)+2);break;
    case 0x01: KeyVal = ((i<<4)+1);break;
    default:KeyVal = 0;break;
  } 
    
  delay(30);
}


/*******************************************************************************
**函数名称:void ALL_LED_Init()    Name: void ALL_LED_Init()
**功能描述:初始化LED灯的IO口设为输出
**入口参数:无
**输出:无
*******************************************************************************/
void ALL_LED_Init()
{
  //LED1 Init
//  PD_DDR_bit.DDR2 = 1;    //设置端口PD->2的输入输出方向寄存器为输出方向
//  PD_CR1_bit.C12 = 1;     //设置PD2为推挽输出
//  PD_CR2_bit.C22 = 1;     //设置PD2的输出最大速度为10MHZ
  
  //LED2 Init
  PC_DDR_bit.DDR7 = 1;    //设置端口PC->7的输入输出方向寄存器为输出方向
  PC_CR1_bit.C17 = 1;     //设置PC7为推挽输出
  PC_CR2_bit.C27 = 1;     //设置PC7的输出最大速度为10MHZ
  
  //LED3 Init
  PC_DDR_bit.DDR6 = 1;    //设置端口PC->6的输入输出方向寄存器为输出方向
  PC_CR1_bit.C16 = 1;     //设置PC6为推挽输出
  PC_CR2_bit.C26 = 1;     //设置PC6的输出最大速度为10MHZ
  
  //LED4 Init
  PC_DDR_bit.DDR3 = 1;    //设置端口PC->3的输入输出方向寄存器为输出方向
  PC_CR1_bit.C13 = 1;     //设置PC3为推挽输出
  PC_CR2_bit.C23 = 1;     //设置PC3的输出最大速度为10MHZ
}


/*******************************************************************************
**函数名称:ALLKeyInit()
**功能描述:配置Key1 , Key2 , Key3输入按键
**入口参数:无
**输出:无
*******************************************************************************/
void ALLKeyInit()
{
  //PA1_Init
  PA_DDR_bit.DDR1 = 0;      //GPA->PIN3 设置为输入模式
  PA_CR1_bit.C11 = 1;       //GPA->PIN3 带上拉电阻输入
  PA_CR2_bit.C21 = 0;       //GPA->PIN3  禁止外部中断
  
  //PA2_Init
  PA_DDR_bit.DDR2 = 0;      //GPA->PIN3 设置为输入模式
  PA_CR1_bit.C12 = 1;       //GPA->PIN3 带上拉电阻输入
  PA_CR2_bit.C22 = 0;       //GPA->PIN3  禁止外部中断
  
  //PA3_Init
  PA_DDR_bit.DDR3 = 0;      //GPA->PIN3 设置为输入模式
  PA_CR1_bit.C13 = 1;       //GPA->PIN3 带上拉电阻输入
  PA_CR2_bit.C23 = 0;       //GPA->PIN3  禁止外部中断
  
  //PD2_Init
  PD_DDR_bit.DDR2 = 0;      //GPD->PIN3 设置为输入模式
  PD_CR1_bit.C12 = 1;       //GPD->PIN3 带上拉电阻输入
  PD_CR2_bit.C22 = 0;       //GPD->PIN3  禁止外部中断
  
  //PD3_Init
  PD_DDR_bit.DDR3 = 1;      //GPD->PIN3 设置为输入模式
  PD_CR1_bit.C13 = 1;       //GPD->PIN3 带上拉电阻输入
  PD_CR2_bit.C23 = 1;       //GPD->PIN3  禁止外部中断
  
  //PD4_Init
  PD_DDR_bit.DDR4 = 1;      //GPD->PIN3 设置为输入模式
  PD_CR1_bit.C14 = 1;       //GPD->PIN3 带上拉电阻输入
  PD_CR2_bit.C24 = 1;       //GPD->PIN3  禁止外部中断
  
  //PD5_Init
  PD_DDR_bit.DDR5 = 1;      //GPC->PIN5 设置为输入模式
  PD_CR1_bit.C15 = 1;       //GPC->PIN5 带上拉电阻输入
  PD_CR2_bit.C25 = 1;       //GPC->PIN5  禁止外部中断
  
  //PD6_Init
  PD_DDR_bit.DDR6 = 1;      //GPC->PIN5 设置为输入模式
  PD_CR1_bit.C16 = 1;       //GPC->PIN5 带上拉电阻输入
  PD_CR2_bit.C26 = 1;       //GPC->PIN5  禁止外部中断
}

int main(void)
{
  CLK_CKDIVR = 0x00;              //内部时钟为1分频
  ALL_LED_Init();                 //调用LED1初始化函数
  ALLKeyInit();                   //调用按钮初始化函数

  while(1)
  {  
    Key_Head();
    
    switch(KeyVal)
    {
    case 0x01:
      {
        PC_ODR ^= 0x80;                //异或取反LED2使其亮灭
        break;
      }
    case 0x02:
      {
        PC_ODR ^= 0x40;                //异或取反LED3使其亮灭
        break;
      }
    case 0x04:
      {
        PC_ODR ^= 0x08;                //异或取反LED4使其亮灭
        break;
      }
    case 0x08:
      {
        PC_ODR ^= 0x80;                //异或取反LED2使其亮灭
        PC_ODR ^= 0x40;                //异或取反LED3使其亮灭
        break;
      }
    case 0x11:
      {
        PC_ODR ^= 0x80;                //异或取反LED2使其亮灭
        break;
      }
    case 0x12:
      {
        PC_ODR ^= 0x40;                //异或取反LED3使其亮灭
        break;
      }
    case 0x14:
      {
        PC_ODR ^= 0x08;                //异或取反LED4使其亮灭
        break;
      }
    case 0x18:
      {
        PC_ODR ^= 0x80;                //异或取反LED2使其亮灭
        PC_ODR ^= 0x40;                //异或取反LED3使其亮灭
        break;
      }
    case 0x21:
      {
        PC_ODR ^= 0x80;                //异或取反LED2使其亮灭
        break;
      }
    case 0x22:
      {
        PC_ODR ^= 0x40;                //异或取反LED3使其亮灭
        break;
      }
    case 0x24:
      {
        PC_ODR ^= 0x08;                //异或取反LED4使其亮灭
        break;
      }
    case 0x28:
      {
        PC_ODR ^= 0x80;                //异或取反LED2使其亮灭
        PC_ODR ^= 0x40;                //异或取反LED3使其亮灭
        break;
      }
    case 0x31:
      {
        PC_ODR ^= 0x80;                //异或取反LED2使其亮灭
        break;
      }
    case 0x32:
      {
        PC_ODR ^= 0x40;                //异或取反LED3使其亮灭
        break;
      }
    case 0x34:
      {
        PC_ODR ^= 0x08;                //异或取反LED4使其亮灭
        break;
      }
    case 0x38:
      {
        PC_ODR ^= 0x80;                //异或取反LED2使其亮灭
        PC_ODR ^= 0x40;                //异或取反LED3使其亮灭
        break;
      }
    default:
      {
        KeyVal = 0;
        break;
      }
    }
  }
}

相关分析参考:http://blog.csdn.net/phenixyf/article/details/76090873

http://blog.csdn.net/phenixyf/article/details/76173409




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值