Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Need Help: Problem with time slicing avr

Status
Not open for further replies.

ArdyNT

Full Member level 2
Full Member level 2
Joined
Nov 6, 2012
Messages
126
Helped
7
Reputation
14
Reaction score
7
Trophy points
1,298
Visit site
Activity points
2,304
I build this code, I sue external interrupt to start the timer.

Code:
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// When interrupt occurs, start timer0
    TCCR0 = 0x02;
}

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Reinitializa timer
    TCNT0 = 0xB5;

    counter1++;
    if(counter1 == 40)               
    {
        PORTC.0 = 0;
        counter1 = 0;   
    }
    else
    {
        PORTC.0 = 1;
         
    }

    counter2++;
    if(counter2 == 20)               
    {
        PORTC.1 = 0;
        counter2 = 0;   
    }
    else
    {
        PORTC.1 = 1;
         
    }

}

I get this first picture, and I want the second picture.
dd.png

Help me please to fix my code.
 

Only a guess (I don't use AVR) but shouldn't you clear the interrupt in the interrupt routine or is it automatically done for you?

Keith
 

There are two main errors.
1. You need to disable timer0 interrupt when counter1==40
Add a disable code in the following

....
if(counter1 == 40)
{
PORTC.0 = 0;
counter1 = 0;
counter2 = 0;
TCCR0 = 0x00;; // stop timer0


}
.....

2. remove the counter2 = 0; in the counter2 if condition
 

In general the interrupt flag gets cleated when you enter the interrupt apart from a couple of exceptions where you need to read a register in order to clear it but for the timers or external interrupt that is not needed.
 

You can simplified the code using single counter1 variable as
Code:
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Reinitializa timer
    TCNT0 = 0xB5;

    counter1++;
    if(counter1 == 40)               
    {
        PORTC.0 = 0;
        counter1 = 0;   
        TCCR0 = 0x00;; // stop timer0
    }
    else if(counter1 == 20)               
    {
        PORTC.1 = 0;
    }
    else
    {
        PORTC.1 = 1;
        PORTC.0 = 1;
    }
}
 

If you stop the timer when the counter equals 40 then you will never get the next interrupt in order to set PORTC.0 = 1;


I think this should do

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
    // When interrupt occurs, start timer0
    TCCR0 = 0x02;
}
 
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
    // Reinitializa timer
    TCNT0 = 0xB5;
    
    counter1++;
 
    if(counter1 == 20)
    {
        PORTC.1 = 0;
    }
    else
        if(counter1 == 21)
        {
            PORTC.1 = 1;
        }
        else
            if(counter1 == 40)
            {
                PORTC.0 = 0;
            }
            else
                if(counter1 == 41)
                {
                    PORTC.0 = 1;
                    TCCR0 = 0;      // stop thet timer
                    counter1 = 0; // clear counter
                }
}

 

Hi iukhan, both of your suggestion work well for PORTC.1 only but not for PORTC.0. I've tested it and this is the result.

ff.png


Thanks alexan_e, yeah that code works well now.

- - - Updated - - -

Actually this is for testing purpose, next the value of counter1 will always change. I want to use Counter1 and counter2 and they will be different like in my first code counter1=40 and counter2=20. What should I modify now?
 
Last edited:

Hopefully you understand the logic of the code and you can modify it to do what you want.
I'm not sure what you want to do so presenting you the code using two counters again will not help.
 

alexan_e is right, the timer should be stop when counter1 ==41
Code:
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Reinitializa timer
    TCNT0 = 0xB5;

    counter1++;
    if(counter1 == 41)               
    {
        counter1 = 0;   
        PORTC.0 = 1;
        TCCR0 = 0x00;; // stop timer0
    }
    else if(counter1 == 40)               
    {
        PORTC.0 = 0;
    }
    else if(counter1 == 20)               
    {
        PORTC.1 = 0;
    }
    else
    {
        PORTC.1 = 1;
        PORTC.0 = 1;
    }
}
 

OK friends, I've modify it to become like this:

