STM32之ADC+步驟小技巧(英文)


       神通廣大的各位互聯網的網友們、大家早上中午晚上好好好、今早起來很准時的收到了兩條10086的扣月租的信息、心痛不已、懷着這心情、又開始了STM32的研究、早上做了計算機控制的PID實驗,又讓我想起了飛思卡爾的電磁小車、、曾經的電感電壓采集讓我心碎的多少次、又讓我開心了多少次、但已經成為過去、(軟件和硬件都會影響),呵呵、估計有人已經猜到我接下來要介紹什么了、在你們面前、我已無秘密、額、其實標題也直接“表白”了、看到標題,別嚇到哈、並不是要用英文寫、至於原因是什么、請往下看:

       好吧、言歸正傳:STM32的ADC模塊,請允許我用如此通俗的語言:普通話  來介紹STM32ADC模塊的特色

      1、1MHz轉換速率、12位轉換結果(12位、記住這個12位哈、因為2^12=4096 ,也請記住4096哈

           STM32F103系列:在56MHz時轉換時間為:1μs

                                    在72MHz時轉換時間為:1.17μs

      2、轉換范圍:0~3.6V  (3.6v---->當你需要將采集的數據用電壓來顯示的話:設你采集的數據為:x[0~4095],此時的計算公式就為:(x / 4096) * 3.6)

      3、ADC供電要求:2.4V~3.6 V(可千萬別接到 5V 的石榴裙子底下呀

      4、ADC輸入范圍:VREF-≤ VIN ≤VREF+ (VREF+和VREF-只有LQFP100封裝才有)

      5、雙重模式(帶2個ADC的設備): 8種轉換模式

      6、最多有18個通道:16個外部通道

                                   2個內部通道:連接到溫度傳感器和內部參考電壓(VREFINT = 1.2V)

      ......(略,請看參考手冊哈,由於篇幅,就不過多的列出來了、、說到略、讓我想起了月光寶盒諸葛亮的:略懂略懂、、其實我也是略懂略懂而已、、)

      12、DMA功能(僅ADC1有)

      本博客里,由於篇幅、所以就以獨立模式下的單次轉換為例哈、打開參考手冊可以看到這段話:

       單次轉換模式下,ADC只執行一次轉換。

       該模式既可通過設置ADC_CR2寄存器的ADON位(只適用於規則通道)啟動也可通過外部觸發啟動(適用於規則通道或注入通道),這時CONT位為0

       一旦選擇通道的轉換完成:

       ● 如果一個規則通道被轉換: ─ 轉換數據被儲存在16位ADC_DR寄存器中 ─ EOC(轉換結束)標志被設置 ─ 如果設置了EOCIE,則產生中斷。

       ● 如果一個注入通道被轉換: ─ 轉換數據被儲存在16位的ADC_DRJ1寄存器中 ─ JEOC(注入轉換結束)標志被設置 ─ 如果設置了JEOCIE位,則產生中斷。

       然后ADC停止。

      此圖形象的表明了其背后那不為人知的秘密轉換關系。。雖然單憑看文字就能想象出來、但是、有圖片是不是更加形象呢???

 

     對於以上的寄存器、在此我稍微提提:免得寄存器大神們產生怨氣:好不容易等到你講我老大ADC,卻不把我這些背后的勤勞者給導出來

     好了,那就恕小弟容稟:

     1、ADC狀態寄存器(ADC_SR) 

     

 

    2、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)

    4、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(2、4、6、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個轉換通道且可以采樣不同的順序排列,不同的采樣時間和過采樣的可能性。

例如:- 轉換通道:1、2、8、4、7、3、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()在最開始已經使用 了、、

  所以大家要好好利用官方給的歷程、說到這、你猜我詞窮了嗎?

  答案是否定的、、我還有話要說:

  做一件事要有一個目的、、才不會顯得自己做的很空泛、、我寫博客也一樣、、我想讓我自己理清思路、也希望自己在寫的過程中能領悟到自己在學的時候沒領悟到的知識點、、也希望能幫到跟我有一樣困惑的人、、我把我不懂的理解后寫下來、我也知道會有人跟我一樣遇到同樣不懂的地方、、所以這就是我的目的哈、、希望能幫到你們、、盡管不認識你們、、啊哈、、初學者、難免有出錯、、所以、寫錯或理解錯的請幫我指出來、臣不甚感激,今當遠離,零表涕零,不知所言、、

 

 

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM