PDA

View Full Version : Recording incoming logic signal duration, both edges - how to?



flotulopex
- 5th January 2010, 15:57
Hello,

I'm struggling with a stupid problem for a while now and maybe someone has a good idea out there.

The goal is to record, for every high and low state of an incoming logic signal, its duration.

I'm capturing an incoming IR signal through a receiver module (i.e. TSOP32228) so I don't worry about the carrier frequency and the signal is "loud and clear" for the PIC (no bounce or any other disturbance).

Common IR remote protocols signals can last from 300µs up to around 10ms long.

Since I want to know how long each logic state (high and low) lasts, I first used RCTIME.

With this command, I easily measure half-a-pulse duration. Unfortunately, because of the power supply of the PIC (3V) and the max Xtal speed (8MHz), the resolution (5µs) doesn't permit a precision "good enough". With this method, a 300µs state (low or high) will return a RCTIME value between 50 and 70 which is around ±33% (!). By experience, acceptable values (< ±3%) can be measured starting with measures of incoming signals over 1ms.

I have also tried to "look" at a state change on a PORT. I made it with WHILE and with IF loops. The result is better but still not good enough especially for short signals (less than 1ms).

I then had a look to use INTERRUPTS, RB0/INT. Problem: I can catch only either the falling or the rising edge.

Same happens when I thought about using the Capture Mode of my PIC16LF88 where I have to choose either edge too.

Can anyone give me some advice on the best way for me to go?

Shall I change PIC with a higher Xtal frequency @ low voltage (like PIC16F1827)?

For sure, I don't want to buy an already-made self-learning universal IR remote! ;)

dhouston
- 5th January 2010, 16:36
What type of accuracy are you after? I've had a lot of experience with both IR and RF and have found ±10% is adequate as most of the protocols were developed for battery operation where there can be a lot of variation. What protocol are you trying to capture?

Here's code that I use with X-10 RF signals (which are essentially the same as NEC IR signals) as well as with several other RF protocols. It can handle almost all PDM/PWM signals. The resolution is only limited by the timer prescaler. If you want better resolution, use a faster oscillator. I was replacing a 12C508A in an existing module so had to use the internal 4Mhz oscillator. You can modify this to capture both pulses and spaces. I only needed the time between rising edges here.
'MR26X509.BAS
'PIC12F509 @ 4MHz 663 words uses MPASM

'Pin 1 - Vdd
'Pin 2 - GPIO.5
'Pin 3 - GPIO.4
'Pin 4 - GPIO.3
'Pin 5 - GPIO.2 RS232 output @ 9600bps
'Pin 6 - GPIO.1 Receives up to 48 bits of PDM/PWM RF with lead-in of 2-9mS
'Pin 7 - GPIO.0
'Pin 8 - Vss

'TMR0 1:64 29=1.9mS,145=9.3mS - 1:16 49=0.8mS,93=1.5ms,155=2.5ms
'================================================= ==============

@ __config _IntRC_OSC & _WDT_OFF & _MCLRE_OFF & _CP_OFF

DEFINE OSC 4
DEFINE DEBUG_REG GPIO
DEFINE DEBUG_BIT 2
DEFINE DEBUG_MODE 1
DEFINE DEBUG_BAUD 9600

RF VAR byte[6]
i VAR byte
period VAR byte
bytes VAR byte
sof VAR byte
x VAR byte

OPTION_REG=%11000101 'TMR0 1:64 prescaler, disable TOCKI
TRISIO=%000010 'make GPIO.1 an input, rest outputs
GPIO=%000000 'all outputs low
Debug "MR26X",13,10
Debug "Copyright ",169," 2009 dlh",13,10
Goto init

hexout: If x>>4<10 Then
Debug x>>4+48
Else
Debug x>>4+55
EndIf
if x//16<10 Then
Debug x//16+48
Else
Debug x//16+55
EndIf
Return

init: RF[0]=0:RF[1]=0:RF[2]=0:RF[3]=0:RF[4]=0:RF[5]=0
While GPIO.1=0:Wend 'wait rising edge
TMR0=0 'clear TMR0
OPTION_REG=%11000101 'TMR0 prescaler=64
While GPIO.1=1:Wend 'wait falling edge
sof=TMR0 'read TMR0
If (sof<29) Then init '1920µS
OPTION_REG=%11000011 'TMR0 prescaler=16
While GPIO.1=0:Wend 'wait rising edge
TMR0=0 'reset TMR0
OPTION_REG=%11000011 'TMR0 prescaler=16
i=0
Repeat
While GPIO.1=1 'wait falling edge
If TMR0>175 Then break '2800µS
Wend 'falling edge
While GPIO.1=0 'wait rising edge
If TMR0>175 Then break '2800µS
Wend 'rising edge
Period=TMR0:TMR0=0 'clear TMR0
OPTION_REG=%11000011 'TMR0 prescaler=16
If (period<49) Then init '800µS
If (period>93) Then '1500µS
RF.0(i)=1
EndIf
i=i+1
Until (i>47)
break: If (i<12) Then init
bytes=i/8
If i//8 Then
bytes=bytes+1
EndIf
x=i:GoSub hexout
For i = 0 to bytes-1
x=RF[i]:GoSub hexout
Next
Debug 13,10
GoTo init

