2013-11-21 43 views
0

我試圖實現Binary Code Modulation(也稱爲位角度調製,BAM),作爲PWM的替代方案,因爲PWM引腳數量最少Arduino的。使用BAM的想法是,LED將在不連續的時間開啓和關閉,從而有效地控制LED的亮度。這個「時間」由字節中相應的位值決定。Arduino(AVR ATMega328)Timer1似乎沒有在正確的時間觸發

例如,如果設置爲值85(在255),這是在二進制01010101,這意味着LED將交替接通和斷開狀態,但對於不同的時間長度。第0位'1'表示LED將點亮1滴,而第6位'0'表示LED將熄滅32滴,等等。目標是,這將使LED快速切換到人眼不會注意的位置,從而根據數值產生亮度錯覺。較高的值將涉及較亮的LED顏色。

在實施這一點,我注意到,在LED的刷新速率可以看出。我可以看到LED何時開啓以及何時關閉。它似乎每半秒鐘切換一次港口。因爲我沒有示波器,所以不用等待。我在Arduino上使用Timer1來每8微秒(125KHz)中斷一次。每個中斷將更新連接到LED的PIN的狀態,如果它打開或關閉。

我試着這樣做既使用Timer1 library,並通過寄存器去,但似乎都產生錯誤的結果。目前,我的代碼正在切換一個引腳。如果中斷工作正常(每8us更新一次),那麼我應該看到藍色LED(連接到引腳8)切換狀態每個滴答聲。我的眼睛應該看到的只是一個LED。

注:當定時器1 lib和寄存器之間的切換,只是名字我ISR變化。請參閱代碼中的評論。

可有人請看看我的定時器實現。我有一種感覺,這是問題可能出現的地方,但我無法弄清楚。

