神通廣大的各位互聯網的網友們、你們早上中午晚上好好好、今早起來很準時的收到了兩條10086的扣月租的信息、心痛不已、懷着這心情、又開始了STM32的研究、早上作了計算機控制的PID實驗,又讓我想起了飛思卡爾的電磁小車、、曾經的電感電壓採集讓我心碎的多少次、又讓我開心了多少次、但已經成爲過去、(軟件和硬件都會影響),呵呵、估計有人已經猜到我接下來要介紹什麼了、在大家面前、我已無祕密、額、其實標題也直接「表白」了、看到標題,別嚇到哈、並非要用英文寫、至於緣由是什麼、請往下看:函數
好吧、言歸正傳:STM32的ADC模塊,請容許我用如此通俗的語言:普通話 來介紹STM32ADC模塊的特點ui
一、1MHz轉換速率、12位轉換結果(12位、記住這個12位哈、由於2^12=4096 ,也請記住4096哈)es5
STM32F103系列:在56MHz時轉換時間爲:1μsspa
在72MHz時轉換時間爲:1.17μs3d
二、轉換範圍:0~3.6V (3.6v---->當你須要將採集的數據用電壓來顯示的話:設你採集的數據爲:x[0~4095],此時的計算公式就爲:(x / 4096) * 3.6))code
三、ADC供電要求:2.4V~3.6 V(可千萬別接到 5V 的石榴裙子底下呀)blog
四、ADC輸入範圍:VREF-≤ VIN ≤VREF+ (VREF+和VREF-只有LQFP100封裝纔有)事件
五、雙重模式(帶2個ADC的設備): 8種轉換模式圖片
六、最多有18個通道:16個外部通道ip
2個內部通道:鏈接到溫度傳感器和內部參考電壓(VREFINT = 1.2V)
......(略,請看參考手冊哈,因爲篇幅,就不過多的列出來了、、說到略、讓我想起了月光寶盒諸葛亮的:略懂略懂、、其實我也是略懂略懂而已、、)
十二、DMA功能(僅ADC1有)
本博客裏,因爲篇幅、因此就以獨立模式下的單次轉換爲例哈、打開參考手冊能夠看到這段話:
單次轉換模式下,ADC只執行一次轉換。
該模式既可經過設置ADC_CR2寄存器的ADON位(只適用於規則通道)啓動也可經過外部觸發啓動(適用於規則通道或注入通道),這時CONT位爲0。
一旦選擇通道的轉換完成:
● 若是一個規則通道被轉換: ─ 轉換數據被儲存在16位ADC_DR寄存器中 ─ EOC(轉換結束)標誌被設置 ─ 若是設置了EOCIE,則產生中斷。
● 若是一個注入通道被轉換: ─ 轉換數據被儲存在16位的ADC_DRJ1寄存器中 ─ JEOC(注入轉換結束)標誌被設置 ─ 若是設置了JEOCIE位,則產生中斷。
而後ADC中止。
此圖形象的代表了其背後那鮮爲人知的祕密轉換關係。。雖然單憑看文字就能想象出來、可是、有圖片是否是更加形象呢???
對於以上的寄存器、在此我稍微提提:省得寄存器大神們產生怨氣:好不容易等到你講我老大ADC,卻不把我這些背後的勤勞者給導出來
好了,那就恕小弟容稟:
一、ADC狀態寄存器(ADC_SR)
二、ADC控制寄存器1(ADC_CR1)
3、ADC控制寄存器2(ADC_CR2)
EXTSEL[2:0]:選擇啓動規則通道組轉換的外部事件 (External event select for regular group)
ALIGN:數據對齊 (Data alignment)
RSTCAL:復位校準 (Reset calibration)
CAL:A/D校準 (A/D Calibration)
CONT:連續轉換 (Continuous conversion)
ADON:開/關A/D轉換器 (A/D converter ON / OFF)
四、ADC採樣時間寄存器1(ADC_SMPR1)
SMPx[2:0]:選擇通道x的採樣時間 (Channel x Sample time selection)
5、ADC規則序列寄存器1(ADC_SQR1)
L[3:0]:規則通道序列長度 (Regular channel sequence length)
SQ1[4:0]:規則序列中的第1個轉換 (1st conversion in regular sequence)(ADC規則序列寄存器3(ADC_SQR3))
6、ADC規則數據寄存器(ADC_DR)
DATA[15:0]:規則轉換的數據 (Regular data)
(因爲寄存器過於多,咱們就不在這一一列舉了哈、、由於我主要是用庫,因此寄存器相關的位都不具體介紹了哈、請你們參照中文手冊)
在這裏,向你們介紹下:數據對齊:
ALIGN位用於設置對齊方式:右或左;
對於注入通道,轉換結果是減去偏移量的值,能夠爲一個負數,在右對齊時擴展位位符號位。
那咱們如今要怎麼來實現呢??這個問題、相信你們在看了那麼多的寄存器以後急迫想要知道的吧、、前面的只是個熱身、、接下來步驟以下:
1、開啓ADC1的時鐘,因爲ADC1是在PA1上,因此同時也要打開PA的時鐘,並進行相關的配置、對於這個配置,要把PA1設置成模擬輸入,爲何呢??你們打開中文參考手冊能夠看到
啊哈、、這下子清楚了吧、
2、復位ADC1,(本人以爲不必、爲何,待會我會跟你說,留下懸念先),設置ADC1的分頻因子,(記住,這裏的ADC的時鐘不能超過14MHZ),並且其採樣週期長點會好點,
ADCCLK---最快可達14MHz, 時鐘來自通過分頻器的PCLK2(二、四、六、8分頻)
整個轉換時間 = 採樣時間 + 12.5個週期(固定時間)
在14MHz和採樣時間位1.5週期時 轉換時間:1μs (14個週期 cycles)
當ADCCLK=14MHz和1.5週期的採樣時間:
TCONV = 1.5 + 12.5 = 14週期 = 14×(1 / (14 × 1000000)) = 1μs
其採樣週期一覽表:
涉及到採樣週期、這裏來看看轉換序列:
最多達16個轉換通道且能夠採樣不一樣的順序排列,不一樣的採樣時間和過採樣的可能性。
例如:- 轉換通道:一、二、八、四、七、三、11
- 不一樣的採樣時間;
- Oversampling of channel 7。
3、初始化ADC1的參數、設置ADC1的工做模式和規則序列的相關信息;
你們經過打開"stm32f10.adc.h"能夠看到:
typedef struct { uint32_t ADC_Mode; //設置ADC模式-->獨立模式 FunctionalState ADC_ScanConvMode; //設置是否開啓掃描模式 --->否 FunctionalState ADC_ContinuousConvMode; //設置是否開啓連續轉換模式 ---->否 uint32_t ADC_ExternalTrigConv; //設置啓動規則轉換組轉換模式---->軟件觸發
uint32_t ADC_DataAlign; //設置數據對齊方式----->右對齊 uint8_t ADC_NbrOfChannel; //設置規則序列的長度---->順序進行規則轉換的ADC通道數目1 }ADC_InitTypeDef;
4、使能ADC並校準
注:在設置完了以上信息後,使能AD轉換器,執行復位校準和AD校準(這兩步校準必定要,不然數據將不許)
還有記住,每次進行校準以後都要等待校準結束,可是經過什麼方式知道校準結束呢?
這裏是經過獲取校準狀態來判斷是否校準結束,相關的庫函數請看代碼
分別的庫函數請看待會的代碼。(請用比較老外的方式去看,也就是用英語啦,爲何呢?請看下文)
5、讀取AD的值
固然,這裏說讀取AD值並非那麼的簡單,以上咱們只是準備好了AD,尚未設置相關的規則序列通道,採樣順序,以及採樣週期,設置完以後啓動AD轉換就好了、而後才直接讀取哈、、
相關的庫函數請看代碼、
void Adc_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* Enable ADC1 and GPIOA clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//12MHZ /* Configure PA.1 (ADC Channel) as analog input -------------------------*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); //ADC_DeInit(ADC1);//在這裏復位被我註釋掉了、至於爲何,我待會會說 /* ADC1 configuration ------------------------------------------------------*/ ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//這裏對應上面所講的配置,在這裏就不給出註釋了 ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); /* Enable ADC1 *///知道我爲啥要在上面提醒你們要用老外的方式來看了吧、由於這裏的註釋都是用英文的
//請不要覺得我裝逼,我這樣作是有緣由的、、緣由我待會會說、你也會明白我最初的標題爲什麼那樣寫
ADC_Cmd(ADC1, ENABLE); /* Enable ADC1 reset calibration register */ ADC_ResetCalibration(ADC1); /* Check the end of ADC1 reset calibration register */ while(ADC_GetResetCalibrationStatus(ADC1)); /* Start ADC1 calibration */ ADC_StartCalibration(ADC1); /* Check the end of ADC1 calibration */ while(ADC_GetCalibrationStatus(ADC1)); }
u16 Get_val(u8 ch) { u16 DataValue; //又是英文註釋、、啊哈 /* ADC1 regular channel14 configuration */ ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5); /* Start ADC1 Software Conversion */ ADC_SoftwareStartConvCmd(ADC1, ENABLE); /* Test if the ADC1 EOC flag is set or not */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
//FlagStatus Status;
//Status = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
//while(!Status);---->這樣作實現不了、請注意
/*Returns the ADC1 Master data value of the last converted channel*/
DataValue = ADC_GetConversionValue(ADC1);
return DataValue;
}
u16 ADC_Get_aveg(u8 ch,u8 n)
{
u32 ad_sum = 0;
u8 i;
for(i=0;i<n;i++)
{
ad_sum += Get_val(ch);
delay_ms(5);
}
return (ad_sum / n);
}
adcx=ADC_Get_aveg(ADC_Channel_1,10);//獲取AD數值(0~4095)
temp=(float)adcx*(3.3/4096);//獲取相應的電壓值
到了這一步,咱們已經完成了AD採集數據的任務、接下來,有人可能有時候會以爲很納悶,爲何有些人知道要完成特定的功能,它的步驟是怎麼樣的、爲何我就不知道??這個問題嘛、、接下來我講的但願能稍微幫你,也但願你能好好的借鑑、
步驟小技巧:其實也沒啥的、你們知道下載庫的文件的時候,裏面都有包含每一個模塊的例子和一個模版、拿ADC這個模塊來舉例:
點擊main.c能夠看到神奇的一幕:
你們仔細看看,能夠發如今官方給的歷程中的步驟裏並無復位ADC的函數,我的以爲因此沒有必要去復位固然復位也不是什麼壞事哈、看你我的、、看到這、應該明白了我前面的說法了吧、還有、你們應該也注意到了、都是英文的註釋、、因此看到這你們也清楚了,前面不是我裝逼、、因此呢、其實英語對於咱們來講仍是很重要的、、那有人問,時鐘的分頻因子呢?怎麼沒有設置??不急哈、、請看:
對於分頻因子的設置,也在這個函數裏:而這個RCC_Configuration()在最開始已經使用 了、、
因此你們要好好利用官方給的歷程、說到這、你猜我詞窮了嗎?
答案是否認的、、我還有話要說:
作一件事要有一個目的、、纔不會顯得本身作的很空泛、、我寫博客也同樣、、我想讓我本身理清思路、也但願本身在寫的過程當中能領悟到本身在學的時候沒領悟到的知識點、、也但願能幫到跟我有同樣困惑的人、、我把我不懂的理解後寫下來、我也知道會有人跟我同樣遇到一樣不懂的地方、、因此這就是個人目的哈、、但願能幫到大家、、儘管不認識大家、、啊哈、、初學者、不免有出錯、、因此、寫錯或理解錯的請幫我指出來、臣不甚感激,今當遠離,零表涕零,不知所言、、