【STM32嵌入式系统设计与开发】——17ADC(ADC按键应用)

发布于:2024-04-12 ⋅ 阅读:(72) ⋅ 点赞:(0)


STM32资料包:
百度网盘下载链接:链接:https://pan.baidu.com/s/1mWx9Asaipk-2z9HY17wYXQ?pwd=8888
提取码:8888

一、任务描述

在这里插入图片描述

二、任务实施

观察电路图:
TXD(底板) ————————> PA10
RXD(底板) ————————> PA9
AD按键端口(底板) ————————> PA1
通过 ADC 采样获取按键的状态,根据采样值判断按键是否被按下,并返回对应的按键编号(ADKEY_AK1、ADKEY_AK2、ADKEY_AK3、ADKEY_AK4)或者无按键情况(ADKEY_NO),并打印在串口助手中
在这里插入图片描述

1、工程文件夹创建

步骤1:复制工程模板“1_Template”重命名为“14_ADC”。
在这里插入图片描述
步骤2:修改项目工程名,先删除projects文件夹内除了Template.uvprojx文件外的所有内容并修改为“ADC.uvprojx”。并删除output/obj和output/lst中的所有文件。
在这里插入图片描述
步骤3:运行“PassiveBeep.uvprojx”打开目标选项“Options for Target”中的“Output”输出文件,并修改可执行文件名称为“ADC”点击“OK”保存设置。最后点击“Rebuild”编译该工程生成Usart文件。
在这里插入图片描述
步骤4:复制2_LEDTest中的"1_LED"和文件复制到hardware中。
在这里插入图片描述
步骤5:在system文件夹中新建一个adc文件夹并在该文件夹下新建adc.c和adc.h两个文件。
在这里插入图片描述
步骤6:工程组文件中添加“1_LED”和“2_ADCKEY”文件夹内的所有文件。
在这里插入图片描述
步骤7:工程组文件中添加“adc”文件夹内的所有文件。
在这里插入图片描述
步骤6:目标选项添加添加头文件路径。
在这里插入图片描述

2、函数编辑

(1)主函数编辑

基于STM32的检测定时器超时状态并翻转LED的状态,同时检测AD按键状态并输出按下的按键编号到串口。
请添加图片描述
步骤2:循环函数编写

while(1) // 进入无限循环
{	
	if(WaitTimerOut(3))                  // 如果等待计时器超时(3秒)
		LED = !LED;                      // 切换 LED 的状态(取反)
	
	temp = AdKeyScan();                  // 读取 AD 按键的状态
	if(temp)                             // 如果检测到按键按下(按键值不为0)
		printf("AK%d被按下!\r\n", temp); // 打印按下的按键编号
}	

在这里插入图片描述

(2)ADC模拟数字转化函数()

步骤1:初始化ADC

/*********************************************************************
 @Function  : 初始化ADC
 @Parameter : N/A
 @Return    : N/A
**********************************************************************/
void Adc_Init(void)
{ 
	/*初始化结构体*/
	ADC_InitTypeDef ADC_InitStructure;                                  // 定义 ADC 初始化结构体
	GPIO_InitTypeDef GPIO_InitStructure;                                // 定义 GPIO 初始化结构体
		
	/* 时钟使能 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);	

	/* 设置ADC分频因子 */
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);                                   // 将ADC时钟设置为PCLK2的1/6,此处PCLK2为72MHz,分频后为12MHz
		
	/* 引脚配置 */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;                           // 配置PA1为ADC输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                       // 模拟输入模式
	GPIO_Init(GPIOA, &GPIO_InitStructure);                              // 初始化GPIOA	

	/* 复位ADC1 */
	ADC_DeInit(ADC1);  
		
	/* ADC配置 */
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                  // 独立模式,单独使用ADC1
	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;                             // 转换通道数量为1
	ADC_Init(ADC1, &ADC_InitStructure);                                 // 初始化ADC1
		
	/* 使能ADC */
	ADC_Cmd(ADC1, ENABLE);

	/* 复位校准 */
	ADC_ResetCalibration(ADC1);
	while (ADC_GetResetCalibrationStatus(ADC1));                        // 等待复位校准结束

	/* 开始校准 */
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1));                             // 等待校准结束

	/* 使能软件转换启动功能(可根据需要启用) */
	// ADC_SoftwareStartConvCmd(ADC1, ENABLE);	

}

在这里插入图片描述

(3)获得ADC值函数(Get_Adc())

/*********************************************************************
 @Function  : 获得ADC值
 @Parameter : ch : 通道值 0~3
 @Return    : ADC值
**********************************************************************/
uint16_t Get_Adc(uint8_t ch)   
{
	/*设置指定ADC的规则组通道,一个序列,采样时间*/
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );	//ADC1,ADC通道,采样时间为239.5周期	  
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		                        //使能指定的ADC1的软件转换启动功能
	
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));                     //等待转换结束

	return ADC_GetConversionValue(ADC1);	                            //返回最近一次ADC1规则组的转换结果
	
}

在这里插入图片描述

(4)获得ADC的平均值函数(Get_Adc_Average())

/*********************************************************************
 @Function  : 获得ADC的平均值
 @Parameter : ch : 通道值 0~3
						  times :采集次数
 @Return    : ADC平均值
**********************************************************************/
uint16_t Get_Adc_Average(uint8_t ch, uint8_t times)
{

	uint32_t temp_val = 0;      // 初始化累加变量为0
	uint8_t t;                  // 循环计数变量

	for (t = 0; t < times; t++) // 循环执行指定次数
	{
		temp_val += Get_Adc(ch);  // 获取指定通道的ADC值并累加到temp_val
		delay_ms(5);              // 延时5毫秒,等待下一次采样		
	}
	return temp_val / times;    // 返回ADC采样值的平均值

}