#include <TimerOne.h> 
    #include <SPI.h> 
    #include "avr/io.h" 
    #include "LEDArray.h" 

    #define TIMER_US  (8) //125KHz in microseconds 
    #define NUM_OF_LEDS  ((LEDS_PER_ROW)*(LEDS_PER_COL)) 
    #define LEDS_PER_ROW (8) 
    #define LEDS_PER_COL (8) 

    volatile byte BAM_pos = 0; 
    volatile byte BAM_tick = 0; 

    // OutputDataH, OutputDataM, and OutputDataL 
    // totals to 24 bits. There are 24 pins 
    // that I need to shift data to. These three variables 
    // will hold the data value corresponding to the associated 
    // bit level 
    volatile byte OutputDataH = 0; 
    volatile byte OutputDataM = 0; 
    volatile byte OutputDataL = 0; 
    //bool UpdateLedOutput = 1; 

    volatile byte green = 0; 
    volatile byte blue = 0; 

    void InitTimer(){ 
     TCCR1A = 0; 
     TCCR1B = 0; 
     TCNT1 = 0; 

     OCR1A = 127;   // compare match register == 16MHz/((prescalar=1)*125KHz) - 1 
     TCCR1B |= (1 << WGM21); // CTC mode 
     TCCR1B |= (1<<CS20); // 1x prescaler 
     TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt 
    } 

    void InitPins(){ 
     // initialize the digital pin as an output. 
     SHIFT_REGISTER |= (DATA | CLOCK | SS); 
     // set control pins as low 
     SHIFT_PORT &= ~(DATA | LATCH | CLOCK); 

      // initialize the led pins for testing 
      pinMode(4, OUTPUT); 
      pinMode(8, OUTPUT); 
    } 

    ISR(TIMER0_COMPA_vect){ 
    //void timerISR(){ //use this with Timer1 Library instead 
     //ISR(TIMER1_COMPA_vect){ 
     //Move onto next bit, reset BAM state 
     if(BAM_tick >= 120){ //8 + 16 + 32 + 64 
      BAM_tick = 0; 
      BAM_pos = 0; 
     } 

     // Move onto the next bit at these ticks. Ticks are in 8 microsecond increments 
     if(BAM_tick==8 || BAM_tick == 24 || BAM_tick == 56){ 
      BAM_pos++; 
     } 

     BAM_pos %= 4; //wrap counter after going through four bits 

    // if(UpdateLedOutput){ Change the LED state only when the bit position is updated 

      //For every LED, look at enabled bit, if true determine corresponding LEDs_Output bits through the LEDs rgb values 
      //There are 3 groups of LEDs, each using 1 byte (8 bits -> 8 pins) 
      //We, therefore, have a HIGH, MIDDLE, and LOW byte values that we will shift out 
      for(int i=0; i<8; i++){ 
       if(((ledOutput.all) & (1<<i))){ 
       //ledOutput.all is of size 24 bits. each bit tells us whether the pin should be enabled for this tick or not 
        OutputDataH |= (1<<i); 
       } 
      } 
      for(int i=8; i<16; i++){ 
       if(((ledOutput.all) & (1<<i))){ 
        OutputDataM |= (1<<i); 
       } 
      } 
      for(int i=16; i<24; i++){ 
       if(((ledOutput.all) & (1<<i))){ 
        OutputDataL |= (1<<i); 
       } 
      }   

      UpdateLedOutput = 0; 
    // } 

     //Update LED OUTPUT after we have reach the end of the bits time 
    // if(BAM_tick==8 || BAM_tick == 24 || BAM_tick == 56){ 
    //  UpdateLedOutput = 1; 
    // } 

     //Consume the tick 
     BAM_tick++; 

     //Shift out the data 
     /*Latch_Low(); 
     sendData(OutputDataH); 
     sendData(OutputDataM); 
     sendData(OutputDataL); 
     Latch_High(); 
     Latch_Low(); 
     */ 


     //different shifting data 
    /* 
     if(green & (1<<BAM_pos)) 
      //PORTD |= (1<<PORTD4); 
      digitalWrite(4, LOW); 
     else 
      digitalWrite(4, HIGH); 
      //PORTD &= (0<<PORTD4); 

     if(blue & (1<<BAM_pos)) 
      //PORTB |= (1<<PORTB0); 
      digitalWrite(8, LOW); 
     else 
      digitalWrite(8, HIGH);//PORTB &= (0<<PORTB0); 
     */ 
     digitalWrite(8, digitalRead(8) ^1); 
    } 




    void setup() { 
     InitData(); 
     InitPins(); 
     InitTimer(); 
     //Timer1.initialize(TIMER_US); 
     //Timer1.attachInterrupt(timerISR); 
     EnableSPI(); //Enable SPI as Master 
     Serial.begin(9600); 
    } 


    void loop() { 
     // do almost nothing! 
     while(1){ 
     PulseThroughColors(); 
     } 
    } 

    //This should slowly increase the brightness of the corresponding pin on the RGB LED 
    // Blue should increase brightness, and then decrease it in the opposite manner, indefinitely 
    void PulseThroughColors(){ 
     blue = 0; 
     green = 0; 
     int i=0; 
     for(i=0; i< 255; i++) 
      blue = i; 
     for (i=255; i>0; i--) 
      blue = 0; 
     //for(i=0; i< 255; i++) 
     // green = i; 
     //for (i=255; i>0; i--) 
     // green = 0; 
    } 

回答

1

所以在我的代碼中有兩個錯誤。首先,我提高了計數器在250KHz(4us)時中斷。其次,我設置BAM級別(接近ISR結束時)的方式不正確。我忘了我有一個共陽極LED,這意味着爲了打開一個顏色,我必須將相應的引腳設置爲低電平,而不是高電平,如我的示例所示。固定部分位於下方。謝謝所有看過這個的人。

void InitTimer(){ 
    TCCR1A = 0; 
    TCCR1B = 0; 
    TCNT1 = 0; 

    TCCR1A = B00000000; 
    TCCR1B = B00001011; 
    OCR1A=30; 
    TIMSK1 = B00000010; 
} 

ISR(...){ 
........ 
if(green & (1<<BAM_pos)) 
    PORTD &= ~(1<<PORTD4); 
else 
    PORTD |= (1<<PORTD4); 

if(blue & (1<<BAM_pos)) 
    PORTB &= ~(1<<PORTB0); 
else 
    PORTB |= (1<<PORTB0); 
} 
相關問題