Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Reading PWM Signal

Status
Not open for further replies.

mrfunkyjay

New Member
Hello there,

I have an idea in my mind to "read" PWM signal produced by receiver of r/c. One thing I know is the servo, for instance, takes red and black cables for +5V and GND function while the white colored wire is for PWM Signal.

In my mind, I want to have a simulation where moving servo to the most left will generate a blinking signal to an orange LED. It does the same function to the right (but the port for the other orange LED would be different).

I have also did experiments, in addition to that I have jumped into several facts that I need to write a program that would "catch" those signals and process them, in order to give further feedbacks to LEDs.

Several questions arrise, but FYI I have PICDEM2 Demo board w/ MPLAB ICD2, PIC18F4520 uC, and a very basic knowledge in C Programming. My questions are:

1. I have found several issues regarding this, and I am asking myself whether I have to master (or at least understand) the meaning of CCP or ECCP module in this uC? Because from what I heard, CCP or Capture-Compare-PWM might give solution to my idea here.

2. If my 1st statement was wrong, what do you think I can do next? Is there any tuts on this? Kindly guide me along, thank you so much.

I think it is enough for now, I would say thank you very much for helping me out, thanks!
 
Assuming that you are using C18 then you could simply time the pulse in software.

Something like,
Code:
//counts the length of a pulse on a pin.
int GetPulse(){
int count;
    count=0;          //initialise count
    while(Pin==0);    //wait for pin to be high
    while(Pin==1){    //count while pin is high
        count++;      //increment count
    }
    return count;     //tell the calling routine
}

You will get weird numbers in count but they will be consistent.

Mike.
 
Last edited:
what does it do? it looks like a program counter there. care to explain a bit more?? thanks. and this is what you mean by "reading" pwm signals?
 
it cleares my complicated thought now. so after executing this source code, GetPulse() can be used to progress some kind of flashing modes of LEDs. So important thing is, I need to "read" the PWM signals from the receiver and make several parameters to be put into the source code.

for example:

1ms pulse width means turning left (servo head)
1.5ms pulse width means neutral position
2ms pulse width means turning right

from this, I can just use the GetPulse(), check how long is the pulse width from this steering channel, and then when it is 1ms, for example, left LED blinks.

Do correct me if I'm wrong!

Btw, so what CCP does mean???
 
from this, I can just use the GetPulse(), check how long is the pulse width from this steering channel, and then when it is 1ms, for example, left LED blinks.
Yes, you can. It's not the most elegant solution but it will work.
Btw, so what CCP does mean???

The CCP module will do the timing for you to a much greater accuracy. You sounded like you weren't really comfortable with it and so I suggested the above alternative.

Mike.
 
As an after thought, here is a routine that I used to time an infra red pulse. It returns the time in 100uS units so 1mS=10 1.5=15 etc.
Code:
unsigned char GetPulse(void){
unsigned char count;
    count=0;
    IR_tris=1;
    while(IR_in==1); 
    while(IR_in==0){
        count++;
        Delay100TCYx(2);   //100uS assumes 8MHz
    }
    return count;
}
It's not completely accurate but should be within a couple of percent.

Mike.
 
Mike, to be honest you are really correct. I put myself now in a middle of a cool project of my own but no source/enough knowledge to realize it.
I would really want to know how to do it, finish this project, even though it is just a prototype or I even don't make the PCB, but with designing, when I fulfill the requirements I am far most satisfied.

I've read like 30+ tuts and some of them gave me ASM codes which I avoid the most.

Back 2 topic:
If you mentioned that way, I can conclude that CCP could count the Pulse Width of PWM signals the most accurately, am I correct?

Then what actually this Capture - Compare do? CapCom for short. :) Care to explain in easy way for me to understand? Thanksss!!!
 
You setup the CCP so that it copies the count in timer1 (or 3) to the CCP registers when a pin goes high. You then set it to do the same when the pin goes low. The difference between the values is the length of the pulse. It can be setup so that it all works on interrupt and so doesn't use any processor time but if your not doing anything else then simply counting it is so much easier.

Mike.
 
Today, I did some experiments using Tektronix Oscilloscope finding the duty cycle from one of the channel outputs of the receiver.

I got a period of 16ms and when the servo is turning:
(Ton are)
Left: 1.16ms
Middle: 1.48ms
Right: 1.88ms

