【蓝桥杯嵌入式扩展板】ADC按键详解(附程序源码)

前期需要掌握知识

  1. ADC采集
  2. 一些简单的电路知识

一、实验须知

实验前连接 [A5->AKEY]
这里我还用到了数码管,因此连接了**[A1->SER][A2->RCK][A3->SCK]**
数码管,不再讲解,参考以前的文章

https://blog.csdn.net/qq_45689790/article/details/114106264

在这里插入图片描述

二、硬件原理图

在这里插入图片描述

三、程序

1、ADC相关

static void ADCx_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_APB2PeriphClockCmd(ADC_GPIO_CLK,ENABLE);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStruct.GPIO_Pin = ADC_GPIO_PIN;
	GPIO_Init(ADC_GPIO_PORT,&GPIO_InitStruct); 
}

static void ADCx_Config(void)
{
	ADC_InitTypeDef ADC_InitStruct;
	
	RCC_APB2PeriphClockCmd(ADC_CLK,ENABLE);
	
	ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStruct.ADC_NbrOfChannel = 1;
	ADC_InitStruct.ADC_ScanConvMode = DISABLE;
	ADC_Init(ADC_x,&ADC_InitStruct);
	
	//配置ADC时钟为PCLK2的8分频,即9MHz
	RCC_ADCCLKConfig(RCC_PCLK2_Div8); 
	
	ADC_RegularChannelConfig(ADC_x,ADC_Channelx,1,ADC_SampleTime_13Cycles5);
	
	ADC_Cmd(ADC_x,ENABLE);
	
	//初始化ADC 校准寄存器  
	ADC_ResetCalibration(ADC_x);
	//等待校准寄存器初始化完成
	while(ADC_GetResetCalibrationStatus(ADC_x));
	//ADC开始校准
	ADC_StartCalibration(ADC_x);
	//等待校准完成
	while(ADC_GetCalibrationStatus(ADC_x));
	ADC_SoftwareStartConvCmd(ADC_x,ENABLE);  //如果使能连续转换,那么直接软件触发一次转换即可
}

void ADCx_Init(void)
{
	ADCx_GPIO_Config();
	ADCx_Config();
}

uint16_t ADC_Read(void)
{
	uint16_t ADC_Value = 0;
	//ADC_SoftwareStartConvCmd(ADC_x,ENABLE);
	while(ADC_GetFlagStatus(ADC_x, ADC_FLAG_EOC) == RESET);
	ADC_Value = ADC_GetConversionValue(ADC_x);
	ADC_ClearFlag(ADC_x, ADC_FLAG_EOC);

	return ADC_Value;
}
}

“bsp_adc.h”

#ifndef _BSP_ADC_H
#define _BSP_ADC_H
#include "stm32f10x.h"

#define ADC_GPIO_PORT		GPIOA
#define ADC_GPIO_PIN		GPIO_Pin_5
#define ADC_GPIO_CLK		RCC_APB2Periph_GPIOA

#define ADC_x						ADC1
#define ADC_CLK					RCC_APB2Periph_ADC1
#define ADC_Channelx		ADC_Channel_5

void ADCx_Init(void);
uint16_t ADC_Read(void);
#endif /*_BSP_ADC_H*/

2、按键相关

static uint16_t btn_buff[BTN_BUFF_LEN];
//
uint16_t Read_Btn(void)
{
	//滤波函数
	u16 tmp = 0;
	u8 i = 0,j = 0;
	for(i=0; i<BTN_BUFF_LEN; i++){
		btn_buff[i] = ADC_Read();
	}
	
	for(i=0; i<BTN_BUFF_LEN; i++)//冒泡排序
	{
		for(j=0; j<	BTN_BUFF_LEN-i; j++)
		{
			if(btn_buff[j+1] < btn_buff[j]) //大的放后边
			{
				tmp = btn_buff[j+1];
				btn_buff[j+1] = btn_buff[j];
				btn_buff[j] = tmp;
			}
		}
	}
	if(BTN_BUFF_LEN % 2 == 0)
	{
		return(btn_buff[BTN_BUFF_LEN/2-1] + btn_buff[BTN_BUFF_LEN/2])/2;
	}else
	{
		return(btn_buff[BTN_BUFF_LEN/2]);
	}
}

uint8_t Scan_Btn(void)
{
	u16 btn_tmp = 0;

	btn_tmp = Read_Btn();
	if(btn_tmp < 0x0FFF/14){
		return 1;
	}else if((btn_tmp > 0x0FFF/14) && (btn_tmp < 0x0FFF/14*3)){
		return 2;
	}else if((btn_tmp > 0x0FFF/14*3) && (btn_tmp < 0x0FFF/14*5)){
		return 3;
	}else if((btn_tmp > 0x0FFF/14*5) && (btn_tmp < 0x0FFF/14*7)){
		return 4;
	}else if((btn_tmp > 0x0FFF/14*7) && (btn_tmp < 0x0FFF/14*9)){
		return 5;
	}else if((btn_tmp > 0x0FFF/14*9) && (btn_tmp<0x0C00)){//(btn_tmp < 0x0FFF/14*11))
		return 6;
	}else if((btn_tmp > 0x0C00) && (btn_tmp < 0X0D00)){
		return 7;
	}else if((btn_tmp > 0X0D00)&& (btn_tmp < 0x0FDF)) { //
		return 8;
	}
	else{
		return 0;	//error status & no key
	}
}

“bsp_button.h”

#ifndef _BSP_BUTTON_H
#define _BSP_BUTTON_H
#include "stm32f10x.h"
#define BTN_BUFF_LEN	50

uint16_t Read_Btn(void);
uint8_t Scan_Btn(void);
#endif /*_BSP_BUTTON_H*/

“main”

