简体   繁体   English

Arduino (AVR ATMega328) Timer1 似乎没有在正确的时间触发

[英]Arduino (AVR ATMega328) Timer1 does not seem to trigger at the right time

I am trying to implement Binary Code Modulation (also known as Bit Angle Modulation, BAM), as an alternative to PWM due to the minimal number of PWM pins on the Arduino.由于 Arduino 上的 PWM 引脚数量最少,我正在尝试实现二进制代码调制(也称为位角调制,BAM),作为 PWM 的替代方案。 The idea behind using BAM is that the LED will be on and off in discrete times, effectively controlling the brightness of the LED.使用 BAM 背后的想法是 LED 将在离散时间打开和关闭,从而有效地控制 LED 的亮度。 This "time" is determined by corresponding bit value in the byte.这个“时间”由字节中相应的位值决定。

For example, if set to the value 85 (out of 255), which is 01010101 in binary, this means that the LED will alternate on and off states, but for different time lengths.例如,如果设置为值 85(共 255 个),即二进制 01010101,这意味着 LED 将交替打开和关闭状态,但时间长度不同。 The 0th bit '1' means the LED will be on for 1 tick, while the 6th bit '0' means the LED will be off for 32 ticks, and so forth.第 0 位“1”表示 LED 将亮起 1 个滴答声,而第 6 位“0”表示 LED 将熄灭 32 个滴答声,依此类推。 The goal is that this will toggle the LED fast enough to where the human eye won't notice, creating the illusion of brightness depending on the value.目标是这将足够快地将 LED 切换到人眼不会注意到的地方,根据值产生亮度错觉。 A higher value would relate to a brighter LED color.较高的值与更亮的 LED 颜色有关。

While implementing this, I noticed that the refresh rate on the LED could be seen.在执行此操作时,我注意到可以看到 LED 上的刷新率。 I can see when the LED is on and when it is off.我可以看到 LED 什么时候亮,什么时候灭。 It appears to toggle the port once every half second.它似乎每半秒切换一次端口。 There's no wait to know since I do not have an oscilloscope.由于我没有示波器,所以迫不及待想知道。 I am using Timer1 on the Arduino to interrupt every 8 microseconds (125KHz).我在 Arduino 上使用 Timer1 每 8 微秒(125KHz)中断一次。 Each interrupt will update the status on the PIN connected to the LED, if it is on or off.每次中断都会更新连接到 LED 的 PIN 上的状态,无论是打开还是关闭。

I've tried doing this using both the Timer1 library , and going through the registers, but both seem to produce erroneous results.我已经尝试使用Timer1 库和通过寄存器来执行此操作,但两者似乎都会产生错误的结果。 Currently, my code is toggling one pin.目前,我的代码正在切换一个引脚。 If the interrupt is working properly (updating every 8us), then I should see the blue LED (connected to pin 8) toggle states every tick.如果中断正常工作(每次更新8US),那么我应该看到蓝色的LED(连接到引脚8)切换状态每一个刻度。 What my eye should see is just an LED on.我的眼睛应该看到的只是一个 LED 灯。

Note: When switching between Timer1 lib and the registers, my ISR changes just in name.注意:在 Timer1 库和寄存器之间切换时,我的 ISR 只是在名称上发生了变化。 See the comment in code.请参阅代码中的注释。

Can someone please look at my Timer implementation.有人可以看看我的 Timer 实现。 I have a feeling this is where the problem might lie, but I cannot figure it out.我有一种感觉,这就是问题所在,但我无法弄清楚。

    #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;
    }

So there were two bugs in my code.所以我的代码中有两个错误。 First, I upped the counter to interrupt at 250KHz (4us).首先,我增加了计数器以 250KHz (4us) 中断。 Secondly, the way I was setting my BAM levels (near the end of the ISR) was incorrect.其次,我设置 BAM 级别(接近 ISR 末尾)的方式不正确。 I forgot that I have a common anode LED, which means that in order to turn on a color, I have to set the corresponding pin LOW, not HIGH as shown in my example.我忘了我有一个共阳极 LED,这意味着为了打开颜色,我必须将相应的引脚设置为低电平,而不是我的示例中所示的高电平。 The fixed segments are located below.固定段位于下方。 Thank you all who looked at this.谢谢所有看过这个的人。

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM