STM32F407 HAL库定时器触发ADC采集与DMA数据传输(定时器TIM+ADC+DMA)

news2024/10/6 12:39:05

在STM32F407系列微控制器的开发中,结合定时器、ADC(模数转换器)与DMA(直接存储器访问)控制器,能够显著提升数据采集与传输的效率。本文将指导你如何使用STM32 HAL库,通过定时器触发ADC1的单通道采集,利用DMA传输数据,最终通过串口将电压值打印出来。具体实现中,我们将读取ADC1的通道5(对应引脚PA5),并将转换得到的电压值发送到串口助手上进行显示。

 一、开发环境

硬件:正点原子探索者 V3 STM32F407开发板

单片机:STM32F407ZGT6

Keil版本:5.32

STM32CubeMX版本:6.9.2

STM32Cube MCU Packges版本:STM32F4xx_DFP.2.14.0

  二、配置STM32CubeMX

  1. 启动STM32CubeMX,新建STM32CubeMX项目
  2. 选择MCU:在软件中选择你的STM32型号-STM32F407ZGT6。
  3. 选择时钟源:

  4. 配置时钟:
  5. 使能Debug功能:Serial Wire
  6. HAL库时基选择:SysTick
  7. USART1配置:选择异步模式。
  8. 开启外部时钟:配置系统时钟,确保ADC和串口的外部时钟已开启。

  9. 配置ADC

1)选择ADC1作为采集模块。

2)设置ADC1的通道5(对应引脚PA5)为采集通道。

3)配置采样时间和分辨率。通常,采样时间越长,ADC的转换精度越高,但也会增加转换时间。

4)启用连续禁用模式。

5)禁用扫描模式,因为我们只采集一个通道。

10.配置定时器3

  • 时钟源频率:84 MHz
  • 预分频器(Prescaler)的值:0
  • 周期(Period)的值:840 - 1 = 839(因为是从0开始计数,所以实际周期是840个时钟周期,但寄存器中存储的是839)
  • 定时器时钟频率 = 时钟源频率 / (预分频器值 + 1) = 84 MHz / (1 + 1) = 84 MHz / 1 = 84 MHz
  • 定时器输出频率 = 定时器时钟频率 / (周期值 + 1) = 假设的定时器时钟频率 84 MHz / 840 = 100 kHz

11.配置工程参数:在Project标签页中,配置项目名称和位置,选择工具链MDK-ARM。​ 12.生成代码:在Code Generator标签页中,配置工程外设文件与HAL库,勾选头文件.c和.h文件分开,然后点击Project > Generate Code生成代码。 

