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

news2024/11/25 18:55:53

目录

前言

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.coloradmin.cn/o/1563509.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内网渗透学习-漏洞利用

1、漏洞搜索与利用 漏洞1&#xff1a;后台弱口令 漏洞2&#xff1a; 在yxcms有个留言功能&#xff0c;常常存在存储型xss漏洞 先用<h1>123xss</h1>测试一下会不会解析 登录管理员账号审核留言&#xff0c;发现xss脚本解析了 写入xss弹窗 再次返回管理员审核页面&…

Hive on Spark 配置

目录 1 Hive 引擎简介2 Hive on Spark 配置2.1 在 Hive 所在节点部署 Spark2.2 在hive中创建spark配置文件2.3 向 HDFS上传Spark纯净版 jar 包2.4 修改hive-site.xml文件2.5 Hive on Spark测试2.6 报错 1 Hive 引擎简介 Hive引擎包括&#xff1a;MR&#xff08;默认&#xff09…

leaflet知识点:leaflet.draw的使用指南

一&#xff0c;安装插件 npm i leaflet-draw --save 二&#xff0c;引入插件 import "leaflet-draw"; import "leaflet-draw/dist/leaflet.draw.css";三&#xff0c;使用插件 leaflet-draw的插件使用有两种方法。 1. 作为工具栏控件加入到地图种使用 //…

linux离线安装NodeJs

一、官方下载 地址&#xff1a;Node.js — Download Node.js 选择linux系统版本 为了防止安装过程出现一些适配问题&#xff0c;我没有选择下载最新版&#xff0c;实际应该下载你的前端所用的nodejs版本 未完待续。。

深度解析Android APP加固中的必备手段——代码混淆技术

Android APP 加固是优化 APK 安全性的一种方法&#xff0c;常见的加固方式有混淆代码、加壳、数据加密、动态加载等。下面介绍一下 Android APP 加固的具体实现方式。 混淆代码 使用 ipaguard工具可以对代码进行混淆&#xff0c;使得反编译出来的代码很难阅读和理解&#xff…

3.5网安学习第三阶段第五周回顾(个人学习记录使用)

本周重点 ①SSRF服务器端请求伪造 ②序列化和反序列化 ③Vaudit代码审计 本周主要内容 ①SSRF服务器端请求伪造 一、概述 SSRF: server site request forgery (服务器端请求伪造)。 SSR: 服务端请求&#xff0c;A服务器通过函数向B服务器发送请求。 SSRF发生的前提条件…

idea 报错 Could not list the contents of folder “ftps

idea 报错 Could not list the contents of folder "ftps 解决方案 这里看到了网上的解决方案&#xff0c;顺便再记录一下。打开 【高级】菜单 - 取消勾选 被动模式。然后点击测试连接&#xff0c;显示连接成功&#xff01; ftp中的主动模式和被动模式 主动模式&…

1.JavaEE进阶篇 - 为什么要学习SpringBoot呢?

文章目录 1.为什么要学框架&#xff1f;2.框架的优点展示(SpringBoot VS Servlet)2.1 Servlet 项⽬开发2.1.1 创建项⽬2.1.2 添加引⽤2.1.3 添加业务代码2.1.4 运⾏项⽬(配置tomcat)2.1.5 Maven配置2.1.5.1修改本地Maven仓库地址2.1.5.2 配置settings.xml文件2.1.5.3项目 本地仓…

Nginx开发实战三:替换请求资源中的固定数据

文章目录 1.效果预览2.下载Nginx解压并初始化3.字符串替换模块安装4.修改nginx配置文件并重启 1.效果预览 页面初始效果 页面替换后效果 说明:页面是内网的一个地址&#xff0c;我们通过nginx可以很便捷的将其改为外网访问&#xff0c;但是在外网访问这个地址后&#xff0c…

剑指offer--数组中重复的数字

一.题目描述 在一个长度为 n 的数组 nums 里的所有数字都在 0&#xff5e;n-1 的范围内。数组中某些数字是重复的&#xff0c;但不知道有几个数字重复了&#xff0c;也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。 算法1.排序,然后遍历,时间复杂度O(nlogn),空…

