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.
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

I don't need to include #include <stdint.h> manually, just by using #include <avr/io.h> it gets included and should work (avr studio).
Anyway the alternative is to use unsigned char instead of uint8_t

- - - Updated - - -

Any comments/suggestions? Which part should I fix ?

it is not the pulse part of the code so it is probably the adc part.
What is the rate of ADC sampling?
If you get a new adc result while you are in the middle of the pulse then you may miss the pulse return to the default state.

suppose that the adc gives a x of 40 , when you reach 40 the pin is set to low , then you may get a new reading and x equals 30 , now when you reenter the interrupt x+1 is not 41 but 31 so the pulse never returns to the default state.
 

I don't need to include #include <stdint.h> manually, just by using #include <avr/io.h> it gets included and should work (avr studio).
Anyway the alternative is to use unsigned char instead of uint8_t
I use codevisionavr and that's why I need to include it manually, but it already works anyway, so there is no more problem in this part.


What is the rate of ADC sampling?
I'm not sure with this one. I just use codevision to generate it (10-bit adc), ADC Clock frequency: 750.000 kHz, qrystal value 12MHz
ADCSRA=0x84;
If I'm not wrong the sampling is 750.000/13.


If you get a new adc result while you are in the middle of the pulse then you may miss the pulse return to the default state.
suppose that the adc gives a x of 40 , when you reach 40 the pin is set to low , then you may get a new reading and x equals 30 , now when you reenter the interrupt x+1 is not 41 but 31 so the pulse never returns to the default state.

Is there any special way to avoid this problem?
 

This should solve it, it prevent the x/y value change while the pulse is low
Code:
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
    static uint8_t pulse_flag = 0;
    // Reinitializa timer
    TCNT0 = 0xB5;

    if(PORTC.1 && (adc1 <= 500))
    {
        if(x >= 1)
        {
            x = x - 1;
        }
    }

    if(PORTC.1 && (adc1 >= 600))
    {
        if(x <= 180)
        {
            x = x + 1;
        }
    }

    if(PORTC.0 && (adc2 <= 300))
    {
        if(y >= 1)
        {
            y = y - 1;
        }
    }

    if(PORTC.0 && (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 cannot find what's wrong now, I did not get any pulse.
PORTC. always 1 (not active)
 

PORTC.0 and PORTC.1 are set to 1 during initialization, are they not?

- - - Updated - - -

Code:
while(1)
    {
        adc1 = read_adc(1);
        adc2 = read_adc(2);
    }

This can be another cause of problem , these functions can be interrupted an any point and get wrong values.

- - - Updated - - -

I hope adc1 and adc2 are declared as volatile
 

Code:
volatile unsigned int adc1;
volatile unsigned int adc2;


Code:
PORTC=0xFF;   // active low
DDRC=0xFF;

Still I don't get any pulse,

This can be another cause of problem , these functions can be interrupted an any point and get wrong values.
Could be,
But previously I've used this value to shift the pulse and it works, but using different method which is Timer1 Compare. I'm running out of idea, really.
 

Can you try by replacing the ADC result with predefined values with the code of post#23

Code:
while(1)
    {
        adc1 =600;
        adc2 = 300;
	delay_ms(1000);
	adc1 =400;
        adc2 = 500;
	delay_ms(1000);		
    }

- - - Updated - - -

you need to include delay.h
 

I've replaced them, nothing happen. So I think this is not caused by the adc value. maybe something else
 

I'm not sure if
Code:
if(PORTC.1 && (adc1 <= 500))
behaves differently from
Code:
if((PORTC.1==1) && (adc1 <= 500))

so can you replace all four conditions and retry

The other alternative as I would use in gcc is
Code:
if((PORTC & 0x2) && (adc1 <= 500))  // for PORTC.1
if((PORTC & 0x1) && (adc1 <= 500))  //  for PORTC.0
 

1. I use the second one, but I think they should be the same
2. I tried to replace them with this and it still doesn't work:

Code:
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
    static uint8_t pulse_flag = 0;
    // Reinitializa timer
    TCNT0 = 0xB5;

    if((PORTC & 0x2) && (adc1 <= 500)) 
    {
        if(x >= 1)
        {
            x = x - 1;
        }
    }

    if((PORTC & 0x2) && (adc1 >= 600))
    {
        if(x <= 180)
        {
            x = x + 1;
        }
    }

    if((PORTC & 0x1) && (adc1 <= 300))
    {
        if(y >= 1)
        {
            y = y - 1;
        }
    }

    if((PORTC & 0x1) && (adc1 >= 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
    }
}


3. But when I change into the following code, I see the pulse, but I don't know whether it is right or not

Code:
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
    static uint8_t pulse_flag = 0;
    // Reinitializa timer
    TCNT0 = 0xB5;

    if((PORTC & 0x2) && (adc1 <= 500)) 
    {
        if(x >= 1)
        {
            x = x - 1;
        }
    }

    if((PORTC & 0x2) && (adc1 >= 600))
    {
        if(x <= 180)
        {
            x = x + 1;
        }
    }

    if((PORTC & 0x1) && (adc1 <= 300))
    {
        if(y >= 1)
        {
            b = y - 1;
        }
    }

    if((PORTC & 0x1) && (adc1 >= 400))
    {
        if(y <= 180)
        {
            b = y + 1;
        }
    }

    counter1++;

    if(counter1 == x)
    {
        PORTC.1 = 0;
    }
    else
        if(counter1 == x + 1)
        {
            PORTC.1 = 1;
            pulse_flag++;
        }
        else
            if(counter1 == b)
            {
                PORTC.0 = 0;
            }
            else
                if(counter1 == b + 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
    }
}

you can see 'b' in there, but when I change the second 'x' with 'a' as what I do with 'b', it is not working again.
 

that doesn't make sense, x and y are only used inside the interrupt right?
make them local static variables inside the interrupt


also
Code:
 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++;
                }