三、代码实现与部署

  1.  main.c增加代码:main.c的第1行添加printf的头文件#include<stdio.h>。​​​​​ADC电压换算时用到公式:待测电压=(ADC的返回值/4095​)∗3.3V​.

    /* USER CODE BEGIN Header */
    #include<stdio.h>
    /**
      ******************************************************************************
      * @file           : main.c
      * @brief          : Main program body
      ******************************************************************************
      * @attention
      *
      * Copyright (c) 2024 STMicroelectronics.
      * All rights reserved.
      *
      * This software is licensed under terms that can be found in the LICENSE file
      * in the root directory of this software component.
      * If no LICENSE file comes with this software, it is provided AS-IS.
      *
      ******************************************************************************
      */
    /* USER CODE END Header */
    /* Private user code ---------------------------------------------------------*/
    /* USER CODE BEGIN 0 */
    
    #define ADC_DMA_BUF_SIZE        200          /* ADC DMA采集 BUF大小, 应等于ADC通道数的整数倍 */
    
    uint16_t g_adc_dma_buf[ADC_DMA_BUF_SIZE];   /* ADC DMA BUF */
    extern __IO uint8_t g_adc_dma_sta;               /* DMA传输状态标志, 0,未完成; 1, 已完成 */
    // 当前ADC值的索引  
    volatile uint16_t adc_index = 0;  
    /* USER CODE END 0 */
    
    /**
      * @brief  The application entry point.
      * @retval int
      */
    int main(void)
    {
      /* USER CODE BEGIN 1 */
    
      /* USER CODE END 1 */
    
      /* MCU Configuration--------------------------------------------------------*/
    
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();
    
      /* USER CODE BEGIN Init */
    
      /* USER CODE END Init */
    
      /* Configure the system clock */
      SystemClock_Config();
    
      /* USER CODE BEGIN SysInit */
    
      /* USER CODE END SysInit */
    
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_DMA_Init();
      MX_USART1_UART_Init();
      MX_ADC1_Init();
      MX_TIM3_Init();
      /* USER CODE BEGIN 2 */
    	HAL_TIM_Base_Start(&htim3);                           //开启定时器3
        // 启动ADC采集并通过DMA传输数据到缓冲区  
       HAL_ADC_Start_DMA(&hadc1, (uint32_t*)g_adc_dma_buf, ADC_DMA_BUF_SIZE);
    	 while (!g_adc_dma_sta);                                   //等待转换完毕
        
    	for (uint16_t i = 0; i < ADC_DMA_BUF_SIZE; i++)
    	{
        printf("%.3f\r\n", g_adc_dma_buf[i] * 3.3 / 4095); //数据打印,查看结果
    	}
    
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
    	}
      /* USER CODE END 3 */
    }
  2. stm32f4xx_it.c增加代码

    ADC(模数转换器)负责进行数据采集,而DMA(直接存储器访问)则负责将这些数据高效地搬运到指定的内存区域。当DMA完成数据的搬运任务后,整个ADC的采集过程也随之宣告结束。此时,DMA会触发一个中断信号,通知CPU搬运操作已经完成。

    响应这个DMA中断的是DMA2_Stream0_IRQHandler函数。一旦此函数被调用,它便会执行一系列操作来告知CPU:ADC的采集工作已经全部完成。在程序层面,我们可以通过检查一个名为g_adc_dma_sta的标志位的状态变化,来确认ADC的采集过程是否已经结束。

    /* USER CODE BEGIN 0 */
    __IO uint8_t g_adc_dma_sta =0;  
    /* USER CODE END 0 */
    /**
      * @brief This function handles DMA2 stream0 global interrupt.
      */
    void DMA2_Stream0_IRQHandler(void)
    {
      /* USER CODE BEGIN DMA2_Stream0_IRQn 0 */
    
      /* USER CODE END DMA2_Stream0_IRQn 0 */
      HAL_DMA_IRQHandler(&hdma_adc1);
      /* USER CODE BEGIN DMA2_Stream0_IRQn 1 */
       g_adc_dma_sta = 1;    
      /* USER CODE END DMA2_Stream0_IRQn 1 */
    }
    
  3.  usart.c增加代码:usart.c的第1行添加头文件#include <stdio.h>
    #include <string.h>,在末尾用户代码区增加如下代码。printf调用“fputc()”,“fgetc()”,该函数会使用HAL_UART_Transmit发送数据。
    /*
    * 添加如下代码,可不在工程设置中勾选Use MicroLIB
    */
    #pragma import(__use_no_semihosting)
    
    struct __FILE
    {
    	int a;
    };
    
    FILE __stdout;
    FILE __stdin;
    
    void _sys_exit(int x)
    {
    }
    
    
    /*****************************************************
    *function: 写字符文件函数
    *param1: 输出的字符
    *param2: 文件指针
    *return: 输出字符的ASCII码
    ******************************************************/
    int fputc(int ch, FILE *f)
    {
    	HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 10);
    	return ch;
    }
    /*****************************************************
    *function: 读字符文件函数
    *param1: 文件指针
    *return: 读取字符的ASCII码
    ******************************************************/
    int fgetc(FILE *f)
    {
    	uint8_t ch = 0;
    	HAL_UART_Receive(&huart1, (uint8_t*)&ch, 1, 10);
    	return (int)ch;
    }
  4. 连接USART1:用USB转TTL工具连接当前硬件USART1的PA9、PA10,GND。​​
  5. 打开串口助手:​​
  6. 编译代码:Keil编译生成的代码。
  7. 烧录程序:将编译好的程序用ST-LINK烧录到STM32微控制器中。

四、运行结果

