在以往學習中,使用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;
}