jianhong_wu 发表于 2015-7-10 11:56:35

CH452A按键扫描驱动C程序分享给大家。

本帖最后由 jianhong_wu 于 2015-7-11 11:50 编辑

坚鸿-深圳:
最近做项目需要用到CH452A按键扫描集成驱动芯片,现在把已经测试通过了的驱动代码分享给大家,供大家参考。
我用的是stm32f407单片机,主频率达到168MHz。
硬件连接简述:
CH452A芯片可以驱动8x8一共64个按键,但是本程序只是驱动4x4一共16个按键。硬件上行列扫描的连接是分别用CH452A芯片的DIG7至DIG4,以及SEG7至SEG4这8个引脚。
实现的功能:
每按一个按键都能让蜂鸣器发出一个短暂的声音。

main.c源文件代码如下:
#include "stm32f4xx.h"
#include "main.h"
#include "led.h"
#include "key.h"

int main(void)
{
LED_Configuration();
beep_Configuration();
SysTick_Configuration();
ch452_initial(); //跟按键有关的CH452A芯片初始化
while (1)
{
key_service();
}
}


void SysTick_Configuration(void) //SysTick定时器中断配置
{
if (SysTick_Config(SystemCoreClock / 1000))
{
while (1);
}
}


SysTick的定时中断函数如下:
void SysTick_Handler(void)
{

if(1==Gu8VoiceStart)
{

if(Gu16VoiceCnt!=0)
{
Gu16VoiceCnt--;
beep_ON;
}
else
{
beep_OFF;
Gu8VoiceStart=0;
}
}
}
key.c的源文件代码如下:
#include "stm32f4xx.h"
#include "key.h"
#include "delay.h"


u8 Gu8KeySec=0;
u16 Gu16VoiceCnt=0;
u8 Gu8VoiceStart=0;


void beep_Configuration(void) //蜂鸣器IO口设置
{

GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOF, ENABLE);

GPIO_InitStructure.GPIO_Pin =GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOF, &GPIO_InitStructure);
}

void ch452_initial(void)
{
if(key_board_config())
KEY_INT_Config();
}

void Key_GPIO_Init(void) //按键IO口设置
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;

RCC_AHB1PeriphClockCmd(KEY_SDA_GPIO_Clock | KEY_SCL_GPIO_Clock, ENABLE);
RCC_AHB1PeriphClockCmd(KEY_INT_GPIO_Clock, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

GPIO_InitStructure.GPIO_Pin = KEY_SDA_PIN ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_Init(KEY_SDA_GPIO,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = KEY_SCL_PIN ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_Init(KEY_SCL_GPIO,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = KEY_INT_PIN;
GPIO_Init(KEY_INT_GPIO, &GPIO_InitStructure);

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOG, EXTI_PinSource6);
EXTI_InitStructure.EXTI_Line = EXTI_Line6;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}


void KEY_INT_Config(void) //中断配置
{
NVIC_InitTypeDef NVIC_InitStructure;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}


void EXTI9_5_IRQHandler(void) //有按键被按下时,中断入口函数
{
if(EXTI_GetITStatus(EXTI_Line6)!= RESET )
{



key_scan(); //按键扫描和处理


EXTI_ClearITPendingBit(EXTI_Line6);
EXTI_ClearFlag(EXTI_Line6);
}
}


void key_scan(void) //按键扫描和处理
{
u8 u8KeyRead;
u8KeyRead = I2C_Read_Byte(0x6F);
switch(u8KeyRead)
{
case 0x7F:
Gu8KeySec=1;
break;
case 0x77:
Gu8KeySec=2;
break;
case 0x6F:
Gu8KeySec=3;
break;
case 0x67:
Gu8KeySec=4;
break;
case 0x7E:
Gu8KeySec=5;
break;
case 0x76:
Gu8KeySec=6;
break;
case 0x6E:
Gu8KeySec=7;
break;
case 0x66:
Gu8KeySec=8;
break;
case 0x7D:
Gu8KeySec=9;
break;
case 0x75:
Gu8KeySec=10;
break;
case 0x6D:
Gu8KeySec=11;
break;
case 0x65:
Gu8KeySec=12;
break;
case 0x7C:
Gu8KeySec=13;
break;
case 0x74:
Gu8KeySec=14;
break;
case 0x6C:
Gu8KeySec=15;
break;
case 0x64:
Gu8KeySec=16;
break;
}

}


void key_service(void) //按键服务程序
{


switch(Gu8KeySec)
{
case 1:

Gu16VoiceCnt=const_voice_short; //让蜂鸣器发出声音,操作的细节在SysTick定时器中断里
Gu8VoiceStart=1;
Gu8KeySec=0;
break;
case 2:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;
case 3:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;
case 4:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;
case 5:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;
case 6:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;
case 7:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;
case 8:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;
case 9:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;

case 10:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;

case 11:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;

case 12:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;

case 13:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;

case 14:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;

case 15:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;

case 16:

Gu16VoiceCnt=const_voice_short;
Gu8VoiceStart=1;
Gu8KeySec=0;
break;
}

}


void SDA_IN_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = KEY_SDA_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init(KEY_SDA_GPIO,&GPIO_InitStructure);
}

