ADC按键电路实现

发布时间 2023-10-24 15:24:30作者: ZaiLi

在程序设计以及硬件电路设计中,通常使用GPIO连接按键,通过检测外部按键按下的高低电平实现按键的检测。当我们需要多个按键且GPIO资源不够的时候,我们可以利用MCU的ADC功能,实现对按键的检测。

ADC按键检测电路如下:

当没有按键按下时,ADC检测IO口电压为3.3V。

当第1个按键按下时,ADC检测IO口电压为825mV,如下图:

当第2个按键按下时,ADC检测IO口的电压为1.32V,如下图:

 以此类推,当第3、4、5个按键按下时,电压分别如下图:

从上图结果可知,不同按键按下,ADC会采集到不到的电压,通过该原理,可以利用ADC实现对按键的检测,具体实现代码可参考下程序:

void adc_Init(void)
{
    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE ); //使能GPIOA时钟和ADC

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC时钟分频为6分频
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;   //配置ADC为独立模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //设置在单通道模式下执行转换
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  //设置在单次模式下执行转换
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //设置转换不是由外部触发启动
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //设置ADC数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1;                //顺序进行规则转换的ADC通道的数目
    ADC_Init(ADC1, &ADC_InitStructure);                    //根据ADC_InitStructure中指定的参数初始化ADC1寄存器

    ADC_Cmd(ADC1, ENABLE); //使能ADC1

    ADC_ResetCalibration(ADC1); //重置ADC1校准寄存器。

    while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束

    ADC_StartCalibration(ADC1); //开启AD校准

    while(ADC_GetCalibrationStatus(ADC1));      //等待校准结束
}

u16 get_adc(u8 ch)
{
    ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );//为所选ADC常规通道配置其在序列器中的相应列组及其采样时间。

    ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能ADC1软件启动转换

    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC )); //等待转换结束

    return ADC_GetConversionValue(ADC1); //返回常规通道的最后一个ADC1转换结果数据
}

u16 Get_Adc_Average(u8 ch,u8 times)
{
    u32 temp_val=0;
    u8 t;
    for(t=0;t<times;t++)
    {
        temp_val+=get_adc(ch);
        Delay_Ms(5);
    }
    return temp_val/times;
}
/*********************************************************************
 * @fn      main
 *
 * @brief   Main program.
 *
 * @return  none
 */
int main(void)
{
    u16 adc;
    u16 sw=0;
    u8 key=0;
    float temp;



    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
    USART_Printf_Init(115200);
    adc_Init();

    printf("SystemClk:%d\r\n",SystemCoreClock);
    printf("This is printf example\r\n");

    while(1)
    {
        adc=Get_Adc_Average(ADC_Channel_1,10);
        temp=(float)adc*(3.3/4096);
//        printf("adc:%d\r\n",adc);
//        printf("volate:%0.2f\r\n",temp);

        if(temp>1.62&&temp<1.66)
        {
            sw=1;
        }
        else if(temp>2.86&&temp<2.90)
        {
            sw=2;
        }
        else if(temp>2.95&&temp<3.05)
        {
            sw=3;
        }
        else if(temp>3.13&&temp<3.15)
        {
            sw=4;
        }

        key = sw;
        sw=0;
        adc=0;
        temp=0;
        switch(key)
        {
            case 1:
                printf("sw1 press\r\n");
                key = 0;
                break;
            case 2:
                printf("sw2 press\r\n");
                key = 0;
                break;
            case 3:
                printf("sw3 press\r\n");
                key = 0;
                break;
            case 4:
                printf("sw4 press\r\n");
                key = 0;
                break;
            default:
                break;
        }
        Delay_Ms(50);

    }
}