【STM32F407 ADC+DMA采集压力变送器数据(HAL库)】

这篇具有很好参考价值的文章主要介绍了【STM32F407 ADC+DMA采集压力变送器数据(HAL库)】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 内容简述

之前项目中需要对麦克传感器的mpm480隔爆压力变送器(4-20ma输出)的数据进行实时采集,使用STM32F407作为控制器,使用信号转换模块将压力变送器4-20ma的输出转换为0-3.3v的信号量,输入到STM32F407板子的ADC1的通道10,并使用DMA2通道0数据流0将采集的多个值从外设直接存入存储器,并对该次采集的值进行排序、去掉过大过小值后取平均值,最后在FreeRTOS实时操作系统的一个任务中计算出测得的气压值。

2. 电路连接

本文采用的是二线制压力变送器,连接如下图。
注意:黄色线(输出电压)连接板子的ADC1的通道10 (PC0)引脚、并需要共地!

二线制压力变送器电路连接图

f407dma adc hal,学习总结,嵌入式,单片机,stm32,嵌入式硬件

信号转换模块电路连接图

f407dma adc hal,学习总结,嵌入式,单片机,stm32,嵌入式硬件

ADC通道图

f407dma adc hal,学习总结,嵌入式,单片机,stm32,嵌入式硬件

3. GPIO、ADC、DMA初始化

ADC采集后通过DMA传输到目标内存缓冲区地址,即定义的数组ADC_ConvertedValue[ADC_SAMPLE_PNUM],本文在.h文件中设置ADC_SAMPLE_PNUM的参数为50,即一次性传输50个数据。
注意:
ADC_Handle.Init.Resolution = ADC_RESOLUTION_12B; 代表用12位数值代表采集的值,即最大2的12次方,4096;
ADC_Config.SamplingTime = ADC_SAMPLETIME_56CYCLES; 采样周期选择,采样周期越短,ADC 转换数据输出周期就越短但数据精度也越低,采样周期越长,ADC 转换数据输出周期就越长同时数据精度越高。

bsp_adc.c
#include "./adc/bsp_adc.h"

/*--------定义变量、结构体----------*/
volatile int16_t ADC_ConvertedValue[ADC_SAMPLE_PNUM] = {0};//存储采集的数据
DMA_HandleTypeDef DMA_Init_Handle;
ADC_HandleTypeDef ADC_Handle;//ADC句柄
ADC_ChannelConfTypeDef ADC_Config;


/*--------GPIO初始化----------*/
static void Rheostat_ADC_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    // 使能 GPIO 时钟
    RHEOSTAT_ADC_GPIO_CLK_ENABLE();
    // 配置 IO
    GPIO_InitStructure.Pin = RHEOSTAT_ADC_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStructure.Pull = GPIO_NOPULL ; //不上拉不下拉
    HAL_GPIO_Init(RHEOSTAT_ADC_GPIO_PORT, &GPIO_InitStructure);
}


/*--------DMA、ADC参数初始化----------*/
static void Rheostat_ADC_Mode_Config(void)
{

    /*-----------DMA Init 结构体参数 初始化------------*/
    // ADC1使用DMA2,数据流0,通道0,这个是手册固定死的
    // 开启DMA时钟
    RHEOSTAT_ADC_DMA_CLK_ENABLE();
    // 数据传输通道
    DMA_Init_Handle.Instance = RHEOSTAT_ADC_DMA_STREAM;
    // 数据传输方向为外设到存储器
    DMA_Init_Handle.Init.Direction = DMA_PERIPH_TO_MEMORY;
    // 外设寄存器只有一个,地址不用递增
    DMA_Init_Handle.Init.PeriphInc = DMA_PINC_DISABLE;
    // 存储器地址固定
    DMA_Init_Handle.Init.MemInc = DMA_MINC_ENABLE;
    // // 外设数据大小为半字,即两个字节
    DMA_Init_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    //	存储器数据大小也为半字,跟外设数据大小相同
    DMA_Init_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    // 循环传输模式
    DMA_Init_Handle.Init.Mode = DMA_CIRCULAR;
    // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
    DMA_Init_Handle.Init.Priority = DMA_PRIORITY_HIGH;
    // 禁止DMA FIFO	,使用直连模式
    DMA_Init_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    // FIFO 大小,FIFO模式禁止时,这个不用配置
    DMA_Init_Handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    DMA_Init_Handle.Init.MemBurst = DMA_MBURST_SINGLE;
    DMA_Init_Handle.Init.PeriphBurst = DMA_PBURST_SINGLE;
    // 选择 DMA 通道,通道存在于流中
    DMA_Init_Handle.Init.Channel = RHEOSTAT_ADC_DMA_CHANNEL;
    //初始化DMA流,流相当于一个大的管道,管道里面有很多通道
    HAL_DMA_Init(&DMA_Init_Handle);
    /*---------------开启DMA传输,需要修改一次传输的个数---------------*/
    HAL_DMA_Start(&DMA_Init_Handle, RHEOSTAT_ADC_DR_ADDR, (uint32_t)&ADC_ConvertedValue, ADC_SAMPLE_PNUM);

    // 开启ADC时钟
    RHEOSTAT_ADC_CLK_ENABLE();
    /*-------------ADC Init 结构体 参数 初始化------------*/
    // ADC1
    ADC_Handle.Instance = RHEOSTAT_ADC;
    // 时钟为fpclk 4分频
    ADC_Handle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;
    // ADC 分辨率
    ADC_Handle.Init.Resolution = ADC_RESOLUTION_12B;
    // 禁止扫描模式,多通道采集才需要
    ADC_Handle.Init.ScanConvMode = DISABLE;
    // 连续转换
    ADC_Handle.Init.ContinuousConvMode = ENABLE;
    // 非连续转换
    ADC_Handle.Init.DiscontinuousConvMode = DISABLE;
    // 非连续转换个数
    ADC_Handle.Init.NbrOfDiscConversion   = 0;
    //禁止外部边沿触发
    ADC_Handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
    //使用软件触发,外部触发不用配置,注释掉即可
    //ADC_Handle.Init.ExternalTrigConv      = ADC_EXTERNALTRIGCONV_T1_CC1;
    //数据右对齐
    ADC_Handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    //转换通道 1个
    ADC_Handle.Init.NbrOfConversion = 1;
    //使能连续转换请求
    ADC_Handle.Init.DMAContinuousRequests = ENABLE;
    //转换完成标志
    ADC_Handle.Init.EOCSelection          = DISABLE;
    // 初始化ADC
    HAL_ADC_Init(&ADC_Handle);
    //---------------------------------------------------------------------------
    ADC_Config.Channel      = RHEOSTAT_ADC_CHANNEL;
    ADC_Config.Rank         = 1;
    // 采样时间间隔
    ADC_Config.SamplingTime = ADC_SAMPLETIME_56CYCLES;
    ADC_Config.Offset       = 0;
    // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期
    HAL_ADC_ConfigChannel(&ADC_Handle, &ADC_Config);

    HAL_ADC_Start_DMA(&ADC_Handle, (uint32_t*)&ADC_ConvertedValue, 1);
}

4. 排序、求平均值

必须先将保存采集数据的数组ADC_ConvertedValue赋值给数组isarray,使用冒泡排序的方法,两个数比较大小,较大的数下沉,较小的数冒起来,再对采集的50个值的中间10个取平均值。

