Go Down

Topic: Interrupts and time handling problems. (Read 2 times) previous topic - next topic

jano

hi!

i want to have a couple of square oscillators (and some other stuff), but i have problems with the timing. this part of the code give me a square wave on pin 7 with variable frequency by connecting a potentiometer in analog0, but the 'resolution' of frequency is not enough, the max frequency is about 29khz  (i have no problem with this) but the step to the next is too big (15khz - 10khz - 7khz, etc, the idea is to control it trough midi+cv), i want something more smooth. because that i want to use the TIMER0_COMPA_vect (as i understood the timer go until the number in OCR0A and generates the interrupt when done) seems easy to change the resolution of the frequency counter, but it don't change the frequency out on pin 7 when i put other number in OCR0A, the output of the pin 6 can vary from 31250 to 8Mhz but the frequency on 7 remains unchanged. anyone have an idea about this? thanks in advance, and i sorry for my bad english  :~

Code: [Select]



#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <pins_arduino.h>

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

//para el generador de frecuencia
int freq_1=100;  // frecuencia osc 1
float t_high_1=1;  // tiempo alto osc 1
int t_low_1=1;   // tiempo bajo osc 1
int pot=0;
volatile byte icnt1;             // var inside interrupt
volatile byte c4ms;              // counter


boolean high_1=true;  // determinacion del tiempo actual
boolean high_2=true;  // en los dos osciladores
const int high_bit_7=B10000000;  //salida de oscilador 1 en pin 7 puerto D
const int low_bit_7=B01111111;
const int high_bit_4=B00010000;  //salida de oscilador 2 en pin 4 puerto D
const int low_bit_4=B11101111;

void setup() {

  pinMode(5,OUTPUT);    // pin5=  PWM para correccion de la rampa 1 - timer 0 - OC0A
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);    // pin7= salida de frecuencia oscilador 1 PORTD7 - timer 1
  pinMode(4,OUTPUT);    // pin4= salida de frecuencia oscilador 2 PORTD4 - timer 1

  cli();

  Setup_timer0();
  sbi (TIMSK0,OCIE0A);          //habilita la interrupcion del timer 0 en compare match con OCR0A
  sbi (TIMSK0,OCIE0B);
  sbi (TIMSK0,TOIE0);
 
  sei();
}

void loop () {
 
  if (c4ms > 10) {                 
     c4ms=0;
     pot=analogRead(0)+20;      // lee el potenciometro conectado en 0
     freq_1=pot/5;           
  }
    t_low_1=freq_1/2;
 
}


void Setup_timer0() {

// Timer0 Clock Prescaler to : 1
  sbi (TCCR0B, CS20);
  cbi (TCCR0B, CS21);
  cbi (TCCR0B, CS22);


//modos de comparacion de los registros OCR 
  sbi (TCCR0A, COM0A0);  // toggle pin 6 en Compare Match con OCR0A
  cbi (TCCR0A, COM0A1);
  sbi (TCCR0A, COM0B0);  // toggle pin 4 en Compare Match con OCR0B
  cbi (TCCR0A, COM0B1);
 

 
// Timer0 modo CTC
  cbi (TCCR0A, WGM00); 
  sbi (TCCR0A, WGM01);
  cbi (TCCR0A, WGM02);
}

ISR(TIMER0_COMPA_vect) {
 
  OCR0A=145;
 
 
if (high_1==true){
    PORTD = PORTD | high_bit_7;
    t_high_1--;
    if (t_high_1==0){
     high_1=false;
     t_high_1=t_low_1;
    }
  }
  if (high_1==false){
   PORTD = PORTD & low_bit_7;
   t_high_1--;
   if (t_high_1==0){
     high_1=true;
     t_high_1=t_low_1;
   }
  }
 
    if (icnt1++ == 125) {  // increment variable c4ms
    c4ms++;
    icnt1=0;
   }

}

ISR(TIMER0_OVF_vect) {

 
}

LuthiersDrapaires

Ey Jano!
aqui el santi....

i think the problem is with the analog read, which makes everything go slower... it happened to me once...
(it is better explained here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1208715493/11)

try attaching this code at the top, it will make the reading faster:

Code: [Select]
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// set prescale to 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;

jano

oeee!! santi!  :D

