2

I am trying to write a delay function in C, which should take 0.5 seonds then carry on. I am aware that there are libraries for this purpouse, I want to make it myself.

#include <avr/interrupt.h>
#include <avr/io.h>
#define bitset(var,bitno) ((var) |= (1 << (bitno)))

int volatile time_unit;

ISR(TIMER0_COMPA_vect) {

  time_unit += 1;
}

void wait_func(){
  TCNT0 = 0;
  time_unit = 0;
  while (time_unit < 31);
}


int main(void){
  DDRD = 1;
   cli();
  bitset(TCCR0A, WGM01);
  bitset(TCCR0B, CS00);
  bitset(TCCR0B, CS02);
  OCR0A = 0xFF;
  bitset(TIMSK0, OCIE0A);
  sei();

  while(1){
    PIND = 0;
    wait_func();
    PIND = 1;
    wait_func();
  };
}

The timer is in CTC- Mode 1024 prescaler, counting 31*255 (OCR0A = 0xFF) times should give about 0.5 seconds at a base clockrate of 16MHz of the Arduino Atmega328p. The code works, but it turns the LED on and of at a rate of 1 second, (1 sec on 1 sec off). I do not understand why.

0

1 Answer 1

3
  • PIND = 1; toggles the state of bit 0 of PORTD.
  • PIND = 0; does nothing at all; no toggling of any pins.

So you're simply just not toggling as often as you think. Your delay itself is otherwise fine. Change PIND = 0; to PIND = 1; and it will work as expected. Having done that you can get rid of one set of PIND = 1; and wait_func(); call.

Alternately, if you want to follow the current form of the code, set and clear the bit on PORTD directly:

while(1){
  PORTD &= ~1; // or &= 0xFE
  wait_func();
  PORTD |=  1; 
  wait_func();
}

For what it's worth:

  • The semicolon after your while loop does nothing.
  • The time_unit should probably be an unsigned char / uint8_t.
  • Unless you're running really tight on code space, it's probably best not to rely on the prior state of the timer hardware registers.
5
  • Sorry for the maybe trivial question but I always thought that PIND=1 loads the bit 0b00000001 to register PIND , why does it toggle? Aug 5, 2021 at 21:55
  • That's just how the AVR GPIO registers are designed. It allows for a single write to flip a bit rather than doing a set of read, modify, and write instructions. PIND's naming in in the spirit of reading from the port.
    – timemage
    Aug 5, 2021 at 21:59
  • Is this true for every GPIO register? Aug 5, 2021 at 22:09
  • I think yes, if I understand what you're asking. For the other GPIO ports on the ATMege328P, writng a 1 in a PINx bit index causes the bit at that same index to toggle in the associated PORTx register. Many (not all) other AVR parts follow this same scheme for their ports.
    – timemage
    Aug 5, 2021 at 23:21
  • See Page 60 in the ATMega328P datasheet.
    – StarCat
    Aug 6, 2021 at 8:59

Not the answer you're looking for? Browse other questions tagged or ask your own question.