Attiny and highspeed external interrupt

Hey Guys,

I need help… That’s the first time i have to use a standalone Microcontroller. I try to use the Attiny45. Things like the Arduino Blink example, working as expected.

Here is the problem:

I have a signal, wich is a squarewave betwen 0V and +5V with 20000 Hz and a duty cycle of 50%.
It’s a sync signal from a highspeed camera. The camera takes a picture every rising flank.

I have to switch two Led’s with the rising flank, alternating.

My first try was with a normal digitalRead(), delayMicroseconds() and digitalWrite() but at 1000Hz sync frequenz, the Oszi shows that the controller is switching the LED only with 30Hz.

My next try would be to use external interrupts… But for a noob like me, that is to much and my sketch doesn’t work.

EDIT:


That’s how my signals should look like.
blue = sync freq.
red = respond

And that is the diagram, right now I will use the Button and if it’s working I will go on to the square wave.

//Attiny45 interrupt test
//LED is on PA1 
//Pushbutton is on PA0 (using external INT0 interrupt)

#include <avr/interrupt.h> 

int led = 1;
int button = 0;
//for setting register bits with AVR code
//cbi and sbi are standard (AVR) methods for setting, or clearing, bits in PORT (and other) variables. 
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif 



void setup(void)
{
  cli(); //disable global interrupts
  pinMode(led, OUTPUT);
  pinMode(button,INPUT); 

  // Set ISC01= 1 and ISC00 = 0 to generate an external interrupt request on the rising edge of INT0
  sbi(MCUCR,ISC01);
  cbi(MCUCR,ISC01); 

  //enable external interrupt request 0
  sbi(GIMSK,INT0);

  sei(); //enable global interrupts

}

void loop(void)
{
  //nothing right now

}


//external interrupt ISR (for INT0 pin)
ISR(INT0_vect)
{
  blink_led();
}

void blink_led(void)
{
  digitalWrite(led,HIGH);
  delay(1000);  //delay one second
  digitalWrite(led,LOW); 
}

Can somebody give me a little help please?
Sorry for my bad English.

untitled.png

Blink-without-delay and Direct Port Manipulation for output speed.
20000Hz = 50uS period

byte D2 = 2;
byte D3 = 3;
unsigned long currentTime;
unsigned lone previousTime;
unsigned long elapsedTime;
unsigned long duration = 50;

void setup(){
pinMode (D2, OUTPUT); // set up initial levels
digitalWrite (D2, HIGH);
pinMode (D3, OUTPUT);
digitalWrite (D3, LOW);
}
void loop(){
while(1){ // use a while to avoid time spent recycling thru main() and loop() code
currentTime = micros(); // capture the time now
elapsedTime = currentTime - previousTime; // how much time has passed?
if (elapsedTime >= duration){ // duration set to 50.  did enough time pass?
previousTime = previousTime + duration; // set for next time check
PIND = PIND | 0b00001100; // toggle outputs by writing 1 to input register
} // end time check
} // end while
} // end loop

Thanks for the hint with the direct port manipulation.

After changing PIND to PINB and, redefine BIN to BINARY in Print.h the code is running.

But the time when the LED’s change there status, in reference to my sync signal, is not constant.
The LED’s start toggling if they get power, but they should:

  1. detect a rising flank in the sync signal

  2. wait offset length

  3. LED#1 = HIGH

  4. wait puls length

  5. LED#1 = LOW

  6. detect a rising flank in the sync signal

  7. wait offset length

  8. LED#2 = HIGH

  9. wait puls length

  10. LED#2 = LOW

Your example is working but I need a input, so I think I have to set DDRB0 as input???

But how do I implement the flank detection???

This is the adopted code without input or interupt:

#include <avr/io.h>
#include <avr/iotn45.h>

byte I1 = 0;
byte D2 = 2;
byte D3 = 3;
unsigned long currentTime;
unsigned long previousTime;
unsigned long elapsedTime;
unsigned long duration = 500;

void setup(){
pinMode (D2, OUTPUT); // set up initial levels
digitalWrite (D2, HIGH);
pinMode (D3, OUTPUT);
digitalWrite (D3, LOW);
pinMode(I1, INPUT_PULLUP);
}
void loop(){
  while(1){ // use a while to avoid time spent recycling thru main() and loop() code
    currentTime = micros(); // capture the time now
    elapsedTime = currentTime - previousTime; // how much time has passed?
      if (elapsedTime >= duration){ // duration set to 50.  did enough time pass?
         previousTime = previousTime + duration; // set for next time check
          PINB = PINB | 0b00001100;
         } // toggle outputs by writing 1 to input register
      } // end time check
  } // end while
} // end loop

If everything is working the standart LED’s get replaced by cree high power LED’s.

Thank you

So I move forward but there is still work to do.

This is my code:

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

volatile int i = 1;

void interrupt_init()
{
  // rising edge on INT0 creates an interrupt
  MCUCR |= (1 << ISC00)|(1 << ISC01);
  // turns on interrupt for INT0
  GIMSK |= (1 << INT0);
  // allow global interrupts
  sei();
  //or 'SREG |= (1 <<  7);'

}

int main(void)
{  
  //PB0 as OUTPUT
  DDRB |= (1 << PB0);
  //PB1 as OUTPUT
  DDRB |= (1 << PB1);
  //PB2 as INPUT
  DDRB &= ~(1 << PB2);
  
  // initialize interrupt
  interrupt_init();
  
  // loop forever
  while(1)
  {
    
  }
}



ISR(INT0_vect){
  
  if(i=1){
    PORTB |= (1 << PB1);
    PORTB &= ~(1 << PB0);
    i = 2;
  }
  
  if(i=2){
    PORTB |= (1 << PB0);
    PORTB &= ~(1 << PB1);
    i = 1;
  }
}

and here ar my results on an oszi:

red = sync signal
blue = LED#1

blue = LED#2

can somebody tell me why they are not the same puls lenght?

Thanks

Something like this ?:

The blue is the original pulse

if(i=1)

I think you mean

if(i==1)
volatile byte even=0;

ISR(PCINT0_vect) {
  if (even<=1){
    PORTB^=_BV(3);
  }

  if (even<=3 && even>1){
    PORTB^=_BV(0);
  }

  even++;
  if (even==4){
    even=0;
  }
}

void setup()
{ 
  pinMode(3,OUTPUT);
  pinMode(0,OUTPUT);
  GIMSK = _BV(PCIE);    // Enable pin change interrupt Table 9.3.2
  PCMSK = _BV(PCINT4);  // Enable the interrupt for only pin 4,Table 9.3.4
}

void loop ()   {
} //loop