线反转法接线图如下。其原理简单来说就是:
四个行引脚推挽输出低电平(置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;
}