前言
最近在学习山景BP10_128DBG开发板,想使用开发板上的按键,看了看原理图和之前用过的按键好像有点不一样。常见的按键都是判断IO口是否被拉低或拉高来判断按键是否被按下。山景BP10_128DBG开发板上的按键是ADC按键,每个按键按下之后ADC的采样值是不同的,通过ADC采样回来的值进而判断哪个按键按下。这种方式核心思想就是用一个ADC通道来节约IO口,对于IO紧张的芯片是一个不错的解决思路。
我把ADC按键给封装起来了,给用户提供一个.c和.h文件
adckey.c代码
#include "adckey.h"
// ADC_CHANNEL_VIN = 0, /**channel 0*/
// ADC_CHANNEL_VBK, /**channel 1*/
// ADC_CHANNEL_VDD1V2, /**channel 2*/
// ADC_CHANNEL_VCOM, /**channel 3*/
// ADC_CHANNEL_GPIOA20_A23, /**channel 4*/
// ADC_CHANNEL_GPIOA21_A24, /**channel 5*/
// ADC_CHANNEL_GPIOA22_A25, /**channel 6*/
// ADC_CHANNEL_GPIOA26, /**channel 7*/
// ADC_CHANNEL_GPIOA27, /**channel 8*/
// ADC_CHANNEL_GPIOA28, /**channel 9*/
// ADC_CHANNEL_GPIOA29, /**channel 10*/
// ADC_CHANNEL_GPIOA30, /**channel 11*/
// ADC_CHANNEL_GPIOA31, /**channel 12*/
// ADC_CHANNEL_GPIOB0, /**channel 13*/
// ADC_CHANNEL_GPIOB1, /**channel 14*/
// ADC_CHANNEL_POWERKEY /**channel 15*/
//以下定义的宏是按键按下后返回对应的键值
#define KEY8_PRESS 8
#define KEY9_PRESS 9
#define KEY10_PRESS 10
#define KEY11_PRESS 11
#define KEY12_PRESS 12
#define KEY13_PRESS 13
#define KEY14_PRESS 14
#define KEY15_PRESS 15
#define KEY16_PRESS 16
#define KEY17_PRESS 17
#define KEY18_PRESS 18
#define KEY19_PRESS 19
#define KEY20_PRESS 20
#define KEY21_PRESS 21
#define KEY22_PRESS 22
#define KEY23_PRESS 23
#define KEY24_PRESS 24
#define KEY25_PRESS 25
#define KEY26_PRESS 26
#define KEY27_PRESS 27
#define KEY28_PRESS 28
#define KEY29_PRESS 29
/*
以下两个数组存放的是ADC按键按下之后ADC采样回来的原始数据
获取ADC的值与下方数组的值进行比较就可以知道那个按键被按下了
*/
uint16_t ADC1_Key_Data[11] = {1200, 1485, 1577, 1644, 1720, 1850, 2190, 2584, 2922, 3309, 3650};
uint16_t ADC2_Key_Data[11] = {47, 370, 730, 1060, 1447, 1814, 2193, 2592, 2926, 3314, 3650};
/*
ADC_Key初始化函数
(0, 0)ADC1_KEY和ADC2_Key都不初始化
(1, 0)ADC1_KEY初始化和ADC2_Key不初始化
(0, 1)ADC1_KEY不初始化和ADC2_Key初始化
(1, 1)ADC1_KEY和ADC2_Key都初始化
*/
void ADC_Key_Init(bool ADC1_Key_Enable, bool ADC2_Key_Enable)
{
SarADC_Init();
if(ADC1_Key_Enable){
GPIO_RegOneBitClear(GPIO_A_ANA_EN, GPIO_INDEX20);//channel
GPIO_RegOneBitSet(GPIO_A_ANA_EN, GPIO_INDEX23);
}
if(ADC2_Key_Enable){
GPIO_RegOneBitSet(GPIO_A_ANA_EN, GPIO_INDEX26);//channel
}
if(ADC1_Key_Enable && ADC2_Key_Enable){
GPIO_RegOneBitClear(GPIO_A_ANA_EN, GPIO_INDEX20);
GPIO_RegOneBitSet(GPIO_A_ANA_EN, GPIO_INDEX23);//channel
GPIO_RegOneBitSet(GPIO_A_ANA_EN, GPIO_INDEX26);//channel
}
}
/*
获取ADC_Key的采样值,范围是0-4095(2^12 - 1)
*/
uint16_t ADC_Key_Data_Get(ADC_Key_CHANNEL_SEL adc_key_channel)
{
uint16_t ADC_Key_Data = 0;
if(adc_key_channel == ADC1_Key_Channel){
ADC_Key_Data = ADC_SingleModeDataGet(ADC_CHANNEL_GPIOA20_A23);
}
if(adc_key_channel == ADC2_Key_Channel){
ADC_Key_Data = ADC_SingleModeDataGet(ADC_CHANNEL_GPIOA26);
}
return ADC_Key_Data;
}
/*
开发板对应按键返回函数
adc_key_channel用于选择那个ADC_Key
根据adc_key_data来判断两个ADC组中具体哪个按键按下了
*/
uint8_t ADC_Key_Press_Return(ADC_Key_CHANNEL_SEL adc_key_channel, uint16_t adc_key_data)
{
int temp[11];
uint8_t i = 0;
int min;
uint8_t index;
memset(temp, 0x00, sizeof(temp));
//ADC_Key1组中的按键返回
if(adc_key_channel == ADC1_Key_Channel){
//先计算adc_key_data和标准ADC按键返回值的差值
for(i = 0; i < 11; i++){
temp[i] = adc_key_data - ADC1_Key_Data[i];
//DBG("temp[%d] = %d\r\n", i, temp[i]);
}
//先默认temp[0]是差值最小的,下面比较都是在正整数的基础上进行的
if(temp[0] < 0){
min = -temp[0];
index = 0;
}
else{
min = temp[0];
index = 0;
}
//遍历数组temp找到差距最小的下标
for(i = 0; i < 11; i++){
if(temp[i] < 0){
temp[i] = -temp[i];
}
if(min > temp[i]){
min = temp[i];
index = i;
}
}
switch(index){
case 0:
return KEY9_PRESS;
case 1:
return KEY11_PRESS;
case 2:
return KEY13_PRESS;
case 3:
return KEY15_PRESS;
case 4:
return KEY17_PRESS;
case 5:
return KEY19_PRESS;
case 6:
return KEY21_PRESS;
case 7:
return KEY23_PRESS;
case 8:
return KEY25_PRESS;
case 9:
return KEY27_PRESS;
case 10:
return KEY29_PRESS;
}
}
//ADC_Key2组中的按键返回
if(adc_key_channel == ADC2_Key_Channel){
//先计算adc_key_data和标准ADC按键返回值的差值
for(i = 0; i < 11; i++){
temp[i] = adc_key_data - ADC2_Key_Data[i];
}
//先默认temp[0]是差值最小的,下面比较都是在正整数的基础上进行的
if(temp[0] < 0){
min = -temp[0];
index = 0;
}
else{
min = temp[0];
index = 0;
}
//遍历数组temp找到差距最小的下标
for(i = 0; i < 11; i++){
if(temp[i] < 0){
temp[i] = -temp[i];
}
if(min > temp[i]){
min = temp[i];
index = i;
}
}
switch(index){
case 0:
return KEY8_PRESS;
case 1:
return KEY10_PRESS;
case 2:
return KEY12_PRESS;
case 3:
return KEY14_PRESS;
case 4:
return KEY16_PRESS;
case 5:
return KEY18_PRESS;
case 6:
return KEY20_PRESS;
case 7:
return KEY22_PRESS;
case 8:
return KEY24_PRESS;
case 9:
return KEY26_PRESS;
case 10:
return KEY28_PRESS;
}
}
}
adckey.h代码
#ifndef __ADCKEY_H
#define __ADCKEY_H
#include "sadc_interface.h"
#include "irqn.h"
#include "adc.h"
#include "string.h"
#include "delay.h" //这个头文件在mv_utils的inc文件夹下
#include "gpio.h"
#include "type.h"
/*
定义一个ADC_Key_CHANNEL_SEL的枚举
以便于用户使用ADC_Key,而不用去管到底是哪个ADC通道进行采样,哪个IO进行模拟复用
*/
typedef enum __ADC_Key_CHANNEL_SEL
{
ADC1_Key_Channel,
ADC2_Key_Channel
}ADC_Key_CHANNEL_SEL;
void ADC_Key_Init(bool ADC1_Key_Enable, bool ADC2_Key_Enable);
uint16_t ADC_Key_Data_Get(ADC_Key_CHANNEL_SEL adc_key_channel);
uint8_t ADC_Key_Press_Return(ADC_Key_CHANNEL_SEL adc_key_channel, uint16_t adc_key_data);
#endif
提供的一个样例测试代码,死循环扫描哪个ADC按键被按下
void SarADC_DCSingleMode(void)
{
uint16_t DC_Data;
uint8_t key;
DBG("SarADC DC example\n");
//GPIOA23做为ADC采样输入引脚
//BP10开发板上按下不同的按键串口会打印输出不同的电压采样值
ADC_Key_Init(1, 1);
while(1)
{
DC_Data = ADC_Key_Data_Get(ADC1_Key_Channel);
//DBG("ADC1_Data = %d\r\n", DC_Data);
key = ADC_Key_Press_Return(ADC1_Key_Channel, DC_Data);
DBG("key %d is pressed\r\n", key);
DelayMs(500);
DC_Data = ADC_Key_Data_Get(ADC2_Key_Channel);
//DBG("ADC2_Data = %d\r\n", DC_Data);
key = ADC_Key_Press_Return(ADC2_Key_Channel, DC_Data);
DBG("key %d is pressed\r\n", key);
DelayMs(500);
}
}
按下开发板上对应按键之后串口会打印出来,当没有按键按下之默认是key28和key29,所以这两个按键在这种方式中就会不起作用,尽量就别用。
总结
以上就是本文的全部内容,希望可以帮你使用到ADC_Key。