STM32 HAL库F103系列之ADC实验(一)

 ADC工作原理:

1、输入通道:

 2、转换序列:

A/D转换被组织为两组:规则组(常规转换组)注入组(注入转换组)

规则组最多可以有16个转换,注入组最多有4个转换

 规则组和注入组执行优先级对比

 3、触发源:

触发转换的方法有两种:

        (1ADON位触发转换(仅限F1系列)

                当ADC_CR2寄存器的ADON位为1时,再单独ADON位写1,只能启动规则组转换

        2)外部事件触发转换

                外部事件触发转换分为:规则组外部触发注入组外部触发

 4、转换时间:

 

5、数据寄存器:

6、中断:

7、单次转换模式和连续转换模式:

8、扫描模式:

不同模式组合的作用

单通道ADC采集实验

实验需要用杜邦线把RV1和ADC给连接起来

实验要求:

1,功能描述

        通过ADC1通道1PA1)采集电位器的电压,并显示ADC转换的数字量及换算后的电压值

2,确定最小刻度

        VREF+ = 3.3V  0VVIN3.3V  最小刻度 = 3.3 / 4096   F4/F7/H7系列还需要考虑ADC分辨率

 3,确定转换时间

        采样时间239.5ADC时钟周期为例,可以得到转换时间为21us

4,模式组合

        单次转换模式、不使用扫描模式

配置步骤:

1,配置ADC工作参数、ADC校准

        HAL_ADC_Init()HAL_ADCEx_Calibration_Start()

2ADC MSP初始化

        HAL_ADC_MspInit()     配置NVICCLOCKGPIO

3,配置ADC相应通道相关参数

        HAL_ADC_ConfigChannel()

4,启动A/D转换

        HAL_ADC_Start()

5,等待规则通道转换完成

       HAL_ADC_PollForConversion()

 6,获取规则通道A/D转换结果

        HAL_ADC_GetValue()

相关HAL库函数介绍:

 关键结构体介绍:

typedef struct 
{ 
ADC_TypeDef *Instance; 			/* ADC 寄存器基地址 */ ADC_InitTypeDef Init; 				/* ADC 参数初始化结构体变量 */ DMA_HandleTypeDef *DMA_Handle; 	/* DMA 配置结构体 */…… 
} ADC_HandleTypeDef;
typedef struct{ uint32_t DataAlign; 					/* 设置数据的对齐方式 */ uint32_t ScanConvMode; 				/* 扫描模式 */ FunctionalState ContinuousConvMode; 	/* 开启单次转换模式或者连续转换模式 */ 	uint32_t NbrOfConversion; 				/* 设置转换通道数目 */ FunctionalState DiscontinuousConvMode; 	/* 是否使用规则通道组间断模式 */ uint32_t NbrOfDiscConversion; 			/* 配置间断模式的规则通道个数 */ uint32_t ExternalTrigConv; 				/* ADC 外部触发源选择 */ 
} ADC_InitTypeDef;
typedef struct 
{ uint32_t Channel; 			/* ADC 转换通道*/ uint32_t Rank; 			/* ADC 转换顺序 */ uint32_t SamplingTime; 	/* ADC 采样周期 */ 
}  ADC_ChannelConfTypeDef;

 原理图:

 源码

adc.c

