前言
本文是基于嵌入式开发板CT117E,stm32f103RBT6。
一、原理图
二、由原理图得到的信息
- 各个按键连接的电阻的阻值不一样。
- 按键按下电路连通。
- 电路连通后,每个按键按下的adc值都不一样,通过这个去判断是哪个按键按下。
- 根据自己开发板测得的数据,进行代码的编写,不用死记硬背各个按键按下的adc值。
三、ADC按键初始化
adc_key.c
#include "adc_key.h"
u16 adc_val;
void adc_key_init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
/* Configure PC.01, PC.02 and PC.04 (ADC Channel11, Channel12 and Channel14)
as analog input ----------------------------------------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channels configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_239Cycles5);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* Start ADC1 calibration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
}
adc_key.h
#ifndef ADC_KEY_H
#define ADC_KEY_H
#include "stm32f10x.h"
extern u16 adc_val;
u8 adc_key_read(void);
void adc_key_init(void);
#endif
四、ADC按键应用函数
u16 Adc_GetButtonVal(void){
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));
ADC_ClearFlag(ADC1,ADC_FLAG_EOC);
return ADC_GetConversionValue(ADC1);
}
u16 get_adc(void) //对获取的adc值进行滤波,冒泡排序取中间值
{
u16 adc_buff[50];
u8 i,j;
for(i=0;i<50;i++)
{
adc_buff[i]=Adc_GetButtonVal();
}
for(i=0;i<50-1;i++)
{
for(j=0;j<50-i-1;j++)
{
if(adc_buff[j]>adc_buff[j+1])
{
adc_buff[j]=adc_buff[j] ^ adc_buff[j+1];
adc_buff[j+1]=adc_buff[j] ^ adc_buff[j+1];
adc_buff[j]=adc_buff[j] ^ adc_buff[j+1];
}
}
}
adc_val = (adc_buff[24] + adc_buff[25])/2;
return adc_val;
}
u8 adc_key_read(void) //判断是哪个按键按下
{
u16 temp = 0;
temp = get_adc();
if(temp<0x0015) return 1;
else if(temp<0x0250) return 2;
else if(temp<0x0500) return 3;
else if(temp<0x0700) return 4;
else if(temp<0x0A00) return 5;
else if(temp<0x0C00) return 6;
else if(temp<0x0E00) return 7;
else if(temp<0x0FC0) return 8;
else return 0;
}
五、ADC按键在主函数的应用方法
按键按下需要进行消抖,这里用一个前后台的思想,在系统滴答定时器中每50ms就会把按键标志位置1,然后在主函数中,判断这个标志位,再调用按键获取函数,达到消抖的效果。
while(1)
{
if(key_flag) //50ms获取一次,达到按键消抖的效果
{
key=adc_key_read();
if(key!=0)
{
seg_show(16,16,key); //数码管显示按键值
//Delay_Ms(50); //消抖
// sprintf((char *)buff,"adc_val: %x ",adc_val); //显示获取到的12位的电压值
// LCD_DisplayStringLine(Line5,buff);
}
key_flag=0;
}
}