bsp_adc.c
/*--------排序、求平均值----------*/
int16_t ADC1_Proc_Value(void)
{
    uint16_t temp = 0;
    uint32_t sum = 0;
    uint32_t value = 0;
    uint16_t isarray[ADC_SAMPLE_PNUM] = {0};

    for(int i = 0; i < ADC_SAMPLE_PNUM; i++)
    {
        isarray[i] = ADC_ConvertedValue[i];
    }
    //排序
    for(int i = 0; i < ADC_SAMPLE_PNUM - 1; i++)
    {
        for(int j = i + 1; j < ADC_SAMPLE_PNUM; j++)
        {
            if(isarray[j] < isarray[i])
            {
                temp = isarray[i];
                isarray[i] = isarray[j];
                isarray[j] = temp;
            }
        }
    }

//		printf("\r\nisarray[0]=%d\r\n",isarray[0]);
//		printf("\r\nisarray[1]=%d\r\n",isarray[1]);
//		printf("\r\nisarray[2]=%d\r\n",isarray[2]);
//		printf("\r\nisarray[3]=%d\r\n",isarray[3]);
//		printf("\r\nisarray[4]=%d\r\n",isarray[4]);
//		printf("\r\nisarray[5]=%d\r\n",isarray[5]);
//		printf("\r\nisarray[6]=%d\r\n",isarray[6]);
//		printf("\r\nisarray[7]=%d\r\n",isarray[7]);
//		printf("\r\nisarray[8]=%d\r\n",isarray[8]);
//		printf("\r\nisarray[9]=%d\r\n",isarray[9]);
//		printf("\r\nisarray[10]=%d\r\n",isarray[10]);
//		printf("\r\nisarray[11]=%d\r\n",isarray[11]);
//		printf("\r\nisarray[23]=%d\r\n",isarray[23]);
//		printf("\r\nisarray[24]=%d\r\n",isarray[24]);
//		printf("\r\nisarray[25]=%d\r\n",isarray[25]);
//		printf("\r\nisarray[26]=%d\r\n",isarray[26]);
//		printf("\r\nisarray[27]=%d\r\n",isarray[27]);
//		printf("\r\nisarray[28]=%d\r\n",isarray[28]);
//		printf("\r\nisarray[29]=%d\r\n",isarray[29]);

//去掉过大过小值,求平均值
    for(int k = 20; k < ADC_SAMPLE_PNUM - 20; k++)
    {
        sum += isarray[k];
    }
    printf("\r\nsum=%d\r\n", sum);
    value = sum / (ADC_SAMPLE_PNUM - 40);

    printf("\r\nvalue=%d\r\n", value);

    return value;
}

5. 头文件以及宏定义等

bsp_adc.h
#ifndef __BSP_ADC_H
#define	__BSP_ADC_H

#include "stm32f4xx.h"
#define ADC_SAMPLE_PNUM             50//AD 采样点数数  


// ADC GPIO 宏定义
#define RHEOSTAT_ADC_GPIO_PORT              GPIOC
#define RHEOSTAT_ADC_GPIO_PIN               GPIO_PIN_0
#define RHEOSTAT_ADC_GPIO_CLK_ENABLE()      __GPIOC_CLK_ENABLE()

// ADC 序号宏定义
#define RHEOSTAT_ADC                        ADC1
#define RHEOSTAT_ADC_CLK_ENABLE()           __ADC1_CLK_ENABLE()
#define RHEOSTAT_ADC_CHANNEL                ADC_CHANNEL_10

// ADC DR寄存器宏定义,ADC转换后的数字值则存放在这里
#define RHEOSTAT_ADC_DR_ADDR                ((uint32_t)ADC1+0x4c)

// ADC DMA 通道宏定义,这里我们使用DMA传输
#define RHEOSTAT_ADC_DMA_CLK_ENABLE()       __DMA2_CLK_ENABLE()
#define RHEOSTAT_ADC_DMA_CHANNEL            DMA_CHANNEL_0
#define RHEOSTAT_ADC_DMA_STREAM             DMA2_Stream0

void Rheostat_ADC_GPIO_Config(void);
void Rheostat_ADC_Mode_Config(void);
int16_t ADC1_Proc_Value(void);
#endif 

6. 主函数任务程序

本文是建立在移植FreeRTOS实时操作系统,所以创建的一个任务代表ADC的采集,如果是裸板,那么while(1)中前4行即该传感器的对应关系计算方式,该对应关系是通过之前在4ma->0v、20ma->3.3v测的数据计算得到的。

main.c
/**********************************************************************
  * @ 函数名  : ADC_Task
  * @ 功能说明: ADC_Task任务主体
  * @ 参数    :   
  * @ 返回值  : 无
  ********************************************************************/
static void ADC_Task(void* parameter)
{	
    while (1)
    {
		float value=ADC1_Proc_Value();
		float ADC_P=244.140625f*value+100000;
		printf("\r\nvalue=%f\r\n",value);
		printf("\r\nADC_P=%0.2fPa\r\n" ,ADC_P);	    

		vTaskDelay(500);   /* 延时500个tick */
    }
}

7. 总结

以单通道可以类似地写出多通道的ADC+DMA数据采集,可以用二维数组保存数据。文章来源地址https://www.toymoban.com/news/detail-597012.html

