2017-09-03 5 views
0

J'essaie de configurer une interruption et un compteur/minuteur. L'interruption est externe, lisant la logique basse de la broche. La minuterie devrait augmenter chaque 100 us et ajouter jusqu'à count variable. J'ai configuré l'interruption, qui fonctionne bien après la mise en place d'une minuterie, ni l'interruption ni le minuteur ne fonctionnent. Le code est par exemple:Configuration de l'interruption et de la minuterie atmega 328p [C/C++]

volatile boolean allowCount = false, timerFlag = false; 
volatile unsigned int counter; 
boolean pulseLow = false; 


void setup(){ 

Serial.begin(9600); 

// initialize external pin interrupt. 
PCICR = 0b00000010; // 1. PCIE1: Pin Change Interrupt Enable 1 
EICRA |= bit (ISC10); // set wanted flags (low logic level causes interrupt) 
PCMSK1 = 0b00010000; // Enable Pin Change Interrupt for A4 


// TODO Interrupt settings not working together 


// initialize Timer1 
cli();   // disable global interrupts 
TCCR1A = 0;  // set entire TCCR1A register to 0 
TCCR1B = 0;  // same for TCCR1B 

// set compare match register to desired timer count: 
OCR1A = 0x18; 
// turn on CTC mode: 
TCCR1B |= (1 << WGM12); 
// Set CS10 and CS12 bits for 64 prescaler: 
TCCR1B |= (1 << CS10); 
TCCR1B |= (1 << CS11); 
// enable timer compare interrupt: 
TIMSK1 |= (1 << OCIE1A); 


} 

void loop(){ 
    if (allowCount == true) 
    { timer100_uS(); 

     if (counter > 50 && pulseLow == false){ 
      DDRC |= (1 << DDC3); // sets bit DDC3 to 1 within register DDRC   
      //set pin 3(A3) ouput as sourcing Vcc(HIGH) 
      PORTC |= (1 << PORTC3); 
      timerReset(); 
      pulseLow = true; 
     } 
     if (pulseLow == true){ 
      timer100_uS(); 
      if (counter >= 500){ 
       //set pin3 of port C to LOW (A3); 
       PORTC &= ~(1 << PORTC3); 
       pulseLow = false 
       timerReset(); 
     } 

    } 
// external pin interrupt 
ISR(PCINT1_vect){ 
    if (allowCount == false) 
    allowCount = true; 
} 
// timer/counter interrupt 
ISR (TIMER1_COMPA_vect) 
{ 
    if (timerFlag == true){ 
     counter++; 
    } 
} 

void timer_100uS(void){ 
    timerFlag = true; 
    cli(); 
} 

void timerReset(void){ 
    sei(); 
    timerFlag = false; 
    counter = 0; 
} 

Valeur de OCR0A est calculée comme étant de 24 (0x18) avec prédiviseur 64 et 16 MHz sur la base de la formule suivante:

OCRn = [ (clock_speed/Prescaler_value) * Desired_time_in_Seconds ] - 1 

Comment configurer différentes interruptions de telle sorte que ils ne se chevauchent pas? Ou mieux encore, est-il possible de configurer la minuterie pour qu'elle n'utilise pas d'interruption? Merci d'avoir lu!

+0

juste ne pas définir l'interruption permettent dans les minuteries registre de contrôle oui ? puis interrogez le (s) registre (s) d'état pour voir si le minuteur a fait ce que vous attendiez de lui. –

+0

pouvez-vous les utiliser séparément seulement faire une chose ou l'autre mais pas les deux, l'interruption fonctionne-t-elle pour chaque situation? Quelle est la source de votre interruption externe (un bouton ou un signal provenant d'un autre appareil)? Si un bouton, comment gérez-vous le rebond? –

+0

@old_timer A quoi ressemblerait la lecture du compteur/valeur du compteur à partir du registre d'état? counterValue = SREG? L'interruption externe lit le signal analogique de passage par zéro, cela fonctionne à chaque fois. – flowian

Répondre

0

Merci pour les réponses @old_timer, @klasyc. assez tard, mais je l'ai résolu en utilisant timer0 au lieu de timer1 avec les paramètres suivants dans la configuration:

// initialize external pin interrupt. 
PCICR = 0b00000010; // 1. PCIE1: Pin Change Interrupt Enable 1 
EICRA |= bit (ISC10); // set wanted flags (falling edge causes interrupt) 
PCMSK1 = 0b00001000; // Enable Pin Change Interrupt for A3 

TCCR0B = 0; 
TCCR0A = 0; 
//set CTC mode 
TCCR0A = (1 << WGM01); 

// set OCR0A value for 1 us counter (OCRxn = (freq/prescaler)*desired_value)-1 
OCR0A = 15; 

// set compare match counter 
TIMSK0 |= (1 << OCIE0A); 


//set prescaler 
TCCR0B |= (1 << CS00); 

et en dehors de la boucle:

ISR(TIMER0_COMPA_vect){ 
    counter++; 
} 
0

Comme je peux le voir, vous utilisez ATMega328 avec des bibliothèques Arduino. Votre problème est que la bibliothèque Arduino utilise en interne Timer 1 à des fins internes. Par conséquent, si vous ajoutez votre propre gestionnaire d'interruptions pour le temporisateur 1, vous remplacez le gestionnaire d'interruptions d'Arduino pour le temporisateur 1 qui casse la bibliothèque.

Si vous voulez rester avec la bibliothèque Arduino, utilisez la bibliothèque aussi pour contrôler la minuterie: Arduino Timer1

+0

* Pour une raison quelconque, le formatage ne fonctionne pas comme prévu, vous pouvez donc simplement lire cette réponse à la place. Oui, j'utilise Arduino mini pro 16 MHz Je ne pense pas qu'il est possible de compter jusqu'à 10 uS avec minuterie 0 et minuterie 2, parce qu'ils sont 8 minuteries bits qui permet prédiviseur 256. Alors oui, le Timer 1 semble être seulement une option. Comment vérifier tous les registres? Si c'est trop compliqué, je préfère programmer le code directement en avr sur la puce arduino. – flowian

+0

Après avoir vérifié Arduino [code source] (https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring.c#L241) il semble que la bibliothèque Arduino essaie de configurer et d'utiliser tous les timers et le seul moyen "officiel" est d'utiliser leurs fonctions de bibliothèque. Par conséquent, j'ai changé ma réponse en fonction de ce fait. Pour votre question du commentaire: pour vérifier un registre de processeur il suffit d'écrire son contenu en série comme une variable normale :) – klasyc