观察结果:一旦程序烧录完成并运行,串口助手打印出PA5的电压,当接地的时候得出的电压值是0,当输入正弦波得到如下结果。

0.073
0.137
0.361
0.735
1.248
1.724
2.242
2.721
3.09
3.3
3.3
3.3
3.158
2.783
2.326
1.809
1.256
0.798
0.417
0.164
0.068
0.128
0.356
0.723
1.189
1.71
2.235
2.713
3.111
3.3
3.3
3.3
3.169
2.832
2.337
1.809
1.3
0.764
0.418
0.175
0.073
0.134
0.358
0.713
1.183
1.702
2.223
2.702
3.095
3.3
3.3
3.3
3.173
2.807
2.346
1.824
1.31
0.817
0.429
0.176
0.064
0.094
0.347
0.7
1.164
1.684
2.216
2.699
2.978
3.3
3.3
3.3
3.173
2.782
2.345
1.838
1.319
0.824
0.438
0.172
0.071
0.121
0.343
0.697
1.171
1.678
2.22
2.692
3.076
3.273
3.3
3.3
3.184
2.822
2.361
1.86
1.328
0.836
0.434
0.201
0.057
0.116
0.34
0.679
1.065
1.655
2.186
2.66
3.063
3.3
3.3
3.3
3.197
2.869
2.379
1.884
1.348
0.80.103
0.069
0.216
0.507
0.939
1.415
1.947
2.454
2.899
3.219
3.3
3.3
3.3
3.016
2.596
2.102
1.579
1.065
0.618
0.288
0.098
0.069
0.212
0.506
0.915
1.401
1.939
2.466
2.899
3.222
3.3
3.3
3.3
3.016
2.609
2.107
1.596
1.065
0.625
0.294
0.108
0.07
0.202
0.499
0.907
1.405
1.926
2.451
2.887
3.219
3.3
3.3
3.3
3.025
2.609
2.119
1.593
1.083
0.629
0.297
0.106
0.068
0.2
0.494
0.901
1.396
1.929
2.437
2.888
3.219
3.3
3.3
3.3
3.025
2.619
2.122
1.598
1.086
0.637
0.303
0.106
0.067
0.21
0.486
0.902
1.386
1.914
2.43
2.879
3.212
3.3
3.3
3.3
3.036
2.634
2.14
1.603
1.09
0.635
0.297
0.113
0.068
0.203
0.482
0.89
1.381
1.907
2.414
2.872
3.214
3.3
3.3
3.3
3.049
2.633
2.144
1.617
1.102
0.65
0.308
0.119
0.068
0.195
0.484
0.872
1.376
1.901
2.417
2.862
3.208
3.3
3.3
3.3
3.007
2.646
2.154
1.633
1.115
0.663
0.312
0.108
0.065
0.172
0.462
0.873
1.398
1.888
2.401
2.866
3.197
3.3
3.3
3.3
3.049
2.649
2.152
1.629
1.11
0.704
0.319
0.104
0.066
0.191
0.473
0.857
1.351
1.877
2.4
2.854
3.201
3.3
3.3
3.3
3.069
2.664
2.173
1.647
1.131
0.674
0.326
0.084
0.068
0.189
0.46
0.855
1.347
1.87
2.387
2.837
3.198
3.3
3.3
3.3
3.063
2.67
2.181
1.66
1.145
0.687
0.332

​导入excel看波形,采样点数 = 采样频率 / 信号频率 = 100kHz / 10kHz = 10。

为了验证采样率是否是100k,ADC去采集信号发生器产生的5k信号,excel看波形,可以看到一个周期20个点。采样点数 = 采样频率 / 信号频率 = 100kHz / 5kHz = 20,说明采样率为100k。

再进一步验证,ADC去采集信号发生器产生的10k信号,excel看波形,可以看到一个周期10个点。采样点数 = 采样频率 / 信号频率 = 100kHz / 10kHz = 10。说明采样率为100k。

​五、注意事项

1.确保你的开发环境和工具已经正确安装和配置。

2.如果没有打印电压值,按一下复位键,检查连接和电源是否正确,注意根据你所用的硬件来接线,不要接错线。
3.在串口打印数据时,要确保波特率等参数与串口助手设置一致。

