ATTiny4313 trying to implement a delay() function using Timer1 but it's not generating the delay

Thread Starter

ronnygrr

Joined Mar 30, 2024
5
I am working on a crosswalk project using an ATTiny4313 and the clock is set in the simulator as 8Mhz. The rest of the code works fine, I have made multiple tests and I am pretty sure it works. I have to generate delays using interruptions, in this case, I am generating the interruption by comparison between the Timer 1 and the OCR1A register. As you can see in the code, I set that register as 255, so according to the datasheet, by this equation and using 1024 as the prescaler:
1712991466733.png
The f_{OC} will be 15.26 Hz, which would be 65.5 ms of period T, which means that every 65.5 ms I am generating an interruption, from what I can understand. My subroutine is simply increasing an int variable called segs, so the delay function I made is pretty simple. What I want my code to do, to test the correct functioning of this delay is to blink an LED and leave it ON for whatever the argument in seconds I pass to it, so that if call it like delay(2); it should do nothing for that amount of time but turns out my LED stays ON forever, I have tried everything but nothing is working, maybe I could get some help in here.

This is the hardware:

1712991855077.png
And this is the code in C:
C:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

// Pines del semáforo peatonal 1
#define RED_PEATON1 PB7
#define GREEN_PEATON1 PB6

// Pines del semáforo peatonal 2
#define RED_PEATON2 PB5
#define GREEN_PEATON2 PB4

// Pines del semáforo vehicular
#define RED_VEHICULAR PB3
#define GREEN_VEHICULAR PB2

// Definición de los estados para la FSM
#define esperando_boton 0
#define blink_vehicular 1
#define detener_trafico 2
#define blink_peatonal 3

// Variables globales del programa
int boton;

int segs = 0;
int un_seg = 0; // Un acumulador
int tres_segs = 0;
int diez_segs = 0;

// Preambulo de funciones
void boton_init();
void timer_init();
void cruzando();
void detenido();
void delay(float seconds);

// Interrupciones

ISR(INT0_vect){ // Subrutina que alterna B1 entre 1 y 0
    boton = !boton;
}

ISR(TIMER1_COMPA_vect){
    segs++;
}

// Inicio de la función main

int main(void)
{
    boton_init();
    sei();
    timer_init();
    
    DDRB |= (1 << RED_PEATON1) | (1 << GREEN_PEATON1) | (1 << RED_PEATON2) | (1 << GREEN_PEATON2); // Pines de semaforos peatonales como salidas
    DDRB |= (1 << RED_VEHICULAR) | (1 << GREEN_VEHICULAR); // Pines del semáforo vehicular como salidas
    
    boton = 0; // Inicializo la variable B1 en 0

    while (1)
    {
        if (boton == 1)
        {
            for (int i = 0; i < 10; i++)
            {
                PORTB ^= (1 << RED_PEATON1);
                delay(2);
            }
            boton = 0;
        } else
        {
            PORTB &= ~(1 << RED_PEATON1);
        }
    }
}

// Final de la función main

// Funciones del programa
void boton_init() { // Se establece para detectar flancos positivos en el pin PD2
    GIMSK |= (1 << INT0); // Habilitar la INT0 (interrupción externa)
    MCUCR |= (1 << ISC01); // Configurar como flanco descendente
}

void timer_init(){
    TCCR1B |= (1 << WGM12) | (1 << CS12) | (1 << CS10); // Esto me activa el prescaler de 1024 y el modo CTC
    TIMSK |= (1 << OCIE1A);
    OCR1A = 18; // Esto va a hacer que se genere una interrupción cada ~10ms
}

void cruzando(){
    PORTB |= (1 << GREEN_PEATON1)| (1 << GREEN_PEATON2) | (1 << GREEN_VEHICULAR);
    PORTB &= ~(1 << RED_PEATON1) & ~(1 << RED_PEATON2) & ~(1 << RED_VEHICULAR);
}

void detenido(){
    PORTB &= ~(1 << GREEN_PEATON1) & ~(1 << GREEN_PEATON2) & ~(1 << GREEN_VEHICULAR);
    PORTB |= (1 << RED_PEATON1) | (1 << RED_PEATON2) | (1 << RED_VEHICULAR);
}

void delay(float seconds) {
    TCNT1 = 0x00; // Reseteo del timer 1
    segs = 0; // Reseteo a la variable segs
    while (segs < 15*seconds) {
        // No haga nada
    }
}
 

MrChips

Joined Oct 2, 2009
30,987
In English, we don't say "interruption and interruptions". We say "interrupt and interrupts".

Have you checked that the delay( ) function by itself works?
 

Thread Starter

ronnygrr

Joined Mar 30, 2024
5
In English, we don't say "interruption and interruptions". We say "interrupt and interrupts".

Have you checked that the delay( ) function by itself works?
Thank you, it's not my first language. And yes I did and it's not working, it's actually what I've been trying to fix, you got any ideas?
 

MrChips

Joined Oct 2, 2009
30,987
I would begin by testing a simple loop such as the following:
C:
while (1)
{
   PORTB ^= (1 << RED_PEATON1);
   delay(2);
}
What software debugging tools are you using?
Do you have access to an oscilloscope?

For testing, try replacing the delay( ) function with a software version, using very large delay values. An LED flashing very rapidly would appear as if the LED was on all the time.
C:
void delay(long int d)
{
   while (--d);
}
 

Thread Starter

ronnygrr

Joined Mar 30, 2024
5
I would begin by testing a simple loop such as the following:
C:
while (1)
{
   PORTB ^= (1 << RED_PEATON1);
   delay(2);
}
What software debugging tools are you using?
Do you have access to an oscilloscope?

For testing, try replacing the delay( ) function with a software version, using very large delay values. An LED flashing very rapidly would appear as if the LED was on all the time.
C:
void delay(long int d)
{
   while (--d);
}
I am doing that, actually that's how i began debugging that code, I provided all of it as a way to give more context, but its really not doing anything it's like if it never passes the line when it turns ON.

C:
PORTB |= (1 << RED_PEATON1);
delay(2);
PORTB &= ~(1 << RED_PEATON1);
delay(2);
 

MrChips

Joined Oct 2, 2009
30,987
So, your delay( ) is not working.
Can you check that you are actually getting TIMER1 interrupt requests?
Does your IDE allow you to set break points? If not, toggle an LED every time an interrupt is received.
Do you have access to an oscilloscope?
 

Jony130

Joined Feb 17, 2009
5,528
This version works in the Atmel studio simulator and in proteus win ATtiny2313.

C:
#include <avr/io.h>
//#include <util/delay.h>
#include <avr/interrupt.h>

// Pines del semáforo peatonal 1
#define RED_PEATON1 PB7
#define GREEN_PEATON1 PB6

// Pines del semáforo peatonal 2
#define RED_PEATON2 PB5
#define GREEN_PEATON2 PB4

// Pines del semáforo vehicular
#define RED_VEHICULAR PB3
#define GREEN_VEHICULAR PB2

// Definición de los estados para la FSM
#define esperando_boton 0
#define blink_vehicular 1
#define detener_trafico 2
#define blink_peatonal 3

// Variables globales del programa
int boton;

uint16_t segs = 0;
int un_seg = 0; // Un acumulador
int tres_segs = 0;
int diez_segs = 0;

// Preambulo de funciones
void boton_init();
void timer_init();
void cruzando();
void detenido();
void delay(uint16_t seconds);

// Interrupciones

ISR(INT0_vect){ // Subrutina que alterna B1 entre 1 y 0
    boton = !boton;
}

ISR(TIMER1_COMPA_vect){
    segs++;
}

// Inicio de la función main

