矩阵键盘程序,作为麦知club小车项目的一部分,从IAR状态机应用修改而来。
IAR7.4+STM32CUBEMX调试通过。
键盘行4,列3,每条线都有10K上拉电阻。改到4×4矩阵也很容易。
行线设置为 输入,针脚为浮空; 列线设置为开漏输出。
不支持长按和组合键,主要是我不会改。
在OS中使用20ms任务周期调用。
以下贴出代码。
keypad.h
/*
*
* Name: keypad.h
*/
#ifndef KEYPAD_H
#define KEYPAD_H
#include "stm32f1xx_hal.h"
#include "pinname.h"
#define PORT_KEY GPIOD
#define COLS (GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6)
// 读pin
//#define In(GPIO_Pin) (PORT_KEY->IDR & GPIO_Pin)
#define In(GPIO_Pin) HAL_GPIO_ReadPin(PORT_KEY, GPIO_Pin)
// 写1到Pin
//#define High(GPIO_Pin) PORT_KEY->BSRR = GPIO_Pin
#define High(GPIO_Pin) HAL_GPIO_WritePin(PORT_KEY, GPIO_Pin, GPIO_PIN_SET)
// 写0到Pin
//#define Low(GPIO_Pin) PORT_KEY->BSRR = (uint32_t)GPIO_Pin << 16
#define Low(GPIO_Pin) HAL_GPIO_WritePin(PORT_KEY, GPIO_Pin, GPIO_PIN_RESET)
/*
* 0 1 2 3
* 4 5 6 7
* 8 9 10 11
* 12 13 14 15
*/
typedef enum {
Key_Up = 0x02,
Key_Left = 0x03,
Key_Right = 0x04,
Key_Down = 0x08,
Key_On = 0x09,
Key_Mode = 0x0a,
Key_None = 0xFF
} KeyPressed;
static const int row_count = 4;
static const int col_count = 3;
uint16_t bus_out(void);
void Keypad(void);
char AnyKey(void);
char SameKey(void);
char ScanKey(void);
void FindKey(void);
void ClearKey(void);
void Read(void);
/** Start the keypad interrupt routines */
void Start(void);
/** Stop the keypad interrupt routines */
void Stop(void);
void Cols_out(uint16_t v);
void Scan_Keyboard(void);
KeyPressed getKey(void);
#endif // KEYPAD_H
keypad.c
/*
*
* Name: keypad.cpp
*
*/
#include "keypad.h"
// State:
char KeyState;
// Bit pattern after each scan:
char KeyCode;
// Output value from the virtual 74HC922:
KeyPressed KeyValue;
// KeyDown is set if key is down:
char KeyDown;
// KeyNew is set every time a new key is down:
char KeyNew;
// 映射表
char KeyTable[12][2];
// Pin of Row
uint16_t _rows[] = {KEYx0, KEYx1, KEYx2, KEYx3};
uint16_t _cols[] = {KEYy0, KEYy1, KEYy2};
//构造函数
void Keypad(void)
{
Stop();
KeyState = 0; // 按键状态初始 0
}
//扫描键盘
void Scan_Keyboard(void){
switch (KeyState) {
case 0: {
if (AnyKey()) {
char scankey = ScanKey();
if (scankey != 0xff)
KeyCode = scankey;
KeyState = 1;
}
break;
}
case 1: {
if (SameKey()) {
FindKey();
KeyState = 2;
}
else
KeyState = 0;
break;
}
case 2: {
if (SameKey()) {
}
else
KeyState = 3;
break;
}
case 3: {
if (SameKey()) {
KeyState = 2;
}
else {
ClearKey();
KeyState = 0;
}
break;
}
}
// func end
}
// 有键按下
char AnyKey(void) {
//Start(); //拉低
int r = -1;
for (r = 0; r < row_count; r++) {
if (In(_rows[r]) == 0) // In macro
break;
}
//Stop(); //恢复
if (!(0 <= r && r < row_count))
return 0;
else
return 1;
}
// 键按下, 键值相同
char SameKey(void) {
// char KeyCode_new = KeyCode;
char KeyCode_new = ScanKey();
if (KeyCode == KeyCode_new)
return 1;
else
return 0;
}
// 扫描键
char ScanKey(void) {
/* 行扫描 */
int r = -1;
for (r = 0; r < row_count; r++) {
if (In(_rows[r]) == 0) // In macro
break;
}
/* 若没有找到有效行,返回 */
if (!(0 <= r && r < row_count)) {
return 0xff;
}
/* 列扫描,找出行上哪个被拉低 */
int c = -1;
for (c = 0; c < col_count; c++) {
// 轮流输出列线
Cols_out(~(1 << c));
if (In(_rows[r]) == 0) // In macro
break;
}
/* 给所有的列重新充电 */
Start();
/* 若没有找到有效列,返回 */
if (!(0 <= c && c < col_count))
return 0xff;
return r * col_count + c;
}
// FindKey compares KeyCode to values in KeyTable.
// If match, KeyValue, KeyDown and KeyNew are updated.
void FindKey(void) {
KeyValue = (KeyPressed)KeyCode;
KeyDown = 1;
KeyNew = 1;
}
void ClearKey(void) {
KeyDown = 0;
}
KeyPressed getKey(void) {
if(KeyNew)
{
KeyNew = 0;
return KeyValue;
}
else
return Key_None;
}
void Start(void)
{
/* 列输出0, 拉低行 */
PORT_KEY->BRR = COLS;
}
void Stop(void)
{
/* 列输出1,使行不被拉低 */
PORT_KEY->BSRR = COLS;
}
// cols bus output
void Cols_out(uint16_t v)
{
if ((v & 0x01) > 0) //0b001
High(_cols[0]);
else
Low(_cols[0]);
if ((v & 0x02) > 0) //0b010
High(_cols[1]);
else
Low(_cols[1]);
if ((v & 0x04) > 0) //0b100
High(_cols[2]);
else
Low(_cols[2]);
}
按键操作可以改到寄存器操作,提高速度。
使用mbed写,会更省事,可惜VBT6的RAM太少。
上一篇:STM32F103利用模拟I2C驱动ADS1115
下一篇:STM32F103控制ADS1115采集模拟信号
推荐阅读最新更新时间:2024-03-16 15:38