#include "./BSP/ADC/adc.h"ADC_HandleTypeDef g_adc_handle;/* ADC单通道*/
void adc_init(void)
{ADC_ChannelConfTypeDef adc_ch_conf = {0};g_adc_handle.Instance = ADC1;g_adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;g_adc_handle.Init.ScanConvMode = ADC_SCAN_DISABLE;g_adc_handle.Init.ContinuousConvMode = DISABLE;g_adc_handle.Init.NbrOfConversion = 1;g_adc_handle.Init.DiscontinuousConvMode = DISABLE;g_adc_handle.Init.NbrOfDiscConversion = 0;g_adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START;//软件触发HAL_ADC_Init(&g_adc_handle);HAL_ADCEx_Calibration_Start(&g_adc_handle);adc_ch_conf.Channel = ADC_CHANNEL_1;adc_ch_conf.Rank = ADC_REGULAR_RANK_1;adc_ch_conf.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;HAL_ADC_ConfigChannel(&g_adc_handle, &adc_ch_conf);
}
/* ADC MSP初始换函数*/
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{if(hadc->Instance == ADC1){RCC_PeriphCLKInitTypeDef adc_clk_init = {0};GPIO_InitTypeDef gpio_init_struct;__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_ADC1_CLK_ENABLE();gpio_init_struct.Pin = GPIO_PIN_1;gpio_init_struct.Mode = GPIO_MODE_ANALOG;            /* 模拟功能 */HAL_GPIO_Init(GPIOA, &gpio_init_struct);       /* 初始化LED0引脚 */adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC;adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6;HAL_RCCEx_PeriphCLKConfig(&adc_clk_init);}
}
/* 获得ADC转换后的结果函数*/
uint32_t adc_get_result(void)
{HAL_ADC_Start(&g_adc_handle);HAL_ADC_PollForConversion(&g_adc_handle, 10);return (uint16_t)HAL_ADC_GetValue(&g_adc_handle);
}

adc.h

#ifndef __ADC_H
#define __ADC_H#include "./SYSTEM/sys/sys.h"void adc_init(void);
uint32_t adc_get_result(void);#endif

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/ADC/adc.h"int main(void)
{uint16_t adcx;float temp;HAL_Init();                                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9);                 /* 设置时钟, 72Mhz */delay_init(72);                                     /* 延时初始化 */usart_init(115200);                                 /* 串口初始化为115200 */led_init();                                         /* 初始化LED */lcd_init();                                         /* 初始化LCD */adc_init();lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);lcd_show_string(30, 70, 200, 16, 16, "ADC TEST", RED);lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);lcd_show_string(30, 110, 200, 16, 16, "ADC1_CH1_VAL:", BLUE);lcd_show_string(30, 130, 200, 16, 16, "ADC1_CH1_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */while (1){adcx = adc_get_result();lcd_show_xnum(134, 110, adcx, 5, 16, 0, BLUE);  /* 显示ADCC采样后的原始值 */temp = (float)adcx * (3.3 / 4096);              /* 获取计算后的带小数的实际电压值,比如3.1111 */adcx = temp;                                    /* 赋值整数部分给adcx变量,因为adcx为u16整形 */lcd_show_xnum(134, 130, adcx, 1, 16, 0, BLUE);  /* 显示电压值的整数部分,3.1111的话,这里就是显示3 */temp -= adcx;                                   /* 把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111 */temp *= 1000;                                   /* 小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数。 */lcd_show_xnum(150, 130, temp, 3, 16, 0X80, BLUE);/* 显示小数部分(前面转换为了整形显示),这里显示的就是111. */LED0_TOGGLE();delay_ms(100);}}

单通道ADC采集(DMA读取)实验

 实验简要:

1,功能描述   (通过DMA读取数据)

        通过ADC1通道1PA1)采集电位器的电压,并显示ADC转换的数字量及换算后的电压值

2,确定最小刻度

        VREF+ = 3.3V  0VVIN3.3V  最小刻度 = 3.3 / 4096  (F4/F7/H7系列还需要考虑ADC分辨率)

3,确定转换时间

       采样时间239.5ADC时钟周期为例,可以得到转换时间为21us

 4,模式组合

       连续转换模式、不使用扫描模式 

配置步骤:

1,初始化DMA

        HAL_DMA_Init()

2,将DMAADC句柄联系起来

        __HAL_LINKDMA()

3,配置ADC工作参数、ADC校准

        HAL_ADC_Init()HAL_ADCEx_Calibration_Start()

4ADC MSP初始化

        HAL_ADC_MspInit()     配置NVICCLOCKGPIO

5,配置ADC相应通道相关参数

        HAL_ADC_ConfigChannel()

6,使能DMA数据流传输完成中断

        HAL_NVIC_SetPriority()HAL_NVIC_EnableIRQ()

7,编写DMA数据流中断服务函数

        DMAx_Channely_IRQHandler()

8,启动DMA,开启传输完成中断

        HAL_DMA_Start_IT()

9,触发ADC转换,DMA传输数据

        HAL_ADC_Start_DMA

