首页 > 其他分享 >STM32&ADC

STM32&ADC

时间:2024-08-07 23:26:54浏览次数:13  
标签:DMA HAL Init STM32 init ADC adc

ADC简介:有打moba游戏的别搞混了,这不是射手adc。在32中,ADC的全称为:Analog-to-Digital Converter,指模拟/数字转换器 也就是模拟-数字电路的转换器。其实通俗的来讲,它就是一个电压表

目录

一.ADC原理

1.ADC框图

2.通道

3.规则组/注入组&转换顺序

4.转换触发

5.周期 

6.转换模式

7.校验 

二.配置

1.ADC基本配置流程(代码)

2.进阶用法:ADC与DMA结合使用

好了,祝你看完就会。


一.ADC原理

1.ADC框图

重点看红框内部的结构就行了,通过接触GPIO来将外接设备的模拟电压进行转换,变为数字逻辑电平,这就是它的主要功能。

2.通道

再经典不过的东西,TIM,DMA都有的东西。功能也和它们差不多,这里对应的自然就是GPIO。不同的通道固定只能监听固定的GPIO口。

这里唯一不同的点就是不同的ADC(比如ADC1和ADC2)同时监听PA0口并不会像其他外设一样出问题,完全可以同时监听(但本质上是间歇性监听,就是不断轮番监听)。另外一般在应用场景中ADC是要同时监听多个通道的。

3.规则组/注入组&转换顺序

规则组:如果把ADC看作一个测量电压的机器,那么规则组就是他的流水线。其上面按Rank摆放着一组通道(GPIO口),ADC就依次测量并且把数据放在寄存器中。

注入组:很简单,注入组看作中断执行的流水线即可。(假设正在执行规则组此时进来一组注入组则优先执行完注入组再回过头执行规则组。

转换顺序:由三个寄存器控制,看一眼图就行。

4.转换触发

大体来说其实就是硬件自动触发还是软件控制触发:

可以看到要么就是各种定时器或者外部中断触发要么就是软件触发。一般还是软件触发用的比较多也比较方便。

5.周期 

首先ADC的是中原是PCLK,他的时钟源不能超过14Mhz。再应用中,通过选择采集时间来控制对应的周期:

采样时间随箭头增长。

6.转换模式

主要分为三种:
扫描模式:只循环测量规则组的第一个(不论组里配置了几个通道)
循环模式:测量完后继续从头重复测量
间歇模式:不用。
另外,当哪一种模式都不配置的时候,它就变为普通模式,就是你触发它一次它测量一次:

7.校验 

这个看起来可有可无的东西其实再最终结果中产生的影响还是蛮大的:
1.一定要校验,否则电压测量会有约0.05的误差
2.必须再初始化后进行,不然数据特别不正常。(别问问就是作者吃过瘪了)

二.配置

1.ADC基本配置流程(代码)

ADC的流程和其他基本外设配置的流程也极度相似:

ADC基本初始化(数据对齐;搬运模式;转换触发)HAL_ADC_Init()        
                                |
通道配置(通道选择;测量时间;规则通道Rank选择)HAL_ADC_ConfigChannel()
                                |
               校验 HAL_ADCEx_Calibration_Start()
                                |
经典Msp配置(对应GPIO口配置;时钟使能;分频数选择;对应IO口时钟来源)HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
                                |
                  软件触发  HAL_ADC_Start(&adc_init);
                                |
     等待测量结束返回对应值  HAL_ADC_PollForConversion(&adc_init,10);

#include "adc.h"

ADC_HandleTypeDef adc_init = {0};
ADC_ChannelConfTypeDef adc_channel_init = {0};
void ADC_INIT(){
	//ADC基本模式配置
	adc_init.Instance = ADC1;
	adc_init.Init.ContinuousConvMode = DISABLE;				//连续转变模式配置
	adc_init.Init.DiscontinuousConvMode = DISABLE;			//间断转变模式配置
	adc_init.Init.DataAlign = ADC_DATAALIGN_RIGHT;			//测得数据对齐模式
	adc_init.Init.ExternalTrigConv = ADC_SOFTWARE_START;	//触发模式
	adc_init.Init.NbrOfConversion = 1;						//转变数量
	adc_init.Init.NbrOfDiscConversion = 0;					//间断模式转变量
	adc_init.Init.ScanConvMode = DISABLE;					//扫描模式
	//ADC通道配置
	adc_channel_init.Channel = ADC_CHANNEL_1;					//通道选择
	adc_channel_init.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;	//测量时间
	adc_channel_init.Rank = ADC_REGULAR_RANK_1;					//规则通道位置配置
						
	HAL_ADC_Init(&adc_init);
	HAL_ADC_ConfigChannel(&adc_init,&adc_channel_init);
	HAL_ADCEx_Calibration_Start(&adc_init);						//校验,否则电压测量会有约

}

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc){
	if(hadc->Instance == ADC1){
		__HAL_RCC_ADC1_CLK_ENABLE();
		__HAL_RCC_GPIOA_CLK_ENABLE();
		
		GPIO_InitTypeDef gpio_init;
		gpio_init.Mode = GPIO_MODE_ANALOG;
		gpio_init.Pin = GPIO_PIN_1;
		//ADC时钟配置
		RCC_PeriphCLKInitTypeDef PeriphClkInit;
		PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;		//ADC时钟分频
		PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;		//外设时钟选择
		
		HAL_GPIO_Init(GPIOA,&gpio_init);
		HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);	
	}
}

