Search code examples
avravr-gccatmegaatmelatmega16

Pulse width measurment


I want to measure pulse duration, but I need to measure 4 signals so I can't use Timer capture interruption as there is only 1 pin ICP1 providing that option (or can?). So I try to implement something like arduino pulseIn with the difference that I use timer (arduino has some other implementation but very similar).

The actual problem is that pulseIn doesn't return any and just goes on working in the endless loop.

Using ATmega16. Testing only on PB2 now.

unsigned long pulseIn()
{
    unsigned long duration = 0;
    DDRB = 0x00;

    /* Initiate timer and wait for the end of previous pulse*/
    initTime1();
    while(getPortBPin(2) == 1);

    /* Wait for current pulse begin */
    while(getPortBPin(2) != 1);

    /* Time before previous pulse ended */
    TCNT1 = 0;
    overflowCounter = 0;

    /* Wait for current pulse end */
    while(getPortBPin(2) == 1);

    /* Closk freq is 2 MHz = 1/2 us per tick */
    duration = (TCNT1+overflowCounter*65536)/2;
    overflowCounter = 0;
    stopTimer1();

    return duration;
}

void initTime1()
{
    /* Noise filtering */
    TCCR1B = (1 << ICNC1);

    /* Set prescaling factor to 8 */
    TCCR1B |= (1 << CS11);

    /* Enable overflow interruption */
    TIMSK = (1 << TOIE1);

    /* Clear counter */
    TCNT1  = 0;
}

void stopTimer1()
{
    TCCR1B = 0;
    TIMSK = 0;
    TCNT1 = 0;
}


uint8_t getPortBPin(uint8_t pin)
{
    if(pin < 0 || pin > 8)
    {
        return 0;
    }    

    return (uint8_t)((PINB >> pin) & 0x01);
}

UPDATE

That's my proteus scheme. Signal comes from generator. Frequency is 1kHz and width is 50%. Аmplitude is 5 volts. Proteus scheme

UPDATE

Sorry, that was a stupid mistake. It works fine. Debug things I have didn't work as expected.


Solution

  • I cannot find where is the problem in your code. but here are some debugging steps i could follow:

    1) What the pin always read? logic 1 or 0, maybe the pulse voltage is not high enough so the AVR cannot sense it.

    2) The multiplication in duration = (TCNT1+overflowCounter*65536 - timestamp)/2; is taking alot of CPU time, maybe it take more time then the pulse so the pulse goes low before AVR enters the last while loop. Of course that dependant on wither the pulse is continous or only one pulse. Also i don't know why are you using timestamp as you already cleared overflowcounter. I think this line should be deleted.

    UPDATE

    To measure four signals pulse, i recommend to use PORTB change interrupt, when interrupt happens, you can mask the port to see which signal has changed and calculate it's duration.