藍橋杯嵌入式擴展板模塊之按鍵

藍橋杯嵌入式擴展板模塊之按鍵

硬件介紹

U1S1這是我見到過最NB的硬件電路,我當時還以爲是矩陣鍵盤,沒想到它採用的是ADC採集它的分壓值。。

在這裏插入圖片描述
其中ADC_Key你就把它當做一個ADC採集口,當S按鍵按下後,ADC採集的電壓就會改變,所以你要做的就是根據採集電壓的不同區判斷是哪個按鍵被按下。有人可能會擔心這樣可能不精確會造成誤判什麼的,我後面寫了之後發現根本不會出現。

Button.c

#include "button.h"
u16 Button_Num[length];
void Adc_ButtonInit(void){
	ADC_InitTypeDef ADC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_ADCCLKConfig(RCC_PCLK2_Div6); 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	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 = DISABLE;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1, &ADC_InitStructure);

	ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_239Cycles5);

	ADC_DMACmd(ADC1, ENABLE);
	ADC_Cmd(ADC1, ENABLE); 
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));

}

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 Read_Button(void){
	u16 i=0,j=0,temp=0;
	for(i=0;i<50;i++){
		Button_Num[i] = Adc_GetButtonVal();
	}

	for(i=0;i<length-1;i++){
		for(j=0;j<length-i-1;j++){
			if(Button_Num[j]>Button_Num[j+1]){
				temp = Button_Num[j];
				Button_Num[j] = Button_Num[j+1];
				Button_Num[j+1] = temp;
			}
		}
	}

	if(length%2==0)
		return (Button_Num[length/2-1]+Button_Num[length/2])/2;
	else
		return Button_Num[length/2];
}

u8 Scan_Button(void){
	u16 temp = Read_Button();
	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;
}

Button.c函數實現的講解

  1. Button_Num[length]這個數組是用來存放ADC採集的數值的,它的長度length自己設置就可以了,但是最好設置比較大一點,一般情況下50即可。
  2. Adc_ButtonInit()這個就是一個普通的ADC初始化的步驟,但是需要注意的有兩點,其一是RCC_ADCCLKConfig(RCC_PCLK2_Div6)需要對ADC六分頻,其二是ADC_RegularChannelConfig函數的第四個參數最好是ADC_SampleTime_239Cycles5,這樣會採集的更加精確一些。
  3. Adc_GetButtonVal()這個函數就是獲取ADC值,沒什麼可說的。
  4. Read_Button()這個函數中,第一個for循環是用連續讀滿整個數組,第二個就是冒泡排序,後面返回的就是這個數組最中間的數值,說白了這個函數就是簡單的進行個濾波。
  5. Scan_Button()這個函數就是用來判斷是哪個按鍵被被按下了,temp後面的值就是對應拓展版按鍵按下後ADC採集到的值,而這個值是怎麼來的就很有意思了。有的人選擇直接背下來,我倒是認爲不可,因爲比賽的板子有可能電阻的不同,就會導致相應的偏差,我想到一個辦法就是你挨個試,怎麼試呢?你前面不是已經寫出來Read_Button()這個函數了麼,你把它的值直接顯示在LCD上,然後每次通過按鍵就會發現那個數值的變化,然後你根據那個數值的變化,去選一個相應的範圍就可以了,我認爲這是最快最安全的方法!

Button.h

#ifndef __BUTTON_H
#define __BUTTON_H

#include "stm32f10x.h"
#define length 50

u16 Read_Button(void);
u8 Scan_Button(void);
u16  Adc_GetButtonVal(void);
void Adc_ButtonInit(void);

#endif

總結

這個模塊在思想上可以說非常簡單了,但就是有點點麻煩。因爲我要做的事採集ADC的值要求的就是一個準,因此我們可以選擇浪費一點時間,去讀出最準確的數值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章