uint32_t value_get(){
	HAL_ADC_Start(&adc_init);					//软件启动转换
	HAL_ADC_PollForConversion(&adc_init,10);	//等待转换结束
	return (uint16_t)HAL_ADC_GetValue(&adc_init);			//返回

}

2.进阶用法:ADC与DMA结合使用

 流程和上面基本一样,只是有以下区别:
1.转换模式调为循环模式                              adc_init.Init.ContinuousConvMode = ENABLE;
2.通道初始化需要同时初始化多个                adc_channel_init.Channel = ADC_CHANNEL_2;
3.ADC初始化转化数量需要更改                           adc_init.Init.NbrOfConversion = 2 
4.Msp引脚初始化需要增加                      gpio_init.Pin = GPIO_PIN_1|GPIO_PIN_2;
5.数据对齐方式需要更改                        

dma_init.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
这个对齐方式是位了对应ADC的精度,配合后续传输和返回值的处理,后面会详细解释。

ADC部分:

#include "adc.h"

ADC_HandleTypeDef adc_init = {0};
ADC_ChannelConfTypeDef adc_channel_init = {0};
void ADC_INIT(){
	//ADC基本模式配置
	adc_init.Instance = ADC1;
	adc_init.Init.ContinuousConvMode = ENABLE;				//连续转变模式配置
	adc_init.Init.DiscontinuousConvMode = DISABLE;			//间断转变模式配置
	adc_init.Init.ScanConvMode = DISABLE;					//扫描模式配置
	adc_init.Init.DataAlign = ADC_DATAALIGN_RIGHT;			//测得数据对齐模式
	adc_init.Init.ExternalTrigConv = ADC_SOFTWARE_START;	//触发模式
	adc_init.Init.NbrOfConversion = 2;					//转变数量
	adc_init.Init.NbrOfDiscConversion = 0;					//间断模式转变量
					//扫描模式
	//ADC通道配置
	adc_channel_init.Channel = ADC_CHANNEL_1;					//通道选择
	adc_channel_init.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;	//测量时间
	adc_channel_init.Rank = ADC_REGULAR_RANK_1;					//规则通道位置配置
							
	HAL_ADC_Init(&adc_init);	
	HAL_ADC_ConfigChannel(&adc_init,&adc_channel_init);
	
	adc_channel_init.Channel = ADC_CHANNEL_2;					//通道选择
	adc_channel_init.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;	//测量时间
	adc_channel_init.Rank = ADC_REGULAR_RANK_2;					//规则通道位置配置
	
	HAL_ADC_ConfigChannel(&adc_init,&adc_channel_init);
	
	HAL_ADCEx_Calibration_Start(&adc_init);					//校验,否则电压测量会有约0.05的误差
																//注意: 

}

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc){
	if(hadc->Instance == ADC1){
		__HAL_RCC_ADC1_CLK_ENABLE();
		__HAL_RCC_GPIOA_CLK_ENABLE();
		
		GPIO_InitTypeDef gpio_init;
		gpio_init.Mode = GPIO_MODE_ANALOG;
		gpio_init.Pin = GPIO_PIN_1|GPIO_PIN_2;
		
		//ADC时钟配置
		RCC_PeriphCLKInitTypeDef PeriphClkInit;
		PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;		//ADC时钟分频
		PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;		//外设时钟选择
		
		HAL_GPIO_Init(GPIOA,&gpio_init);
		HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
	
	}
}

DMA的配置则并不难,不多赘述,上代码:

#include "dma.h"

DMA_HandleTypeDef dma_init = {0};
extern ADC_HandleTypeDef adc_init;
void DMA_INIT(){
	__HAL_RCC_DMA1_CLK_ENABLE();	
	dma_init.Instance = DMA1_Channel1;	
	dma_init.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;		//千万千万千万注意,M和P千万千万不能对应错啊	
	dma_init.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;	
	dma_init.Init.MemInc = DMA_MINC_ENABLE;			//内存递增使能
	dma_init.Init.PeriphInc = DMA_PINC_DISABLE;
	dma_init.Init.Direction = DMA_PERIPH_TO_MEMORY;	
	dma_init.Init.Priority = DMA_PRIORITY_MEDIUM;
	dma_init.Init.Mode = DMA_CIRCULAR;		//循环模式
	HAL_DMA_Init(&dma_init);
	__HAL_LINKDMA(&adc_init,DMA_Handle,dma_init);
}

