蓝桥杯STM32F103RB扩展板ADC按键

实验功能:
使用ADC按键(8个),键入值分别代表1-8,在三个数码管上通过键入值向左移动显示
eg:
默认数码管不显示,第一次键入3,在第一个数码管上显示3
第二次键入8,第一位数码管显示8,第二位数码管显示3
第三次键入6,第一位数码管显示6,第二位数码管显示8,第三位数码管显示3
………………


涨见识了,ADC按键这波操作是真服,通过判断ADC采集到的值,来确定按键,

原理图:

在这里插入图片描述

每段按键加上电阻,达到分压的效果,通过ADC转换,就可以测得不同按键按下的值

计算公式

转换值=4095R/(1000+R) 此处R1的值就是1000
eg:
S1:接GND采集到的值为0
S2:4095
R2/(R1+R2)
S6:按键按下采集到的值:4095*(R2+R3+R4+R5+R6)/(R1+R2+……+R6)
根据计算可以得到s1-s8按键按下采集到的值分别为:
s1 0
s2 534
s3 1149
s4 1755
s5 2367
s6 2880
s7 3507
s8 3984
对于采集到的值会存在一定的误差,这是不可避免的,通过比较中间值来处理这种也涨见识了
如:S1 ,S2采集到的值分别为 0 和 534 这时候取一个中间值267,,<267则作为按键S1按下,>267则作为按键S2按下.比较这个中间值可以避免采集值存在误差带来的问题。
所有计算结果如下:在这里插入图片描述

软件设计

ADC初始化

void ADC1_Init_AKEY(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  ADC_InitTypeDef ADC_InitStruct;
  // 运行GPIOA和ADC1时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
  // PA5-IN5模拟输入
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOA, &GPIO_InitStruct);
  // 初始化ADC1
  ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;  
  ADC_InitStruct.ADC_ScanConvMode = DISABLE;
  ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStruct.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStruct);
  // 配置通道5
  ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1,
    ADC_SampleTime_1Cycles5);    
  ADC_InjectedChannelConfig(ADC1, ADC_Channel_4, 1,
    ADC_SampleTime_1Cycles5);						 
  ADC_AutoInjectedConvCmd(ADC1, ENABLE);				
// 启动ADC1
  ADC_Cmd(ADC1, ENABLE);   
  // 校准ADC1
  ADC_StartCalibration(ADC1);//ADC转化校准
  while(ADC_GetCalibrationStatus(ADC1));
}

unsigned int ADC1_Conv(void)
{
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能软件触发
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));//获取标志状态
  return ADC_GetConversionValue(ADC1);//获取ADC转化值
}

unsigned int ADC1_InjeConv(void)
{
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_JEOC));
  ADC_ClearFlag(ADC1, ADC_FLAG_JEOC);
  return ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);
}

按键扫描

unsigned char AKEY_Read(void)
{
  unsigned char ucAkey_Val = 0;
  unsigned int  uiAdc_Val = ADC1_Conv();

  if(uiAdc_Val < 6000)						
  {
    Delay_AKEY(100);							
    uiAdc_Val = ADC1_Conv();
    if(uiAdc_Val < 4095)					
    {
      if(uiAdc_Val > 3745)				
        ucAkey_Val = 8;
      else if(uiAdc_Val > 3193)		
        ucAkey_Val = 7;
      else if(uiAdc_Val > 2623)		
        ucAkey_Val = 6;
      else if(uiAdc_Val > 2061)		
        ucAkey_Val = 5;
      else if(uiAdc_Val > 1452)	
        ucAkey_Val = 4;
      else if(uiAdc_Val > 841)		
        ucAkey_Val = 3;
      else if(uiAdc_Val > 267)			
        ucAkey_Val = 2;
      else
        ucAkey_Val = 1;
			}
		
}
  return ucAkey_Val;
}




void Delay_AKEY(unsigned int ms)
{
  unsigned int i, j;

  for(i=0; i<ms; i++)
    for(j=0; j<7992; j++);			// SYSCLK = 72MHz
//  for(j=0; j<1598; j++);			// SYSCLK = 8MHz
}

这里注意这一段的配置
if(uiAdc_Val < 6000) 可以较大不能较小
{
Delay_AKEY(100);
uiAdc_Val = ADC1_Conv();
if(uiAdc_Val < 4095) 不能过大或过小

main.c程序

#include "key.h"
#include "led.h"
#include "lcd.h"
#include "seg.h"
#include "adc.h"
#include "usart.h"


unsigned char ucLed = 1;
unsigned char ucAkey_Long;
unsigned long ulTick_ms, ulAkey_Time;
unsigned int key_number;//LCD显示
unsigned char  pucStr[21];
unsigned char ucDot;  //小数点
int seg[3]={17,17,17};




void LCD_Proc(void);
void AKEY_Proc(void);
void ledAll_turn (void);
void seg_left(void);

int main(void)
{
  
 
  SysTick_Config(72000);			// 定时1ms(HCLK = 72MHz)
  LED_Init();
	
	STM3210B_LCD_Init();
  LCD_Clear(Blue);
  LCD_SetBackColor(Blue);
  LCD_SetTextColor(White);
	ADC1_Init_AKEY();
  SEG_Init();
	
	
  
	
	
  while(1)
  {
	 AKEY_Proc();
   LCD_Proc();
	 SEG_Disp(seg[2],seg[1],seg[0],ucDot);	
	}
}
unsigned char ucAkey_Val;
int jishu=0;

void AKEY_Proc(void)
{
  ucAkey_Val =  AKEY_Read();
  if(ucAkey_Val != ucAkey_Long)
   {
    ucAkey_Long = ucAkey_Val;
    ulAkey_Time = ulTick_ms;
	 }
  else
    ucAkey_Val = 0;
  if(ucAkey_Val)
  {
   key_number=ucAkey_Val;
	 ledAll_turn();
	 seg_left();
	}
	
	
}


//函数功能:数码管数值每按一次左移一位
void seg_left(void)
{
	ucDot++;
	if(seg[0])
	 {
		seg[2]=seg[1];
		seg[1]=seg[0]; 
	 }
	  seg[0]=ucAkey_Val;
}



//函数功能:LCD上显示键入值
void LCD_Proc(void)
{ //注:使用sprintf需要加"usart.h"
  sprintf((char*)pucStr, "  key number:%02d     ", key_number);
  LCD_DisplayStringLine(Line4, pucStr);
}


//函数功能:控制所有LED翻转
int ledall[8]={1 ,2 ,4, 8, 16, 32, 64 ,128  };
int i;
void ledAll_turn (void)
{
	i=ucAkey_Val;
if(ucLed == ledall[i-1])
		ucLed=0;
else
	ucLed = ledall[i-1];
  LED_Disp(ucLed);
}



// SysTick中断处理程序
void SysTick_Handler(void)
{
  ulTick_ms++;
}






完整工程下载>>GitHub

选择第7个工程

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值