通过上述步骤,你就可以在STM32F407上实现基于定时器触发的单通道ADC采集与DMA数据传输,并通过串口打印电压值的功能了。

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

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

相关文章

认知战认知作战:欧盟向中国纯电动车加关税为背景的认知作战方式与策略

认知战认知作战&#xff1a;欧盟向中国纯电动车加关税为背景的认知作战方式与策略 关键词&#xff1a;欧盟, 中国, 纯电动车, 关税, 认知战, 舆论战, 政治动员, 外交反击, 市场份额, 保护主义, 技术升级, 中立第三方, 友军, 国际贸易, 合作与竞争,认知作战,新质生产力,人类命运…

信号用wire类型还是reg类型定义

wire类型就是一根线&#xff0c;线有两端&#xff0c;一端发生改变&#xff0c;经过线传递的信号当然也会发生改变&#xff0c;reg类型则不同&#xff0c;可以把reg类型理解为存储数据的寄存器&#xff0c;当满足一定条件时&#xff0c;数值才被激活发生改变。 那么&#xff0…

英国本科毕业论文写作如何确立论点

英国本科毕业论文关系到留学生是否能顺利毕业。因此&#xff0c;写好英国本科毕业论文也便成了留学生在毕业季的头等大事。那么应当怎么做才能更好地完成毕业论文呢&#xff1f;在本文中&#xff0c;英国翰思教育将从论点这个内容展开说说&#xff0c;如果高质量地完成毕业论文…

2024 uniapp入门教程 01:含有vue3基础 我的第一个uniapp页面

uni-app官网uni-app,uniCloud,serverless,快速体验,看视频&#xff0c;10分钟了解uni-app,为什么要选择uni-app&#xff1f;,功能框架图,一套代码&#xff0c;运行到多个平台https://uniapp.dcloud.net.cn/ 准备工作&#xff1a;HBuilder X 软件 HBuilder X 官网下载&#xf…

AI产品经理的崛起

“It will be unthinkable not to have artificial intelligence integrated into a product. Because everyone will expect it.” _Sam Altman, CEO & Co-founder (OpenAI)_正如Sam Altman所说的&#xff0c;2024年人工智能技术继续快速发展。我们看到了各种AI模型&#…

[Python] 《人生重开模拟器》游戏实现

文章目录 优化点一&#xff1a;多元化的天赋系统示例天赋&#xff1a;天赋选择代码&#xff1a; 优化点二&#xff1a;更加多样化的随机事件年龄阶段划分&#xff1a;随机事件代码&#xff1a; 优化点三&#xff1a;设定人生目标人生目标示例&#xff1a;人生目标代码&#xff…

ubunut声卡配置 播放视频没有声音的解决方法 alsamixer和pavucontrol的使用方法

文章目录 &#x1f319;ubuntu22.04网页没有声音&#xff0c;声卡提示Dummy Output方法一&#xff1a;切换内核&#x1f319;方法二&#xff1a;使用知乎的方法 &#x1f319;ubuntu22.04 连接蓝牙耳机&#xff0c;1秒后断连解决方法ubuntu声音操作alsamixerpavucontrol通过are…

高校校园交友系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;基础数据管理&#xff0c;论坛管理&#xff0c;公告信息管理&#xff0c;轮播图信息管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;用户&#…

15分钟学 Python 第40天:Python 爬虫入门(六)第一篇

Day40 &#xff1a;Python 爬取豆瓣网前一百的电影信息 1. 项目背景 在这个项目中&#xff0c;我们将学习如何利用 Python 爬虫技术从豆瓣网抓取前一百部电影的信息。通过这一练习&#xff0c;您将掌握网页抓取的基本流程&#xff0c;包括发送请求、解析HTML、存储数据等核心…

【青训入营】青海湖租车之旅

# 问题描述油价飞升的今天&#xff0c;我们尽量减少花费。我们出门旅游&#xff0c;有时候租车去旅游也是一种不错的方式。这次我们这次旅游是从「青海湖」到「景点 X」&#xff0c;景点 X 可以是「敦煌」、「月牙泉」等&#xff0c;线路的路径是唯一的&#xff0c;假设我们每走…

