STM8“线反转式”扫描矩阵键盘

431 阅读2分钟
线反转法接线图如下。其原理简单来说就是:
四个行引脚推挽输出低电平(置0), 四个列引脚上拉输入,
如果有按键按下,会连通行与列,导致某个列引脚电压被拉低,故输出寄存器不再是0X0F,而是0X0E,0X0D,0X0B,0X07,
这样就判断出了那一列被按下。
此时反转输入输出,用同样的方法监测那一行被按下。
最后返回键值。

//------------------------------header------------------------------------------
#include "iostm8s208mb.h"
//------------------------------common datatype---------------------------------
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
//------------------------------macros------------------------------------------
#define LCDRS       PF_ODR_ODR0
#define LCDRW       PF_ODR_ODR3
#define LCDEN       PF_ODR_ODR4
#define LCDDATA     PB_ODR
#define KeyPortIn   PC_IDR
#define KeyPortOut  PC_ODR
//------------------------------function declare--------------------------------
void GPIO_init(void);
void delay(u16 count);
void LCD_init(void);
void LCD_write(u8 data,u8 cmd_flag);
void LCD_display(void);
void LCD_lr_DIS(u8 line,u8 row,u8 z);
u8 KEY_scan(void);
//------------------------------------------------------------------------------
u8 line1[]="==4*4 Keyboard==";
u8 line2[]="[Keynum]:       ";
u8 table3[]={'0','1','2','3','4','5','6','7','8','9'};
//------------------------------main--------------------------------------------
void main( void )
{
    GPIO_init();
    LCD_init();
    LCD_display();
    u8 keydown;
    while (1)
    {
        keydown=KEY_scan();
        if(keydown!=0XFF)
        {
            LCD_lr_DIS(2,12,table3[keydown/10]);
            LCD_lr_DIS(2,13,table3[keydown%10]);
            delay(300);
        }
        LCD_lr_DIS(2,12,'N');
        LCD_lr_DIS(2,13,'o');
    }
}
//------------------------------functions---------------------------------------
void GPIO_init(void)
{
    PF_DDR=0XFF;
    PF_CR1=0XFF;
    PF_CR2=0X00;
    PF_ODR=0X00;

    PB_DDR=0XFF;
    PB_CR1=0XFF;
    PB_CR2=0X00;
    PB_ODR=0X00;

    PC_DDR=0XF0;
    PC_CR1=0XFF;
    PC_CR2=0X0F;
}
void delay(u16 count)
{
    u8 i,j;
    while (count--)
    {
        for(i=0;i<50;i++)
            for(j=0;j<50;j++);
    }
}
void LCD_init(void)
{
    LCD_write(0X38,0);
    LCD_write(0X0E,0);
    LCD_write(0X06,0);
    LCD_write(0X01,0);
}
void LCD_write(u8 data,u8 cmd_flag)
{
    LCDRS=cmd_flag;
    LCDRW=0;
    LCDEN=1;
    delay(1);
    LCDDATA=data;
    LCDEN=0;
    delay(1);
}
void LCD_display(void)
{
    LCD_write(0X80,0);
    for (u8 i = 0; i < 16; i++)
    {
        LCD_write(line1[i],1);
    }
    LCD_write(0XC0,0);
    for (u8 i = 0; i < 16; i++)
    {
        LCD_write(line2[i],1);
    }    
}
void LCD_lr_DIS(u8 line,u8 row,u8 z)
{
    switch (line)
    {
    case 1:
        LCD_write(0X80+row,0);
        LCD_write(z,1);
        break;
    case 2:
        LCD_write(0XC0+row,0);
        LCD_write(z,1);
        break;
    default:
        break;
    }    
}
u8 KEY_scan(void)
{
    PC_DDR=0XF0;
    PC_CR1=0XFF;
    PC_CR2=0X00;
    KeyPortOut=0X0F;
    u8 keypress=0XFF;
    if(KeyPortIn != 0X0F)
    {
        delay(10);
        switch (KeyPortIn)
        {
            case 0X0E:keypress=0;break;
            case 0X0D:keypress=1;break;
            case 0X0B:keypress=2;break;
            case 0X07:keypress=3;break;
            default:keypress=0XFF;break;
        };
        PC_DDR=0X0F;
        PC_CR1=0XFF;
        PC_CR2=0X00;
        KeyPortOut=0XF0;
        if(KeyPortIn!=0XF0)
        {
            delay(10);
            switch (KeyPortIn)
            {
                case 0XE0:keypress +=0;break;
                case 0XD0:keypress +=4;break;
                case 0XB0:keypress +=8;break;
                case 0X70:keypress +=12;break;
                default:keypress=0XFF;break;
            };
            while(KeyPortIn!=0XF0);//按键松手检测
        }
    }
    return keypress;
}