0

对不起我的英语不好。我在使用 pwm 的 attiny13 上有一些问题。pwm 在调整时效果很好。然而,当 OCR0B 值变为零或最大值时,led 不会完全关闭或打开。我尝试使用“ PORTB &= ~ (1<<); ”,而 OCROX 为零,但它不起作用。之后我发现我必须添加“ISR(TIM0_COMPA_vect)”进行中断。我最近开始做微小的工作,所以这对我来说太难了,尤其是 avr 方面,请忽略我的文盲。这是代码,我用过。

#define F_CPU 1200000
#define LED PB1 

#include <avr/io.h>

const int  buttonPin = 4;    // the pin that the pushbutton is attached to

int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 1;
int model; // previous state of the button

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:

}

void adc_setup (void)
{
    // Set the ADC input to PB2/ADC1
    ADMUX |= (1 << MUX0);
    ADMUX |= (1 << ADLAR);

    // Set the prescaler to clock/128 & enable ADC
    // At 9.6 MHz this is 75 kHz.
    // See ATtiny13 datasheet, Table 14.4.
    ADCSRA |= (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN);
}

void pwm_setup (void)
{
    // Set Timer 0 prescaler to clock/8.
    // At 9.6 MHz this is 1.2 MHz.
    // See ATtiny13 datasheet, Table 11.9.
    TCCR0B |= (1 << CS01);

    // Set to 'Fast PWM' mode
    TCCR0A |= (1 << WGM01) | (1 << WGM00);

    // Clear OC0B output on compare match, upwards counting.
    TCCR0A |= (1 << COM0B1);
}

void pwm_write (int val)
{
    OCR0B = val;
}

void button()
{
buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
      model = buttonPushCounter % 5 ;
    } else {
      // if the current state is LOW then the button went from on to off:
    }
    // Delay a little bit to avoid bouncing
    delay(250);
  }
  lastButtonState = buttonState;
}

int main (void)
{
    int adc_in;

    // LED is an output.
    DDRB |= (1 << LED);  

    adc_setup();
    pwm_setup();

    while (1) {
        // Get the ADC value
        button();
        //adc_in = adc_read();
        // Now write it to the PWM counter
        switch(model)
        {
         case 0:
         pwm_write(0);
         //PORTB &= ~ (1<<PB3);
         break;
         case 1:
         pwm_write(50);
         break;
         case 2:
         pwm_write(100);
         break;
         case 3:
         pwm_write(150);
         break;
         case 4:
         pwm_write(255);
         //PORTB |= (1<<PB3);
         break;
        }

}
}

我发现另一个代码通过使用带有两个按钮的中断成功打开、关闭和调整 LED,但我不明白代码如何在 OCR0X 上写入值。有人可以在第二个代码处向我解释 OCR0X 和 duty(count, pwm value) 之间的联系。因为我需要在那些 OCR0X 中写入常量值。

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>


#define PWM_PIN      PB0
#define KEY_UP_PIN    PB1
#define KEY_DOWN_PIN    PB2

#define PWM_DUTY_MIN    (0)
#define PWM_DUTY_MAX    (100)
#define PWM_DUTY_STEP   (1)
#define KEY_UP      (1 << 1)
#define KEY_DOWN    (1 << 2)

static volatile uint8_t duty = 0;
static uint8_t counter = 0;
static void process(void);
static uint8_t read_keys(void);

ISR(TIM0_COMPA_vect)
{

  if (duty > PWM_DUTY_MIN && duty < PWM_DUTY_MAX) {
    if (counter == 0) {
      PORTB |= _BV(PWM_PIN);
    } else if (counter == duty) {
      PORTB &= ~_BV(PWM_PIN);
    }
    if (++counter == PWM_DUTY_MAX) {
      counter = 0;
    }
  }
}

int
main(void)
{

  /* setup */
  DDRB |= _BV(PWM_PIN); // set PWM pin as OUTPUT
  PORTB |= _BV(KEY_UP_PIN)|_BV(KEY_DOWN_PIN);
  TCCR0A |= _BV(WGM01); // set timer counter mode to CTC
  TCCR0B |= _BV(CS00); // set prescaler
  OCR0A = 95; // set Timer's counter max value (96 - 1)
  TIMSK0 |= _BV(OCIE0A); // enable Timer CTC interrupt
  sei(); // enable global interrupts

  _delay_ms(100); // time of debounce

  /* loop */
  while (1) {
    process();
    _delay_ms(8);
  }
}

void
process(void)
{
  uint8_t keys;

  if (!(keys = read_keys())) {
    return;
  }

  if ((keys & KEY_UP) && duty < PWM_DUTY_MAX) {
    duty += PWM_DUTY_STEP;
  }

  if ((keys & KEY_DOWN) && duty > PWM_DUTY_MIN) {
    duty -= PWM_DUTY_STEP;
  }

  if (duty == PWM_DUTY_MIN) {
    PORTB &= ~_BV(PWM_PIN);
  } else if (duty == PWM_DUTY_MAX) {
    PORTB |= _BV(PWM_PIN);
  }
}

static uint8_t
read_keys(void)
{
  uint8_t result = 0;

  if ((PINB & _BV(KEY_UP_PIN)) == 0) {
    result |= KEY_UP;
  }

  if ((PINB & _BV(KEY_DOWN_PIN)) == 0) {
    result |= KEY_DOWN;
  }

  return result;
}
4

0 回答 0