这里写目录标题
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(模数转换器)引脚对这些电压进行采集。采集到的电压值随后用于判断按下了哪个按键,从而实现按键功能。