End

Bruce
- 5th January 2010, 17:16
If you have an 18F2431 on-hand you can do it all in hardware with the motion feedback
module capture. It will record the time for every state change. Very handy for learning
different remote control encoders, IR signals, etc..

I have a code example if you're interested.

flotulopex
- 5th January 2010, 18:58
Hi Dave,

I'm recording all kind of remotes like ones for TVs as well as garage-door openers, electric-shades and so on. My remote is ment to be really "universal", well at least I dream it will be so.

As where most TV protocols work fine with my code, the other ones don't use "standard" protocols and that's the reason why I have to record both signal's state durations with, appearently, a little more precision.

This is the "learning sequence" of the code I currently work on:
<html><head></head><body><!--StartFragment--><pre><code><font color="#000000">LEARN:
<b>PULSIN </b>IRM_Out, 0, l_Bit[0] <font color="#000080"><i>'get the first Low pulse
</i></font><b>TOGGLE </b>C_Led <font color="#000080"><i>'indicate the &quot;waiting state&quot; to user
</i></font><b>IF </b>l_Bit[0] = 0 <b>THEN </b>LEARN: <font color="#000080"><i>'wait for the first pulse to start recording
</i></font>C_Led = 1 <font color="#000080"><i>'led is ON, learn has started
</i></font><b>RCTIME </b>IRM_Out, 1, h_Bit[0] <font color="#000080"><i>'get first High pulse from IR Module
</i></font><b>FOR </b>Ctr_A = 1 <b>TO </b>(Max_Bit - 1)
<b>RCTIME </b>IRM_Out, 0, l_Bit[Ctr_A] <font color="#000080"><i>'get Low pulse (1 to 38) from IR Module
</i></font><b>RCTIME </b>IRM_Out, 1, h_Bit[Ctr_A] <font color="#000080"><i>'get High pulse (1 to 38) from IR Module
</i></font><b>NEXT </b>Ctr_A
<b>RCTIME </b>IRM_Out, 0, l_bit[Max_Bit] <font color="#000080"><i>'get last Low pulse from IR Module
</i></font><b>RCTIME </b>IRM_Out, 1, H_bit[Max_Bit] <font color="#000080"><i>'get last High pulse from IR Module
</i></font>C_Led = 0
<b>END</b></code></pre><!--EndFragment--></body></html>
Full code is in attached ZIP file.

I'll try to adapt your code to my usage and see what I get. Thanks a lot for that.

Bruce,

I have only some 10F, 12F and 16F in my drawer :(

Nevertheless, I'm going to grab the datasheet of this particular PIC and see what this function does. Something new to learn ;)

dhouston
- 5th January 2010, 20:00
Roger,

My code is for RF so you'll need to change polarities. I'm checking for timeout during the initial pulse of each bit but am not recording the duration. It shouldn't take much modification.

Is this a commercial project? If it's just a one-off for your own use, you might want to consider a ZX328n from ZBasic. At $10 (plus some supporting components), it comes with a bootloader preloaded. ZBasic (free compiler) has built-in functions (InputCapture and InputCaptureEx) that will do what you wish with 37.8nS resolution.

However, I doubt you need better than 50µS resolution. Years ago I did what you're doing only instead of doing it in real-time, recorded codes as .WAV files using a soundcard and then decoded them afterwards. As I recall I was able to automatically handle all of the protocols I came across.

You might also consider USB-UIRT which not only captures the codes (as Philips Pronto CCF files) but also measures the IR carrier frequency.

gmglickman
- 5th January 2010, 21:58
I've had some luck using the capture function of the CCP module.

Set up an interrupt (or just poll the CCP1 flag) and alternate between setting CCP1CON=$04 and CCP1CON=$05 to capture TMR1 to CCPR1H:CCPR1L on falling and rising edges, respectively. As TMR1 runs, you can save as many transitions as memory allows. (You may be able to use just the highbyte, depending on the resolution you need.)

To transmit the recorded signal, set up as compare mode CCP1CON=$0A and toggle the output on and off.

flotulopex
- 6th January 2010, 07:56
Thanks bruce.

This is absolutely non-commercial. It is more about to see how "far" I can go using PICs. I will adapt your code; it is always worth a try ;)

gmglickman,

Would you have some code snippet to share? I did something similar but didn't work well.

BTW, I have already made some remotes for friends of mine; all remotes are working fine. You can see how one look like here http://home.citycable.ch/flotulopex/REMI/REMI_Frames_e.htm