【STM32嵌入式系统设计与开发】第17讲:ADC按键应用

这里写目录标题

  • STM32资料包: 百度网盘下载链接:链接:https://pan.baidu.com/s/1mWx9Asaipk-2z9HY17wYXQ?pwd=8888 提取码:8888
  • 一、任务描述
  • 二、任务实施
  • 1、工程文件夹创建
  • 2、函数编辑
  • (1)主函数编辑
  • (2)ADC模拟数字转化函数()
  • (3)获得ADC值函数(Get_Adc())
  • (4)获得ADC的平均值函数(Get_Adc_Average())
  • (5)ADC按键初始化函数(AdKeyScan())
  • 3、头文件添加
  • 4、头文件编辑
  • 4、知识链接
  • (1)ADC框图理解
  • (2)按键原理
  • 5、工程测试

  • 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、工程测试

    作者:iot鑫鹏

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【STM32嵌入式系统设计与开发】第17讲:ADC按键应用

    发表回复