当前位置: 首页 > news >正文

STM32F407寄存器操作(多通道单ADC+DMA)

1.前言

又是半年没更新了,趁着端午放假有点时间,并且最近项目要用这块知识,我就顺带研究一下ADC吧。

一般来说ADC主要用法包含了1.单通道软件触发(这是最简单和最常用的用法)2.单通道多次采集(需要快速采集数据,常见应用场景就是示波器)3.多通道采集(多个传感器数据)。

其中1、2我在前面的文章里也都介绍过了,这次我就说一说多通道采集。若是不能使用多通道采集,那么407里面两个ADC只能用两个通道,非常浪费。而407内一个ADC包涵16个通道,如此多的通道量基本能覆盖大部分应用场景了。

OK,那么废话不多说,下面我们正式开始介绍。

2.理论介绍

首先我们看看手册上关于这块的描述

这次我就以规则通道为例了,我们所有数据应该都是存放在DR寄存器里,这就会导致一个问题——数据覆盖。因此我们使用扫描模式时必须要用DMA配合使用。理论上来说如果全部使用注入通道,配置会比较简单,因为每个注入通道ADC都有保存的寄存器。不过这次教程我还是以较难的规则通道为例,一次性解决这个问题。

我们看到手册上对于扫描模式的开启只需要关注ADC->CR1里的SCAN,还是比较简单的。

我们看到CR1寄存器里,SCAN是第八位

给第八位置1即可

3.ADC配置

3.1ADC初始化

我首先把程序放出来,这里我用的是通道0和通道3

void init_adc1()
{init_adc12_chinal(0);	//初始化通道0init_adc12_chinal(3);	//初始化通道3ADC1->CR1&=~(3<<24);	//15 ADCCLK 周期ADC1->CR1|=(1<<8);		//扫描模式ADC1->CR2&=~(1<<1);		//单次转换ADC1->CR2&=~(1<<11);	//数据右对齐ADC1->CR2&=~(3<<28);	//禁止触发检测ADC1->SQR1&=~(0XF<<20);	//重置规则通道序重置列长度ADC1->SQR1|=1<<20;     	//2个转换在规则序列中//设置通道0的采样时间ADC1->SMPR2&=~(7<<(3*0));		//通道0	采样时间清空	  ADC1->SMPR2|=(7<<(3*0)); 		//通道0  480个周期,提高采样时间可以提高精确度//设置通道3的采样时间ADC1->SMPR2&=~(7<<(3*3));		//通道3	采样时间清空	  ADC1->SMPR2|=(7<<(3*3)); 		//通道3  480个周期,提高采样时间可以提高精确度//ADC1->CR2|=1<<8;			//使能DMA模式ADC1->CR2|=1<<0;	   	//开启AD转换器	  
}

基本上没有什么特殊的,按照手册上描述的,给第8位置1

记得把要使用的ADC通道初始化好,配置好采样时间,通道数量正确即可

然后是触发的程序

void adc1_scanf(void)
{ADC1->SQR3=0;	//重置规则通道转换配置ADC1->SQR3|=0<<0;	//设置第一次规则转换通道0ADC1->SQR3|=3<<5;	//设置第二次规则转换通道3ADC1->CR2|=1<<30;	//开始转换
}

与软件触发类似,就是要多配置一个通道

3.2主程序

主程序里我们依次初始化DMA,ADC然后触发一次ADC即可

int main(void)
{Stm32_Clock_Init(336,25,2,7);//设置时钟,168MhzNVIC_SetGroup(1);//设置中断分组,分组1init_PinClock();//初始化所有时钟delay_init(168);//初始化延时init_DMAClock();//初始化DMA时钟init_DMA2_S0C0(2);//DMA2 ADC1转换init_adc1(0);//初始化ADCadc1_scanf();//触发ADC
}

3.3测试

我们首先要看一下ADC程序是否正确

那么改如何测试呢?我们外部通道是PA0和PA3,我们的转换顺序是PA0-PA3。那么我们首先将PA3接地,那么程序运行结束后ADC的DR寄存器里应该是最后一次转换的数据,即PA3管脚的电压,但是因为PA3接地的,那么DR寄存器里首先应该是PA0的浮空值,之后应该被PA0覆盖为0。之后我们再把PA0接地,同理DR寄存器里应首先是PA0管脚的0,之后被覆盖为PA3的浮空值。

OK,我们来测试一下,首先把PA3接地。

可以看到DR寄存器内的数据为0

之后我们再把PA0接地

数据也是正常的浮空数据了

4.DMA配置

下面我来说说加上DMA后该怎么写,配合上DMA后ADC读取到的数据就不会丢失了,所有的数据都可以正常读取进RAM里,而且没有什么标志位,比较简单。

4.1DMA初始化

程序如下,与上一次篇配置是一样的,这里不做过多的介绍了

