STM8單片機ADC單次掃描模式

這是我參與8月更文挑戰的第13天,活動詳情查看:8月更文挑戰markdown

  當STM8單片機使用ADC功能讀取多個通道的值時,可使用單次模式,採樣完一個通道以後,從新初始化另外一個通道,而後採樣,採樣完成後繼續從新初始化切換下一個通道。可是這樣採樣起來太麻煩。STM8單片機提供了一個掃描模式,能夠依次按照順序採樣多個通道的值,多個通道所有采樣完成後,會置位標誌位,這樣就能夠一次性將多個通道的值所有讀出來。app

其中官方文檔介紹以下:函數

image.png

  從文檔中能夠看出,採樣都是從0通道開始的,好比想採樣3個通道值,那麼採樣的通道號就爲0---3。若是想採樣三、4通道,那麼也得從0通道開始,也就是說要從0通道開始掃描到4通道,就算0、一、2通道不用,它也會掃描,就這一點很差。post

image.png

  單次採樣的時候,ADC_CSR寄存器中的通道號指的是要採樣的通道號,要採樣那個通道就設置爲幾,而在掃描模式下,這個通道號指的是要掃描的最大通道號,掃描都是從0通道開始。這裏設置時要注意。ui

  單次掃描模式的配置其實也很簡單,只是比單次模式多了一個開啓掃描的設置。下面直接經過寄存器來講明單次掃描模式的設置方法。url

image.png

  首先看ADC_CSR寄存器,這個寄存器裏面只須要設置一個通道轉換位,這個通道指的是掃描的最大通道。在單次模式下這個通道指的是要讀取的通道值,而在掃描模式下,這個通道指的是,最大掃描通道數。掃描都是從0通道開始。EOC位是轉換結束標誌位,這個在初始化的時候不用設置,只是在讀取數據的時候通道判斷這個位來讀取。spa

image.png

  接下來看ADC_CR1寄存器,這個寄存器要設置的只有一個,就是ADON位,用來控制ADC的轉換開關,爲1時啓動轉換功能,爲0時關閉轉換功能。預分頻位和單次轉換模式默認值都爲0,恰好符合咱們的需求,也就是默認2分頻,單次轉換模式。3d

image.png

  接下來看ADC_CR2寄存器,這個寄存器必須設置的位其實只有一個,就是要要使用掃描模式必須設置SCAN位爲1,其餘位使用默認值就行。若是數據對齊方式使用左對齊的話,就不用設置。這裏使用的是數據右對齊,因此須要將ALIGN位也設置爲1.其餘位默認爲0.code

image.png

  最後就是這個ADC_TDR寄存器,用來禁止施密特觸發器,主要是用來下降單片機功耗。固然這個寄存器不用設置也能夠。若是要設置的話,使用了哪幾個ADC通道,就將對應的通道位置1就行。orm

  下面就能夠開始編寫代碼了:

#include "adc.h"
#include "main.h"
#include "led.h"

_Bool ADC_flag = 0;                     //ADC轉換成功標誌
u16 ADC_DB[10] = {0};
u16 adc_data[5] = {0};

//AD通道引腳初始化
void ADC_GPIO_Init( void ) {
    PD_DDR &= ~( 1 << 2 );              //PD2 設置爲輸入
    PD_CR1 &= ~( 1 << 2 );              //PD2 設置爲懸空輸入

    PD_DDR &= ~( 1 << 3 );              //PD3 設置爲輸入
    PD_CR1 &= ~( 1 << 3 );              //PD3 設置爲懸空輸入

    PC_DDR &= ~( 1 << 4 );              //PC4 設置爲輸入
    PC_CR1 &= ~( 1 << 4 );              //PC4設置爲懸空輸入
}

