蓝桥杯嵌入式学习笔记(7):ADC程序设计

目录

前言

1. ADC原理

1.1 主要特性

1.2 模拟输出电路图

2. 使用CubeMX进行源工程的配置

2.1 引脚配置

2.2 配置AD1 

2.3 配置AD2

2.4 配置时钟

3. 代码编程 

3.1 预备工作 

3.2 bsp_adc.h文件编写

3.3 bsp_adc.c文件编写

3.4 main.c编写

3.4.1 时钟函数配置

3.4.2 头文件引用

3.4.3 变量声明

3.4.4 子函数声明

3.4.5 函数定义

 3.4.6 main函数编写

4. 测试


前言

因本人备赛蓝桥杯嵌入式省赛,故编写此学习笔记进行学习上的记录。

上文我们实现了IIC程序设计,本文我们进行ADC程序设计。

1. ADC原理

STM32G431内部集成2个有最高12位ADC(ADC1、ADC2),它们是逐次逼近型模数转换器。

1.1 主要特性

可配置的转换精度:6位,8位,10位,12位

转换电压范围: 0 ~ VREF+(一般接到3.3V电源,不能超过STM32芯片电源电压)

19个转换通道:16个外部通道(IO引脚) + 3个内部通道(温度传感器、内部电压参考、电池供电监测)

采样时间可配置

扫描方向可配置

多种转换模式:单次,连续

数据存放对齐方式可配置:左对齐,右对齐(ADC的结果存储在一个左对齐或右对齐的 16 位数据寄存器中)

启动转换方式可配置:软件触发,硬件触发

可设置上下门限的模拟看门狗

DMA功能

在转换结束、注入转换结束以及发生模拟看门狗或溢出事件时产生中断

1.2 模拟输出电路图

嵌入式实训平台CT117E-M4的模拟输出如下

其中PB15引脚连接R37电阻,PB12引脚连接R38电阻。

2. 使用CubeMax进行源工程的配置

2.1 引脚配置

将PB12配置为ADC1_IN11

将PB15配置为ADC2_IN15

2.2 配置AD1 

​ 

在Pinout&Configuration页面中的【Analog】目录中AD1的Mode选择IN11 Single。

在【Config】中配置【ADC_Settings】的【Clock Prescaler】选择【Asynchronous clock mode divided by 2】。

在【Config】中配置【ADC_Regular_Conversion Mode】的【Rank】选择【Sampling Time】为【640.5 Cycles】。

2.3 配置AD2

在Pinout&Configuration页面中的【Analog】目录中AD2的Mode选择IN15 Single。

在【Config】中配置【ADC_Settings】的【Clock Prescaler】选择【Asynchronous clock mode divided by 2】。

在【Config】中配置【ADC_Regular_Conversion Mode】的【Rank】选择【Sampling Time】为【640.5 Cycles】。

2.4 配置时钟

在【Clock Configuration】 中将ADC12的时钟源改为PLLP

配置完成后就生成代码

3. 代码编程 

3.1 预备工作 

接下来我们在Test_Project工程里的Src文件夹创建BSP\ADC\bsp_adc.c,同理,在Inc文件夹创建BSP\ADC\bsp_adc.h。这就是我们后面要编写的中间层代码文件。

打开Test_Project工程,进行文件Group的添加

在bsp_adc.c中添加依赖头文件

#include "ADC/bsp_adc.h"

 在Group中添加HAL库的相关文件,添加stm32g4xx_hal_adc.c和stm32g4xx_hal_adc_ex.c。

在stm32g4xx_hal_conf.h中去掉#define HAL_ADC_MODULE_ENABLED 的注释

#define HAL_ADC_MODULE_ENABLED  

3.2 bsp_adc.h文件编写

拷贝Source工程生成的adc.h代码,并定义获取ADC的函数

#include "main.h"extern ADC_HandleTypeDef hadc1;
extern ADC_HandleTypeDef hadc2;void ADC1_Init(void);
void ADC2_Init(void);uint16_t getADC1(void);
uint16_t getADC2(void);

3.3 bsp_adc.c文件编写

 拷贝Source工程生成的adc.c代码。

