1. 程式人生 > >6.ADC模數轉換(內容詳細,有幾點明白20171113)

6.ADC模數轉換(內容詳細,有幾點明白20171113)

6.ADC模數轉換

回顧了一下學習嵌入式軟體的整個過程,我發現缺少了一種探索的精神?這些設計都有例項,我也是按照例項先理解後然後在利用自己的想法實現。看到實驗題目,我首先會看例程程式碼,看看用到了哪些庫中外設器件的知識,然後學習相關庫,最後根據瞭解到的流程和學習到的相關函式庫方面的知識自己在重新寫一遍程式,最後在模擬,然後下載到板子中測試,成功後寫總結,這從學習角度來說似乎已經足夠了,但是其中少了最重要的一步,思考?這個實驗的目的是什麼?為了實現這個目的我需要知道什麼,需要怎麼做?知道結果再重新處理直接處理省下了這一步,是簡單,但效果卻並不好,特別是想脫離底層程式碼作整體架構的設計,學會選擇和思考這一步才是最重要的,也是關鍵的。因此我決定轉換思路,從現在開始改變實驗的方法。

1.要求

    本次ADC模數轉換實驗要求並不複雜,接收板上電位器的輸入電壓,經過A/D轉換後通過串列埠在PC機上輸出。

2.問題解析

分析要求,就會發現ADC、GPIO、USART以及RCC模組就是本次實驗所需要的用到的外設,因為其它模組通過前面的學習和實踐都有了一定的基礎,那麼學習ADC模組,掌握暫存器以及相關庫函式就是本程式設計的第一個關鍵。首先根據開發板手冊,瞭解STM32處理器所帶的ADC是12位的模擬數字轉換器,它有18個通道,其中16個外部通道和2個內部訊號源,而本次電位器對應通道10,且GPIO口對應為PC0,電位器最高3.3V,這是硬體相關的資料(來自原理圖/開發板手冊,學會查資料也是軟體編寫的基礎)。

 3.總結

  以上我們可以得出輸入電壓的範圍為0~3.3V,輸出的數字量為0~0xFFF,這樣我們將得到的數字量即可通過公式digital = (analog/0x1000)*3.3轉換成模擬量,通過串列埠輸出,我們初始化需要配置的就有AD1的10號外部通道(單通道模式)以及GPIOC的埠0,配置為模擬輸入(具體參考STM32中文參考手冊8.1.11),同時選擇串列埠1輸出到PC端,配置同上一章節。

<庫函式學習即使用>

因為ADC1對應的GPIO口為PC0,所以要進行PC0埠的初始化,並不難,這裡不再贅述。

typedefstruct

{

u32 ADC_Mode;                          //明確ADC1和ADC2的工作方式,獨立或其它組合

FunctionalState  ADC_ScanConvMode; //通道工作方式,單通道還是多通道(掃描)

FunctionalState  ADC_ContinuousConvMode;//工作在連續還是單次模式

u32 ADC_ExternalTrigConv;         //A/D轉換啟動規則

u32 ADC_DataAlign;                    //判斷轉換資料的對齊方式

u8 ADC_NbrOfChannel;                  //明確規則轉換通道的具體數目 1~16

}ADC_InitTypeDef

瞭解上述結構體代表含義,下面就可以初始化相關暫存器實現ADC外設的配置:

ADC_InitTypeDef ADC_InitStructure;

ADC_InitStructure.ADC_Mode =ADC_Mode_Independent;    //ADC1和ADC2工作在獨立模式

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 =1;                 //ADC通道數目為1

ADC_Init(ADC1, &ADC_InitStructure);

上面的其它都好理解,但是最後一個ADC_NbrOfChannel有內容需要了解,

ADC通道的規則組和注入組:規則組可配置1~16個,注入組最多配置4個

在AD轉換中,規則組定義的是ADC掃描通道的順序,按照規則組配置時的取樣順序從小到大依次掃描ADC通道,而注入組的優先順序高於規則組,當注入組轉換觸發時就打斷規則組的掃描而執行注入組的通道掃描,具體流程類似於中斷中的搶佔。本次ADC的轉換僅僅使用到一個埠,這些不用考慮,但是在多通道AD/DA採集時,規則組和注入組要根據實際情況進行配置。

注意:配置通道的規則組和注入組是一定要在使能ADC轉換之前的。

配置規則組/注入組的函式如下:

ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1, ADC_SampleTime_55Cycles5 );

上面函式共有四個變數,分別對應著選擇的AD口,AD轉換通道(具體值可通過檢視原理圖確定),取樣順序(本例子表示取樣順序1,不同埠不可重複),取樣週期(55.5個ADC時鐘週期,具體時間可根據設定的時鐘頻率計算).

ADC_Cmd(ADC1, ENABLE);     //使能ADC轉換

下面這一段就是ADC的校準,可以減小因電容器組變化而照成的準精度誤差。這個校準具體的實現我也不清楚,就按照下面的庫函式呼叫嗎,但是一定不能忘了它,千里之堤,潰於蟻穴;細節真的很重要,特別是在大型軟體中。 

ADC_ResetCalibration(ADC1);                   //重置ADC校準暫存器

while(ADC_GetCalibrationStatus(ADC1))       //等待ADC校準暫存器重置完成

{

}

ADC_StartCalibration(ADC1);                   //ADC進入校準狀態

while(ADC_GetCalibrationStatus(ADC1))       //等待ADC校準完成

{

}

ADC_SoftwareStartConvCmd(ADC1,ENABLE);    //軟體方式啟動ADC1轉換

那麼直接定義

u16  ADValue;

ADValue =ADC_GetConversionValue(ADC1);    //返回最近一次規則組的轉換結果

Precent = (ADValue*100/0x1000);

Voltage = Precent*33;

printf("\r\n\n ADCConvertedValue is0x%x, Percent is %d%%, voltage is %d.%d%dV",

    ADValue,Precent,Voltage/1000,(Voltage%1000)/100,(Voltage%100)/10);

printf("\n ADC output output");

注意:使用了printf函式作為輸入輸出時,包含標頭檔案#include”stdio.h” ;

Target下要選擇useMicroLib,否則是不會有輸出的(串列埠章節已經說明,重要)。

即可以實現模數的轉換。看到這你是不是覺得實驗已經結束了,畢竟我們已經實現要求了嗎。從功能上,本實驗已經夠了。

但是ADValue =ADC_GetConversionValue(ADC1);  /*返回最近一次規則組的轉換結果*/,

    通過該函式,就可以實現ADC轉換後每一次資料的讀取,在通過串列埠輸出到PC端顯示,這當然沒有問題,

但是ADC轉換是很快的,通過上述函式獲得ADC轉換後的資訊的話CPU資源佔用率會很高,那麼有沒有什麼簡單的方法呢?這裡就涉及到DMA模組,具體參見下章。