相关库函数介绍:

 相关结构体介绍:

typedef struct 
{ uint32_t Direction; 				/* 传输方向 */ uint32_t PeriphInc; 				/* 外设(非)增量模式 */ uint32_t MemInc; 				/* 存储器(非)增量模式 */ uint32_t PeriphDataAlignment; 	/* 外设数据宽度 */ uint32_t MemDataAlignment; 		/* 存储器数据宽度 */ uint32_t Mode; 					/* 操作模式 */ uint32_t Priority; 				/* DMA通道优先级 */ 
}DMA_InitTypeDef; 

 源码

adc.c

#include "./BSP/ADC/adc.h"DMA_HandleTypeDef g_dma_adc_handle;
ADC_HandleTypeDef g_adc_dma_handle;
uint8_t g_adc_dma_sta;/* ADC DMA读取 初始化函数 */
void adc_dma_init(uint32_t mar)
{ADC_ChannelConfTypeDef adc_ch_conf;__HAL_RCC_DMA1_CLK_ENABLE();g_dma_adc_handle.Instance = DMA1_Channel1;g_dma_adc_handle.Init.Direction = DMA_PERIPH_TO_MEMORY;g_dma_adc_handle.Init.PeriphInc = DMA_PINC_DISABLE;g_dma_adc_handle.Init.MemInc = DMA_MINC_ENABLE;g_dma_adc_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;g_dma_adc_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;g_dma_adc_handle.Init.Mode = DMA_NORMAL;g_dma_adc_handle.Init.Priority = DMA_PRIORITY_MEDIUM;HAL_DMA_Init(&g_dma_adc_handle);__HAL_LINKDMA(&g_adc_dma_handle, DMA_Handle, g_dma_adc_handle);g_adc_dma_handle.Instance = ADC1;g_adc_dma_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;g_adc_dma_handle.Init.ScanConvMode = ADC_SCAN_DISABLE;g_adc_dma_handle.Init.ContinuousConvMode = ENABLE;g_adc_dma_handle.Init.NbrOfConversion = 1;g_adc_dma_handle.Init.DiscontinuousConvMode = DISABLE;g_adc_dma_handle.Init.NbrOfDiscConversion = 0;g_adc_dma_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START;HAL_ADC_Init(&g_adc_dma_handle);HAL_ADCEx_Calibration_Start(&g_adc_dma_handle);adc_ch_conf.Channel = ADC_CHANNEL_1;adc_ch_conf.Rank = ADC_REGULAR_RANK_1;adc_ch_conf.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;HAL_ADC_ConfigChannel(&g_adc_dma_handle, &adc_ch_conf);HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 3, 3);HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);HAL_DMA_Start_IT(&g_dma_adc_handle, (uint32_t)&ADC1->DR, mar, 0);HAL_ADC_Start_DMA(&g_adc_dma_handle, &mar ,0);
}/* ADC MSP初始化函数 */
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{if(hadc->Instance == ADC1){GPIO_InitTypeDef gpio_init_struct;RCC_PeriphCLKInitTypeDef adc_clk_init = {0};__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_ADC1_CLK_ENABLE();gpio_init_struct.Pin = GPIO_PIN_1;gpio_init_struct.Mode = GPIO_MODE_ANALOG;HAL_GPIO_Init(GPIOA, &gpio_init_struct); adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC;adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6;HAL_RCCEx_PeriphCLKConfig(&adc_clk_init);}
}/* 使能一次ADC DMA传输函数 */
void adc_dma_enable(uint16_t cndtr)
{
//    ADC1->CR2 &= ~(1 << 0);
//    
//    DMA1_Channel1->CCR &= ~(1 << 0);
//    while (DMA1_Channel1->CCR & (1 << 0));
//    DMA1_Channel1->CNDTR = cndtr;
//    DMA1_Channel1->CCR |= 1 << 0;//    ADC1->CR2 |= 1 << 0;
//    ADC1->CR2 |= 1 << 22;__HAL_ADC_DISABLE(&g_adc_dma_handle);__HAL_DMA_DISABLE(&g_dma_adc_handle);while (__HAL_DMA_GET_FLAG(&g_dma_adc_handle, __HAL_DMA_GET_TC_FLAG_INDEX(&g_dma_adc_handle)));DMA1_Channel1->CNDTR = cndtr;__HAL_DMA_ENABLE(&g_dma_adc_handle);__HAL_ADC_ENABLE(&g_adc_dma_handle);HAL_ADC_Start(&g_adc_dma_handle);
}/* ADC DMA采集中断服务函数 */
void DMA1_Channel1_IRQHandler(void)
{if (DMA1->ISR & (1<<1)){g_adc_dma_sta = 1;DMA1->IFCR |= 1 << 1;}
}

