引言:在进行ADC转换时,如果只采集一个IO的转换,那转换后的数据将会存储在数据寄存器,每转换一次,数据寄存器就被新来的数据覆盖,因此,只进行一个通道转换是没问题的。但如果是多通道转换呢?数据寄存器只会保存最后一个通道转换的数据,因为前面都被覆盖了,串口上所有通道显示的电压值也全是最后一个通道的AD转换数据。所以,DMA传输横空出世了,它的作用是在ADC第一个通道转换完成后第一时间将数据转运出来,防止被下一个通道转运的数据覆盖,把转运后的数据存在一个和通道数数目一样的数组里面就好了,这样,就能第一时间把所有通道数据保留在数组里面,然后用串口一一显示。
那么啥是DMA呢?就好比你在学校里面自己写作业自己交,CPU就相当于你自己,你不但要自己写作业,还要自己去交,是不是很费时间呢,如果学委帮你把作业去交,你就能省出时间去做更多有意义的事情,学委就好比DMA。总的来说,CPU无时无刻的在进行数据之间的运算、存储、传输,DMA的出现能帮助CPU传输数据,减少CPU的负担。
#include "stm32f10x.h" // Device header
#include <stdio.h>
uint16_t AD_Value[2];//定义数据用来存放ADC两个通道转换的数据
int fputc(int ch,FILE *f) //加入这个函数就能使用C语言的printf()打印<stdio.h>
{
USART_SendData(USART1,ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)== RESET);
return ch;
}
void Adc_Init(void)
{
/*开启各个外设的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOA,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//AD特有的分频函数,6分频,就是72/6=12MH
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//ADC用的是模拟输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
GPIO_Init(GPIOA,&GPIO_InitStructure);
/*ADC_RegularChannelConfig(ADCx,通道y,序列z,采样时间),通道:0~17,序列:1~18*/
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//允许连续转换
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//软件触发
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式,就是只用ADC1
ADC_InitStructure.ADC_NbrOfChannel = 2; //2个通道转换
ADC_InitStructure.ADC_ScanConvMode = ENABLE;//扫描模式,就是扫描多个通道的
ADC_Init(ADC1,&ADC_InitStructure);
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//ADC1的数据寄存器地址
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//16位半字
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不自增
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;存储器地址
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;存储器、半字
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;存储器地址不自增
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设作为传输源
DMA_InitStructure.DMA_BufferSize = 2;//计数器,一个通道就计一次,这里使用两个通道
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环模式
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//非存储器到存储器
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//DMA通道响应的优先级设置
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/*使能*/
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
/*ADC数据校准*/
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
/*ADC软件触发*/
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
void Usart1_Init(uint32_t bound)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = bound;//波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;//同时能发送和接收
USART_InitStructure.USART_Parity = USART_Parity_No;//无检验位
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//传输数据宽度:一个字节
USART_Init(USART1,&USART_InitStructure);
USART_Cmd(USART1,ENABLE);
USART_ClearFlag(USART1,USART_FLAG_TC);//清除发送标志位
}
void delay(u32 num)//ms延时函数
{
u16 i,j;
for(i=0;i<num;i++)
for(j=0;j<0x800;j++);
}
int main(void)
{
Adc_Init();
Usart1_Init(9600);
while(1)
{
/*ADC转换后的数据是整数,最大为4095,要强制转换为float*/
printf("AD0电压V= %.2f\r\n",(float)AD_Value[0]/4095*3.3);
printf("AD1电压V= %.2f\r\n",(float)AD_Value[1]/4095*3.3);
delay(3900);//延时
}
}
电压转换公式:V=AD转换值/4095*3.3