STM32同时测量4路模拟电压,用DMA自动搬运到数组内,不用软件干预。

2024-03-21 05:52

本文主要是介绍STM32同时测量4路模拟电压,用DMA自动搬运到数组内,不用软件干预。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

下午我做的实验室同时测量4路模拟信号,测量的结果通过ADC开启DMA触发,叫数据转运小帮手自动把数据搬走,放到数组内,就省去了,各种检测啊,恢复标志位啊,等等的麻烦操作,直接去读数组的值就好了,数据已经被更新了。是不是很方便呢?好了,先看看实验的结果:

这样看起来是不是和上篇文章的结果差不多呢?

再来看看主函数中的操作吧,就很简单了:

这样看是不是就非常简单了啊,只是调用一下初始化函数,就把需要读的4路模拟电压数据放到了一个数组中了,接下来就来看看这个初始化到底都干了些什么工作吧?我先来简单的总结一下初始化顺序:代码中可能有点不一样,那是没有总结的结果。

1:/*开启时钟(ADC1,GPIOA,DMA1)*/

2:/*设置ADC时钟*/

3:/*GPIO初始化*/(模拟输入模式,A0,A1,A2,A3四个端口)

4:/*规则组通道配置*/(序列1放通道0,序列2放通道1,序列3放通道2,序列4放通道3)

5:/*ADC初始化*/(独立模式,数据右对齐,不使用外部触发,连续转换,扫描模式,通道数4)

6:/*DMA初始化*/(外设地址:ADC的DR也就是电压值的寄存器

                                        数据宽度:16位的半字

                                        地址自增:外设不自增,内存地址(目标地址)自增

                                        传输方向:外设为源

                                        转运次数:4(一次16位)

                                        DMA_Mode模式:循环模式

                                        DMA_M2M存储器到存储器:失能,由ADC外设触发转运

                                        优先级:中等)

7:    /*DMA使能*/ DMA_Cmd()

8:      /*ADC1触发DMA1使能*/  ADC_DMACmd

9:     /*ADC使能*/ADC_Cmd()

10:/*ADC校准*/  复位校准   开始校准

11:/*ADC触发*/    ADC_SoftwareStartConvCmd

好了总共总结起来就是上面的11步就能实现STM32自动把4路模拟信号的值搬运到一个数组中,完成在主函数中只调用数组就能知道结果的目标。下面开始展示我写的程序了,感觉有点乱,就不整理了:

MyADC.c文件:

#include "stm32f10x.h"                  // Device headeruint16_t AD_Value[4];       //###########################void MyADC_Init(void){//开始RCC时钟,包括ADC和GPIO的时钟,ADCCLK的分频器也需要配置一下。RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);   //开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //开启GPIOA的时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);      // ADC的时钟选择6分频,也就是72M/6=12M//配置GPIO,把需要用的GPIO配置成模拟输入的模式GPIO_InitTypeDef GPIO_InitStruct;    //GPIO初始化的结构体GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;  // 模式为模拟输入GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;       // 初始化端口0GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;  //端口频率50MGPIO_Init(GPIOA, &GPIO_InitStruct);           // GPIOA初始化//配置多路开关,把左边的通道接入规则组列表里ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_28Cycles5); //ADC1规则配置(ADC1,通道1,列表1,转换时间28.5个时钟(12M))ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_28Cycles5);  //#############################ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_28Cycles5);  //###########################ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_28Cycles5);  //XXXXXXXXXXXXXXXX//配置ADC转换器,用结构体配置,一大块的参数。ADC_InitTypeDef ADC_InitStruct;                    //ADC初始化结构体ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;            //连续转换模式:开启  ####################ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;            // 数据对齐:右对齐ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;   //ADC中断触发:空,也就是软件触发ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;               // ADC模式:独立模式ADC_InitStruct.ADC_NbrOfChannel = 4;                   //规则组中的通道数:4   #######################################3ADC_InitStruct.ADC_ScanConvMode = ENABLE;             //扫描模式:开启 ######################################ADC_Init(ADC1, &ADC_InitStruct);                    //ADC初始化//************************************************//调用DMA_Init,初始化各个参数(包括外设和存储器的起始地址,数据宽度,地址是否自增,方向,传输计数器,是否需要自动重装,选择触发源,通道优先级)DMA_InitTypeDef DMA_InitStruct;DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;        //######################################DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;   //数据宽度,按半字的宽度(16位)搬运  #######################DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;    //不启用地址自增   ########################// 以上是外设站点(数据来源)的起始地址、数据宽度、是否自增。DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)AD_Value;  //###############################DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;  //数据宽度,按半字的宽度粘贴  #######################DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;       //启用地址++自增//以上3条是存储器(目的地)的起始地址、数据宽度、是否自增。DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;    //传输方向DMA_InitStruct.DMA_BufferSize = 4;  //缓存区大小,其实就是传输计数器 传输4次半个字(16位)  ##########################DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;   //传输模式,其实就是是否启用自动重装    自动重装  ###############DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;   //选择是硬件触发还是软件触发    硬件触发  ######################DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;   // 优先级    选择中等优先级DMA_Init(DMA1_Channel1, &DMA_InitStruct);  //第一个参数选择了是哪个DMA到哪个DMA通道,第二个参数结构体//调用DMA_CMD,通道使能(要在对应的外设调用XXX_DMACmd开启一下触发信号的输出,如果需要DMA的中断,就调用DMA_ITConfig,开启中断输出,再在NVIC里,配置中断通道,最后写中断函数就行了)DMA_Cmd(DMA1_Channel1, ENABLE);           //###################  失能改使能  ADC_DMACmd(ADC1, ENABLE);      //开启ADC1的DMA请求   ##################################//************************************************//打开ADC_CMD()开启ADC。ADC_Cmd(ADC1, ENABLE);                        // ADC开启//校准ADCADC_ResetCalibration(ADC1);                        // 复位校准ADCwhile(ADC_GetResetCalibrationStatus(ADC1) == SET);    // 等待校准标志位置0ADC_StartCalibration(ADC1);                         // 开始复位校准ADCwhile(ADC_GetCalibrationStatus(ADC1) == SET);          // 等待开始校准结束标志位置0ADC_SoftwareStartConvCmd(ADC1, ENABLE);  //软件触发
}