i just tried it, but it's the same, even if i disable the analog read and adjust the divisor 't_low_1' at the lowest 1 the output on pin 7 is 28khz, the next step 14khz, next 9.7khz, and in the out pin 6 (OCR0A) the frequency right now is 500khz (OCR0A=15), the question is: why the out in pin 7, if i use 1 as divisor of the count is not the half of OCR0A? or it don't works in that way?


Code: [Select]

#include <avr/interrupt.h>
#include <pins_arduino.h>

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

//para el generador de frecuencia
int freq_1=10;  // frecuencia osc 1
float t_high_1=1;  // tiempo alto osc 1
int t_low_1=20;   // tiempo bajo osc 1
int pot=0;
byte icnt1;             // var inside interrupt
byte c4ms;              // counter
long count=0;

boolean high_1=true;  // determinacion del tiempo actual
boolean high_2=true;  // en los dos osciladores
const int high_bit_7=B10000000;  //salida de oscilador 1 en pin 7 puerto D
const int low_bit_7=B01111111;
const int high_bit_4=B00010000;  //salida de oscilador 2 en pin 4 puerto D
const int low_bit_4=B11101111;

void setup() {

  pinMode(5,OUTPUT);    // pin5=  PWM para correccion de la rampa 1 - timer 0 - OC0A
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);    // pin7= salida de frecuencia oscilador 1 PORTD7 - timer 1
  pinMode(4,OUTPUT);    // pin4= salida de frecuencia oscilador 2 PORTD4 - timer 1

  //Serial.begin(9600);
  PORTD=high_bit_7;
 
  cli();

  // set prescale to 16
  sbi(ADCSRA,ADPS2) ;
  cbi(ADCSRA,ADPS1) ;
  cbi(ADCSRA,ADPS0) ;

  Setup_timer0();
  sbi (TIMSK0,OCIE2A);          //habilita la interrupcion del timer 0 en compare match con OCR0A
  sbi (TIMSK0,OCIE2B);
  sbi (TIMSK0,TOIE2);
 
  sei();
}

void loop () {
 
  if (c4ms > 10) {                 
     c4ms=0;
     t_low_1=(analogRead(0)+2)/2;
     
         
  }
   
 
 
}


void Setup_timer0() {

// Timer0 Clock Prescaler to : 1
  sbi (TCCR0B, CS20);
  cbi (TCCR0B, CS21);
  cbi (TCCR0B, CS22);


//modos de comparacion de los registros OCR 
  sbi (TCCR0A, COM0A0);  // toggle pin 6 en Compare Match con OCR0A
  cbi (TCCR0A, COM0A1);
  sbi (TCCR0A, COM0B0);  // toggle pin 4 en Compare Match con OCR0B
  cbi (TCCR0A, COM0B1);
 

 
// Timer0 modo CTC
  cbi (TCCR0A, WGM00); 
  sbi (TCCR0A, WGM01);
  cbi (TCCR0A, WGM02);
}

ISR(TIMER0_COMPA_vect) {
 
 
 
if (t_high_1==0){
    PORTD = ~PORTD;
    t_high_1=t_low_1;
    }
t_high_1--;


 
    if (icnt1++ == 125) {  // increment variable c4ms
    c4ms++;
    icnt1=0;
   }
   
  OCR0A=15;

}

ISR(TIMER0_OVF_vect) {


 
}


Senso

Variables that are shared with a function/main and an ISR must be declared volatile, so for example your c4ms should be declares this way:
volatile byte c4ms;

And using the Atmega adc at 1Mhz seems a bit nonsense, because at that speed you may have something like 3-4 bits of usefull data, the rest is just noise.

jano

hi!

thanks Senso for let me know what for is the 'volatile', but this is not the problem, neither the a/d conversion, i can delete this part of the code and put the value of t_low_1 'by hand' and have the same result
the question is more like: should the timer work in that way? because as i understand the datasheet of atmel168 the timer should stop and generate the interrupt COMPA, and since the interrupt count up 1 (at the end of the pot, or manually writen) the frequency out of the pin 7 should be the half of the OCR0A (pin 6), but if i put i.e. 60 on OCR0A the pin 6 runs at 131khz and the pin 7 at 25khz, others values of OCR0A make the same, so what i missing?

Go Up