Code:
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
    // Reinitializa timer
    TCNT0 = 0xB5;
    
    counter1++;
    counter2++;
 
    if(counter1 == 38)
    {
        PORTC.1 = 0;
    }
    else
        if(counter1 == 39)
        {
            PORTC.1 = 1;
        }
        else
            if(counter2 == 130)
            {
                PORTC.0 = 0;
            }
            else
                if(counter2 == 131)
                {
                    PORTC.0 = 1;
                    TCCR0 = 0;      // stop thet timer
                    counter1 = 0;   // clear counter
                    counter2 = 0;
                }
}

It works actually but if I change counter1 to be greater than counter2, only PORTC.0 is triggered
If counter2 > counter 1, it is OK.

how do I find the solution for this case? since sometime counter1 may be greater than counter2, and counter2 may also greater than counter1
 
Last edited:

When you say that counter 1 may he higher than counter 2 or the opposite what do you refer to , the value of the variable or the values used in the conditions (like if(counter2 == 130))

Since you stop the counter and clear both counter variables when you restart the timer the counts will be predefined and incremented together , wont they?

- - - Updated - - -

I don't even see the point of having two counter variables in your example
 

I mean the value used in the condition. In that code, if I change "38" to be some value that is greater than "130", let say counter1=140, it doesn't work

Ok let me explain more,

For my system, counter 1 will be determined by ADC1, for example:
*if ADC1 < 100 then counter1=counter1 - 5
*if ADC1 > 150 then counter1=counter1+ 5

counter 2 will be determined by ADC2, for example:
*if ADC2 < 50 then counter2=counter2 - 5
*if ADC1 > 80 then counter2=counter2 + 5

So that means sometime counter1 may be greater than counter2 but sometime counter1 may be smaller than counter2. So now how is the solution for this problem?
I'm sorry for my bad English.
 

You can use

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
    static uint8_t pulse_flag = 0;
    // Reinitializa timer
    TCNT0 = 0xB5;
    
    counter1++;
 
    if(counter1 == 20)
    {
        PORTC.1 = 0;
    }
    else
        if(counter1 == 21)
        {
            PORTC.1 = 1;
            pulse_flag++;
        }
        else
            if(counter1 == 40)
            {
                PORTC.0 = 0;
            }
            else
                if(counter1 == 41)
                {
                    PORTC.0 = 1;
                    pulse_flag++;
                }
 
    if(pulse_flag == 2) // only stop timer after both pulses have completed
    {
        pulse_flag = 0; // clear flag
        TCCR0 = 0;      // stop thet timer
        counter1 = 0; // clear counter
    }
}

 
Last edited:

Sorry, it still the same error

static uint8_t pulse_flag = 0;

is for AVR GCC isn't it?

- - - Updated - - -

Ahaa I found it, I must add:

#include <stdint.h>

and now it works.

Thank you very much alexan
 

Hi, now I combine the code again and I don't know why it doesn't work well.
Here is it:

Code:
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
    static uint8_t pulse_flag = 0;
    // Reinitializa timer
    TCNT0 = 0xB5;
    if(adc1 <= 500)
    {
        if(x>=1)
            {
                x = x - 1;
            }
    }
    
    if(adc1 >= 600)
    {
        if(x<=180)
            {
                x = x + 1;
            }    
    }


     if(adc2 <= 300)
    {
        if(y>=1)
            {
                y = y - 1;
            }
    }
    
    if(adc2 >= 400)
    {
        if(y<=180)
            {
                y = y + 1;
            }    
    }
    
    counter1++;
 
    if(counter1 == x)
    {
        PORTC.1 = 0;
    }
    else
        if(counter1 == x + 1)
        {
            PORTC.1 = 1;
            pulse_flag++;
        }
        else
            if(counter1 == y)
            {
                PORTC.0 = 0;
            }
            else
                if(counter1 == y + 1)
                {
                    PORTC.0 = 1;
                    pulse_flag++;
                }
 
    if(pulse_flag == 2) // only stop timer after both pulses have completed
    {
        pulse_flag = 0; // clear flag
        TCCR0 = 0;      // stop thet timer
        counter1 = 0; // clear counter
    }
}

void main(void)
{
while (1)
      {
        adc1=read_adc(1);
        adc2=read_adc(2);
      }
}

I need the adc value will determine the value in the counter1, but I didn't get a good result.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top