adc.h

#ifndef __ADC_H
#define __ADC_H#include "./SYSTEM/sys/sys.h"void adc_dma_init(uint32_t mar);
void adc_dma_enable(uint16_t cndtr);#endif

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/ADC/adc.h"#define ADC_DMA_BUF_SIZE        100         /* ADC DMA采集 BUF大小 */
uint16_t g_adc_dma_buf[ADC_DMA_BUF_SIZE];   /* ADC DMA BUF */extern uint8_t g_adc_dma_sta;               /* DMA传输状态标志, 0,未完成; 1, 已完成 */int main(void)
{uint16_t i;uint16_t adcx;uint32_t sum;float temp;HAL_Init();                             /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */delay_init(72);                         /* 延时初始化 */usart_init(115200);                     /* 串口初始化为115200 */led_init();                             /* 初始化LED */lcd_init();                             /* 初始化LCD */adc_dma_init((uint32_t)&g_adc_dma_buf); /* 初始化ADC DMA采集 */lcd_show_string(30,  50, 200, 16, 16, "STM32", RED);lcd_show_string(30,  70, 200, 16, 16, "ADC DMA TEST", RED);lcd_show_string(30,  90, 200, 16, 16, "ATOM@ALIENTEK", RED);lcd_show_string(30, 110, 200, 16, 16, "ADC1_CH1_VAL:", BLUE);lcd_show_string(30, 130, 200, 16, 16, "ADC1_CH1_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */adc_dma_enable(ADC_DMA_BUF_SIZE);   /* 启动ADC DMA采集 */while (1){if (g_adc_dma_sta == 1){/* 计算DMA 采集到的ADC数据的平均值 */sum = 0;for (i = 0; i < ADC_DMA_BUF_SIZE; i++)   /* 累加 */{sum += g_adc_dma_buf[i];}adcx = sum / ADC_DMA_BUF_SIZE;           /* 取平均值 *//* 显示结果 */lcd_show_xnum(134, 110, adcx, 4, 16, 0, BLUE);      /* 显示ADCC采样后的原始值 */temp = (float)adcx * (3.3 / 4096);                  /* 获取计算后的带小数的实际电压值,比如3.1111 */adcx = temp;                                        /* 赋值整数部分给adcx变量,因为adcx为u16整形 */lcd_show_xnum(134, 130, adcx, 1, 16, 0, BLUE);      /* 显示电压值的整数部分,3.1111的话,这里就是显示3 */temp -= adcx;                                       /* 把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111 */temp *= 1000;                                       /* 小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数。 */lcd_show_xnum(150, 130, temp, 3, 16, 0X80, BLUE);   /* 显示小数部分(前面转换为了整形显示),这里显示的就是111. */g_adc_dma_sta = 0;                                  /* 清除DMA采集完成状态标志 */adc_dma_enable(ADC_DMA_BUF_SIZE);                   /* 启动下一次ADC DMA采集 */}LED0_TOGGLE();delay_ms(100);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/636808.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【GIS面试】GIS算法介绍

作者&#xff1a;后端小肥肠 1. 前言 在地理信息系统&#xff08;GIS&#xff09;的领域中&#xff0c;算法扮演着极其重要的角色&#xff0c;它们使得复杂的空间数据分析成为可能。无论是在环境科学、城市规划&#xff0c;还是在灾害管理等众多领域&#xff0c;高效和精确的算…

【信号与系统 - 10】拉普拉斯变换

1 定义 周期信号的傅里叶变换那篇提到了&#xff1a; F ( j w ) ∫ − ∞ ∞ e − j w t f ( t ) d t F(jw)\int^{\infty}_{-\infty}e^{-jwt}f(t)dt F(jw)∫−∞∞​e−jwtf(t)dt 这个定义式需要满足绝对可积&#xff0c;即 ∫ − ∞ ∞ ∣ f ( t ) ∣ d t < ∞ \int…

C++11 数据结构5 队列的概念,队列的顺序存储,实现,测试

一&#xff0c;队列的概念 队列是一种特殊的受限制的线性表。 队列&#xff08;queue&#xff09;是只允许在一端进行插入操作&#xff0c;而在另一端进行删除操作的线性表。 队列是一种先进先出的t&#xff08;First In First Out&#xff09;的线性表&#xff0c;简称FIF…

这8款3DMAX建筑室内插件一个都不能少!

3DMax是一款经典的建筑室内场景设计和渲染软件&#xff0c;它能够帮助3D设计师、建筑师和艺术家实现他们的创意概念。本文推荐的8款建筑室内插件&#xff0c;将使3DMax如虎添翼&#xff0c;大大节约设计师们的工作时间&#xff0c;提高工作效率。 1.3DMAX楼层平面图生成器&…

idea使用plantuml插件报错(类图):Dot Executable: /opt/local/bin/dot

报错提示&#xff1a; 解决方式&#xff1a; 方式一: 直接设置Remote Rendering即可 &#xff08;使用服务器地址&#xff09; 无特殊要求可直接使用默认提供的服务地址&#xff0c;也可自行搭建服务替换地址。 自行搭建服务可参考&#xff1a; 在本地Windows 11 系统的桌面…

C++ 程序的内存分配

C 程序的内存分配 C 程序的内存分配栈堆数据区程序代码区参考 C 程序的内存分配 一个 C 编译的程序占用内存分为以下几个部分&#xff08;从高地址到低地址&#xff09;&#xff1a; 内核空间&#xff1a;由操作系统创建并控制&#xff0c;用户代码不能读写。栈&#xff1a;由…

【ds】替换空格

用‘%20’替换空格 var replaceBlank (charArr)> {if (!charArr || charArr.length 0) return var len charArr.lengthlet spaceLen 0for (let i 0; i < len; i) {if (charArr[i] ) {spaceLen}}var extraLen spaceLen * 2 // -> 20% 每一个空格需要增加2个ch…

Pytest精通指南(23)钩子函数-执行顺序(pytest-ordering)

文章目录 前言应用场景插件安装参数分析装饰方法装饰类装饰模块 前言 pytest-ordering 是一个pytest插件&#xff0c;它允许用户自定义测试用例的执行顺序。 默认情况下&#xff0c;pytest会按照模块、类、函数定义的顺序以及它们的名称的字母顺序来执行测试用例。 但通过使用 …

Kafka集群搭建可视化指南

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Kafka集群搭建可视化指南 前言准备工作硬件要求环境准备 kafka集群的部署与配置3.1 单节点部署与多节点集群搭建单节点部署&#xff1a;多节点集群搭建&#xff1a; 3.2 Broker配置与优化3.3 Topic的创…

如何30天快速掌握键盘盲打

失业后在家备考公务员&#xff0c;发现了自己不正确的打字方式&#xff0c;决定每天抽出一点时间练习打字。在抖音上看到一些高手的飞速盲打键盘后&#xff0c;觉得使用正确的指法打字是很必要的。 练习打字&#xff0c;掌握正确的键盘指法十分关键。 练习打字的第一步是找到…

RIP最短路实验(思科)

华为设备参考&#xff1a;RIP最短路实验&#xff08;华为&#xff09; 一&#xff0c;技术简介 RIP&#xff08;Routing Information Protocol&#xff0c;路由信息协议&#xff09;是一种基于距离矢量的内部网关协议&#xff0c;工作原理是每个路由器周期性地向邻居路由器发…

分享一款嵌入式开源按键框架代码工程MultiButton

一、工程简介 MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块。 Github地址&#xff1a;https://github.com/0x1abin/MultiButton 这个项目非常精简&#xff0c;只有两个文件&#xff1a; &#xff08;1&#xff09;可无限扩展按键&#xff1b; &#xff08;2&#x…