CVE-2023-4427:Out-of-bounds access in ReduceJSLoadPropertyWithEnumeratedKey

文章目录 前言环境搭建for-in && enum cache漏洞分析漏洞利用总结参考 前言 之前分析调试漏洞时&#xff0c;几乎都是对着别人的 poc/exp 调试&#xff0c;感觉对自己的提升不是很大&#xff0c;所以后面分析漏洞时尽可能全面分析&#xff0c;从漏洞产生原理、如何稳定…

前端学习<三>CSS进阶——0102-CSS布局样式

前言 css 进阶的主要内容如下。 1、css 非布局样式 html 元素的分类和特性 css 选择器 css 常见属性&#xff08;非布局样式&#xff09; 2、css 布局相关 css 布局属性和组合解析 常见布局方案 三栏布局案例 3、动画和效果 属于 css 中最出彩的内容。 多背景多投影特…

(C)1007 素数对猜想

1007 素数对猜想 问题描述 输入样例&#xff1a; 20 输出样例&#xff1a; 4 解决方案&#xff1a; #include<stdio.h> #include<string.h> #include<math.h> int main(){int n,d;int a[100000];int flag,jishu0;scanf("%d",&n);memset(a,-1,…

HubSpot出海CRM的优势有哪些?

强大的客户关系管理能力&#xff1a;HubSpot出海CRM提供了一套完整的客户关系管理功能&#xff0c;企业可以轻松地记录、整理和分析客户的各种信息&#xff0c;包括基本资料、购买历史、沟通记录等。这使得企业能够更深入地了解客户的需求和偏好&#xff0c;为后续的营销和销售…

持续交付/持续部署流水线介绍(CD)

目录 一、概述 二、典型操作流程 2.1 CI/CD典型操作流 2.2 CI/CD操作流程说明 2.3 总结 三、基于GitHubDocker的持续交付/持续部署流水线&#xff08;公有云&#xff09; 3.1 基于GitHubDocker的持续交付/持续部署操作流程示意图 3.2 GitHubDocker持续交付/持续部署流水…

2023.4.7 机器学习周报

目录 引言 Abstract 文献阅读 1、题目 2、引言 3、过去方案和Motivation 4、Segment Anything模型 5、创新点 6、实验过程 7、实验结果 1、评价绩效 2、检测评价 3、跟踪评价 8、 结论 总结 引言 本周阅读了一篇关于高效的任意分割模型的文献&#xff0c;用于自…

1区、TOP、CCF推荐,最快16天录用!4月刊源表已更新!

毕业推荐 SSCI • 社科类&#xff0c;分区稳步上升&#xff08;最快13天录用&#xff09; IEEE&#xff1a; • 计算机类&#xff0c;1区(TOP)&#xff0c;CCF推荐 SCIE • 计算机工程类&#xff0c;CCF推荐&#xff08;最快16天录用&#xff09; 2024年4月 SCI/SSCI/EI…

环境搭建 | Windows 11系统从0开始搭建SonarQube环境分析C sharp项目代码

1 安装&使用流程 JDK 17环境搭建Sonarqube 10.0安装PostgreSQL 12数据库安装配置MSBuild下载安装SonarScanner for MSBuild使用SonarQube分析C#代码并上传到服务器 注意&#xff1a;SonarQube环境搭建时对各个软件的版本都有要求&#xff0c;如果你不确定使用何版本&…

窥探未来:Web3如何颠覆传统互联网

随着科技的迅速发展&#xff0c;Web3正逐渐成为人们关注的焦点。与传统的Web2相比&#xff0c;Web3代表了一种全新的互联网模式&#xff0c;其潜力和影响力引发了人们对未来的期待和探索。本文将深入探讨Web3如何颠覆传统互联网的各个方面&#xff0c;并展望其可能带来的未来变…

缺省参数

缺省参数 缺省参数概念 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时&#xff0c;如果没有指定实 参则采用该形参的缺省值&#xff0c;否则使用指定的实参。 void Func(int a 0) {cout<<a<<endl; } int main() {Func(); // 没有传…