LINUX.ORG.RU

Arduino Uno (Atmega328p) ШИМ

 ,


0

1

Второй день туплю над даташитом и не могу решить простейшую проблему: один раз в секунду нужно сгенерировать пульс частотой 40 кГц продолжительностью, скажем, 1 мс.

Что-то не поддаётся мне логика таймеров и прерываний... Вернее, принцип понятен, я даже добился пульсации, где длина пульса = длине паузы, а дальше - никак.

Киньте мануал, где это разжёвывается для нубов или покажите, в какой регистр какой флаг воткнуть.

Вот код

const byte LED = 9;
#define CPU_FREQ     (16000000)
#define SIG_FREQ     (40000)
#define PLS_CYCLES   ((CPU_FREQ/(2*SIG_FREQ)))

ISR (TIMER1_COMPA_vect)
{
    TCCR0A ^= _BV(COM0A0) ;  //Toggle OC1A on Compare Match
    if ( (TCCR0A & _BV (COM0A0)) == 0) {
        digitalWrite (LED, LOW);
    }
}

void setup()
{
  pinMode (LED, OUTPUT);

  // Timer 0 : 40 kHz PWM                       
  TCCR0A = _BV(WGM01); // CTC                    
  TCCR0B = _BV(CS00);  // no prescaler           
  // 1 tick = 1/16MHz =	62.5 ns                  
  // half period duration is 1/(2*40kHz) = 12.5 us
  // We have to wait 12500/62.5 = 200 clock cycles
  OCR0A =  PLS_CYCLES - 1;

  // Timer 1: interpulse gap                     
  TCCR1A = _BV (WGM12); // CTC                   
  TCCR1B = _BV(CS10) /*| _BV(CS11)*/ | _BV(CS12); // prescaler of 1024
  // 1 tick = 1024/16MHz = 64 us                 
  // We have to wait 999ms/64us = 15609 clock cycles
  OCR1A  =  15609 - 1 ;
  TIMSK1 = _BV(OCIE1A);   // enable Timer1 Interrupt

  Serial.begin(115200);
}

void loop()
{}



Последнее исправление: float (всего исправлений: 2)

Оставлю здесь корявенькое решение для истории, чтобы потом легче было искать.

const byte LED = 9;  // Timer 1 "A" output: OC1A
#define CPU_FREQ     (16000000L)
#define SIG_FREQ     (40000L)
#define INNER_CYCLES ((CPU_FREQ/(2L*SIG_FREQ)))

static const long timer2_OCR2A_Setting = 256;
static volatile unsigned cnt = 0;

ISR (PCINT2_vect)
{
    // if pin 3 now high, turn on OC1A on compare match
    if (PIND & _BV (3) && !(cnt%62) ) { // 62*16ms = 992 ms
	TCCR1A |= _BV (COM1A0) ;  // OC1A on Compare Match ON
    }  else {
	TCCR1A &= ~_BV (COM1A0) ;  // OC1A on Compare Match OFF
	digitalWrite (LED, LOW);  // ensure output pin off
    }
    cnt++;
}

void setup() {
    pinMode (LED, OUTPUT);
    pinMode (3, OUTPUT);  // OC2B
    
    // set up Timer 1 to 40 kHz
    TCCR1A = 0; 
    TCCR1B = _BV(WGM12) | _BV (CS10);   // CTC, No prescaler
    OCR1A =  INNER_CYCLES - 1;
    
    // Timer 2:
    // 1 tick = 1024/16MHz = 64 us
    // We wait 256 clock cycles = 250*64us = 16 ms
    TCCR2A = _BV (WGM20) | _BV (WGM21) | _BV (COM2B1);   // Fast PWM mode
    TCCR2B = _BV (WGM22) | _BV (CS20) | _BV (CS21) | _BV (CS22) ;  // prescaler of 1024 (datasheet p.162)
    OCR2A  = timer2_OCR2A_Setting - 1;
  
    // pin change interrupt
    PCMSK2 |= _BV (PCINT19);  // want pin 3
    PCIFR  |= _BV (PCIF2);    // clear any outstanding interrupts
    PCICR  |= _BV (PCIE2);    // enable pin change interrupts for D0 to D7
}

void loop()
{
    //OCR2B = /*timer2 duty cycle*/
}

float
() автор топика

В девелопменте надо про коды писать.

Napilnik ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.