[寄存器版本]STM32F407 独立ADC-DMA-双通道
程序员文章站
2022-06-09 10:50:54
...
STM32F407 独立ADC-DMA-双通道之寄存器版本
最近自学了ADC采样实验,但是发现基本都是库函数版本的,因此就想着把自己写的寄存器版本的代码写出来,顺便复习一下。
功能
使用ADC1的通道5和通道9,采集电压,并通过串口打印出来。
开发环境
Keil uVision5编辑器
FlyMcu下载器
XCOM V2.6串口调试助手
ADC简介
时钟选择:
ADC时钟挂载在APB2总线上,可以配置ADC通用寄存器进行分频,但是注意分频后不要超过36M。
通道选择:
每个ADC有18个通道,其中外部通道有16个,可以分为2组:规则通道和注入通道。
代码编写
main.c函数如下:
extern u16 ADC_ConvertedValue[2];
float ADC_Vol[2] = {0,0};
int main(void)
{
Stm32_Clock_Init(336,8,2,7);
delay_Init(168);
uart_Init(84,115200);
Led_Init();
Dma2_Init();
Adc1_Init();
while(1)
{
LED0 = !LED0;
ADC_Vol[0] = (float)ADC_ConvertedValue[0]/4096(float)3.3;
ADC_Vol[1] = (float)ADC_ConvertedValue[1]/4096(float)3.3;
printf("\r\n ADC_ConvertedValue[0] = 0x%04x \r\n",ADC_ConvertedValue[0]);
printf("\r\n ADC_ConvertedValue[1] = 0x%04x \r\n",ADC_ConvertedValue[1]);
printf("\r\n ADC_Vol[0] = %f V \r\n",ADC_Vol[0]);
printf("\r\n ADC_Vol[1] = %f V \r\n",ADC_Vol[1]);
delay_ms(1000);
}
}
led.c函数如下:
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;
}
adc.c函数如下:
void ADC1_Init(void)
{
ADC1_Io_Init();
ADC1_Config();
}
void ADC1_Io_Init(void)
{
RCC->AHB1ENR |= 1<<0;//使能GPIOA时钟
RCC->AHB1ENR |= 1<<1;//使能GPIOB时钟
GPIO_Set(GPIOA,PIN5,GPIO_MODE_AIN,0,0,GPIO_PUPD_NONE);
GPIO_Set(GPIOB,PIN1,GPIO_MODE_AIN,0,0,GPIO_PUPD_NONE);
}
void ADC1_Config(void)
{
RCC->APB2ENR |= 1<<8;
ADC->CCR |= 1<<16;//4分频
ADC->CCR &= ~(31<<0);//独立模式
ADC1->CR1 &= ~(3<<24);//12位分辨率
ADC1->CR1 |= 1<<8;//使能扫描模式
ADC1->CR2 &= ~(1<<11);//数据右对齐
ADC1->CR2 &= ~(1<<1);//单次转换模式
ADC1->SMPR2 |= 7<<3*5;//通道5采样时间
ADC1->SMPR2 |= 7<<3*9;//通道9采样时间
ADC1->SQR1 |= 1<<20;//2次转换
ADC1->SQR3 |= 5<<0;//通道5第一次转换
ADC1->SQR3 |= 9<<5;//通道9第二次转换
ADC1->CR2 |= 1<<9;//只要发生数据转换且DMA = 1,便会发出DMA请求
ADC1->CR2 |= 1<<8;//使能DMA模式
ADC1->CR2 |= 1<<0;//使能ADC
ADC1->CR2 |= 1<<30;//开始转换规则通道
}
dma.c函数如下:
u16 ADC_ConvertedValue[2] = {0,0};
void Dma2_Init(void)
{
RCC->AHB1ENR |= 1<<22;//使能DMA2时钟
DMA2_Stream0->CR &= ~(1<<0);//禁止数据流
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 |= 2;//要传输的数据项的总数
DMA2_Stream0->CR &= ~(7<<25);//选择通道0
DMA2_Stream0->CR |= 1<<16;//优先级 中
DMA2_Stream0->FCR &= ~(1<<2);//使能直接模式
DMA2_Stream0->CR |= 1<<13;//存储器数据大小 半字 16位(MSIZE)
DMA2_Stream0->CR |= 1<<11;//外设数据大小 半字 16位 (PSIZE)
DMA2_Stream0->CR |= (1<<10);//每次数据传输后,存储器地址指针递增(MSIZE)
DMA2_Stream0->CR &= ~(1<<9);//外设地址指针固定
DMA2_Stream0->CR |= 1<<8;//使能循环模式
DMA2_Stream0->CR &= ~(3<<6);//数据传输方向 外设到存储器
DMA2_Stream0->CR |= 1<<0;//使能数据流
}
下载验证
通道5采集0V电压,通道9采集3.3V电压。