问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

STM32F407基于沁恒CH455芯片的矩阵键盘扫描程序设计

创作时间:
作者:
@小白创作中心

STM32F407基于沁恒CH455芯片的矩阵键盘扫描程序设计

引用
CSDN
1.
https://blog.csdn.net/A_B__C_/article/details/138270326

本文将详细介绍如何使用STM32F407VET6单片机和沁恒CH455H芯片实现矩阵键盘扫描功能。通过外部中断的方式上报键值信息,并通过串口打印。

一、前言

使用STM32F407VET6单片机,沁恒CH455H数码管控制及键盘控制芯片,通过外部中断的方式上报键值信息,并通过串口打印。

二、硬件设计

(1)CH455H

CH455 是数码管显示驱动和键盘扫描控制芯片。CH455 内置时钟振荡电路,可以动态驱动 4 位数码管或者 32 只 LED;同时还可以进行 28 键的键盘扫描;CH455 通过 SCL 和 SDA 组成的 2 线串行接口与单片机等交换数据。

芯片特点:

  • 内置显示电流驱动级,段电流不小于 25mA,字电流不小于 160mA。
  • 动态显示扫描控制,支持 8×4 或者 7×4,直接驱动 4 位数码管或者 32 只发光管 LED。
  • 内置 28 键键盘控制器,基于 7×4 矩阵键盘扫描。
  • 高速 2 线串行接口,时钟速度从 0 到 4MHz,兼容两线 I2C 总线,节约引脚。
  • 内置上电复位,支持 2.7V~5V 电源电压。
  • 提供低电平有效的键盘中断,提供按键释放标志位,可供查询按键按下与释放。
  • 内置时钟振荡电路,不需要外部提供时钟或者外接振荡元器件,更抗干扰。

也就是说,CH455H芯片可以同时进行4位8段数码管和74矩阵键盘的扫描。这里,仅以44矩阵键盘为例,设计电路。DIG0DIG3为列扫描,SEG0SEG1为行扫描,INT引脚连接单片机的E0引脚。SCL和SDA通过4.7k电阻上拉。

(2)矩阵键盘

在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态。这样的行列式键盘结构能够有效地提高单片机系统中I/O口的利用率。节约单片机的资源,其本质和独立按键类似,就是进行逐行扫描和逐列扫描,然后判断是第几行的第几列个按键,进而进行整体按键值得确定。但在使用时,单片机需要定时的逐行逐列扫描按键状态,不仅使用了定时器,而且在程序量较大或对时序要求较高时,定时扫描的方法就比较耗费资源。

图示为4*4矩阵键盘电路图。SEG和DIG分别连接CH455H芯片的SEG和DIG引脚,DIG0DIG3、H1H4引脚单独引出。不使用CH455芯片时,可通过单片机扫描DIG和H1~H4引脚进行按键扫描。

(3)STM32F407VET6单片机

单片机部分仅说明引脚连接:SCL连接PB8,SDA连接PB9,INT连接PE0。

(4)原理图和PCB

原理图

PCB

三、程序设计

CH455 的键盘扫描功能支持 7×4 矩阵的 28 键键盘。在键盘扫描期间,DIG3~DIG0 引脚用于列扫描输出,SEG6~SEG0 引脚都带有内部下拉电阻,用于行扫描输入。

CH455 所提供的按键代码为 8 位,位 7 始终为 0,位 2 始终为 1,位 1~位 0 是列扫描码,位 5~位 3 是行扫描码,位 6 是状态码(键按下为 1,键释放为 0)。例如,连接 DIG1 与 SEG4 的键被按下,则按键代码是 01100101B 或者 65H,键被释放后,按键代码通常是 00100101B 或者 25H(也可能是其它值,但是肯定小于 40H),其中,对应 DIG1 的列扫描码为 01B,对应 SEG4 的行扫描码为 100B。单片机可以在任何时候读取按键代码,但一般在 CH455 检测到有效按键产生键盘中断时读取按键代码,此时按键代码的位 6 总是 1,另外,如果需要了解按键何时释放,单片机可以通过查询方式定期读取按键代码,直到按键代码的位 6 为 0。

写操作包括以下 6 个步骤:输出启动信号、输出字节 1、应答 1、输出字节 2、应答 2、输出停止信号。其中,启动信号和停止信号如上所述,应答 1 和应答 2 总是固定为 1,输出字节 1 和输出字节 2 各自包含 8 个数据位,即一个字节数据。