//設置爲 單次掃描模式
//ch 爲ADC通道 連續轉換AIN0---AINch 通道的數據
void ADC_CH_Init( u8 ch ) {
    char l = 0;
    ADC_GPIO_Init();    
    ADC_CR1 &= ~( 7 << 4 );   //預分頻 2
    ADC_CR2 &= ~( 1 << 6 );   //不使用外部觸發
    //禁止 AIN2 AIN4 的施密特觸發器,下降 IO 靜態功耗 PD5,PD6 上的通道若是施密特方式禁用會致使串口沒法收發數據!
    ADC_TDRL |= ( 1 << 2 );
    ADC_TDRL |= ( 1 << 3 );
    ADC_TDRL |= ( 1 << 4 );

    ADC_CR1 &= ~( 1 << 1 );   //單次轉換
    ADC_CSR |= 0x04;          //配置通道號最大的那個
    ADC_CR2 |= ( 1 << 3 );    //右對齊

    ADC_CR1 |= ( 1 << 0 );    //開啓 ADC
    ADC_CR2 |= ( 1 << 1 );    // SCAN = 1 開啓掃描模式

    //當首次置位ADON位時,ADC從低功耗模式喚醒。爲了啓動轉換必須第二次使用寫指令來置位ADC_CR1寄存器的ADON位。
    for( l = 0; l < 10; l++ );  //延時,保證ADC模塊的上電完成 至少7us
    ADC_CR1 |= ( 1 << 0 );      //再次將CR1寄存器的最低位置1 使能ADC 並開始轉換
}

u16 ain2_val = 0,ain3_val = 0,ain4_val = 0;
//讀取採樣電壓值
u16 ReadVol_CHx( void ) {
    u16 voltage = 0;
    u16 temph = 0;
    u8 templ = 0;
    while( 1 )
    {
        LED = !LED;             //程序運行一圈耗時 15us 
        while( ( ADC_CSR & 0x80 ) == 0 );      //等待轉換結束 等待時間爲 4us
        ADC_CSR &= ~( 1 << 7 );               // 轉換結束標誌位清零 EOC

        //讀取 AIN2 的值
        templ = ADC_DB2RL;
        temph = ADC_DB2RH;
        temph = ( u16 )( templ | ( u16 )( temph << ( u16 )8 ) );
        ain2_val =  temph;
        
        //讀取 AIN3 的值
        templ = ADC_DB3RL;
        temph = ADC_DB3RH;
        temph = ( u16 )( templ | ( u16 )( temph << ( u16 )8 ) );
        ain3_val =  temph;

        //讀取 AIN4 的值
        templ = ADC_DB4RL;
        temph = ADC_DB4RH;
        temph = ( u16 )( templ | ( u16 )( temph << ( u16 )8 ) );
        ain4_val =  temph;
        
        ADC_CR1 |= 0x01;                        //開啓一次轉換
    }
    return voltage;
}

複製代碼

初始化流程就按照上面分析的流程進行,在啓動ADC轉換的時候,須要開啓兩次。

image.png

  系統啓動後ADC默認是在低功耗模式下,第一次設置ADON位是將ADC從低功耗模式喚醒,而後須要延時1個轉換週期,等待系統轉換穩定。因此在初始化的時候須要設置兩次ADON爲1。因爲這裏使用的是單次觸發模式,因此每次轉換完成以後,ADC默認就關閉了,若是要繼續轉換,就須要手動將ADON位設置爲1.

  也可使用中斷的方式來進行讀取數據。

#include "adc.h"
#include "main.h"
#include "led.h"

_Bool ADC_flag = 0;                     //ADC轉換成功標誌

u16 ADC_DB[10] = {0};
u16 adc_data[5] = {0};

//AD通道引腳初始化
void ADC_GPIO_Init( void ) {
    PD_DDR &= ~( 1 << 2 );              //PD2 設置爲輸入
    PD_CR1 &= ~( 1 << 2 );              //PD2 設置爲懸空輸入

    PD_DDR &= ~( 1 << 3 );              //PD3 設置爲輸入
    PD_CR1 &= ~( 1 << 3 );              //PD3 設置爲懸空輸入

    PC_DDR &= ~( 1 << 4 );              //PC4 設置爲輸入
    PC_CR1 &= ~( 1 << 4 );              //PC4設置爲懸空輸入
}

//設置爲 單次掃描模式
//ch 爲ADC通道 連續轉換AIN0---AINch 通道的數據
void ADC_CH_Init( u8 ch ) {
    char l = 0;
    ADC_GPIO_Init();

    ADC_CR1 &= ~( 7 << 4 );   //預分頻 2
    ADC_CR2 &= ~( 1 << 6 );   //不使用外部觸發
    //禁止 AIN2 AIN4 的施密特觸發器,下降 IO 靜態功耗 PD5,PD6 上的通道若是施密特方式禁用會致使串口沒法收發數據!
    ADC_TDRL |= ( 1 << 2 );
    ADC_TDRL |= ( 1 << 4 );

    ADC_CR1 &= ~( 1 << 1 );   //單次轉換
    ADC_CSR |= 0x04;          //配置通道號最大的那個
    ADC_CR2 |= ( 1 << 3 );    //右對齊

    ADC_CR1 |= ( 1 << 0 );    //開啓 ADC
    ADC_CR2 |= ( 1 << 1 );    // SCAN = 1 開啓掃描模式

    ADC_CSR |= ( 1 << 5 );    //EOCIE 使能轉換結束中斷

    //當首次置位ADON位時,ADC從低功耗模式喚醒。爲了啓動轉換必須第二次使用寫指令來置位ADC_CR1寄存器的ADON位。
    for( l = 0; l < 10; l++ );  //延時,保證ADC模塊的上電完成 至少7us
    ADC_CR1 |= ( 1 << 0 );      //再次將CR1寄存器的最低位置1 使能ADC 並開始轉換

}
u16 ain2_val = 0, ain3_val = 0, ain4_val = 0;
u16 temph = 0;
u8 templ = 0;
//讀取採樣電壓值
u16 ReadVol_CHx( void ) {
    u16 voltage = 0;
    if( ADC_flag == 1 )
    {
        ADC_flag = 0;
        //單通道掃描模式,轉換結果存儲在 ADC_DBxR 寄存器中
        //讀取 AIN2 的值
        templ = ADC_DB2RL;
        temph = ADC_DB2RH;
        temph = ( u16 )( templ | ( u16 )( temph << ( u16 )8 ) );
        ain2_val =  temph;

        //讀取 AIN3 的值
        templ = ADC_DB3RL;
        temph = ADC_DB3RH;
        temph = ( u16 )( templ | ( u16 )( temph << ( u16 )8 ) );
        ain3_val =  temph;

        //讀取 AIN4 的值
        templ = ADC_DB4RL;
        temph = ADC_DB4RH;
        temph = ( u16 )( templ | ( u16 )( temph << ( u16 )8 ) );
        ain4_val =  temph;

        ADC_CR1 |= 0x01;                        //開啓一次轉換
    }
    return voltage;
}
//AD中斷服務函數 中斷號22
#pragma vector = 24 // IAR中的中斷號,要在STVD中的中斷號上加2
__interrupt void ADC_Handle( void ) {
    ADC_CSR &= ~( 1 << 7 );               // 轉換結束標誌位清零 EOC
    ADC_flag = 1;                       // ADC中斷標誌 置1
}
複製代碼

中斷的開啓就是將ADC_CSR寄存器的EOCIE位設置爲1,而後當全部的通道轉換完成以後,就會產生一次中斷,在中斷中讀取數據。

  這裏要注意的地方是在掃描模式時,採樣的數據結果不是存放在ADC_DR寄存器中,而是存放在ADC_DBxR寄存器中,通道幾就存放在對應的ADC_DBxR寄存器中,這個寄存器分爲高位和低位兩個。好比通道2的數據,就存放在ADC_DB2RL和ADC_DB2RH寄存器中,在讀取數據的時候也要注意,若是數據是左對齊必須先讀高8位,再讀低位。若是數據是右對齊必須先讀低8位,在讀高8位。

image.png

image.png

數據對齊在官方手冊中有詳細的說明,在使用的時候要注意這一點。

相關文章
相關標籤/搜索