void SDA_OUT_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = KEY_SDA_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_Init(KEY_SDA_GPIO,&GPIO_InitStructure);
}


u8 Get_edition(void)
{
u8 edition_value;

I2C_Write_Byte(0x60,0x40);

edition_value = I2C_Read_Byte(0x61);

if(edition_value==0x20)

return 1;

else

return 0;
}



void I2C_Stop(void)
{
delay(50);
SCL_High;
delay(50);
SDA_High;
delay(50);
}

void I2C_Start(void)
{
SDA_High;
SCL_High;
delay(50);
SDA_Low;
delay(50);
SCL_Low;
}

void data_trans(u8 outdata)
{
u8 i;
for(i=0;i<8;i++)
{
delay(20);
if(outdata & 0x80)
SDA_High;
else
SDA_Low;
delay(30);
SCL_High;
delay(50);
SCL_Low;
outdata=outdata<<1;
}
delay(50);
SDA_IN_Config();
delay(10);
SCL_High;
}

u8 data_receive(void)
{
u8 indata=0x00;
u8 i;

for(i=0;i<8;i++)
{
indata = indata<<1;
delay(50);
SCL_High;
if(KEY_SDA_GPIO->IDR & KEY_SDA_PIN)
indata=indata+1;
delay(50);
SCL_Low;
}
delay(50);
SCL_High;
return indata;
}

void I2C_Write_Byte(u8 reg_addr,u8 data)
{
I2C_Start();
data_trans(reg_addr);
while(ACK_STATE);
delay(50);
SDA_OUT_Config();
SCL_Low;
data_trans(data);
while(ACK_STATE);
delay(50);
SCL_Low;
SDA_OUT_Config();
I2C_Stop();
}

u8 I2C_Read_Byte(u8 reg_addr)
{
u8 temp_data;
I2C_Start();
data_trans(reg_addr);
while(ACK_STATE);
delay(50);
SCL_Low;
temp_data=data_receive();
delay(50);
SDA_OUT_Config();
I2C_Stop();
return (temp_data);
}


u8 key_board_config(void)
{

Key_GPIO_Init();
I2C_Write_Byte(0x6E,0x80);

if(Get_edition())
{
I2C_Write_Byte(0x68,0x22);
}

return (1);

}


key.h的头文件代码如下:

#ifndef _KEY_
#define _KEY_

#include "stm32f4xx_gpio.h"

#define const_voice_short 100


#define KEY_SDA_PIN GPIO_Pin_13
#define KEY_SCL_PIN GPIO_Pin_3

#define KEY_SDA_GPIO GPIOC
#define KEY_SDA_GPIO_Clock RCC_AHB1Periph_GPIOC

#define KEY_SCL_GPIO GPIOB
#define KEY_SCL_GPIO_Clock RCC_AHB1Periph_GPIOB

#define KEY_INT_PIN GPIO_Pin_6
#define KEY_INT_GPIO GPIOG
#define KEY_INT_GPIO_Clock RCC_AHB1Periph_GPIOG

#define SDA_High GPIO_SetBits(KEY_SDA_GPIO,KEY_SDA_PIN)
#define SDA_Low GPIO_ResetBits(KEY_SDA_GPIO,KEY_SDA_PIN)
#define SCL_High GPIO_SetBits(KEY_SCL_GPIO,KEY_SCL_PIN)
#define SCL_Low GPIO_ResetBits(KEY_SCL_GPIO,KEY_SCL_PIN)
#define ACK_STATE KEY_SDA_GPIO->IDR & KEY_SDA_PIN

#define beep_OFF GPIO_ResetBits(GPIOF , GPIO_Pin_8)
#define beep_ON GPIO_SetBits(GPIOF , GPIO_Pin_8)

void beep_Configuration(void);
void Key_Init(void);
void KEY_INT_Config(void);
void Key_GPIO_Init(void);
void Delay(__IO uint32_t nTime);
void EXTI9_5_IRQHandler(void);

void SDA_IN_Config(void);
void SDA_OUT_Config(void);
u8 I2C_Read_Byte(u8 reg_addr);
void I2C_Write_Byte(u8 reg_addr,u8 data);
void I2C_Start(void);
void I2C_Stop(void);
u8 data_receive(void);
void data_trans(u8 outdata);

u8 Get_edition(void);
u8 key_board_config(void);
void key_scan(void);
void key_service(void);
void ch452_initial(void);

extern u8 Gu8KeySec;
extern u16 Gu16VoiceCnt;
extern u8 Gu8VoiceStart;

#endif


delay.c源文件如下:
#include "stm32f4xx.h"
#include "delay.h"


void delay(unsigned long Delay11_MS)
{
unsigned long Delay11_us;
for(Delay11_us=0;Delay11_us<Delay11_MS;Delay11_us++);
}


其它关联度不大的源文件就不再列出。




重庆-风雪 发表于 2015-7-10 19:13:23

鸿哥,为什么你贴出来的代码那么好看,我贴出来的那么丑呢?

jianhong_wu 发表于 2015-7-11 11:49:51

重庆-风雪 发表于 2015-7-10 19:13
鸿哥,为什么你贴出来的代码那么好看,我贴出来的那么丑呢?

贴代码用编辑工具“<>”。
页: [1]
查看完整版本: CH452A按键扫描驱动C程序分享给大家。