细说MCU的ADC模块单通道连续采样的实现方法

news/2024/7/23 11:07:26 标签: 单片机, 嵌入式硬件

 

目录

一、工程依赖的硬件及背景

二、设计目的

三、建立工程 

1、配置GPIO

2、选择时钟源和Debug

3、配置ADC

4、配置系统时钟和ADC时钟 

5、配置TIM3

6、配置串口

四、代码修改

1、重定义TIM3中断回调函数

2、启动ADC及重写其回调函数

3、定义用于存储转换结果的数组

4、重定义回调函数

5、在主程序中编写发送数据代码

6、在主程序初始化代码中使能ADC中断和TIM3中断

7、配置printf函数

五、运行并查看结果


        在单次测量的例子中,当每次操作按键B1后,都要重复进行启动ADC、等待转换,然后读换结果这些步骤。实际应用中,很多时候是让ADC连续进行采样。此时,可以使能ADC的连续转换。在此转换模式下,ADC完成一次转换后会开始新的转换。

一、工程依赖的硬件及背景

        文章依赖的硬件及工程配置参考本文作者的其他文章:细说MCU的ADC模块单通道单次采样的实现方法-CSDN博客文章浏览阅读1.1k次,点赞12次,收藏19次。由于希望在产生按键中断时,启动ADC采样,所以,需要重定义外部中断EXTI的回调函数。这个回调函数可以写在main.c文件后面的一个注释对中。https://wenchm.blog.csdn.net/article/details/139884221

二、设计目的

        信号源:通过TIM3连续产生PWM波形,并通过LD2(PA5)显示并输出。

        PA0为ADC1的信号输入,即把PA5的信号输出通过导线连接给PA0。

        USART2为串口输出。ADC1_IN1采集信号源输入,达到ADCSampleFlag==1时,开始通过串口发送数据到显示设备,直到发送数据完毕时,ADCSampleFlag==0;

        正常情况下:ADCSampleFlag==0时,ADC1开始采集数据到寄存器,直到达到SIZE的规模时,ADCSampleFlag==1;

        注意:本例只是为了演示相关功能,事实,信号源是连续的时候,两次ADC1的采集间隔中是存在漏采的情况的。

三、建立工程 

1、配置GPIO

        配置PA5为输出(GPIO_Output),默认输出电平Low,推挽输出,上拉,速度High,标识为LED;PA5引脚输出高电平时LD2点亮,默认的低电平时熄灭;

2、选择时钟源和Debug

        使用片外时钟晶体作为HSE的时钟源。在SYS中将Debug设置为Serial Wire。 

3、配置ADC

        选择Analog中的ADC1,在其模式(Mode)区,通道1(IN1)选择IN1 Single-ended(单端);其它参数设置可暂时均保持默认值。时钟预分频参数(Clock Prescaler)选择Asynchronous clock mode dividedby 1(其他选项亦可)。 

4、配置系统时钟和ADC时钟 

        将系统时钟(SYSCLK)频率配置为170 MHz,设置ADC1的时钟频率为42.5 MHz。

        设置ADC1的预分频参数为256,该参数将ADC1的时钟分频256倍,这个数值的选择与ADC1采样频率有关。

        使能ADC1的连续转换模式;

        在Rank下的采样时间选择为92.5个周期。这个参数决定着ADC的转换时间,则在12位分辨率时ADC1的转换时间为:92.5+12+0.5=105个ADC的时钟周期。 

        使能ADC1的中断;

        ADC中断优先级设置为1;

5、配置TIM3

        将Clock Source选择为内部时钟,

        将预分频因子和计数器周期分别设置为999,16999;

        TIM3中断优先级设置为1;

6、配置串口

        选择 Connectivity中的 USART2,其模式( Mode)选择异步( Asynchronous),其他参数设置均保持默认(波特率为115200 bit/ s),不开启中断。将 USART2的两个引脚 PA2和 PA3均设置为上拉。

四、代码修改

        打开main.c,修改代码。

1、重定义TIM3中断回调函数

        重定义 HAL_TIM_PeriodElapsedCallback(),在其中使PA5(LD2)的输出状态翻转。产生5Hz的信号源,修改预分频因子和计数器周期数值,可以改变信号源的频率。

/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
	ADC1ConvertedData[ADC1Data_index] = HAL_ADC_GetValue(&hadc1);
	if(ADCSampleFlag == 0)
		ADC1Data_index++;
	if(ADC1Data_index == ADC_CONVERTED_DATA_BUFFER_SIZE)
	{
		ADCSampleFlag = 1;
		ADC1Data_index = 0;
	}
}
//信号源
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
}
//串口打印
int __io_putchar(int ch)
{
	HAL_UART_Transmit(&huart2,(uint8_t *)&ch,1,0xFFFF);
	return ch;
}
/* USER CODE END 4 */

2、启动ADC及重写其回调函数

        关于ADC中断的使用,与外部中断、串口中断、定时器中断等的使用方法是类似的。关键点有两个:一是重写回调函数,二是在主程序初始化时开启中断

        ADC中断相关的回调函数可以用:

HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc);

        启动ADC中断的库函数为:

HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc);

3、定义用于存储转换结果的数组

        定义一个数组,用于存储A/D转换结果。每执行一次回调函数,就将此次A/D转结果存入数组,直到存满。随后,在主程序中,通过串口送出数组中存储的数据。为此,需要在主程序中定义几个变量(放到注释对中):