下面是MyADC.h文件:

#ifndef __MYADC_H
#define __MYADC_Hextern uint16_t AD_Value[4]; void MyADC_Init(void);#endif

下面是主函数main.c文件:

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "MyADC.h"
#include "Delay.h"int main(void)
{OLED_Init();       //oled  屏幕初始化MyADC_Init();       //ADC初始化OLED_ShowString(1,1,"Val_1:");OLED_ShowString(2,1,"Val_2:");OLED_ShowString(3,1,"Val_3:");OLED_ShowString(4,1,"Val_4:");while(1){OLED_ShowNum(1,7, AD_Value[0], 4);      //显示val的数值,这个数值的范围为0-4095OLED_ShowNum(2,7, AD_Value[1], 4);OLED_ShowNum(3,7, AD_Value[2], 4);OLED_ShowNum(4,7, AD_Value[3], 4);Delay_ms(200);}
}

好了,通过上面的一顿操作猛如虎,编译下载后就能看到自己想要的结果了,想要屏幕上的字不闪的那么快主函数中的循环内就加大点延时,不在乎就小点或是没有,我为了拍照拍全就加了200毫秒的延时,就能拍全了。

这篇关于STM32同时测量4路模拟电压,用DMA自动搬运到数组内,不用软件干预。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/831926

相关文章

微信公众号脚本-获取热搜自动新建草稿并发布文章

《微信公众号脚本-获取热搜自动新建草稿并发布文章》本来想写一个自动化发布微信公众号的小绿书的脚本,但是微信公众号官网没有小绿书的接口,那就写一个获取热搜微信普通文章的脚本吧,:本文主要介绍微信公众... 目录介绍思路前期准备环境要求获取接口token获取热搜获取热搜数据下载热搜图片给图片加上标题文字上传图片

SpringBoot中封装Cors自动配置方式

《SpringBoot中封装Cors自动配置方式》:本文主要介绍SpringBoot中封装Cors自动配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录SpringBoot封装Cors自动配置背景实现步骤1. 创建 GlobalCorsProperties

idea中创建新类时自动添加注释的实现

《idea中创建新类时自动添加注释的实现》在每次使用idea创建一个新类时,过了一段时间发现看不懂这个类是用来干嘛的,为了解决这个问题,我们可以设置在创建一个新类时自动添加注释,帮助我们理解这个类的用... 目录前言:详细操作:步骤一:点击上方的 文件(File),点击&nbmyHIgsp;设置(Setti

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

一文详解SQL Server如何跟踪自动统计信息更新

《一文详解SQLServer如何跟踪自动统计信息更新》SQLServer数据库中,我们都清楚统计信息对于优化器来说非常重要,所以本文就来和大家简单聊一聊SQLServer如何跟踪自动统计信息更新吧... SQL Server数据库中,我们都清楚统计信息对于优化器来说非常重要。一般情况下,我们会开启"自动更新

Flask 验证码自动生成的实现示例

《Flask验证码自动生成的实现示例》本文主要介绍了Flask验证码自动生成的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习... 目录生成图片以及结果处理验证码蓝图html页面展示想必验证码大家都有所了解,但是可以自己定义图片验证码

Python Excel实现自动添加编号

《PythonExcel实现自动添加编号》这篇文章主要为大家详细介绍了如何使用Python在Excel中实现自动添加编号效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、背景介绍2、库的安装3、核心代码4、完整代码1、背景介绍简单的说,就是在Excel中有一列h=会有重复

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

CSS模拟 html 的 title 属性(鼠标悬浮显示提示文字效果)

《CSS模拟html的title属性(鼠标悬浮显示提示文字效果)》:本文主要介绍了如何使用CSS模拟HTML的title属性,通过鼠标悬浮显示提示文字效果,通过设置`.tipBox`和`.tipBox.tipContent`的样式,实现了提示内容的隐藏和显示,详细内容请阅读本文,希望能对你有所帮助... 效

Springboot的自动配置是什么及注意事项

《Springboot的自动配置是什么及注意事项》SpringBoot的自动配置(Auto-configuration)是指框架根据项目的依赖和应用程序的环境自动配置Spring应用上下文中的Bean... 目录核心概念:自动配置的关键特点:自动配置工作原理:示例:需要注意的点1.默认配置可能不适合所有场景