#include "stm32f10x.h"
#include "bsp_seg.h"
#include "lcd.h"
#include "bsp_adc.h"
#include "bsp_button.h"
#include <stdio.h>
u32 DelayTiming = 0;

void Delay_Ms(u32 nTime)
{
	DelayTiming = nTime;

	while(DelayTiming != 0);
}
char txt[20];

uint8_t key_val = 0;
int main(void)
{
	SysTick_Config(SystemCoreClock/1000);
	
	STM3210B_LCD_Init();
	LCD_Clear(White);
	STM3210B_LCD_Init();
	
	SEG_GPIO_Config();
	ADCx_Init();

	LCD_SetTextColor(White);
	LCD_SetBackColor(Blue);

	LCD_ClearLine(Line0);
	LCD_ClearLine(Line1);
	LCD_ClearLine(Line2);
	LCD_ClearLine(Line3);
	LCD_ClearLine(Line4);
	
	LCD_DisplayStringLine(Line1,(u8*)"    BUTTON DEMO     ");

	LCD_SetTextColor(Blue);
	LCD_SetBackColor(White);
	while(1)
	{
		sprintf(txt, "Button ADC:%04X", Read_Btn());
		LCD_DisplayStringLine(Line6,(uint8_t*)txt);
		
		key_val = Scan_Btn();
		
		if(key_val != 0)
		{
			SEG_Display(16, 16, key_val);
			sprintf(txt, "Button Value:%d", key_val);
			LCD_DisplayStringLine(Line7,(uint8_t*)txt);
		}
	}
	
}
  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
很抱歉,我无法点击复制并打开C知道体验页。不过我可以提供一份基于AT89C52单片机的ADC数据采集程序,可以通过Keil或其他编译器进行编译和烧录。 ```c #include <reg52.h> // 定义ADC输入端口 #define ADC_PORT P1 sbit ADC_CS = P3^7; // 定义ADC片选引脚 // 定义按键输入端口 sbit KEY_START = P2^0; // 开始采集按键 sbit KEY_STOP = P2^1; // 停止采集按键 // 定义定时器0参数 #define TIMER0_TH 0xFD #define TIMER0_TL 0x4B // 定义采样率 #define SAMPLE_RATE 1000 // 采样率1k // 定义全局变量 unsigned char adc_value; // 存储ADC采样值 unsigned char adc_flag; // ADC采样完成标志 unsigned char sampling_flag; // 采样标志,1表示正在采样,0表示停止采样 // 定义函数 void adc_init(); // ADC初始化函数 void timer0_init(); // 定时器0初始化函数 void start_sampling(); // 开始采样函数 void stop_sampling(); // 停止采样函数 void main() { adc_init(); // 初始化ADC timer0_init(); // 初始化定时器0 sampling_flag = 0; // 初始状态为停止采样 while (1) { // 判断开始采样按键是否按下 if (!KEY_START) { start_sampling(); // 开始采样 } // 判断停止采样按键是否按下 if (!KEY_STOP) { stop_sampling(); // 停止采样 } // 判断采样是否完成 if (adc_flag) { adc_flag = 0; // 清除ADC采样完成标志 // 将采样值通过串口输出或其他方处理 } } } void adc_init() { ADC_PORT = 0xFF; // 设置ADC输入端口为输入模 ADC_CS = 1; // 禁止ADC片选 } void timer0_init() { TMOD &= 0xF0; // 清除定时器0模位 TMOD |= 0x01; // 设置定时器0为模1 TH0 = TIMER0_TH; // 设置定时器0高字节 TL0 = TIMER0_TL; // 设置定时器0低字节 ET0 = 1; // 允许定时器0中断 EA = 1; // 允许总中断 TR0 = 1; // 启动定时器0 } void start_sampling() { if (!sampling_flag) // 如果当前不在采样状态 { TR0 = 0; // 停止定时器0 TH0 = TIMER0_TH; // 重新设置定时器0高字节 TL0 = TIMER0_TL; // 重新设置定时器0低字节 TR0 = 1; // 启动定时器0 sampling_flag = 1; // 标记为正在采样状态 } } void stop_sampling() { if (sampling_flag) // 如果当前正在采样 { TR0 = 0; // 停止定时器0 sampling_flag = 0; // 标记为停止采样状态 } } void timer0_isr() interrupt 1 { // 判断是否在采样状态 if (sampling_flag) { ADC_CS = 0; // 使能ADC片选 adc_value = ADC_PORT; // 读取ADC采样值 ADC_CS = 1; // 禁止ADC片选 adc_flag = 1; // 标记ADC采样完成 } } ``` 在程序中,我们使用P1口作为ADC输入端口,在P2口定义开始采集和停止采集的按键。定时器0的工作模为模1,计算公为: $$ T = \frac{1}{f_{osc}/12} \times 65536 $$ 其中,$f_{osc}$是单片机的振荡频率,一般为11.0592MHz,计算得到T为1ms。因此,定时器0每隔1ms会产生一次中断,用于触发ADC采样操作。 在程序中,我们使用sampling_flag来标记当前是否在采样状态。当按下开始采集按键时,会调用start_sampling()函数,该函数会将sampling_flag标记为1,表示正在采样。当定时器0中断触发时,会判断当前是否正在采样,如果是则执行ADC采样操作,并将ADC采样值保存在adc_value变量中,同时将adc_flag标记为1,表示ADC采样完成。当按下停止采集按键时,会调用stop_sampling()函数,该函数会将sampling_flag标记为0,表示停止采样。 在主循环中,会检测开始采集和停止采集按键是否按下,并执行相应的操作。同时,也会检测adc_flag是否为1,如果是则表示ADC采样完成,可以将采样值通过串口输出或其他方进行处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Successful 、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值