采用STM32CubeMX和HAL库的模数转换器应用实例

ops/2024/11/1 11:11:54/

目录

STM32的ADC配置流程

模/数(A/D)转换器应用的硬件设计

模/数(A/D)转换器应用的软件设计

1. 通过STM32CubeMX新建工程

2. 通过Keil MDK实现工程


STM32的ADC功能繁多,比较基础实用的是单通道采集,实现开发板上电位器的动触点输出引脚电压的采集,并通过串口输出至PC端串口调试助手。单通道采集适用AD转换完成中断,在中断服务函数中读取数据,不使用DMA传输,在多通道采集时才使用DMA传输。

STM32的ADC配置流程

STM32的ADC功能较多,可以DMA、中断等方式进行数据的传输,结合标准库并根据实际需要,按步骤进行配置,可以大大提高ADC的使用效率。 使用ADC1的通道1进行AD转换,这里需要说明一下,使用到的库函数分布在stm32f1xx_adc.c文件和stm32f1xx_adc.h文件中。下面讲解其详细设置步骤:

(1)开启PA口时钟和ADC1时钟,设置PA1为模拟输入。 STM32F103ZET6的ADC通道1在PA1上,所以,先要使能PORTA的时钟,然后设PA1为模拟输入。同时要把PA1复用为ADC,所以要使能ADC1时钟。使能GPIOA时钟和ADC1时钟都很简单,具体方法为:

__HAL_RCC_ADC1_CLK_ENABLE();//使能ADC1时钟
__HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIOA时钟
初始化PA1为模拟输入,关键代码为:
GPIO_InitTypeDef GPIO_Initure;	
GPIO_Initure.Pin=GPIO_PIN_1;	                   //PA1
GPIO_Initure.Mode=GPIO_MODE_ANALOG;   //模拟
GPIO_Initure.Pull=GPIO_NOPULL;          	//不带上下拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);

(2)初始化 ADC,设置 ADC 时钟分频系数,分辨率,模式,扫描方式,对齐方式等信息。 在HAL库中,初始化ADC是通过函数HAL_ADC_Init实现的,该函数声明为: HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef* hadc); 该函数只有一个入口参数 hadc,为ADC_HandleTypeDef结构体指针类型,结构体定义为:

typedef struct
{
ADC_TypeDef	                      *Instance;//ADC1/ ADC2/ ADC3
ADC_InitTypeDef	            Init;//初始化结构体变量
DMA_HandleTypeDef	            *DMA_Handle; //DMA 方式使用
HAL_LockTypeDef                              Lock;
__IO HAL_ADC_StateTypeDef          State;
__IO uint32_t	                                   ErrorCode;
}ADC  HandleTypeDef;	
该结构体定义和其他外设比较类似,我着重看第二个成员变量Init含义,它是结构体ADC_InitTypeDef类型,结构体ADC_InitTypeDef定义为:
typedef struct
{
uint32_t  DataAlign;//对齐方式:左对齐还是右对齐:ADC_DATAALIGN_RIGHT
uint32_t  ScanConvMode;//扫描模式DISABLE
uint32_t  ContinuousConvMode;//开启连续转换模式或者单次转换模式 DISABLE
uint32_t  NbrOfConversion; //规则序列中有多少个转换1
uint32_t  DiscontinuousConvMode;//不连续采样模式DISABLE
uint32_t  NbrOfDiscConversion;//不连续采样通道数
uint32_t  ExternalTrigConv;//外部触发方式ADC_SOFTWARE_START}ADC_InitTypeDef;

直接把每个成员变量含义注释在结构体定义的后面,请大家仔细阅读上面注释。 这里需要说明一下,和其他外设一样,HAL 库同样提供了 ADC 的 MSP 初始化函数,一般情况下,时钟使能和 GPIO 初始化都会放在MSP初始化函数中。函数声明为: void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc);

(3)开启 AD 转换器。 在设置完了以上信息后,就开启AD转换器了(通过ADC_CR2寄存器控制)。 HAL_ADC_Start(&ADC1_Handler);//开启ADC

(4)配置通道,读取通道 ADC 值。 在上面的步骤完成后,ADC就算准备好了。接下来要做的就是设置规则序列1里面的通道,然后启动ADC转换。在转换结束后,读取转换结果值值就是了。 设置规则序列通道以及采样周期的函数是: HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef* hadc,ADC_ChannelConfTypeDef* sConfig);

该函数有两个入口参数,第一个就不用多说了,接下来看第二个入口参数 sConfig,它ADC_ChannelConfTypeDef 结构体指针类型,结构体定义如下:

typedef struct {  

uint32_t  Channel;//ADC 通道

uint32_t  Rank;    //规则通道中的第几个转换

uint32_t  SamplingTime;    //采样时间

}ADC_ChannelConfTypeDef;

该结构体有四个成员变量,对于 STM32F1 只用到前面三个。Channel 用来设置 ADC 通道, Rank 用来设置要配置的通道是规则序列中的第几个转换,SamplingTime 用来设置采样时间。

使用实例为:     ADC1_ChanConf.Channel=ch;    //通道 ADC1_ChanConf.Rank=1;    //第 1 个序列,序列 1 ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_239CYCLES_5;    //采样时间 HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf);    //通道配置 配置好通道并且使能ADC后,接下来就是读取 ADC 值。这里采取的是查询方式读取,所以还要等待上一次转换结束。此过程HAL库提供了专用函数HAL_ADC_PollForConversion,函数定义为:

HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout); 等待上一次转换结束之后,接下来就是读取 ADC 值,函数为: uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc);

模/数(A/D)转换器应用的硬件设计

开发板板载一个贴片滑动变阻器,电路设计如图11-9所示。 贴片滑动变阻器的动触点连接至STM32芯片的ADC通道引脚。当我们使用旋转滑动变阻器调节旋钮时,其动触点电压也会随之改变,电压变化范围为0~3.3V,亦是开发板默认的ADC电压采集范围。

模/数(A/D)转换器应用的软件设计

ADC_InitTypeDef结构体成员用于设置ADC工作参数,并由外设初始化配置函数,比如MX_ADC1_Init()调用,这些设定参数将会设置外设相应的寄存器,达到配置外设工作环境的目的。初始化结构体定义在stm32f1xx_hal_adc.h文件中,初始化库函数定义在stm32f1xx_hal_adc.c文件中,编程时可以结合这两个文件内注释使用。

ADC_InitTypeDef结构体如下。
typedef struct
{
uint32_t DataAlign; // ADC 数据寄存器对齐格式
FunctionalState ScanConvMode; /* ADC 扫描(多通道)
FunctionalState ContinuousConvMode; // ADC 单次转换或者连续转换选择
uint32_t NbrOfConversion; // ADC 工作模式选择
FunctionalState DiscontinuousConvMode; // ADC 单次转换或者连续转换选择
Uint32_t NbrOfDiscConversion; // ADC 采集通道数
uint32_t ExternalTrigConv; // ADC 转换触发信号选择
} ADC_InitTypeDef;

这些结构体成员说明如下,其中括号内的文字是对应参数在STM32 HAL库中定义的宏:

(1)DataAlign:转换结果数据对齐模式,可选右对齐ADC_DataAlign_Right或者左对齐ADC_DataAlign_Left。一般选择右对齐模式。

(2)ScanConvMode:可选参数为ENABLE和DISABLE,配置是否使用扫描。如果是单通道AD转换使用DISABLE,如果是多通道AD转换使用ENABLE。

(3)ContinuousConvMode:指定是以单一模式(一次转换)还是以常规组的连续模式执行转换,在所选触发发生之后(软件启动或外部触发)。此参数可设置为ENABLE(启用)或DISABLE(禁用)。

(4)NbrOfConversion:指定将在常规组序列器中转换的列组数。要使用常规组序列器并转换多个列组,必须启用参数“ScanConvMode”。此参数必须是介于Min_Data=1和Max_Data=16之间的数字。

(5)DiscontiousConvMode:指定是否按完整序列/不连续序列(主序列细分为连续部分)执行常规组的转换序列。仅当序列器已启用(参数“ScanConvMode”)时,才使用不连续模式。如果序列器被禁用,此参数将被丢弃。只有在禁用连续模式时,才能启用间断模式。如果启用连续模式,则放弃此参数设置。此参数可设置为ENABLE(启用)或DISABLE(禁用)。

(6)NbrOfDiscConversion:指定将细分常规组的主序列(参数NbrOfConversion)的不连续转换数。如果禁用了参数“DisconnectousConvMode”,则放弃此参数。此参数必须是介于Min_Data=1和Max_Data=8之间的数字。

(7)ExternalTrigConv:外部触发选择,可根据项目需求配置触发来源。实际上,我们一般使用软件自动触发。 配置完这些结构体成员值,调用库函数 HAL_ADC_Init()即可把结构体的配置写入到寄存器中。

下面讲述如何通过STM32CubeMX新建工程、如何通过Keil MDK实现工程。

1. 通过STM32CubeMX新建工程

通过STM32CubeMX新建工程的步骤如下:

(1)新建文件夹   Demo目录下新建文件夹ADC,这是保存本章新建工程的文件夹。

(2)新建STM32CubeMX工程 在STM32CubeMX开发环境中新建工程。

(3)选择MCU或开发板 Commercial Part Number和MCUs/MPUs List选择STM32F103ZET6,选择Start Project启动工程。

(4)保存STM32Cube MX工程 使用STM32CubeMX菜单File→Save Project,保存工程。

(5)生成报告 使用STM32CubeMX菜单File→Generate Report生成当前工程的报告文件。

(6)配置MCU时钟树 STM32CubeMX Pinout & Configuration子页面下,选择System Core→RCC,High Speed Clock(HSE)根据开发板实际情况,选择Crystal/Ceramic Resonator(晶体/陶瓷晶振)。

STM32CubeMX切换到Clock Configuration子页面下,根据开发板外设情况配置总线时钟。此处配置PLL Source Mux为HSE,PLLMul为9倍频72MHz,System Clock Mux为PLLCLK,APB1 Prescaler为X2,其余默认设置即可。

(7)配置MCU外设

STM32CubeMX Pinout & Configuration子页面下选择System Core→GPIO,对使用的GPIO口进行设置。ADC1输入端口PC1配置为ADC1_IN11。

在STM32CubeMX中配置完USART1后,会自动完成相关GPIO口的配置,不需用户配置。 配置完ADC端口后,时钟配置页面会提示错误,STM32CubeMX切换到Clock Configuration子页面下,需要修改ADC时钟为12MHz,ADC Prescaler选择/6

STM32CubeMX Pinout & Configuration子页面下选择Analog→ADC1,对ADC1进行设置。IN11为配置GPIO口PC1时自动选择,ADC Parameter Settings默认配置即可

STM32CubeMX Pinout & Configuration子页面下分别配置USART1、NVIC模块,方法同SPI部分。 切换到STM32CubeMX Pinout & Configuration子页面下选择System Core→NVIC,修改Priority Group为2 bits for pre-emption priority(2位抢占优先级),Enabled栏勾选USART1 global interrupt和ADC1 and ADC2 global interrupts,分别修改Preemption Priority(抢占优先级)和Sub Priority(子优先级)

Code Generation页面Select for init sequence ordering栏勾选USART1 global interrupt和ADC1 and ADC2 global interrupts,NVIC Code Generation配置页面

(8)配置工程 STM32CubeMX Project Manager子页面Project栏下Toolchain/IDE选择MDK-Arm,Min Version选择V5,可生成Keil MDK工程;选择STM32CubeIDE,可生成STM32CubeIDE工程。

(9)生成C代码工程 STM32CubeMX主页面,单击GENERATE CODE按钮生成C代码工程。

2. 通过Keil MDK实现工程

通过Keil MDK实现工程的步骤如下:

(1)打开工程   打开ADC\MDK-Arm文件夹下的工程文件。

(2)编译STM32CubeMX自动生成的MDK工程 在MDK开发环境中通过菜单Project→Rebuild all target files或工具栏      Rebuild按钮编译工程。

(3)STM32CubeMX自动生成的MDK工程 main.c文件中函数main()依次调用了HAL_Init()函数用于复位所有外设,初始化Flash接口和Systick定时器。SystemClock_Config()函数用于配置各种时钟信号频率。MX_GPIO_Init()函数初始化GPIO引脚。 文件gpio.c包含了函数MX_GPIO_Init()的实现代码,如下。

void MX_GPIO_Init(void)
{/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();
}

MX_USART1_UART_Init()是USART1的初始化函数。 main()函数外设初始化新增MX_ADC1_Init(),它是ADC1的初始化函数。MX_ADC1_Init()是在文件adc.c中定义的函数,实现STM32CubeMX配置的ADC1设置。单通道采集不需要扫描、启动连续转换、使用内部软件触发无须外部触发事件、使用右对齐数据格式、转换通道为1,采样时间为55CYCLES_5。

MX_ADC1_Init()实现的代码如下。
void MX_ADC1_Init(void)
{ADC_ChannelConfTypeDef sConfig = {0};/** Common config*/hadc1.Instance = ADC1;hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;hadc1.Init.ContinuousConvMode = ENABLE;hadc1.Init.DiscontinuousConvMode = DISABLE;hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;if (HAL_ADC_Init(&hadc1) != HAL_OK){Error_Handler();}/** Configure Regular Channel*/sConfig.Channel = ADC_CHANNEL_11;sConfig.Rank = ADC_REGULAR_RANK_1;sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){Error_Handler();}/* USER CODE BEGIN ADC1_Init 2 *//* USER CODE END ADC1_Init 2 */
} 

MX_ADC1_Init()函数调用了HAL_ADC_Init(),继而调用了adc.c中实现的HAL_ADC_MspInit(),初始化ADC1相关的时钟和GPIO口。HAL_ADC_MspInit()函数实现如下。

void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(adcHandle->Instance==ADC1){/* ADC1 clock enable */__HAL_RCC_ADC1_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();/**ADC1 GPIO ConfigurationPC1     ------> ADC1_IN11*/
GPIO_InitStruct.Pin = GPIO_PIN_1;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);}
}
函数MX_NVIC_Init()实现中断的初始化,代码如下。
static void MX_NVIC_Init(void)
{/* USART1_IRQn interrupt configuration */HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);HAL_NVIC_EnableIRQ(USART1_IRQn);
/* ADC1_2_IRQn interrupt configuration */HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0);HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
}

(4)新建用户文件   不需要新建用户文件,adc.c和usart.c都由STM32CubeMX自动生成。

(5)编写用户代码 usart.h和usart.c文件声明和定义使用到的变量、宏定义。usart.c文件MX_USART1_UART_Init()函数开启USART1接收中断。stm32f1xx_it.c对USART1_IRQHandler()函数添加接收数据的处理。

adc.c文件MX_I2C1_Init()函数启用ADC1,以中断方式开始常规组的转换。   /* USER CODE BEGIN ADC1_Init 2 */   HAL_ADC_Start_IT(&hadc1);   /* USER CODE END ADC1_Init 2 */ 中断服务函数一般定义在stm32f1xx_it.c文件内,HAL_ADC_IRQHandler()是HAL中自带的一个中断服务函数,处理过程中会指向一个回调函数去添加用户代码,这里使用HAL_ADC_ConvCpltCallback()转换完成中断,在ADC转换完成后就会进入中断服务函数,再进入回调函数,在回调函数内直接读取ADC转换结果保存在变量ADC_ConvertedValue(在main.c中定义) 中。

ADC_GetConversionValue()函数是获取ADC转换结果值的库函数,只有一个形参为ADC句柄,该函数返回一个16位的ADC转换结果值。