int main(void)
{
    boton_init();
    sei();
    timer_init();
   
    DDRB |= (1 << RED_PEATON1) | (1 << GREEN_PEATON1) | (1 << RED_PEATON2) | (1 << GREEN_PEATON2); // Pines de semaforos peatonales como salidas
    DDRB |= (1 << RED_VEHICULAR) | (1 << GREEN_VEHICULAR); // Pines del semáforo vehicular como salidas
   
    boton = 0; // Inicializo la variable B1 en 0

    while (1)
    {
        //if (boton == 1)
        //{
            for (int i = 0; i < 10; i++)
            {
                PORTB ^= (1 << RED_PEATON1);
                delay(2);
            }
            boton = 0;
        //} else
        //{
        //    PORTB &= ~(1 << RED_PEATON1);
        //}
    }
}

// Final de la función main

// Funciones del programa
void boton_init() { // Se establece para detectar flancos positivos en el pin PD2
    GIMSK |= (1 << INT0); // Habilitar la INT0 (interrupción externa)
    MCUCR |= (1 << ISC01); // Configurar como flanco descendente
}

void timer_init(){
    TCCR1B |= (1 << WGM12) |(1 << CS12)| (1 << CS10); // Esto me activa el prescaler de 1024 y el modo CTC
    TIMSK |= (1 << OCIE1A);
    OCR1A = 18; // Esto va a hacer que se genere una interrupción cada ~10ms
}

void cruzando(){
    PORTB |= (1 << GREEN_PEATON1)| (1 << GREEN_PEATON2) | (1 << GREEN_VEHICULAR);
    PORTB &= ~(1 << RED_PEATON1) & ~(1 << RED_PEATON2) & ~(1 << RED_VEHICULAR);
}

void detenido(){
    PORTB &= ~(1 << GREEN_PEATON1) & ~(1 << GREEN_PEATON2) & ~(1 << GREEN_VEHICULAR);
    PORTB |= (1 << RED_PEATON1) | (1 << RED_PEATON2) | (1 << RED_VEHICULAR);
}

void delay(uint16_t seconds) {
    TCNT1 = 0x00; // Reseteo del timer 1
   
    while (segs < 15*seconds) {
        // No haga nada
    }
    segs = 0; // Reseteo a la variable segs
}
And this works on a real hardware ATmega32.

C:
/*
 * main.c    ATmega32A    F_CPU = 16000000 Hz
 *
 * Created on: 14.04.2024
 *     Author: admin
*/
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
                                          
// Pines del semáforo peatonal 1
#define RED_PEATON1 PC0

// Variables globales del programa

uint8_t volatile segs = 0;

// Preambulo de funciones
void boton_init();
void timer_init();
void delay( uint16_t seconds );

// Interrupciones


ISR( TIMER1_COMPA_vect ) {
    segs++;
}

// Inicio de la función main

int main( void ) {
    boton_init();
    timer_init();
    sei();

    while ( 1 ) {             
        PORTC ^= ( 1 << RED_PEATON1 );
        delay( 1 );                       
    }                               
}                                     
                            
void boton_init() {

    DDRC |= ( 1 << RED_PEATON1 );
    PORTC |= ( 1 << RED_PEATON1 ); //RED_LED_OFF  (ANODE to Vdd)
}

void timer_init() {
    TCCR1B |= ( 1 << WGM12 ) | ( 1 << CS12 ) | ( 1 << CS10 ); // Esto me activa el prescaler de 1024 y el modo CTC
    TIMSK |= ( 1 << OCIE1A );
    OCR1A = 155; // Esto va a hacer que se genere una interrupción cada ~10ms
    TCNT1 = 0x00;
}
                                                                                                  
void delay( uint16_t seconds ) {                                             
    TCNT1 = 0x00; // Reseteo del timer 1                   
    segs = 0; // Reseteo a la variable segs
    while ( segs < ( 10*seconds ) ) {
        // No haga nada
    }                                                           
}
 
Last edited:
Top