读操作包括以下 6 个步骤:输出启动信号、输出字节 1、应答 1、输入字节 2、应答 2、输出停止信号。其中,启动信号和停止信号如上所述,应答 1 和应答 2 总是固定为 1,输出字节 1 和输入字节 2 各自包含 8 个数据位,即一个字节数据。

下面,仅给出CH455与main.c程序内容。若有需要整个工程,可直接私信。

(1)CH455.h

#ifndef __CH455_H
#define __CH455_H
#include "stm32f4xx.h"                  // Device header
extern unsigned char key;
void CH455_Init(void);
void CH455_EXIT_Init(void);
unsigned char CH455H_Config(void);
unsigned char CH455H_Read_Key(void);
void CH455_Wait_Ack(void);
#endif

(2)CH455.c

#include "ch455.h"
#include "mpuiic.h"
#include "board.h"
unsigned char key = 0;
void CH455_Init(void)
{
    IIC_Init();
    CH455_EXIT_Init();
    CH455H_Config();
}
unsigned char CH455H_Config(void)
{
    //设置系统参数
    IIC_Start();
    IIC_Send_Byte(0x48);
    
    CH455_Wait_Ack();//应答
    
    IIC_Send_Byte(0x11);		/*[KOFF][INTENS][7SEG][SLEEP]0[ENA]
                                    ENA: 	1 	使能显示输出和按键扫描
                                    SLEEP: 	0 	不进入低功耗睡眠状态
                                    7SEG: 	0 	8段模式
                                    INTENS: 001 显示驱动占空比为1/8
                                    KOFF: 	0 	键盘扫描和显示驱动交替进行*/
    CH455_Wait_Ack();//应答
    IIC_Stop();
    return 0;
}
void CH455_EXIT_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct ; 
    EXTI_InitTypeDef    EXTI_InitStruct ;
    
    //使能外设时钟 
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    //初始化GPIOA引脚1 
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN ; 
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP ; 
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 ; 
    GPIO_Init( GPIOE, & GPIO_InitStruct);
    /* 将引脚和中断线进行连接*/
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE , EXTI_PinSource0 );
    EXTI_InitStruct.EXTI_Line = EXTI_Line0 ;//PA1 对应EXTI_Line1 
    EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ; 
    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ; 
    EXTI_InitStruct.EXTI_LineCmd = ENABLE ; 
    EXTI_Init(&  EXTI_InitStruct) ; 
    
        /*配置对应外设中断*/
    NVIC_InitTypeDef NVIC_InitStruct ; 
    NVIC_InitStruct.NVIC_IRQChannel =  EXTI0_IRQn  ;  //外部中断1 通道  IRQn 位于stm32f4xx.h 中196行处 
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =2 ; //抢占优先级 2
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1  ; //响应优先级 2
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ; //使能中断 
    NVIC_Init(& NVIC_InitStruct);
}
/* 读取键值 */
unsigned char CH455H_Read_Key(void)
{
    unsigned char h=0, l=0;
    unsigned char res;
    IIC_Start();
    IIC_Send_Byte(0x4F);
    CH455_Wait_Ack();             //应答
    res = IIC_Read_Byte(0);		//停止应答
    IIC_Stop();                 //产生一个停止条件
    
    h = (res>>3)&0x7;
    l = res&0x3;
    res = h*4+(4-l);
    
    return res;  
}
/* 等待应答 */
void CH455_Wait_Ack(void)
{
    MPU_SDA_IN();      //SDA设置为输入  
    IIC_SDA=1;
    delay_us(1);   
    IIC_SCL=1;
    delay_us(1);	 
    IIC_SCL=0;//时钟输出0 	   
}
/* 按键中断 */
void EXTI0_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line0) == SET) //检查EXTI_Line1中断标志位
    {
        key = CH455H_Read_Key();
        
        EXTI_ClearITPendingBit(EXTI_Line0) ; //及时清除  EXTI_Line1 的标志位
    }
}

(3) main.c

#include "stm32f4xx.h"                  // Device header
#include "board.h"
#include "led.h"  
#include "key.h"  
#include "exit.h"
#include "ch455.h"
#include "usart.h"  
int main(void)
{
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2 ); 
    board_init();
    LED_Init();
    KEY_Init();
    Usart_Config();
    CH455_Init();
    while(1)
    {
        
        printf("%d\r\n", key);
        
        LED1_ON;
        delay_ms(500);
        LED1_OFF;
        delay_ms(500);
    }
}
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号