AD采样回调处理函数HAL_ADC_ConvCpltCallback如下。
/* USER CODE BEGIN 1 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{/* 获取结果 */ADC_ConvertedValue = HAL_ADC_GetValue(AdcHandle);
}
/* USER CODE END 1 */
main.c文件添加对ADC的操作。通过STM32内部ADC1读取通道11(PC1)上面的电压,将ADC转换值发送到串口。/* Infinite loop *//* USER CODE BEGIN WHILE */while (1){Delay(0x1fffff);ADC_Vol =(float)ADC_ConvertedValue/4096*(float)3.3; // 读取转换的AD值printf("\r\n The current AD value = 0x%04X \r\n", ADC_ConvertedValue); printf("\r\n The current AD value = %f V \r\n",ADC_Vol);  
/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */

(6)重新编译工程   重新编译添加代码后的工程。

(7)配置工程仿真与下载项 在MDK开发环境中通过菜单Project→Options for Target或工具栏      配置工程。 打开Debug选项卡,选择使用的仿真下载器ST-Link Debugger。Flash Download下勾选Reset and Run选项。单击确定。

(8)下载工程   连接好仿真下载器,开发板上电。 在MDK开发环境中通过菜单Flash→Download或工具栏    下载工程。 工程下载完成后,连接串口,打开串口调试助手,查看串口收发是否正常,转动电位器,查看串口显示的采样电压是否正常。串口调试助手调试界面(ADC)


http://www.ppmy.cn/ops/130116.html

相关文章

统信UOS适配C#

通过Mono或.NET Core等运行时,在UOS上进行C#应用开发、编译、调试及部署变得便捷。 文章目录 一、环境部署1. C#开发环境安装2. C#开发环境配置二、 C#开发案例三、常见问题1. 图形界面支持2. 调试工具一、环境部署 1. C#开发环境安装 统信UOS V20使用dotnet 7.0 amd64版本,…

springboot框架使用RabbitMQ举例代码

以前分享过一个理论有兴趣的小伙伴可以看下 https://blog.csdn.net/Drug_/article/details/138164180 不多说 还是直接上代码 第一步&#xff1a;引入依赖 可以不指定版本 <!-- amqp --><dependency><groupId>org.springframework.boot</groupId…

Python 工具库每日推荐【Pillow】

文章目录 引言Python图像处理库的重要性今日推荐:Pillow工具库主要功能:使用场景:安装与配置快速上手示例代码代码解释实际应用案例案例:创建图像拼贴案例分析高级特性图像增强图像水印扩展阅读与资源优缺点分析优点:缺点:总结【 已更新完 TypeScript 设计模式 专栏,感兴…

计算机网络(Ⅶ)Web and HTTP

一些术语&#xff1a; Web页&#xff1a;由一些对象组成 对象可以是HTML文件&#xff0c;JPEG图像&#xff0c;Java小程序&#xff0c;声音剪辑文件等 Web页含有一个基本的HTML文件&#xff0c;该基本HTML文件又包含若干对象的引用&#xff08;链接&#xff09; 通过URL对每个对…

五、快速入门K8s之Pod容器的生命周期

一、容器的初始化init ⭐️ init c &#xff1a; init contariner 初始化容器&#xff0c;只是用来初始化&#xff0c;初始化完成就会死亡可以大于的等于一也可以没有&#xff0c;每个init只有在前一个init c执行完成后才可以执行下一个、init容器总是运行到成功完成为止&#…

大语言模型驱动的跨域属性级情感分析——论文阅读笔记

前言 论文PDF下载地址&#xff1a;7156 最近想搜一下基于大语言模型的情感分析论文&#xff0c;搜到了这篇在今年发表的论文&#xff0c;于是简单阅读之后在这里记一下笔记。 如图1所示&#xff0c;在餐厅领域中的"快"是上菜快&#xff0c;属于正面情感&#xff0c;但…

读写chrome.storage.local

修改chrome-extensions-samples\api-samples\storage\stylizr&#xff0c;可以从GitHub下载。读取最好在回调函数里面读取&#xff0c;比较方便。 // Store CSS data in the "local" storage area. const storage chrome.storage.local;// Get at the DOM controls…

总分441数一149专137东南大学820信号数电考研经验电子信息与通信工程电路原920专业基础综合,真题,大纲,参考书。

一. 写在前面的话 本人是23年考生&#xff0c;本科就读于西电电子信息工程&#xff0c;以441分总分&#xff08;数学一149&#xff0c;英语83&#xff0c;专业课820&#xff08;原920信号和数电专业基础综合&#xff09;137&#xff0c;政治73&#xff09;考上东南信院电路与系…