Now my job is to use CCP, measuring the Ton at any instance of time, then when the Ton is less than 1.38ms (let's say) the left LED is blinking and when the Ton is more than 1.58ms the right LED is blinking.

But the bad thing always that I am stuck!! :( I don't really have knowledge in this, can someone help me finding clues?? Thanks.
 
Use the (IR) code above and simply do,
Code:
    while(1){
        Pulse=GetPulse();
        if(Pulse<14){
            //code to blink left LED
        }
        if(Pulse>16){
            //code to blink right LED
        }
    }

Or, is this a school project and you have to use the CCP?

Mike.
 
No this is not a school project, I don't really have to use CCP but it has also to be accurate, in reading the Pulse Width (Ton). Mike thanks, I would try that source code.

Btw, what is this 14 and 16 ???
Does it mean 14 = 1.4ms and 16 = 1.6ms ?

And

what do you define these as:
IR_tris >> ??
IR_in >> the status of input pin, whether it is high or low?
 
IR_tris and IR_in would be #defines.

Code:
#define IR_in   PORTAbits.RA6
#define IR_tris TRISAbits.TRISA6
The above tells the compiler that the pulse will arrive on Port A6.

You are correct on the times.

Mike.
 
Hello, I have tried this code before:

Code:
#include <p18f4520.h>
#include <delays.h>

#pragma config OSC = HS
#pragma config WDT = OFF
#pragma config LVP = OFF

int i, iPulse;
void vLeft(void);
void vRight(void);

/*Counts the length of a pulse on Pin RA0*/
unsigned char GetPulse(void){
unsigned char count;
    count=0;
    TRISAbits.TRISA0=1;
    while(PORTAbits.RA0==1); 
    while(TRISAbits.TRISA0==0){
        count++;
        Delay100TCYx(2);   /*100uS assumes 8MHz*/
    }
    return count;
}

void main(void)
{

TRISA = 0b00000001; /*Initialize RA0 as Input Port to read PWM Signal*/
TRISB = 0b00000000; /*Initialize Port B as Output Port to flash LEDs*/
ADCON1 = 7; /*Digital Input*/

while(1)
	{
		iPulse=GetPulse();
		if(iPulse<14){		/*If the Pulse Width is less than 1.4ms*/
			vLeft();		/*Blinks left LED*/
		}
		if(iPulse>16){		/*If the Pulse Width is less than 1.4ms*/
			vRight();		/*Blinks right LED*/
		}
	}
}

void vLeft(void)
{
	for(i=0;i<1;i++)
	{
		LATBbits.LATB0 = 1;
		Delay10KTCYx(100);
		LATBbits.LATB0 = 0;
		Delay10KTCYx(100);
	}
}
void vRight(void)
{
	for(i=0;i<1;i++)
	{
		LATBbits.LATB1 = 1;
		Delay10KTCYx(100);
		LATBbits.LATB1 = 0;
		Delay10KTCYx(100);
	}
}

I don't know why, but the LED on RB0 flashes forever. I think the iPulse is always lower than 14. I tried to turn left and right with my steering wheel (Transmitter) but nothing change!! Can someone help me?

Btw, I built my own demo board and I used 20Mhz External OSC with 22pF ceramic caps.

Please give me clue, thanks!!
 
I guess you missed the comment on the line,
Code:
    Delay100TCYx(2);   /*100uS assumes 8MHz*/
If you are using a 20MHz clock then the line should be,
Code:
    Delay100TCYx([COLOR="Blue"]5[/COLOR]);   /*100uS with 20MHz*/
This is because 100uS is 500 cycles with a 20MHz oscillator.

Edit, why have you changed the 2nd check to TRISA?
Code:
    while(TRISAbits.TRISA0==0){
This is wrong and won't work. Change it back to PORTA.

Mike.
 
Last edited:
Mike, I have changed all those requirements u gave to me. Now I took V+ and GND from the Receiver Box, connected them to VDD and VSS also MCLR in PIC18F4520. Before, I attached 7805 as 5V regulator to feed the MCU.

The third wire from receiver box (steering channel, ch1) is connected with 470 Ohms resistor (safety) and connected to RA0. I don't know why but the LED at RB0 lights up forever. Do I made any mistake in connecting those??
 
Last edited:
If this is connected direct to an RC receiver then the above code is checking for the wrong polarity signal.

It should be,
Code:
/*Counts the length of a pulse on Pin RA0*/
unsigned char GetPulse(void){
unsigned char count;
    count=0;
    TRISAbits.TRISA0=1;         //make pin input
    while(PORTAbits.RA0==[COLOR="Red"]0[/COLOR]);    //wait until pin goes high 
    while(PORTAbits.RA0==[COLOR="red"]1[/COLOR]){    //while high,
        count++;                //count 100uS intervals
        Delay100TCYx(5);        //100uS with n20MHz clock
    }
    return count;
}

Mike.
 
Status
Not open for further replies.

Latest threads

Back
Top