ADC是Analog-to-DigitalConverter的縮寫。指模/數轉換器或者模擬/數字轉換器。是指將連續變量的模擬信號轉換爲離散的數字信號的器件。典型的模擬數字轉換器將模擬信號轉換爲表示必定比例電壓值的數字信號。git
從STM32F207的數據手冊中下圖看到,STM32F207VC有3個精度爲12bit的ADC控制器,有16個外部通道,而144腳的STM32F207Zx和176腳的STM32F207Ix由於帶PF腳,因此多8個通道,爲24個外部通道。各通道的A/D轉換能夠單次、連續、掃描或間斷執行,ADC轉換的結果能夠左對齊或右對齊儲存在16位數據寄存器中。github
上面說到,STM32F207有3個12bit的ADC控制器,下文將以ADC3的通道10講解。app
首先咱們確認下ADC外設所在的地址總線,從STM32F207數據手冊中下圖看到,ADC屬於APB2總線下,APB2時鐘頻率是60MHz。具體STM32若是經過外部25M晶振獲得的60MHz的APB2,請看《STM32F207時鐘系統解析》。函數
對應GPIO,咱們從STM32F207數據手冊中看到,咱們可使用PC0做爲ADC3的通道10。測試
這裏須要說明的是,以前的文章使用其餘外設時,好比《STM32PWM輸出》中,尋找對應的管腳時,咱們都是從STM32F207數據手冊的Alternatefunctionmapping表中尋找,這是由於ADC對應的管腳使用的是Additionalfunctions,PWM對應的管腳使用的是Alternatefunctions。ui
區別是:spa
Additionalfunctions:附加,輔助功能,引腳被鏈接到其餘模塊使用,使用時直接普通配置便可,例如ADC的採用輸入通道,配置爲模擬輸入。設計
Alternate functions:複用功能,即將IO口用做普通輸入輸出之外的功能,例如串口輸入輸出,使用時須要配置複用模式。3d
在以前的文章《STM32GPIO詳解》中有以下介紹。code
STM32標準外設庫中有以下代碼
typedef enum { GPIO_Mode_IN = 0x00, /*!< GPIO Input Mode */ GPIO_Mode_OUT = 0x01, /*!< GPIO Output Mode */ GPIO_Mode_AF = 0x02, /*!< GPIO Alternate function Mode */ GPIO_Mode_AN = 0x03 /*!< GPIO Analog Mode */ }GPIOMode_TypeDef;
其中GPIO_Mode_AF對應的就是Alternate functions:複用功能,GPIO_Mode_AN對應的就是Additional functions:附加,輔助功能。
下圖是STM32ADC的結構框圖,咱們將其劃分爲7個部分進行講解。
一、輸入電壓範圍
ADC所能測量的電壓範圍就是VREF-≤ VIN ≤ VREF+,把VSSA 和VREF-接地,把VREF+和VDDA 接3V3,獲得ADC的輸入電壓範圍爲:0~3.3V。
二、輸入通道
ADC的信號時經過輸入通道進入單片機內部的,單片機經過ADC模塊將模擬信號轉換爲數字信號。上圖標記②的部分顯示了外部的16個通道,鏈接的GPIO,對應的關係如上面講解的,須要在STM32F207數據手冊的STM32F20xpin and ball definitions表格中尋找。實際上STM32還有內部通道,ADC1的通道 16鏈接到了芯片內部的溫度傳感器,Vrefint 鏈接到了通道17。ADC2的模擬通道 16和 17鏈接到了內部的VSS。
三、轉換通道
外部的16個通道在轉換時又分爲規則通道和注入通道,其中規則通道最多有16路,注入通道最多有4路(注入通道貌似使用很少),下面簡單介紹一下倆種通道:
規則通道
規則通道顧名思義就是,最日常的通道、也是最經常使用的通道,平時的ADC轉換都是用規則通道實的。規則通道和它的轉換順序在ADC_SQRx寄存器中選擇,規則組轉換的總數應寫入ADC_SQR1寄存器的L[3:0]中。
注入通道
注入通道是相對於規則通道的,注入通道能夠在規則通道轉換時,強行插入轉換,至關於一個「中斷通道」吧。當有注入通道須要轉換時,規則通道的轉換會中止,優先執行注入通道的轉換,當注入通道的轉換執行完畢後,再回到以前規則通道進行轉換。最多4個通道,注入組和它的轉換順序在ADC_JSQR寄存器中選擇。注入組裏轉化的總數應寫入ADC_JSQR寄存器的L[1:0]中。
一個ADC控制器有多個通道,這就涉及使用多個通道進行轉換就涉及到一個前後順序的問題了,畢竟規則轉換通道只有一個數據寄存器。多個通道的使用順序分爲倆種狀況:規則通道的轉換順序和注入通道的轉換順序。
規則通道轉換順序
規則通道中的轉換順序由三個寄存器控制:SQR一、SQR二、SQR3,它們都是32位寄存器。SQR寄存器控制着轉換通道的數目和轉換順序,只要在對應的寄存器位SQx中寫入相應的通道,這個通道就是第x個轉換,經過SQR1寄存器就能瞭解其轉換順序在寄存器上的實現了。
注入通道轉換順序
和規則通道轉換順序的控制同樣,注入通道的轉換也是經過注入寄存器來控制,只不過只有一個JSQR寄存器來控制,控制關係以下:
須要注意的是,只有當JL=4的時候,注入通道的轉換順序纔會按照JSQ一、JSQ二、JSQ三、JSQ4的順序執行。當JL<4時,注入通道的轉換順序偏偏相反,也就是執行順序爲:JSQ四、JSQ三、JSQ二、JSQ1。
配置轉換順序的函數
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel,uint8_t Rank, uint8_t ADC_SampleTime)
ADC轉換的輸入、通道、轉換順序都已經說明了,但ADC轉換是怎麼觸發的呢?就像通訊協議同樣,都要規定一個起始信號才能傳輸信息,ADC也須要一個觸發信號來實行模/數轉換。
其一就是經過直接配置寄存器觸發,經過配置控制寄存器CR2的ADON位,寫1時開始轉換,寫0時中止轉換。在程序運行過程當中只要調用庫函數,將CR2寄存器的ADON位置1就能夠進行轉換,比較好理解。
另外,還能夠經過內部定時器或者外部IO觸發轉換,也就是說能夠利用內部時鐘讓ADC進行週期性的轉換,也能夠利用外部IO使ADC在須要時轉換,具體的觸發由控制寄存器CR2決定。
可獨立設置各通道採樣時間
ADC會在數個ADCCLK週期內對輸入電壓進行採樣,可以使用ADC_SMPR1和ADC_SMPR2
寄存器中的SMP[2:0]位修改週期數。每一個通道都可以使用不一樣的採樣時間進行採樣。
總轉換時間的計算公式以下:
Tconv=採樣時間+12個週期
示例:
ADCCLK = 30 MHz且採樣時間=3個週期時:
Tconv= 3+12=15個週期=0.5us (APB2爲60MHz時)
最小採樣時間0.42us(ADC時鐘=36MHz,採樣週期爲3週期下獲得)。
轉換完成後的數據就存放在數據寄存器中,但數據的存放也分爲規則通道轉換數據和注入通道轉換數據的。
規則數據寄存器
規則數據寄存器負責存放規則通道轉換的數據,經過32位寄存器ADC_DR來存放。
注入數據寄存器
注入通道轉換的數據寄存器有4個,因爲注入通道最多有4個,因此注入通道轉換的數據都有固定的存放位置,不會跟規則寄存器那樣產生數據覆蓋的問題。 ADC_JDRx是 32位的,低 16位有效,高 16位保留,數據一樣分爲左對齊和右對齊,具體是以哪種方式存放,由ADC_CR2的 11 位ALIGN 設置。
能夠產生4種中斷
①DMA溢出中斷
當配置了DMA,且DMA溢出時產生中斷
②規則通道轉換完成中斷
規則通道數據轉換完成以後,能夠產生一箇中斷,能夠在中斷函數中讀取規則數據寄存器的值。這也是單通道時讀取數據的一種方法。
③注入通道轉換完成中斷
注入通道數據轉換完成以後,能夠產生一箇中斷,而且也能夠在中斷中讀取注入數據寄存器的值,達到讀取數據的做用。
④模擬看門狗事件
當輸入的模擬量(電壓)再也不閾值範圍內就會產生看門狗事件,就是用來監視輸入的模擬量是否常。
轉換後的數據是一個12位的二進制數,咱們須要把這個二進制數表明的模擬量(電壓)用數字表示出來。好比測量的電壓範圍是0~3.3V,轉換後的二進制數是x,由於12位ADC在轉換時將電壓的範圍大小(也就是3.3)分爲4096(2^12)份,因此轉換後的二進制數x表明的真實電壓的計算方法就是:
y=3.3* x / 4096
電路圖很簡單,能夠在ADC引腳上輸入不一樣的電壓,也能夠直接方便的使用滑動變阻器實現不一樣的電壓變化。
ADC外設配置的結構體
typedef struct { uint32_t ADC_Resolution; /*!< Configures the ADC resolution dual mode. This parameter can be a value of @ref ADC_resolution */ FunctionalState ADC_ScanConvMode; /*!< Specifies whether the conversion is performed in Scan (multichannels) or Single (one channel) mode. This parameter can be set to ENABLE or DISABLE */ FunctionalState ADC_ContinuousConvMode; /*!< Specifies whether the conversion is performed in Continuous or Single mode. This parameter can be set to ENABLE or DISABLE. */ uint32_t ADC_ExternalTrigConvEdge; /*!< Select the external trigger edge and enable the trigger of a regular group. This parameter can be a value of @ref ADC_external_trigger_edge_for_regular_channels_conversion */ uint32_t ADC_ExternalTrigConv; /*!< Select the external event used to trigger the start of conversion of a regular group. This parameter can be a value of @ref ADC_extrenal_trigger_sources_for_regular_channels_conversion */ uint32_t ADC_DataAlign; /*!< Specifies whether the ADC data alignment is left or right. This parameter can be a value of @ref ADC_data_align */ uint8_t ADC_NbrOfConversion; /*!< Specifies the number of ADC conversions that will be done using the sequencer for regular channel group. This parameter must range from 1 to 16. */ }ADC_InitTypeDef;
ADC_Resolution:ADC 工做模式選擇,ADC分辨率
ADC_ScanConvMode:ADC 掃描(多通道)或者單次(單通道)模式選擇
ADC_ContinuousConvMode:ADC 單次轉換或者連續轉換選擇
ADC_ExternalTrigConvEdge:ADC 外部觸發極性配置
ADC_ExternalTrigConv:ADC 轉換觸發信號選擇
ADC_DataAlign:ADC 數據寄存器對齊格式
ADC_NbrOfConversion:ADC轉換通道數目
typedef struct { uint32_t ADC_Mode;//多重ADC模式選擇 uint32_t ADC_Prescaler; //ADC預分頻 uint32_t ADC_DMAAccessMode; //DMA訪問模式 uint32_t ADC_TwoSamplingDelay; //2個採樣階段之間的延遲 }ADC_CommonInitTypeDef;
ADC_CommonInitTypeDef用來配置ADC_CCR寄存器的相關參數
ADC外設和DMA配置代碼
/** * @brief ADC3 channel10 with DMA configuration * @param None * @retval None */ void ADC3_CH10_DMA_Config(void) { ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* Enable ADC3, DMA2 and GPIO clocks ****************************************/ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); /* DMA2 Stream0 channel2 configuration **************************************/ DMA_InitStructure.DMA_Channel = DMA_Channel_2; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = 1; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; 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_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); DMA_Cmd(DMA2_Stream0, ENABLE); /* Configure ADC3 Channel10 pin as analog input ******************************/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOC, &GPIO_InitStructure); /* ADC Common Init **********************************************************/ 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); /* ADC3 Init ****************************************************************/ ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC3, &ADC_InitStructure); /* ADC3 regular channel7 configuration *************************************/ ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 1, ADC_SampleTime_3Cycles); /* Enable DMA request after last transfer (Single-ADC mode) */ ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE); /* Enable ADC3 DMA */ ADC_DMACmd(ADC3, ENABLE); /* Enable ADC3 */ ADC_Cmd(ADC3, ENABLE); }
代碼下載驗證測試
硬件和軟件開源地址:
https://github.com/strongercjd/STM32F207VCT6
點擊查看本文所在的專輯,STM32F207教程