unsigned short adc_scanf[5];//初始化DMA2 组0 通道0
//ADC1
void init_DMA2_S0C0(unsigned int ADCDMAWei)
{DMA2_Stream0 ->CR   = 0;//禁止数据流 ,才能写寄存器 //外设地址寄存器//将所需寄存器的地址放入PAR寄存器DMA2_Stream0 ->PAR  = (unsigned int)(&ADC1->DR);//数据流地址寄存器//M1AR仅在双通道模式下有用//将数据所在地址给M0AR寄存器DMA2_Stream0 ->M0AR = (unsigned int)(&adc_scanf);DMA2_Stream0 ->NDTR = ADCDMAWei;			// 一次传输数量      DMA2_Stream0 ->FCR  = 0x21;		//FIFO所有配置失效DMA2_Stream0 ->CR |= 0<< 6;		//外设到储存器模式//循环模式//当NDTR寄存器减到0时自动重装//单次模式(普通模式)//NDTR减到0后停止DMADMA2_Stream0 ->CR |= 0<< 8;   //非循环模式DMA2_Stream0 ->CR |= 0<< 9;   //外设非增量模式DMA2_Stream0 ->CR |= 1<<10;   //存储器增量模式,指针增加,可用于传输数组DMA2_Stream0 ->CR |= 1<<11;		//外设数据长度:16位DMA2_Stream0 ->CR |= 1<<13;		//存储器数据长度:16位DMA2_Stream0 ->CR |= 2<<16;   //高等优先级//突发传输//DMA占用CPU总线时间,此时CPU无法工作//一个节拍:传输多少次32位变量//应用场景:从ram里读出字节DMA2_Stream0 ->CR |= 0<<21;   //外设突发单次传输DMA2_Stream0 ->CR |= 0<<23;   //存储器突发单次传输DMA2_Stream0 ->CR |= 0<<25;   //通道0DMA2_Stream0 ->CR |= 1<<0;    //使能数据流
}

4.2ADC初始化修改

ADC这里我们需要把CR2里DMA置1

程序如下

void init_adc1()
{init_adc12_chinal(0);	//初始化通道0init_adc12_chinal(3);	//初始化通道3ADC1->CR1&=~(3<<24);	//15 ADCCLK 周期ADC1->CR1|=(1<<8);		//扫描模式ADC1->CR2&=~(1<<1);		//单次转换ADC1->CR2&=~(1<<11);	//数据右对齐ADC1->CR2&=~(3<<28);	//禁止触发检测ADC1->SQR1&=~(0XF<<20);	//重置规则通道序重置列长度ADC1->SQR1|=1<<20;     	//2个转换在规则序列中//设置通道0的采样时间ADC1->SMPR2&=~(7<<(3*0));		//通道0	采样时间清空	  ADC1->SMPR2|=(7<<(3*0)); 		//通道0  480个周期,提高采样时间可以提高精确度//设置通道3的采样时间ADC1->SMPR2&=~(7<<(3*3));		//通道3	采样时间清空	  ADC1->SMPR2|=(7<<(3*3)); 		//通道3  480个周期,提高采样时间可以提高精确度ADC1->CR2|=1<<8;			//使能DMA模式ADC1->CR2|=1<<0;	   	//开启AD转换器	  
}

主函数里面使用方法也是一样的

4.3测试 

首先把PA0接地

可以看到第0位数据为0了

然后再把PA3接地

可以看到第1为是0了

5.结语

STM32F407多通道扫描模式至此就结束了,整个过程还是比较简单的。这样一来ADC的使用范围也比较大了。在此之外ADC还有一个非连续扫描模式,那么我们下一篇文章去看。那么好的,还是老样子,有什么问题评论区见,我们下一篇文章见。

相关文章:

  • PINN for PDE(偏微分方程)1 - 正向问题
  • Beta分布Dirichlet分布
  • Baklib知识中台加速企业服务智能化实践
  • 算法学习--持续更新
  • 头歌之动手学人工智能-Pytorch 之优化
  • 接口自动化常用断言方式
  • 目标检测我来惹1 R-CNN
  • C#实现远程锁屏
  • 【C++】cin和cout的性能问题讨论和优化方法
  • Linux 驱动之设备树
  • c++第四章练习题
  • openpnp - 给M4x0.7mm的直油嘴加油的工具选择
  • day025-网络基础-DNS与ARP协议
  • 征程 6 J6EM 常见 qconfig 配置解读与示例
  • LangGraph(八)——LangGraph运行时
  • 博士论文写作笔记
  • 【大模型DA】Unified Language-driven Zero-shot Domain Adaptation
  • agent-zero: 打造你的AI专属AI助理
  • Canvas: trying to draw too large(256032000bytes) bitmap.
  • JavaScript 模块系统:CJS/AMD/UMD/ESM
  • 东城动态网站制作专业定制/百度爱采购官网
  • 云南旅游网站建设公司/经典软文案例或软文案例
  • 网站制作网免费/百度指数关键词搜索趋势
  • 猎场第几集做的网站推广/seo优化培训课程
  • wordpress网站工具栏/推广普通话海报
  • 网站色彩搭配表/创建一个网站需要什么