/* USER CODE BEGIN PV */
uint16_t ADC1ConvertedData[ADC_CONVERTED_DATA_BUFFER_SIZE]={0};
uint16_t ADC1Data_index =0;
uint8_t ADCSampleFlag =0;
/* USERCODE END PV */

        其中,数组长度ADC_CONVERTED_DATA_BUFFER_SIZE定义到main.h中

/* USER CODE BEGIN Private defines */
#define ADC_CONVERTED_DATA_BUFFER_SIZE (uint16_t) 65
/* USER CODE END Private defines */

4、重定义回调函数

        在main.c中定义回调函数HAL_ADC_ConvCpltCallback():

/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
	ADC1ConvertedData[ADC1Data_index] = HAL_ADC_GetValue(&hadc1);
	if(ADCSampleFlag == 0)
		ADC1Data_index++;
	if(ADC1Data_index == ADC_CONVERTED_DATA_BUFFER_SIZE)
	{
		ADCSampleFlag = 1;
		ADC1Data_index = 0;
	}
}
/* USER CODE END 4 */

5、在主程序中编写发送数据代码

        标志位变量ADCSampleFlag的作用:当数组存满后,该标志位置1,等待串口发送数组中的数据;一旦数据发送完毕,再将该变量赋值为0,继续更新数组中数将数据发送代码放到main函数中的while(1)循环中,实现代码如下: 

/* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	if(ADCSampleFlag == 1)
	 	{
	 		for(uint16_ti=1;i<ADC_CONVERTED_DATA_BUFFER_SIZE;i++)
	 		{
	 			printf("ADC1ConvertedData[%d] = %d\r\n",i,ADC1ConvertedData[i]);
	 		}
	 		ADCSampleFlag =0;
	 	}
	 	HAL_Delay(1000);
  }
  /* USER CODE END 3 */

6、在主程序初始化代码中使能ADC中断和TIM3中断

        将HAL_ADC_Start_IT()函数与HAL_ADCEx_Calibration_Start()函数放到while(1)之前,MX_ADC1_Init()之后的注释对中:

/* USER CODE BEGIN 2 */
  HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);
  HAL_ADC_Start_IT(&hadc1);
  HAL_TIM_Base_Start_IT(&htim3);
/* USER CODE END 2 */

7、配置printf函数

        在回调函数的最后,使用了 printf函数,将 A/ D转换的结果通过串口送出。

        使用 printf函数从串口送出数据,需要在 main.c中将 stdio.h包含进来;此外,还要给出 putchar函数的定义。

/* USER CODE BEGIN 4 */
int __io_putchar(int ch)
{
	HAL_UART_Transmit(&huart2,(uint8_t *)&ch,1,0xFFFF);
	return ch;
}
/* USER CODE END 4 */

五、运行并查看结果

        示波器采集到的信号源:

         串口接收到的数据:

 


http://www.niftyadmin.cn/n/5546409.html

相关文章

气象探测设备都有哪些设备?

气象探测设备&#xff0c;顾名思义&#xff0c;就是用于观测和测量气象要素的各种仪器和设备的总称。它们种类繁多&#xff0c;功能各异&#xff0c;但共同的目标都是为了获取准确的气象数据&#xff0c;为气象预报和气候研究提供有力支持。 在气象探测设备中&#xff0c;雷达是…

小型简易GIT服务器搭建和使用

搭建GIT服务器的文章有很多&#xff0c;多数在管理的时候都使用了gitosis作为管理工具&#xff0c;但是作为一个小团队(人数少于50人)&#xff0c;我觉得完全可以使用公钥验证的方式&#xff0c;这样会简单不少&#xff0c;下面来看看简易的搭建方法吧。 服务器版本:ubuntu 16…

量化机器人能否识别市场机会?

量化机器人的设计和应用是为了通过高级算法和大数据分析&#xff0c;精确地识别和把握市场中的交易机会。这些机器人的能力不仅仅局限于执行预定的交易策略&#xff0c;更包括在复杂和快速变化的市场环境中识别利润机会。 首先&#xff0c;量化机器人能够处理和分析大量的市场…

数据分析案例-2024 年全电动汽车数据集可视化分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

“爆炸性更新!JDK 17携全新语法特性强势来袭,开发者必看的升级亮点“(1)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;Java进化论 目录 背景 yield关键字 var关键字 空指针异常 密封类 接口中的私有方法 instanceof关键字 背景 Java 8 虽然曾经是使用…

java springboot监听事件和处理事件

在Spring Boot中&#xff0c;监听和处理事件是一种常用的模式&#xff0c;用于在应用程序的不同部分之间传递信息。Spring 的事件发布/订阅模型允许我们创建自定义事件&#xff0c;并在这些事件发生时由注册的监听器进行处理。这里&#xff0c;我将提供一个简单的Spring Boot应…

如何解决群晖Docker注册表查询失败/无法拉取镜像等问题

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 问题概述 📒📒 解决方案 📒🔖 方法一🔖 方法二🔖 方法三⚓️ 相关链接 🚓️📖 介绍 📖 在群晖(Synology)NAS设备上使用Docker时,我们可能会遇到查询Docker注册表失败,无法拉取Docker镜像的问题。这种情况…

【Dell R730 折腾记录】风扇调速--在 Ubuntu 系统上开机自启动并每隔30分钟执行一次风扇定速脚本

前段时间升级了一下机柜里的服务器&#xff0c;替换掉了一台旧的 Dell 服务器&#xff0c;换上了这台 R730。但是无奈于噪音的袭扰&#xff0c;搁置了一段时间。我在这台机器上目前安装了一块 Intel Xeon E5-2630v3 芯片以及一张改过散热的 NVIDIA Tesla P4 计算卡。结果就是散…