今天回答一個(gè)朋友的問題吧,ADC如何使用DMA采集多通道模擬電壓。
1寫在前面
這個(gè)問題其實(shí)之前寫過一些相關(guān)文章,原理我之前也有相關(guān)描述。如果想要徹底弄明白其原理,建議閱讀《參考手冊(cè)》、結(jié)合標(biāo)準(zhǔn)外設(shè)庫來理解。
現(xiàn)在很多人習(xí)慣使用STM32CubeMX來直接生成初始化代碼,如果沒有掌握STM32CubeMX、HAL庫,使用STM32CubeMX生成的代碼,或許就不能滿足你的應(yīng)用。
同時(shí),STM32CubeMX生成的代碼,想要根據(jù)代碼進(jìn)一步了解其原理,其實(shí)很難
ADC轉(zhuǎn)換一些基礎(chǔ)原理,我這里就不過多描述了,請(qǐng)直接看下面標(biāo)準(zhǔn)外設(shè)庫源碼、及后面給的注釋。
下面寫2點(diǎn):ADC軟件單次觸發(fā)轉(zhuǎn)換,和連續(xù)轉(zhuǎn)換。
2
ADC,DMA,單次觸發(fā)轉(zhuǎn)換
這里以ADC,使用DMA,通過軟件單次觸發(fā)轉(zhuǎn)換為例。主要需注意幾個(gè)相關(guān)參數(shù)即可。
1.GPIO配置
2.DMA配置
3.ADC配置
4.ADC單次觸發(fā)轉(zhuǎn)換
5.源代碼
/* 靜態(tài)變量 ------------------------------------------------------------------*/static volatile uint16_t sADC_Buf[3];/************************************************函數(shù)名稱 : ADC_GPIO_Configuration功 能 : ADC引腳配置參 數(shù) : 無返 回 值 : 無作 者 : strongerHuang*************************************************/void ADC_GPIO_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; /* 使能時(shí)鐘 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模擬輸入 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOA, &GPIO_InitStructure);}/************************************************函數(shù)名稱 : ADC_DMA_Configuration功 能 : ADC DMA配置參 數(shù) : 無返 回 值 : 無作 者 : strongerHuang*************************************************/void ADC_DMA_Configuration(void){ DMA_InitTypeDef DMA_InitStructure; /* 使能時(shí)鐘 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); /* 配置DMA */ DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR));//外設(shè)地址 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&sADC_Buf[0]); //內(nèi)存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; //傳輸方向:外設(shè) -> 內(nèi)存 DMA_InitStructure.DMA_BufferSize = 3; //傳輸長(zhǎng)度 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設(shè)遞增:關(guān)閉 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //內(nèi)存遞增:打開 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//數(shù)據(jù)寬度 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //正常模式 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //優(yōu)先級(jí) DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream0, &DMA_InitStructure);}/************************************************函數(shù)名稱 : ADC_Configuration功 能 : ADC參數(shù)配置參 數(shù) : 無返 回 值 : 無作 者 : strongerHuang*************************************************/void ADC_Configuration(void){ ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; /* 使能時(shí)鐘 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); /* ADC配置 */ ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure); ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = ENABLE; //瀏覽模式(多通道) ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //連續(xù)轉(zhuǎn)化模式 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //數(shù)據(jù)右對(duì)齊 ADC_InitStructure.ADC_NbrOfConversion = 3; //轉(zhuǎn)換通道數(shù) ADC_Init(ADC1, &ADC_InitStructure); /* 通道配置 */ ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_3Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_3Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_3Cycles); ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); ADC_DMACmd(ADC1, ENABLE); //使能ADC的DMA功能 ADC_Cmd(ADC1, ENABLE); //使能ADC}/************************************************函數(shù)名稱 : ADC_Initializes功 能 : ADC初始化參 數(shù) : 無返 回 值 : 無作 者 : strongerHuang*************************************************/void ADC_Initializes(void){ ADC_GPIO_Configuration(); ADC_DMA_Configuration(); ADC_Configuration();}/************************************************函數(shù)名稱 : ADC_Get功 能 : 轉(zhuǎn)換參 數(shù) : 無返 回 值 : 無作 者 : strongerHuang*************************************************/void ADC_Get(void){ DMA_Cmd(DMA2_Stream0, DISABLE); //關(guān)閉DMA //內(nèi)存地址 DMA_MemoryTargetConfig(DMA2_Stream0, (uint32_t)sADC_Buf, DMA_Memory_0); DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0); //清除標(biāo)志位 DMA_Cmd(DMA2_Stream0, ENABLE); //使能DMA ADC_SoftwareStartConv(ADC1); //啟動(dòng)轉(zhuǎn)換 while(RESET == DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0)); //等待轉(zhuǎn)換完成 //得到3條通道轉(zhuǎn)換結(jié)果:sADC_Buf //進(jìn)行相關(guān)換算,處理...}
提示:以上源代碼只為方便學(xué)習(xí)和理解,請(qǐng)結(jié)合實(shí)際應(yīng)用修改、或增減代碼。
3
ADC,DMA,連續(xù)轉(zhuǎn)換
我這里寫的連續(xù),是ADC連續(xù)轉(zhuǎn)換,同時(shí),DMA循環(huán)存儲(chǔ)。大部分配置和上面差不多,這種方式也用的比較多,寫給大家。
1.DMA配置
2.ADC配置
3.源代碼
/* 靜態(tài)變量 ------------------------------------------------------------------*/static volatile uint16_t sADC_Buf[3];/************************************************函數(shù)名稱 : ADC_GPIO_Configuration功 能 : ADC引腳配置參 數(shù) : 無返 回 值 : 無作 者 : strongerHuang*************************************************/void ADC_GPIO_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; /* 使能時(shí)鐘 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模擬輸入 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOA, &GPIO_InitStructure);}/************************************************函數(shù)名稱 : ADC_DMA_Configuration功 能 : ADC DMA配置參 數(shù) : 無返 回 值 : 無作 者 : strongerHuang*************************************************/void ADC_DMA_Configuration(void){ DMA_InitTypeDef DMA_InitStructure; /* 使能時(shí)鐘 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); /* 配置DMA */ DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR));//外設(shè)地址 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&sADC_Buf[0]); //內(nèi)存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; //傳輸方向:外設(shè) -> 內(nèi)存 DMA_InitStructure.DMA_BufferSize = 3; //傳輸長(zhǎng)度 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設(shè)遞增:關(guān)閉 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //內(nèi)存遞增:打開 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//數(shù)據(jù)寬度 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循環(huán)模式 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //優(yōu)先級(jí) DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream0, &DMA_InitStructure);}/************************************************函數(shù)名稱 : ADC_Configuration功 能 : ADC參數(shù)配置參 數(shù) : 無返 回 值 : 無作 者 : strongerHuang*************************************************/void ADC_Configuration(void){ ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; /* 使能時(shí)鐘 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); /* ADC配置 */ ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure); ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = ENABLE; //瀏覽模式(多通道) ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //連續(xù)轉(zhuǎn)化模式 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //數(shù)據(jù)右對(duì)齊 ADC_InitStructure.ADC_NbrOfConversion = 3; //轉(zhuǎn)換通道數(shù) ADC_Init(ADC1, &ADC_InitStructure); /* 通道配置 */ ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_3Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_3Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_3Cycles); ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); ADC_DMACmd(ADC1, ENABLE); //使能ADC的DMA功能 ADC_Cmd(ADC1, ENABLE); //使能ADC ADC_SoftwareStartConv(ADC1); //啟動(dòng)轉(zhuǎn)換}/************************************************函數(shù)名稱 : ADC_Initializes功 能 : ADC初始化參 數(shù) : 無返 回 值 : 無作 者 : strongerHuang*************************************************/void ADC_Initializes(void){ ADC_GPIO_Configuration(); ADC_DMA_Configuration(); ADC_Configuration();}/************************************************函數(shù)名稱 : ADC_Get功 能 : 轉(zhuǎn)換參 數(shù) : 無返 回 值 : 無作 者 : strongerHuang*************************************************/void ADC_Get(void){ //得到3條通道轉(zhuǎn)換結(jié)果:sADC_Buf //進(jìn)行相關(guān)換算,處理...}
這種方式比較簡(jiǎn)單,直接去讀取轉(zhuǎn)換結(jié)果就行。實(shí)際應(yīng)用需要濾波,求平均之類的操作。
提示:以上源代碼只為方便學(xué)習(xí)和理解,請(qǐng)結(jié)合實(shí)際應(yīng)用修改、或增減代碼。
-
adc
+關(guān)注
關(guān)注
98文章
6406瀏覽量
543855 -
模擬電壓
+關(guān)注
關(guān)注
6文章
64瀏覽量
18278 -
GPIO
+關(guān)注
關(guān)注
16文章
1189瀏覽量
51847 -
stm32cubemx
+關(guān)注
關(guān)注
5文章
280瀏覽量
14721
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論