最后主函数:

这里唯一要讲的地方就是红框内的部分,你很有可能会问:为什么不干脆定义成uint32还非要等返回接收的时候进行强转呢?
原因很简单,但不知道就很难。 首先主要是由于区别之一的字节对齐问题,ADC的精度是12位,按照字节对齐则正好占两个字节也就是uint16。但ADC的DMA地址是连续的,也就是如果该数据超过这一字节那么就把下个字节也拿来用了。所以如果一开始你就用uint32,那么一个缓存中就会存入两个通道的数据。像这样:

好了,祝你看完就会。

标签:DMA,HAL,Init,STM32,init,ADC,adc
From: https://blog.csdn.net/wwwkkkxxx12138/article/details/140871756

相关文章

  • STM32F407 UART
    //串口(UART)------------------------://1.同步:      步调一致,两个设备之间的通信速度相同//2.异步:      步调不一致,两个设备之间的通信速度不相同//总结:      同步通信:有时钟线连接,并且时钟线可以控制两个设备之间的速度,让速度保持一致    ......
  • STM32F407 SysTick
    //定时器分类:   内核定时器(系统滴答定时器):      延时、定时中断、给操作系统提供时基   基本定时器:      延时、定时中断、时间片   通用定时器:      延时、定时中断、输出比较(PWM)、输入捕获(捕获高/低电平时间、红外信号解码(解NEC......
  • STM32F407 GPIO
    //单片机:   是典型的嵌入式微控制器,英文MCU;是一种集成电路芯片,采用超大规模集成电路技术把FPU,RAM,ROM,I/O口中断系统,定时器计数器等功能集成到一块硅片上,构成的小而完善的计算机系统。//中央处理器(FPU)(168MHz)//随机存储器(RAM)//只读存储器(ROM)//定时器:   重要  ......
  • 关注STM32巡回研讨会,领取NUCLEO boards开发板
    2024年9月3日-13日,万象奥科将携手STM32走进11座城市,共启2024全国巡回研讨会!今年的巡回研讨会以“STM32,不止于芯”为主题,向蝶粉分享近期上市的STM32新品,与大家探讨STM32在智能工业、无线连接边缘A1、安全、图形用户界面等领域如何赋能新质生产力!图1STM32全国巡回研讨会作为STM......
  • NumPy 广播(Broadcast)
    广播(Broadcast)是numpy对不同形状(shape)的数组进行数值计算处理的一种机制,对数组的算术运算通常在相应的元素上进行。#若两个数组a,b形状相同,即a.shape==b.shape——两个数组对应位相乘(其他运算符也行)importnumpyasnpa1=np.array([1,2,3,4])b1=np.arr......
  • STM32学习记录(八):DMA
    什么是DMA?DMA在之前的学习中已经用过了。那么,什么是DMA?Directmemoryaccess(DMA)isusedinordertoprovidehigh-speeddatatransferbetweenperipheralsandmemoryaswellasmemorytomemory.DatacanbequicklymovedbyDMAwithoutanyCPUactions.This......
  • 基于STM32的智能灌溉系统
    目录引言环境准备工作硬件准备软件安装与配置系统设计系统架构硬件连接代码实现初始化代码传感器读取和控制代码应用场景农业灌溉花园自动灌溉常见问题及解决方案常见问题解决方案结论1.引言智能灌溉系统通过实时监测土壤湿度和环境温度,自动控制灌溉设......
  • (CubeIDE/CubeMX STM32引脚布局)将配置的引脚转移到其它引脚
            新建了项目,配置好引脚,但是想将原先的配置换到别的引脚上,我教大家一个方法。    这里以STM32F103芯片为例,其它芯片也同样适用,先打开工程,如下图所示。     假设我现在想使用PA7点灯,但是现在PA7被SPI1占用了,那我们需要知道还有没有其它引脚可......
  • STM32启动文件,在启动文件中理解IAP
    ;********************(C)COPYRIGHT2017STMicroelectronics********************;*FileName:startup_stm32f103xe.s;*Author:MCDApplicationTeam;*Description:STM32F103xEDevicesvectortableforMDK-ARMtoolchain.;*......
  • Android 广播 Broadcast Receiver
    广播(Broadcast)是Android中的一种机制,允许应用程序之间传递消息。广播在Android中扮演着重要角色,能够在不同的组件间传递信息,无论是应用内部还是跨应用。下面我将详细解释广播的机制,并提供几个示例,按照难度逐步增加。广播机制详细解释1.广播的基本概念广播允许应用程序在系统中......