在这里插入图片描述

(5)ADC按键初始化函数(AdKeyScan())


/*********************************************************************
 @Function  : AD按键初始化
 @Parameter : N/A
 @Return    : N/A
**********************************************************************/
uint8_t AdKeyScan(void)
{
	uint16_t adcx; // 定义ADC采样值变量adcx
	/* 读取ADC */
  adcx = Get_Adc_Average(ADC_Channel_1, 10);         // 读取ADC通道1的平均值,采样次数为10次
	
	/* 键值判断 */
	if (adcx > 500)                                  // 如果ADC值大于500
	{
		if ((adcx > 3500) && (adcx < 4200))
				return ADKEY_AK1;                    // 返回ADKEY_AK1,表示检测到按键1被按下

		if ((adcx > 2500) && (adcx < 3200))
				return ADKEY_AK2;                    // 返回ADKEY_AK2,表示检测到按键2被按下

		if ((adcx > 1500) && (adcx < 2200))
				return ADKEY_AK3;                    // 返回ADKEY_AK3,表示检测到按键3被按下

		if ((adcx > 800) && (adcx < 1200))
				return ADKEY_AK4;                    // 返回ADKEY_AK4,表示检测到按键4被按下
	}

}

在这里插入图片描述

3、头文件添加

步骤1:adc所需头文件添加

#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_adc.h"
#include ".\adc\adc.h"
#include ".\delay\delay.h"

在这里插入图片描述
步骤2:添加adckey源文件所需的头文件

#include "stm32f10x_adc.h"
#include ".\adc\adc.h"
#include "adckey.h"

在这里插入图片描述
步骤3:函数声明

	uint32_t temp=0;
	delay_init();                   //启动滴答定时器
    usart1_init(9600);              //USART1初始化
	SystemTinerInit(1000-1,3600-1); //系统时间初始化 定时100ms
    AdKeyInit();                    //AD按键初始化	

在这里插入图片描述

4、头文件编辑

//bord.h
#ifndef __BORD_H_
#define __BORD_H_
#include "system_config.h"

//头文件包含
/*************SYSTEM*****************/
/*#include ".\sys\sys.h"*/
#include ".\delay\delay.h"
#include ".\usart\usart.h"
#include ".\timer\timer.h"
#include ".\adc\adc.h"

/***********Hardweare***************/
#include "led.h"
#include "adckey.h"

/***********Funlibrary***************/





#endif

在这里插入图片描述

步骤2:添加函数声明

//adc.h
#ifndef __ADC_H_
#define __ADC_H_	
#include <stdint.h>

/*函数声明*/
void Adc_Init(void);
uint16_t Get_Adc(uint8_t ch); 
uint16_t Get_Adc_Average(uint8_t ch,uint8_t times); 


#endif

在这里插入图片描述

步骤2:添加中断源文件所需的头文件

//adckey.h
#ifndef __ADKEY_H_
#define __ADKEY_H_	

#include <stdint.h> 

//AD键值枚举
enum ADkey 
{
  ADKEY_NO=0,
	ADKEY_AK1,
	ADKEY_AK2,
	ADKEY_AK3,
	ADKEY_AK4
};

/*函数声明*/
void AdKeyInit(void);
uint8_t AdKeyScan(void);

#endif

在这里插入图片描述

4、知识链接

(1)ADC框图理解

在这里插入图片描述
ADC引脚:
ADC 框图中的引脚用于连接外部模拟信号。通常有一个或多个引脚作为模拟输入,将待转换的模拟信号输入给 ADC。此外,可能还有其他引脚用于控制、时钟输入和数字输出。

ADC输入通道:
ADC 输入通道是连接到 ADC 的引脚,用于接收模拟信号。每个输入通道对应一个物理引脚或者电路连接,可以选择不同的通道来进行模拟信号的采集和转换。

规则通道组和注入通道组:

规则通道组和注入通道组是 ADC 中用于管理转换通道的组织方式。
规则通道组用于常规的模拟输入信号转换,可以选择一个或多个通道进行顺序转换。
注入通道组允许在常规转换中插入一个或多个优先级更高的转换(例如紧急事件处理),通常用于特殊需求或优先级较高的采样。
触发源:
ADC 可以通过不同的触发源启动转换。触发源可以是软件触发(通过编程触发)、定时器触发(定时器计数到特定值触发)、外部触发(外部引脚触发)等。选择合适的触发源可以灵活控制 ADC 的转换时机。

转换时间:
转换时间是 ADC 完成一次模拟到数字转换所需的时间。这个时间取决于 ADC 的工作模式、时钟频率以及转换精度等因素。在设计中需要考虑转换时间来确定系统的响应速度和性能。

数据寄存器:
转换完成后,ADC 将数字化的采样值存储在数据寄存器中。系统可以通过读取数据寄存器来获取 ADC 的转换结果,进而进行后续的数据处理和分析。

中断:
ADC 可以通过中断来提醒系统转换完成或者出现特定的转换事件。通过配置中断使能和中断优先级,可以实现在转换完成后自动触发特定的处理程序,提高系统的实时性和效率。

(2)按键原理

在这里插入图片描述
基本原理是利用电阻分压的方式,通过按下不同的按键改变电路中的电压值,然后使用 ADC(模数转换器)引脚对这些电压进行采集。采集到的电压值随后用于判断按下了哪个按键,从而实现按键功能。

5、工程测试

在这里插入图片描述