2026年STM32驱动4X4矩阵键盘[源码]

STM32驱动4X4矩阵键盘[源码]file i2c keyboard c brief 4x4 矩阵键盘 I2C 驱动实现文件 author Based on CSDN Blog https blog csdn net m0 article details include i2c keyboard h include

大家好,我是讯享网,很高兴认识大家。这里提供最前沿的Ai技术和互联网信息。

/

  • @file i2c_keyboard.c
  • @brief 4x4 矩阵键盘 I2C 驱动实现文件
  • @author Based on CSDN Blog: https://blog.csdn.net/m0_/article/details/ */

#include "i2c_keyboard.h" #include

/

  • @brief I2C 延时函数
  • @note 软件 I2C 需要适当的延时来保证时序正确 */ void I2C_Delay(void) { HAL_Delay(4); }

/

  • @brief I2C 初始化函数
  • @note 配置 PB6 和 PB7 为开漏输出模式 */ void I2C_Init(void) { // 启用 GPIOB 时钟 __HAL_RCC_GPIOB_CLK_ENABLE();

    // 定义 GPIO 初始化结构体 GPIO_InitTypeDef GPIO_InitStructure = {0};

    // 配置 I2C 引脚为开漏输出模式 GPIO_InitStructure.Pin = I2C_Pin_SCL | I2C_Pin_SDA; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD; // 开漏输出模式 GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; // 高速模式 GPIO_InitStructure.Pull = GPIO_NOPULL;

    HAL_GPIO_Init(I2C_Port, &GPIO_InitStructure);

    // 释放 SCL 和 SDA 总线(上拉) HAL_GPIO_WritePin(I2C_Port, I2C_Pin_SCL, GPIO_PIN_SET); HAL_GPIO_WritePin(I2C_Port, I2C_Pin_SDA, GPIO_PIN_SET); }

/

  • @brief I2C 开始信号
  • @note SCL 高电平时,SDA 由高变低 */ void I2C_Start(void) { I2C_W_SDA(1); I2C_W_SCL(1); I2C_Delay(); I2C_W_SDA(0); I2C_Delay(); I2C_W_SCL(0); I2C_Delay(); }

/

  • @brief I2C 停止信号
  • @note SCL 高电平时,SDA 由低变高 */ void I2C_Stop(void) { I2C_W_SDA(0); I2C_Delay(); I2C_W_SCL(1); I2C_Delay(); I2C_W_SDA(1); I2C_Delay(); }

/

  • @brief I2C 发送一个字节
  • @param address 要发送的字节数据
  • @note 高位先发,在 SCL 低电平期间改变数据线状态 */ void I2C_SendByte(uint8_t data)
    else { I2C_W_SDA(0); } data <<= 1; I2C_Delay(); I2C_W_SCL(1); I2C_Delay(); I2C_Delay(); 

    }

    I2C_W_SCL(0); // 确保最后 SCL 为低电平 }

/

  • @brief I2C 主机发送 ACK 应答信号
  • @note 用于读取数据时通知从机继续发送 */ void I2C_ACK(void) { I2C_W_SCL(0); I2C_W_SDA(0); I2C_Delay(); I2C_W_SCL(1); I2C_Delay(); I2C_W_SCL(0); I2C_Delay(); }

/

  • @brief I2C 主机发送 NACK 应答信号
  • @note 用于读取最后一个字节时通知从机停止发送 */ void I2C_NACK(void) { I2C_W_SCL(0); I2C_W_SDA(1); I2C_Delay(); I2C_W_SCL(1); I2C_Delay(); I2C_W_SCL(0); I2C_Delay(); }

/

  • @brief I2C 读取一个字节
  • @param flag 1=发送 ACK,0 发送 NACK
  • @return 读取到的字节数据
  • @note 主机释放 SDA 总线,从机控制数据线 */ uint8_t I2C_ReadByte(uint8_t flag)
    I2C_Delay(); 

    }

    I2C_W_SCL(0);

    // 根据 flag 发送 ACK 或 NACK if(flag) {

    I2C_ACK(); 

    } else {

    I2C_NACK(); 

    }

    return byte; }

/

  • @brief 获取按键值
  • @param value 指向存储按键值的指针
  • @note 从 VK36N16I 芯片读取两个字节并合并为 uint16_t
  • 特别注意:每个 SDA 字节读取之前必须进行 ACK 应答,否则读取不到数据,共应答两次 */ void Get_KeyBoard_Value(uint16_t *value) { uint8_t byte_low = 0; uint8_t byte_high = 0;

    // 开始信号 I2C_Start();

    // 发送读地址 (0xCB) I2C_SendByte(KEYBOARD_I2C_ADDR_READ);

    // 第一个字节读取前进行 ACK 应答 I2C_ACK();

    // 读低字节 byte_low = I2C_ReadByte(1); // 发送 ACK,准备读下一个字节

    // 第二个字节读取前进行 ACK 应答 I2C_ACK();

    // 读高字节 byte_high = I2C_ReadByte(0); // 发送 NACK,最后一个字节

    // 停止信号 I2C_Stop();

    // 将低字节和高字节合并为一个 uint16_t *value = ((uint16_t)byte_high << 8) | byte_low; }

/

  • @brief 根据按键值映射返回对应的字符
  • @param key_value 按键的原始值
  • @return 对应的字符,未匹配返回’!’
  • 按键值映射表 (十进制):
  • 1 -> ‘1’, 16 -> ‘2’, 256 -> ‘3’, 2 -> ‘4’
  • 32 -> ‘5’, 512 -> ‘6’, 4 -> ‘7’, 64 -> ‘8’
  • 1024 -> ‘9’, 128 -> ‘0’, 8 -> ‘*’, 2048 -> ‘#’
  • 4096 -> ‘A’, 8192 -> ‘B’, 16384 -> ‘C’, 32768 -> ’D’ / char get_key_from_value(int key_value) { switch(key_value) { case 1: return ‘1’; case 16: return ‘2’; case 256: return ‘3’; case 2: return ‘4’; case 32: return ‘5’; case 512: return ‘6’; case 4: return ‘7’; case 64: return ‘8’; case 1024: return ‘9’; case 128: return ‘0’; case 8: return ‘’; case 2048: return ‘#’; case 4096: return ‘A’; case 8192: return ‘B’; case 16384: return ‘C’; case 32768: return ’D’; default: return ‘!’; // 如果没有匹配的值,返回特定字符 } }
小讯
上一篇 2026-04-12 09:24
下一篇 2026-04-12 09:22

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/256315.html