STM32F103ADC数模转换用DMA读取学习

本文介绍了STM32F103如何利用DMA进行ADC数据转换的读取,详细讲解了DMA配置流程,包括单次传输与连续传输的差异,以及ADC配置和触发DMA请求的关键步骤。作者强调了编程习惯的重要性,通过实例分享学习过程中的经验教训,旨在帮助新手避免常见错误。
摘要由CSDN通过智能技术生成

stm32的ADC功能比较强大,可以实现多达18通道的ADC转换,而且还可以连续转换。这里采用的板子是STM32F103ZET6,由于初学,只使用了一路ADC通道。这里采用的是ADC1的通道1,没有重映射,引脚是PA1。普中的教程里面关于DMA篇的例程是串口发送。自己想加深对DMA的学习,于是就研究了一下ADC转换的DMA读取法。下面开始正文。

DMA简介

关于DMA的介绍我就不多说,手册上很清楚,我这里放一张图便于阅读。我重点讲一下,配置流程和配置过程中出现过的错误。
配置流程并不复杂,但是要注意,DMA的单次传输和循环传输是不同的。单次模式下,启动DMA传输之前都需要线关闭DMA使能,然后配置传输的数据量,然后再使能DMA,否则只能传输一次。在读取的时候也需要检查传输完成标志位TCx,并且需要手动清除。然后再读数据。如果配置的是连续传输,那么流程就简单了,直接开启,接收来自外设地址的请求,外设地址来多少数据,他就传输多少。不用先失能,再使能,也不用判断TCx标志位。但是一定要注意配置好DMA初始化结构体,我在配置存储器地址增量的时候就没有使其使能,这点是我得到了错误的数据。
在这里插入图片描述

ADC简介

ADC我也不过多赘述,简述一下常用的ADC,以ADC1为例,18通道,这里只用了一个通道,通道1,常规配置就讲了,大家也不会改动,比如分频系数,采样周期,模式什么的,我重点讲一下单通道单次转换和连续转换的区别。单次转换的时候,每次使用都需要软件开启,一般地还需要在转换开始的时候指定转换周期,通道数等参数。连续通道则不用关注。软件开启,使能ADC的DMA功能后,就不用管了,只需要,DMA读取就行了。

配置说明

    ADC1的通道1,DMA1的通道1。ADC采用连续转换模式,DMA采用单次转换。用按键启动。

程序

ADC配置

#include "adc.h"

void ADC1_Init(void)
{
   
		GPIO_InitTypeDef GPIO_InitStructure;
		ADC_InitTypeDef ADC_InitStructure;
		
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
		RCC_ADCCLKConfig(RCC_PCLK2_Div6);				//adc的时钟配置为12M
		
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA, &GPIO_InitStructure);
	
		ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;			//独立模式
		ADC_InitStructure.ADC_ScanConvMode = DISABLE;						//单次扫描,既不用等待所有通道都扫描完成才产生EOC
		ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;			//连续转换
		ADC_InitStructure.ADC_ExternalTrigConv =ADC_ExternalTrigConv_None;		//软件触发
		ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;					//	右对齐
		ADC_InitStructure.ADC_NbrOfChannel = 1;						//通道数1个
		ADC_Init(ADC1, &ADC_InitStructure);
	
		ADC_Cmd</
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你可以参考以下的代码示例,该示例演示了如何在STM32F103系列的MCU上使用自动读取多通道的内部ADC数据。 ```c #include "stm32f10x.h" #define ADC1_DR_ADDRESS ((uint32_t)0x4001244C) void ADC_DMA_Config(void) { ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; // 使能DMA1时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 使能ADC1和GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE); // 配置GPIOA.1和GPIOA.2为模拟输入模式 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); // ADC1配置 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 2; ADC_Init(ADC1, &ADC_InitStructure); // 配置ADC1通道1和通道2为采样时间为55.5个周期的单次转换模式 ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_55Cycles5); // 使能ADC1 DMA ADC_DMACmd(ADC1, ENABLE); // DMA配置 DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_ADDRESS; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_Values; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 2; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); // 使能DMA1通道1 DMA_Cmd(DMA1_Channel1, ENABLE); // 使能ADC1 ADC_Cmd(ADC1, ENABLE); // 开始ADC1的软件转换 ADC_SoftwareStartConvCmd(ADC1, ENABLE); } int main(void) { // 初始化系统时钟等 // 配置ADCDMA ADC_DMA_Config(); while (1) { // 处理ADC采样数据 // 延时等待一段时间 Delay(1000); } } ``` 上述代码中,首先需要调用`ADC_DMA_Config()`函数来配置ADCDMA。在该函数中,首先使能了DMA1的时钟,然后使能了ADC1和GPIOA的时钟。接下来,配置了GPIOA.1和GPIOA.2为模拟输入模式。然后,配置了ADC1的工作模式、采样模式和通道数,并设置了通道1和通道2的采样时间。接着,使能了ADC1的DMA功能,并配置了DMA1_Channel1通道的参数。最后,使能了DMA1_Channel1通道和ADC1,并启动了ADC1的软件转换。 在主函数中,可以在一个无限循环中处理ADC采样数据并进行其他操作。这里使用了一个简单的延时函数`Delay()`来等待一段时间,你可以根据实际需求修改延时时间或使用其他方式来控制采样数据的处理频率。 注意,上述代码中的`ADC_Values`是一个数组用于存储ADC采样值,你需要根据实际需要定义并处理这些采样值。 希望以上代码能帮助到你!如果有任何疑问,请随时提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值