本文共 4200 字,大约阅读时间需要 14 分钟。
在以往学习中,使用ADC采集都是规则单通道软件启动采集的那种方式,这种方式也仅限于学习。在真正的项目中会采集很多路ADC,显示上面方式不合理,这时候就可以使用ADC+DMA进行多路采集,Nice!!!
STM32 ADC 简介
ADC通道与GPIO管脚对应表
DMA简介
更多理论内容可以查看中文参考数据手册
知道以上东西可以撸代码了。
使用固件库配置还是挺"容易"的。看配置代码就理解了。DMA初始化
:
static void ADC_DMA_Init(void){ DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; //ADC外设数据寄存器地址作为基地址 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)g_stTempInfo.ADC_ValTab; //存储数据内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //传输方向为外设到内存 DMA_InitStructure.DMA_BufferSize = 4; //单位是下面的HalfWord 16bit DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //用到多通道ADC, 所以使能自动增加,一个通道转换完的数据放在g_stTempInfo.ADC_ValTab[0], //下一个通道数据就自动存放在g_stTempInfo.ADC_ValTab[1] 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); /* Enable DMA1 Channel1 */ DMA_Cmd(DMA1_Channel1, ENABLE); //使能DMA通道1 }
模拟输入引脚初始化
:
static void GPIO_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //模拟输入引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚 GPIO_Init(GPIOB, &GPIO_InitStructure); }
PA5对应ADC1的通道5,PB0对应ADC1的通道8
ADC初始化
: static void ADC_Init(void){ ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE ); //使能ADC1通道时钟 RCC_ADCCLKConfig(RCC_PCLK2_Div6); //72M/6=12,ADC最大时间不能超过14M ADC_DeInit(ADC1); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1工作在独立模式 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数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 2; //顺序进行规则转换的ADC通道的数目 ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1,ADC_Channel_5, 1, ADC_SampleTime_239Cycles5); //ADC1通道5配置->PA5 第3个参数为转换顺序,转换后的值存在g_stTempInfo.ADC_ValTab[0]中 ADC_RegularChannelConfig(ADC1,ADC_Channel_8, 2, ADC_SampleTime_239Cycles5); //ADC1通道8配置->PB0 第3个参数为转换顺序,转换后的值存在g_stTempInfo.ADC_ValTab[1]中 ADC_DMACmd(ADC1, ENABLE); //使能ADC1的DMA功能 ADC_Cmd(ADC1, ENABLE); //使能ADC1 ADC_ResetCalibration(ADC1); //重置指定的ADC1的校准寄存器 while(ADC_GetResetCalibrationStatus(ADC1)); //获取ADC1重置校准寄存器的状态,设置状态则等待 ADC_StartCalibration(ADC1); //开始指定ADC1的校准状态 while(ADC_GetCalibrationStatus(ADC1)); //获取指定ADC1的校准程序,设置状态则等待 ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 }
初始化GPIO、DMA、ADC
:
void MyADC_Init(void){ GPIO_Init(); ADC_DMA_Init(); //ADC DMA初始化 ADC_Init(); //ADC初始化}
获取多个通道的ADC值
:
void GetAverageAdcVal(stADCTempInfo *TempInfo,u8 n){ u8 x = 0; u32 ledVal = 0; u32 machineVal = 0; if(TempInfo == NULL) { printf("指针为空\r\n"); return; } for(x = 0; x < n; x++) { while(!DMA_GetFlagStatus(DMA1_FLAG_TC1)); //等待DMA传输完成 ledVal += TempInfo->ADC_ValTab[0]; machineVal += TempInfo->ADC_ValTab[1]; delay_ms(1); } ledVal = ledVal / n; TempInfo->averageLedAdcVal = ledVal; machineVal = machineVal / n; TempInfo->averageMachineAdcVal = machineVal;}
转载地址:http://dtzcz.baihongyu.com/