蓝桥杯嵌入式扩展板模块之按键

蓝桥杯嵌入式扩展板模块之按键

硬件介绍

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的值要求的就是一个准,因此我们可以选择浪费一点时间,去读出最准确的数值。

发布了19 篇原创文章 · 获赞 17 · 访问量 4086

猜你喜欢

转载自blog.csdn.net/qq_43605009/article/details/105023748