2012年11月30日 星期五

ADC 讀取可變電阻電壓

說明

這個實驗是在 APP-EDF11-1 開發版上進行,利用 Microchip 的 ADC 模組 (Analog / Digital Converter 類比/數位轉換器) 將可變電阻目前的電壓轉成數位訊號,對應顯示到 8 顆 LED 上。

ADC 讀值顯示到 8 顆 LED


ADC 讀值依等級區分對應顯示到 8 顆 LED

可變電阻的電壓範圍介於 0 ~ 3.3V,經過 ADC 模組轉換後將對應到 0 ~ 1023 範圍 (因 Microchip ADC 模組是十位元精準度,即 2^10 = 1024)。經過 ADC 轉換後,我們即可知道目前可變電阻轉動的量有多少,但 1024 種變化要如何輸出到 8 顆 LED ?

1 顆 LED 可以有兩種變化,一個是亮,一個是滅。2 顆 LED 有 4 種、3 顆有 8 種...8 顆有 2^8 = 256 種。我們必須想辦法將 1024 種降成 256 種,即可在 LED 上顯示了,在這個程式有 2 種方式顯示。

  • 第一個方法是去掉最低的 2 位元,使強迫降成 8 個位元 256 種變化
    LED8 LED7 LED6 LED5 LED4 LED3 LED2 LED1 ADC 值
              太陽 太陽   6
            太陽   太陽   10
        太陽 太陽     太陽   50
      太陽 太陽     太陽     100
    太陽     太陽   太陽 太陽   150
    太陽 太陽 太陽 太陽 太陽 太陽 太陽 太陽 255
  • 另一個方法則是區分等級,有點像是學校成績的分級 (A 級 100~90、B 級 89 ~ 70...),1024 個變化分成 8 個等級,第 1 級 (LED1) 10 ~ 127、第 2 級 (LED1+2) 128 ~ 255、第 3 級 (LED1+2+3) 256 ~ 383...(如下表),對應顯示到 8 顆 LED 上,0 ~ 9 則是不顯示,感覺有點像是電池的電量。
LED8 LED7 LED6 LED5 LED4 LED3 LED2 LED1 ADC 值
                0 ~ 9
              太陽 10 ~ 127
            太陽 太陽 128 ~ 255
          太陽 太陽 太陽 256 ~ 383
        太陽 太陽 太陽 太陽 384 ~ 511
      太陽 太陽 太陽 太陽 太陽 512 ~ 639
    太陽 太陽 太陽 太陽 太陽 太陽 640 ~ 767
  太陽 太陽 太陽 太陽 太陽 太陽 太陽 768 ~ 895
太陽 太陽 太陽 太陽 太陽 太陽 太陽 太陽 896 ~ 1023

 

電路圖

可變電阻 (VR1) 接到 MCU 的 RF2/AN7 腳位,可變電阻調整的電壓範圍介於 0V ~ 3.3V 之間,此 RF2/AN7 接腳上的電壓會透過 MCU 的 ADC 模組將類比的電壓值對應轉換成 10 位元的數位資料 0 ~ 1023 之間。

clip_image001

這可愛的 8 顆 LED 接到 MCU 的 RD0 ~ RD7 接腳,MCU 對接腳送出 1 (高準位) 可點亮 LED (J6 的 Jummper 必須短路到地),ADC 轉換後的結果將會顯示對應到此 8 顆 LED。

clip_image002

 

程式碼

編譯環境:

  • MPLAB X IDE v1.30
  • C18 v3.40

完整專案檔下載:VR1_LED.zip (6 KB)

檔案:main.c

功能切換 (二選一),選完後必須重新編譯,燒錄

#define DEMO_VALUE        // ADC 結果的 ADRESH 值, 輸出到 LED
//#define DEMO_LEVEL // ADC 結果以等級輸出到 LED
主程式,工作很單純,主迴圈中只是進行 ADC 轉換,讀取 ADC 轉換後的值及 LED 的輸出顯示,依照功能設定呼叫對應的函式。
void main(void)
{
unsigned int VR1Value;
InitIO();

while (1) {
ConvertADC();
while (BusyADC());
VR1Value = ReadADC(); // ADC Result: 16 bits

#if defined(DEMO_VALUE)
ShowValue((unsigned char)((VR1Value & 0xFFFC ) >> 2));
#elif defined(DEMO_LEVEL)
ShowLevel(VR1Value);
#endif
}
}
初始化 IO,PORTD 設為輸出方向,ADC 則是使用模組的自動取樣及轉換,讀取 AN7 腳位上接的 VR1 可變電阻電壓值
void InitIO(void)
{
unsigned char adcConfig1, adcConfig2, portConfig;

// On the PIC18F87J50 Family of USB microcontrollers, the PLL will not power up and be enabled
// by default, even if a PLL enabled oscillator configuration is selected (such as HS+PLL).
{
int pll_startup_counter = 27000; // 27000 x 0.083us ~= 2.241 ms
OSCTUNEbits.PLLEN = 1; //Enable the PLL and wait 2+ms until the PLL locks before enabling USB module
while(pll_startup_counter--);
}

LATD = 0x00;
TRISD = 0x00; // Initializee all PORTD(LED) as input pin

// Initialize ADC
/* ADC Configuration:
* FOSC/64 as conversion clock, (1/48M) * 64 = 0.0208us * 64 = 1.3 us
* Result is left justified
* Aquisition time of 4 AD, 1.3us * 2 = 2.6us > 2.45us(Tacq), 另 2 個 TAD 是進行下一個訊號擷取前的延遲時間
* Channel 7 for sampling
* ADC interrupt off
* ADC reference voltage from VDD & VSS
*/
adcConfig1 = ADC_FOSC_64 & ADC_RIGHT_JUST & ADC_4_TAD;
adcConfig2 = ADC_CH7 & ADC_INT_OFF & ADC_REF_VDD_VSS;
portConfig = ADC_7ANA;
OpenADC(adcConfig1, adcConfig2, portConfig);

RCONbits.IPEN = 1;
INTCONbits.GIEH = 0;
INTCONbits.GIEL = 0;
}
方法一顯示:直接將 ADC 轉換的結果,去掉最低的 2 個位元變成 8 位元後,直接輸出到 LED
// Show the value of ADC result to LED
void ShowValue(unsigned char value) {
LATD = value; // ADC Result: 8 bits
}
方法二顯示:將 ADC 轉換的結果,依等級區分對應輸出到 LED
// Show the level of ADC result to LED
void ShowLevel(unsigned int value) {
unsigned char level, result, i;

result = 0;
level = value / 128 + 1; // 1024 / 8 (LEDs) = 128

if (value < 10) level = 0; // Less than 10 -> level 0

for (i = 0; i < level; i++) {
result <<= 1;
result |= 1;
}

LATD = result;
}

參考資料


0 意見:

張貼留言