should be changed to
Code:
 if(counter1 == x)
{
    PORTC.1 = 0;
}
else
    if(counter1 == x + 1)
    {
        PORTC.1 = 1;
        pulse_flag++;
    }

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

since now x and y may have the same value
 

OK2,
Yes x and y are in the interrupt only.
but,
It doesn't work still.

I'm really sorry to make you very busy.

Here I attach the screenshot of proteus file, in case you needed it

Prot.png
 

I give up, I see no reason for this to not work (at least with predefined ADC values) so I don't know what other solution to suggest.
You are also testing it on a virtual simulator so it can be the cause of the problem , I don't know.
 

Well, maybe I should try harder.
 

you can use a couple of breakpoints and check the variable values in each interrupt, you should be able to trace any faults.
 

Hi, hope you still want to help.

I attach the C code and proteus file here and maybe you want to check the pulse. I use torch LDR in the simulation to change the ADC value. I see something "abnormal" is changing in the pulse when I increase or decrease the ADC value. Maybe from here we can analyze the mistake.
 

Attachments

  • Sat.zip
    114.2 KB · Views: 56

In order to debug the code in proteus you should use the .cof file , not the .hex file.
Also move the proteus file inside the sat folder , now when you press pause you will see the source and you can place breakpoints and execute steps.

x,y,z were supposed to be static (so that the value is preserved between interrupts) but you didn't do that, it can't work this way
 

put the below code in the main loop. set a flag in interrupt routine and check if the flag is set in the while(1) loop of main function. If set then execute the below code and clear the flag.

Code:
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;
            }    
    }
 

Adding static seems to fix the problem, can you test it

Code:
    // Local variables initialization
    static unsigned int x = 0;
    static unsigned int y = 0;
    static unsigned int z = 0;
    static uint8_t pulse_flag = 0;
 

Hi all, I think we almost there :)
I did both of your suggestions with minor modification.

First I add static and set them as global variables. (not local anymore)
Second, I move the code in post #38 into the main loop, but not just that part, I move the whole part.

I test it into both proteus and in the real hardware and they are working ALMOST well.

I just get a little problem:
As ADC decrease, x,y,z decrease too, but they did not stop at 1, they decrease until 1 and then all the pulses are LOST.

As ADC increase, x,y,z increase too, but they did not stop at the maximum value
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top