到了这里,关于【STM32F407 ADC+DMA采集压力变送器数据(HAL库)】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32F407以太网DMA描述符和数据链路层收发数据

    本文主要介绍STM32F407单片机MAC内核的DMA描述符,以及如何实现以太网二层的数据收发。这一篇先实现数据链路层的正常收发,下一篇再去介绍如何把LWIP移植到单片机上。大部分资料都是把LWIP移植和以太网卡驱动放在一起介绍,对新手不友好。所以我在这篇文章先把网卡驱动

    2024年02月10日
    浏览(49)
  • stm32F407学习DAY.14 在DMA模式下进行USART串口数据收发(正点原子例程为例)

    目录 一、DMA配置 1、DMA1和DMA2的请求映射 2、DMA挂载总线 3、DMA相关库函数 ​4、DMA配置过程(以串口1为例) 1)进行时钟使能 2)等待DMA可配置 3)初始化DMA(串口1的TX为DMA2 数据流7 通道4,RX为DMA2 数据流5 通道4) a.DMA外设地址par: b.DMA存储器0地址mar: c.数据传输量ndtr: 4)

    2024年02月04日
    浏览(39)
  • 从STM32F407到AT32F407(一)

    雅特力公司的MCU有着性能超群,价格优越的巨大优势,缺点是相关资料少一些,我们可以充分利用ST的现有资源来开发它。 我用雅特力的STM32F437开发板,使用原子 stm32f407的开发板自带程序,测试串口程序,原设定串口波特率为115200,但是输出乱码,波特率改成230400,串口输

    2024年02月02日
    浏览(50)
  • STM32F407的介绍

    内核 32位 高性能ARM Cortex-M4处理器 时钟: 高达168MHz,实际还可以超频一点点 stm32f407的主频通过PLL倍频后能够达到168MHz,而且芯片内置一个16MHz的晶振和一个32KHz的晶振,可以满足不同功耗的需求。 支持FPU(浮点运算)和DSP指令 144引脚 114个IO口 存储器容量: 1024K FLASH, 192K

    2024年02月10日
    浏览(42)
  • STM32F407的时钟

    时钟源用来为环形脉冲发生器提供频率稳定且电平匹配的方波时钟脉冲信号。它通常由石英 晶体振荡器和与非门组成的正反馈振荡电路组成,其输出送至环形脉冲发生器。 F4开发指南P107 F4开发指南P108 HSI高速内部时钟源 High Speed Internal。RC 振荡器,频率为 16MHz。可以直接作为

    2024年02月10日
    浏览(43)
  • STM32F407——串口通信

    本文将对串口通信的分类和基于 stm32 的串口配置进行介绍,以及如何使用串口调试助手进行串口收发功能的调试,旨在帮助还不会使用 stm32 单片机串口资源进行通信的家人们快速学会如何使用串口来进行通信。 (纯干货、快速上手、零基础也能会!!!) (1)串口,即串

    2023年04月08日
    浏览(40)
  • 初识 STM32和STM32F407简介

    2007 年 6 月,ST 在北京发布了全球第一款基于 ARM Cortex M3 内核的 32 位通用微控制 器芯片:STM32F103,以优异的性能,丰富的资源,超高的性价比,迅速占领市场,从此一鸣 惊人,一发不可收拾,截止到 2020 年 6 月,STM32 累计出货量超过 45 亿颗。 战舰开发板使用的 STM32F103ZET6

    2023年04月08日
    浏览(64)
  • STM32F407 --USART使用

    目录 1. 串口配置--普通模式 2. 实现数据的传输主函数 1)单引号双引号的应用数组传输 2)将调试信息用串口打印传送到电脑上 1. 串口配置--普通模式 F407使用的M4内核与F103使用的M3内核不一样,导致在使用配置上有区别。需要在F103配置的基础上专门将GPIO的PIN配置成复用功能

    2024年02月16日
    浏览(46)
  • STM32F407的PWM

    泉水 STM32 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。 高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。 通用定时器也能同时产生多达 4路的 PWM 输出 STM32F407 最多可以同时产生 30 路 PWM 输出! 这里我们仅利用 TIM14的 CH1 产生一路 PWM 输出。 如上所

    2024年02月17日
    浏览(38)
  • STM32F407 移植 FreeRTOS

    本实验是基于正点原子 STM32F407ZG 探索者开发板完成的,所以需要一个STM32F407ZG 探索者开发板 用于移植的基础工程(下面会讲) FreeRTOS源码(下面会讲) 本实验所有用到的代码:基于正点原子STM32F407的FreeRTOS移植工程.zip 1.1 移植前准备 1.1.1 基础工程 由于后续需要用到 LED、

    2024年02月08日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包