佳易王电玩店ps5计时计费系统软件倒计时语音提醒软件操作教程

一、前言 【试用版软件下载可以点击最下方官网卡片】 佳易王电玩店ps5计时计费系统软件倒计时语音提醒软件操作教程 1、时间显示&#xff1a;正常使用时间&#xff0c;直观显示在对应桌旁。 2、倒计时显示&#xff1a;右侧显示剩余多少分钟&#xff0c; 3、定时语音提醒&am…

zookeeper选举kafka集群的controller

zookeeper选举kafka集群的controller目录 文章目录 zookeeper选举kafka集群的controller目录前言一、实操体验controller的选举二、模拟controller选举四、删除controller节点 前言 kafka集群的controller是kafka集群中一个有特殊作用的broker&#xff0c;负责整个kafka集群的…

【网络原理】TCP保持“可靠传输”的秘密--确认应答与超时重传机制

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;计算机网络那些事 在上一篇文章中&#xff0c;我们研究了UDP报文的结构&#xff0c;由于其报头中只有两个字节来记录报文长度&#xff0c;导致一次最多只能传输 64KB 的数据&#xff0c;这完全无法满…

Mamba 架构在医学图像分析中的全面综述:分类、分割、重建及其他应用

Mamba 是一种状态空间模型&#xff08;State Space Model, SSM&#xff09;的特例&#xff0c;作为医学图像分析中模板驱动深度学习方法的替代方案&#xff0c;正日益受到关注。尽管 transformer 是强大的架构&#xff0c;但它也存在一些缺陷&#xff0c;例如计算复杂度为平方级…

图元是什么,图元在组态设计中发挥什么作用

从事HMI设计的小伙伴&#xff0c;肯定听说过图元的这个概念&#xff0c;图元简单可以理解为构成图形的最近本元素&#xff0c;如线、面、几何体等等&#xff0c;在一些组态软件中&#xff0c;图元的的重要性甚至超过了界面&#xff0c;因为有了图元就意味着有了千变万化的界面&…

[ESP32]ESP-IDF使用组件添加U8g2图形库

U8g2 在ESP32使用u8g2的时候可以使用添加component的方式进行, 由于官方的component库没有, 这里我找到了一个可以使用的github库, 使用git的方式进行添加这一个库 具体的原理可以看[官方手册](https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32/api-guides/to…

《Windows PE》4.1.4 手工重构导入表

接下来我们做一个稍微复杂一些的实验&#xff0c;实验需要四个程序&#xff1a; HelloWorld.exe&#xff1a;弹出MessageBox窗口&#xff08;实验1已实现&#xff09;。 Regedit.exe&#xff1a;添加注册表启动项。 LockTray.exe&#xff1a;锁定任务栏窗口。 UnLockTray.exe&…

各省份农林牧渔业总产值统计数据(2000-2022年)

数据来源 《中国统计年鉴》 农业、林业、牧业和渔业作为国民经济的重要组成部分&#xff0c;对于保障国家粮食安全、促进区域经济发展、实现农业农村现代化和乡村振兴具有重要意义。 2000年-2022年全国各省份农林牧渔业总产值统计数据&#xff08;大数据&#xff09;.zip资源…

DBMS-3.1 SQL(1)——SQL概述和DDL

本文章的素材与知识来自李国良老师和王珊老师。 SQL概述 1.定义 2.SQL语句分类 数据定义语言DDL&#xff08;Data Definition Language&#xff09; 一.表 1.创建表 &#xff08;1&#xff09;语法 中括号内的项为可选项。分号标志着一条SQL语句的结束。SQL语句不区分大小…

【Spring Boot React】Spring Boot和React教程 完整版

【Spring Boot & React】Spring Boot和React教程 在B站找到一个不错的SpringBoot和React的学习视频&#xff0c;作者是amigoscode 【Spring Boot & React】Spring Boot和React教程 2023年更新版【Spring Boot React】价值79.9美元&#xff0c;全栈开发&#xff0c;搭…