5个按钮:ADC值对应4个 + 普通IO

ADC按钮初始化

void BoardButtons_Init(void)
{
    GPIO_InitTypeDef gpio;
    ADC_CommonInitTypeDef common;
    ADC_InitTypeDef adc;

    if (s_initialized) return;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA |
                           RCC_AHB1Periph_GPIOF, ENABLE);
    gpio.GPIO_Pin = GPIO_Pin_0;
    gpio.GPIO_Mode = GPIO_Mode_AN; //配置为模拟引脚
    gpio.GPIO_OType = GPIO_OType_PP;
    gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
    gpio.GPIO_Speed = GPIO_Low_Speed;
    GPIO_Init(GPIOA, &gpio);

    gpio.GPIO_Pin = GPIO_Pin_9;
    gpio.GPIO_Mode = GPIO_Mode_IN;
    gpio.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOF, &gpio);

    PeripheralEnable(PeripheralADC1, true);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    ADC_CommonStructInit(&common);
    common.ADC_Mode = ADC_Mode_Independent;
    common.ADC_Prescaler = ADC_Prescaler_Div8;
    common.ADC_DMAAccessMode = 0U;
    common.ADC_TwoSamplingDelay = 0U;
    ADC_CommonInit(&common);

    ADC_StructInit(&adc);
    adc.ADC_Resolution = ADC_Resolution_12b;
    adc.ADC_ScanConvMode = DISABLE;
    adc.ADC_ContinuousConvMode = DISABLE;
    adc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    adc.ADC_ExternalTrigConv = 0U;
    adc.ADC_DataAlign = ADC_DataAlign_Right;
    adc.ADC_NbrOfConversion = 1U;
    ADC_Init(KEY_ADC, &adc);
    ADC_RegularChannelConfig(KEY_ADC, ADC_Channel_0, 1U,
                             ADC_SampleTime_56Cycles);
    ADC_Cmd(KEY_ADC, ENABLE);
}

读取ADC的值(无DMA)

static uint16_t adc_read_average(void)
{
    uint32_t total = 0U;
    uint32_t sample_index;
    for (sample_index = 0U; sample_index < 4U; ++sample_index) {
        uint32_t timeout = 100000U; //读取过程超时时间
        ADC_ClearFlag(ADC1, ADC_FLAG_EOC | ADC_FLAG_STRT | ADC_FLAG_OVR);
        ADC_SoftwareStartConv(ADC1);
        while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET && timeout-- != 0U) {}
        if (timeout == 0U) return 4095U;
        total += ADC_GetConversionValue(ADC1);
    }
    return (uint16_t)(total / 4U);
}

不同电压对应不同的值

typedef enum {
    BOARD_BUTTON_NONE = 0,
    BOARD_BUTTON_UP,
    BOARD_BUTTON_DOWN,
    BOARD_BUTTON_OK,
    BOARD_BUTTON_PHOTO,
    BOARD_BUTTON_BACK,
    BOARD_BUTTON_POWER
} BoardButtonEvent;
static BoardButtonEvent decode_adc(uint16_t raw)
{
    if (raw < 493U) return BOARD_BUTTON_UP;
    if (raw < 1485U) return BOARD_BUTTON_DOWN;
    if (raw < 2414U) return BOARD_BUTTON_OK;
    if (raw < 3449U) return BOARD_BUTTON_PHOTO;
    return BOARD_BUTTON_NONE;
}

Freertos任务去10ms一次轮询查看

bool BoardButtons_Scan(uint32_t now_ms, BoardButtonEvent *event)
{
    BoardButtonEvent decoded;
    bool power_low;
    if (!s_initialized || event == NULL) return false; //是否初始化
    *event = BOARD_BUTTON_NONE;

    /* PF9 short release is BACK; a continuous 3-second press is POWER. */
    power_low = GPIO_ReadInputDataBit(GPIOF, GPIO_Pin_9) == Bit_RESET;
    if (power_low) {
        if (s_power_debounce < 2U) ++s_power_debounce;
        if (!s_power_pressed && s_power_debounce >= 2U) { //防抖
            s_power_pressed = true;
            s_power_pressed_at = now_ms;
            s_power_long_sent = false;
        }
        if (s_power_pressed && !s_power_long_sent &&
            (uint32_t)(now_ms - s_power_pressed_at) >= 3000U) { //电源触发长按
            s_power_long_sent = true;
            *event = BOARD_BUTTON_POWER;
            return true;
        }
    } else {
        s_power_debounce = 0U;
        if (s_power_pressed) {
            s_power_pressed = false;
            if (!s_power_long_sent) {
                *event = BOARD_BUTTON_BACK;
                return true;
            }
        }
    }

    decoded = decode_adc(adc_read_average());
    if (decoded != s_candidate) {
        s_candidate = decoded;
        s_candidate_count = 1U;
        return false;
    }
    if (s_candidate_count < 2U) { //防抖
        ++s_candidate_count;
        return false;
    }
    if (decoded != s_stable) {
        s_stable = decoded;
        if (decoded != BOARD_BUTTON_NONE) {
            *event = decoded;
            return true;
        }
    }
    return false;
}