NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Basic Electronics » Measuring PWM Duty Cycle

July 08, 2012
by dan_engbers
dan_engbers's Avatar

Looking for a way to read a PWM signal from a ultrasonic sensor. Discovered this document and thought maybe others could use it.

Sorry if this is a repost, and looking for any help with getting this up and running. I'll post whatever I discover when I have this working.

Measuring PWM Duty Cycle

July 10, 2012
by Ralphxyz
Ralphxyz's Avatar

Hi dan_engbers, thanks for the Atmel PWM link.

There are lots of discussions here in the Nerdkits forum on ultrasonic sensors.

Plus lukel put a nice code sample in the Nerdkit Community Library.

Which ultrasonic sensor do you have?

Ralph

July 10, 2012
by dan_engbers
dan_engbers's Avatar

I purchased this unit http://futurlec.com/Distance_Sensors.shtml

July 11, 2012
by Ralphxyz
Ralphxyz's Avatar

Yeah that is the same/similar to the one I have.

Look at some of the discussions here on the forum for some code examples.

This device uses the same pin to send the ping and receive the ping.

The device written up in the Nerdkits Community Library uses a separate pin for pinging (four pins instead of three).

It would be nice to have the three pin version added to the Library.

Ralph

September 04, 2012
by dan_engbers
dan_engbers's Avatar

I have it figured out for a single SIG sensor without using interrupts. I'll post the code once I clean it up.

September 13, 2012
by dan_engbers
dan_engbers's Avatar

Here is the working code. Posting it to the library now as well. Normally you'd want to use ICP1 pin but it will not work with the bootloader.

/*
 * PWM for Ultrasonic sensor with a single SIG pin on ATmega168
 *
 * Credit to CommanderBob for PWM without Interrupts
 * http://www.societyofrobots.com/robotforum/index.php?topic=4656.30
 *
 *  Author: Dan Engbers - http://www.engbers.ca
 */

#define F_CPU 14745600

#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include <math.h>

#include "delay.h"
#include "lcd.h"
#include "uart.h"

#define ULTRA_SONIC_MASK (1<<6)

#define ULTRA_SONIC_OUT (DDRD|=ULTRA_SONIC_MASK)
#define ULTRA_SONIC_IN (DDRD&=~ULTRA_SONIC_MASK)
#define ULTRA_SONIC_SET (PORTD|=ULTRA_SONIC_MASK)
#define ULTRA_SONIC_RESET (PORTD&=~ULTRA_SONIC_MASK)
#define ULTRA_SONIC_CAP_RISING (TCCR1B|=(1<<ICES1))     //pg 133
#define ULTRA_SONIC_CAP_FALLING (TCCR1B&=~(1<<ICES1))   //pg 133

#define Clear_ICF1 TIFR1|=(1<<ICF1)             //pg 137
#define ICF1_Empty !(TIFR1 & (1<<ICF1))         //pg 137

void init_hardware (void){
    TCCR1A=0;
    TCCR1B=3;       //pg 134 - 1 (none) - 2 (8) - 3 (64) - 4 (256) - 5 (1024)
    ACSR=(1<<ACIC);     //set ACO for ICP
}

uint16_t get_ultra_sonic (void){
    uint16_t fcap=0,scap=0,dist=0;  //fcap stores first capture, scap stores second
    TCNT1 = 0;          //prevent overflow
    Clear_ICF1;         //clear the capture flag
    ULTRA_SONIC_OUT;        //set pin to output
    ULTRA_SONIC_SET;        //set pin to high
    delay_us (10);          //T1 pulse for >5us
    ULTRA_SONIC_RESET;      //set pin low
    ULTRA_SONIC_IN;         //set pin to input
    ULTRA_SONIC_CAP_RISING;     //capture the rising edge of the pulse
    while (ICF1_Empty){     //wait for capture
        if (TCNT1>50000) return 0xFFFF;
    }       
    Clear_ICF1;         //clear the capture flag
    fcap=ICR1;          //save the captured value
    ULTRA_SONIC_CAP_FALLING;    //capture the falling edge of the pulse
    while (ICF1_Empty){     //wait for capture
        if (TCNT1>50000) return 0xFFFF;
    }       
    Clear_ICF1;         //clear the capture flag
    scap=ICR1;          //save the captured value
    dist=scap-fcap;     //subtract the timer values to find the pulse length
    return dist;
}

int main(void){

    // init Serial Comm
    uart_init();
    FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
    stdin = stdout = &uart_stream;

    uint16_t ac=0;

    init_hardware();
    delay_ms(100);

    while(1){
        ac=get_ultra_sonic();

        fprintf_P(&uart_stream, PSTR("Reading %d\r\n"),ac);

        delay_ms(5);
    }
    return 0;
}

Post a Reply

Please log in to post a reply.

Did you know that you can aim and fire a servo-controlled water gun from your computer? Learn more...