#include "ADC/bsp_adc.h"ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;void ADC1_Init(void)
{ADC_MultiModeTypeDef multimode = {0};ADC_ChannelConfTypeDef sConfig = {0};hadc1.Instance = ADC1;hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;hadc1.Init.Resolution = ADC_RESOLUTION_12B;hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;hadc1.Init.GainCompensation = 0;hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;hadc1.Init.LowPowerAutoWait = DISABLE;hadc1.Init.ContinuousConvMode = DISABLE;hadc1.Init.NbrOfConversion = 1;hadc1.Init.DiscontinuousConvMode = DISABLE;hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;hadc1.Init.DMAContinuousRequests = DISABLE;hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;hadc1.Init.OversamplingMode = DISABLE;if (HAL_ADC_Init(&hadc1) != HAL_OK){Error_Handler();}/** Configure the ADC multi-mode*/multimode.Mode = ADC_MODE_INDEPENDENT;if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK){Error_Handler();}sConfig.Channel = ADC_CHANNEL_11;sConfig.Rank = ADC_REGULAR_RANK_1;sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;sConfig.SingleDiff = ADC_SINGLE_ENDED;sConfig.OffsetNumber = ADC_OFFSET_NONE;sConfig.Offset = 0;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){Error_Handler();}
}void ADC2_Init(void)
{ADC_ChannelConfTypeDef sConfig = {0};hadc2.Instance = ADC2;hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;hadc2.Init.Resolution = ADC_RESOLUTION_12B;hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;hadc2.Init.GainCompensation = 0;hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;hadc2.Init.LowPowerAutoWait = DISABLE;hadc2.Init.ContinuousConvMode = DISABLE;hadc2.Init.NbrOfConversion = 1;hadc2.Init.DiscontinuousConvMode = DISABLE;hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;hadc2.Init.DMAContinuousRequests = DISABLE;hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;hadc2.Init.OversamplingMode = DISABLE;if (HAL_ADC_Init(&hadc2) != HAL_OK){Error_Handler();}sConfig.Channel = ADC_CHANNEL_15;sConfig.Rank = ADC_REGULAR_RANK_1;sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;sConfig.SingleDiff = ADC_SINGLE_ENDED;sConfig.OffsetNumber = ADC_OFFSET_NONE;sConfig.Offset = 0;if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK){Error_Handler();}
}static uint32_t HAL_RCC_ADC12_CLK_ENABLED=0;void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(adcHandle->Instance==ADC1){HAL_RCC_ADC12_CLK_ENABLED++;if(HAL_RCC_ADC12_CLK_ENABLED==1){__HAL_RCC_ADC12_CLK_ENABLE();}__HAL_RCC_GPIOB_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_12;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);}else if(adcHandle->Instance==ADC2){HAL_RCC_ADC12_CLK_ENABLED++;if(HAL_RCC_ADC12_CLK_ENABLED==1){__HAL_RCC_ADC12_CLK_ENABLE();}__HAL_RCC_GPIOB_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_15;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);}
}void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{if(adcHandle->Instance==ADC1){HAL_RCC_ADC12_CLK_ENABLED--;if(HAL_RCC_ADC12_CLK_ENABLED==0){__HAL_RCC_ADC12_CLK_DISABLE();}HAL_GPIO_DeInit(GPIOB, GPIO_PIN_12);}else if(adcHandle->Instance==ADC2){HAL_RCC_ADC12_CLK_ENABLED--;if(HAL_RCC_ADC12_CLK_ENABLED==0){__HAL_RCC_ADC12_CLK_DISABLE();}HAL_GPIO_DeInit(GPIOB, GPIO_PIN_15);}
}

 编写获取ADC1和ADC2的代码,首先进行ADC采集的开始,然后调用HAL库的获取并返回。

uint16_t getADC1(void)
{uint16_t adc = 0;HAL_ADC_Start(&hadc1);adc = HAL_ADC_GetValue(&hadc1);return adc;
}
uint16_t getADC2(void)
{uint16_t adc = 0;HAL_ADC_Start(&hadc2);adc = HAL_ADC_GetValue(&hadc2);return adc;
}

3.4 main.c编写

3.4.1 时钟函数配置

拷贝Source工程生成的时钟配置代码

void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};/** Configure the main internal regulator output voltage*/HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;RCC_OscInitStruct.PLL.PLLN = 20;RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}/** Initializes the peripherals clocks*/PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_ADC12;PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_PLL;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK){Error_Handler();}
}

3.4.2 头文件引用

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "LCD\bsp_lcd.h"
#include "ADC\bsp_adc.h"

3.4.3 变量声明

//变量声明
__IO uint32_t uwTick_Lcd_Set_Point;//LCD减速//*LCD显示专用变量
unsigned char Lcd_Disp_String[22];

3.4.4 子函数声明

//***子函数声明区
void SystemClock_Config(void);
void Lcd_Proc(void);

3.4.5 函数定义

void Lcd_Proc(void)
{if((uwTick - uwTick_Lcd_Set_Point)<200)return;uwTick_Lcd_Set_Point = uwTick;sprintf((char*)Lcd_Disp_String,"R37:%4.2fV",(getADC2()*3.3)/4096);LCD_DisplayStringLine(Line3,Lcd_Disp_String);sprintf((char*)Lcd_Disp_String,"R38:%4.2fV",(getADC1()*3.3)/4096);LCD_DisplayStringLine(Line4,Lcd_Disp_String);
}

 3.4.6 main函数编写

