欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[寄存器版本]STM32F407独立ADC-DMA-单通道

程序员文章站 2022-03-13 17:31:48
...

STM32F407独立ADC+DMA+单通道之寄存器版本

使用寄存器写代码,可以很好地理解STM32F407的底层。本文章使用ADC1单通道采集,配置通道5,采样后的数据通过DMA传输到串口打印出来。
由于是寄存器的版本,里面提到的寄存器请配合《STM32F4xx 中文参考手册》ADC 章节一起阅读,效果会更佳。本文章不多做介绍!

ADC简介

STM32F407ZGT6 有3 个ADC,每个ADC 有12 位、10 位、8 位和6 位可选,每个ADC 有16 个外部通道。另外还有两个内部ADC 源和VBAT 通道挂在ADC1 上。ADC 具有独立模式、双重模式和三重模式,对于不同AD 转换要求几乎都有合适的模式可选。
STM32F407的ADC模拟电路时钟最大为36M,不要超过36M,否则会不准确。
STM32F407将 ADC的转换分为 2个通道组:规则通道组和注入通道组。规则通道相当于正常运行的程序,而注入通道相当于中断。在程序正常运行的时候,注入通道的转换时可以打断规则通道的转化的,在注入通道被转换完成后,规则通道才可以继续转换。

代码的编写

main.c如下:

#include "led.h"
#include "adc.h"
#include "dma.h"
#include "delay.h"
#include "usart.h"

extern u16 ADC_ConvertedValue;
float  ADC_Vol; 

int main(void)
{
	Stm32_Clock_Init(336,8,2,7);
	delay_init(168);
	uart_init(84,115200);
	Led_Init();
	Dma2_Config();
	Adc1_Init();
	
	while(1)
	{
		LED0 = !LED0;
		
		ADC_Vol = (float) ADC_ConvertedValue/4096*(float)3.3;
		printf("\r\n ADC_VAL = 0x%04x \r\n",ADC_ConvertedValue);
		printf("\r\n ADC_VAL = %f V \r\n",ADC_Vol);
		
		delay_ms(1000);
	}
}

dma.c如下

#include "dma.h"
#include "stm32f4xx.h"

u16 ADC_ConvertedValue = 0;

void Dma2_Config(void)
{
	RCC->AHB1ENR |= 1<<22;//使能DMA2时钟
	
	DMA2_Stream0->CR &= ~(1<<0);//关闭DMA2的传输
	while(DMA2_Stream0->CR & 0x01);//等待DMA2可以被设置
	DMA2->LIFCR |= 0x3D<<0;//清空中断标志位
	
	DMA2_Stream0->PAR |= ((u32)&ADC1->DR);//外设地址
	DMA2_Stream0->M0AR |= (u32)&ADC_ConvertedValue;//存储器地址 
	DMA2_Stream0->NDTR |= 1;//要传输的数据项数目 
	DMA2_Stream0->CR &= ~(7<<25);//选择通道0
	DMA2_Stream0->CR |= 1<<16;//优先级为中
	DMA2_Stream0->FCR &= ~(1<<2);//使能直接模式
	DMA2_Stream0->CR &= ~(3<<6);//外设到存储器
	DMA2_Stream0->CR &= ~(1<<9);//外设地址固定
	DMA2_Stream0->CR &= ~(1<<10);//存储器地址固定
	DMA2_Stream0->CR |= 1<<11;//外设数据大小
	DMA2_Stream0->CR |= 1<<13;//存储器数据大小
	DMA2_Stream0->CR |= (1<<8);//使能循环模式  	
	
	DMA2_Stream0->CR |= 1<<0;
}

adc.c如下:

#include "sys.h"
#include "adc.h"

void Adc1_Io_Init(void)
{
	RCC->AHB1ENR |= 1<<0;//使能GPIOA时钟
	GPIO_Set(GPIOA,PIN5,GPIO_MODE_AIN,0,0,GPIO_PUPD_NONE);
}

void Adc1_Config(void)
{
	RCC->APB2ENR |= 1<<8;//使能ADC1时钟
	
	ADC->CCR |= 1<<16; //时钟4分频 
	ADC->CCR &= ~(31<<0);//配置为独立模式
	
	ADC1->CR1 &= ~(3<<24);//12位分辨率
	ADC1->CR1 &= ~(1<<8);//禁止扫描模式
	
	ADC1->CR2 &= ~(3<<28);//禁止触发检测
	ADC1->CR2 &= ~(1<<11);//右对齐
	
	ADC1->CR2 |= 1<<1;//连续转换模式
	
	ADC1->SMPR2 |= (7<<3*5);//通道5的采样时间
	ADC1->SQR1 &= ~(15<<20);//一次转换
	ADC1->SQR3 |= 5<<0;//通道5第一次转换
	
	ADC1->CR2 |= 1<<8;//使能DMA模式
	ADC1->CR2 |= 1<<9;//只要发生数据转换且DMA=1,便发出DMA请求
	
	ADC1->CR2 |= 1<<0;//使能ADC
	ADC1->CR2 |= 1<<30;//开始转换规则通道的 
}

void Adc1_Init(void)
{
	Adc1_Io_Init();
	Adc1_Config();
}

led.c如下:

#include "led.h"
#include "sys.h"

void Led_Init(void)
{
	RCC->AHB1ENR |= 1<<5;
	GPIO_Set(GPIOF,PIN9,GPIO_MODE_OUT,GPIO_OTYPE_PP,GPIO_SPEED_2M,GPIO_PUPD_PU);
	LED0 = 1;
}

相关的.h文件很简单,此处不作编写。

下载验证

上述代码亲测有效。在代码编译成功后,我们通过下载代码到STM32F4开发板上,可以看到如下所示的结果:
[寄存器版本]STM32F407独立ADC-DMA-单通道
分别测试了3.3V和0V电压,由于存在电阻的原因,所以测试在3.3V左右以及0V左右。

相关标签: 嵌入式