stm32F103状态机矩阵键盘

矩阵键盘程序,作为麦知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太少。

### 回答1: 您好!关于 stm32f103 所对应的 4x4 矩阵键盘程序,您可以参考以下代码: ``` #include "stm32f10x.h" #define ROWS 4 #define COLS 4 GPIO_InitTypeDef GPIO_InitStructure; // 按键映射表 const char keymap[ROWS][COLS] = { {'1', '2', '3', 'A'}, {'4', '5', '6', 'B'}, {'7', '8', '9', 'C'}, {'*', '0', '#', 'D'} }; // 初始化 GPIO void GPIO_Config(void) { // 使能 GPIOA 时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 初始化行引脚 PA0 - PA3,设置为推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化列引脚 PA4 - PA7,设置为浮空输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); } // 读取按键状态 char getKey(void) { int row, col; // 将行引脚设置为高电平,列引脚设置为输入 for (row = 0; row < ROWS; row++) { GPIO_ResetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3); GPIO_SetBits(GPIOA, GPIO_Pin_0 << row); for (col = 0; col < COLS; col++) { if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4 << col) == Bit_RESET) { // 等待按键释放 while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4 << col) == Bit_RESET); // 返回按键对应字符 return keymap[row][col]; } } } // 没有按键按下,返回空字符 return '\0'; } int main(void) { char key; GPIO_Config(); while (1) { key = getKey(); if (key != '\0') { // 按键被按下,执行相应操作 // 这里可以添加自己的代码 } } } ``` 该程序使用 GPIOA 的 4 个引脚作为矩阵键盘的行引脚,使用 GPIOA 的另外 4 个引脚作为列引脚。程序首先将行引脚设置为高电平,列引脚设置为输入,然后检测每个按键是否被按下,如果检测到按键被按下,则返回按键对应的字符。您可以根据需要修改 keymap 数组以映射不同的按键。 ### 回答2: STM32F103是一款功能强大的微控制器,能够轻松实现4*4矩阵键盘的数据读取。实现这个功能的关键在于矩阵键盘的工作原理。矩阵键盘通常由一个行和列的矩阵组成,因此需要读取每一行和每一列的数据。对于STM32F103微控制器来说,需要先将每一列与悬空引脚相连,同时将每一行与输入引脚相连。 在程序开发中,首先需要声明引脚的输入和输出,然后开始扫描矩阵键盘。对于每一列引脚,需要将其设置为输出模式,同时输出高电平。然后再读取每一行的电平状态,如果有电平变化,则说明该行对应的按键按下,程序相应地记录下按键的状态。接着,对于下一列,需要将其输出低电平,然后重新读取每一行状态,以便继续记录按键状态。当所有列都扫描完毕,程序就能够得到整个矩阵键盘的按键状态,并可以进行相应的操作。 实现4*4矩阵键盘程序的关键在于代码的编写和调试,需要仔细分析引脚和按键的连接方式,并逐一调试程序,确保能够准确地读取矩阵键盘的按键状态。此外,还需要注意程序的实时性和可靠性,避免由于程序出现问题导致按键读取不准确或程序崩溃等情况。因此,在编写程序时,需要加入各种保护机制和异常处理机制,保证程序的稳定性和可靠性。 总之,STM32F103微控制器可以轻松实现4*4矩阵键盘程序,能够广泛应用于各种嵌入式系统中,为产品的功能提升和应用拓展提供了极大的便利。 ### 回答3: stm32f103矩阵键盘程序4*4的实现可以采用按键扫描的方式。主控芯片通过按键矩阵的行列脚引脚完成与按键的连接,同时,程序需要设置行列的扫描方式,这是因为按键所在的矩阵,需要在一定的时间间隔内进行周期性扫描,以判断当前是否有按键按下,相应地进行按键的收发动作。 在实现矩阵键盘程序的过程中,需要进行如下步骤: 1. 配置主控芯片的引脚,将矩阵键盘的行列脚连接到主控芯片。 2. 编写键盘扫描程序,使主控芯片能够周期性扫描按键矩阵,以判断是否有按键动作产生。键盘扫描程序一般采用轮询方式扫描,也可以使用中断方式进行扫描。 3. 编写按键检测程序,将扫描到的按键编码进行处理,使得按键对应的信息能够被主控芯片识别并处理。按键检测程序需要采用状态机的方式进行编写,以实现较为灵活和可靠的按键检测和处理功能。 4. 进行按键的反馈操作,将按键的信息进行发送或接收处理。 总之,实现stm32f103矩阵键盘程序4*4的过程较为繁琐,需要掌握一定的硬件和软件知识,同时,需要充分了解所采用的主控芯片的特性和编程方法,以保证程序的正确性和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

容沁风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值