int main(void)
{HAL_Init();SystemClock_Config();LCD_Init();LCD_Clear(White);LCD_SetBackColor(White);LCD_SetTextColor(Blue);ADC1_Init();ADC2_Init();while (1){Lcd_Proc();}
}

4. 测试

将代码进行编译并下载到开发板上。效果如下图所示。

​ 

至此,本节就大功告成了! 

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

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

相关文章

windows下通过vscode访问ubuntu(绝大部分Linux下开发所采用的方案)

前言 本篇博客是介绍VSCode远程连接Ubuntu进行开发的解决方案&#xff0c;前提是安装好了VMWare&#xff0c;Ubuntu&#xff0c;windows下的VSCode。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可以关…

黄金票据攻击

黄金票据攻击——域内横向移动技术 一、黄金票据攻击介绍&#xff1a; 黄金票据攻击是一种滥用Kerberos身份认证协议的攻击方式&#xff0c;它允许攻击者伪造域控krbtgt用户的TGT&#xff08;Ticket-Granting Ticket&#xff09;。通过这种方法&#xff0c;攻击者可以生成有效…

vue2项目安装(使用vue-cli脚手架)

使用npm安装 安装镜像&#xff08;使npm创建项目更快&#xff09;&#xff1a;镜像可更换 npm config set registry https://registry.npmmirror.com1.全局安装vue-cli&#xff08;一次&#xff09; npm install -g vue/cli 2. 查看vue-cli 版本 vue --version 3. 创建项目…

“两化”融合试点名单汇总数据(2014至2018年)

01、数据简介 两化融合是指信息化和工业化的高层次的深度结合&#xff0c;其核心在于信息化支撑&#xff0c;追求可持续发展模式。 “两化”融合贯标试点只针对制造业企业&#xff0c;解释变量“两化”融合贯标试点数据来自工业和信息化部办公厅公布的试点名单以及“两化融合…

C语言一维数组及二维数组详解

引言&#xff1a; 小伙伴们&#xff0c;我发现我正文更新的有些慢&#xff0c;但相信我&#xff0c;每一篇文章真的都很用心在写的&#xff0c;哈哈&#xff0c;在本篇博客当中我们将详细讲解一下C语言中的数组知识&#xff0c;方便大家后续的使用&#xff0c;有不会的也可以当…

Redis缓存设计与性能优化【缓存穿透、缓存击穿、缓存雪崩】

Redis缓存设计与性能优化 多级缓存架构缓存设计缓存穿透&#xff08;空数据&#xff09;造成缓存穿透的基本原因有两个&#xff1a;第一&#xff0c; 自身业务代码或者数据出现问题。第二&#xff0c; 一些恶意攻击、 爬虫等造成大量空命中。 缓存穿透问题解决方案&#xff1a;…

类和对象的下篇

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary_walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

《Git版本控制管理》笔记

第三章 git --version查看版本号git --help查看帮助文档裸双破折号分离参数 git diff -w master origin – tools/Makefile将当前目录或任何目录转化为Git版本库 git init 初始化之后项目目录中&#xff0c;有名为.git的文件git status 查看git状态git commit 提供日志消息和作…

数据可视化:智慧农业发展的催化剂

数据可视化在智慧农业中发挥着不可替代的作用。随着科技的不断进步&#xff0c;农业领域也在不断探索创新&#xff0c;以提高生产效率、优化资源利用&#xff0c;从而实现可持续发展。而数据可视化技术的应用&#xff0c;则成为了实现智慧农业目标的重要途径。下面我就从可视化…

晚间兼职攻略:六个副业轻松上手

晚上兼职副业&#xff0c;作为增加额外收入的途径&#xff0c;选择多样且灵活。以下是六个特别适合晚上进行的副业&#xff0c;让你在闲暇时光也能充实自我&#xff0c;获得收益。 1&#xff0c;网络调查与市场研究是一个值得考虑的选项。你可以在晚上抽出空闲时间&#xff0c…

获取用户位置数据,IP定位离线库助您洞悉消费者需求

获取用户位置数据是现代互联网应用中非常重要的一环。通过获取用户的位置数据&#xff0c;可以了解用户所在的地理位置&#xff0c;从而更好地为用户提供个性化的服务和推荐。而IP归属地离线库就是一种非常有用的工具&#xff0c;可以帮助企业准确地获取用户的位置信息。 IP归…

Python控制浏览器——selenium模块

Python控制浏览器——selenium模块 目录 Python控制浏览器——selenium模块准备工作【1】安装selenium【2】安装浏览器驱动【3】测试驱动&#xff08;作者是Edge&#xff09; 导航和操作窗口导航返回前进刷新最大化窗口切换选项卡 查找和操作元素8种基本By定位方式[1]ID[2]Name…