PDA

View Full Version : pulsin: how is it used



xnihilo
- 3rd October 2008, 10:27
Hello,

I would like to use pulsin to record the length of a positive pulse, thus I would use

pulsin trigger,1,pulse_length

if trigger is a pin name and pulse_length is a word variable

As I don't know when the trigger will happen, can I jump to the pulsin when I detect a low to high change on a pin (using a polling loop or an interrupt) or is PULSIN expecting to see the rising edge.
As I understand it from the manual, it will record the pulse even if already on and will stop recording once the pin goes low, it it right?

I don't know if my question is clear enough?




'************************************************* ******************************
'preset the pic specs and config words at chip programming time
@ device pic16F684, intrc_osc_noclkout, BOD_OFF, PWRT_OFF, wdt_off, mclr_off, protect_off
'************************************************* ******************************


'************************************************* ******************************
DEFINE OSC 8 'set OSC value to 8MHz for instructions PAUSE, PAUSEus and SOUND
'************************************************* ******************************

'************************************************* ******************************
'VARIABLES declaration
'IF VARIABLES USED FOUR COUNTER GO OVER 256, USE WORD INSTEAD

pulse_length var word
'************************************************* ******************************


CLEAR 'clears all data ram (128 bytes) and initialize variables (this should however be done in software)

INTCON = 0 'disable interrupts and reset int flags
IOCA = %000000

'************************************************* ******************************
'PWM (single output mode) related registers for porta.5.
'PWM is not used. We use normal output on C5.

T2CON = %00000000 'value:4, 1:1 postscale (unused), Timer2 is OFF, Timer 2 Clock prescaler = 1
PR2 = %00110001 'value: 49, PWM Period: 40.0KHz
CCP1CON = %00000000 'capture/compare/PWM module OFF, no pwm signal on portc.5 at this time
CCPR1L = %00001111 'value: 15, PWM Duty Cycle 8 MSB of 10 bits (2 LSB in bits 5 and 4 of CCP1CON), total: 60d
'************************************************* ******************************


'************************************************* ******************************
'Setting registers

OSCCON = %01110001
CMCON0 = %00000111 'comparators OFF, val = 7
ANSEL = %00000000 'choose digital i/o, val = 0
OPTION_REG = %01111111 'enable porta weak pullups (no weak pull-up available for porta.3), p12
'************************************************* ******************************


'************************************************* ******************************
'Setting ports states, direction and internal weak pull-ups
'USE 10K WPU on RA3 if used as input !!!

TRISA = %000001 'set porta pins directions (1=input, high impedance),portA.3 is always input pin (datasheet p5)
TRISC = %000000
'use 10K WPU on A3
WPUA = %000000

PORTA = %000000 'set port pins logic, A0 will be a default LOW with 100K WPD
PORTC = %000000 'set port pins logic
'************************************************* ******************************
'************************************************* ******************************
'aliasing pins

Symbol trigger = PORTA.0
SYMBOL led = PORTC.3
'************************************************* ******************************

PAUSE 3000 'let the power level stabilize if not already done

'flashes at 5Hz
for i = 0 to 4
High led
PAUSE 100
LOW led
PAUSE 100
NEXT i

PAUSE 2000

start:

While (trigger == 0) : WEND 'while pin is low (no pulse on pin)

'a pulse has been detected (at this step the rising edge is over, the pin is high)
PULSIN trigger,1,pulse_length '16 bits

WRITE 0,pulse_length.lowbyte
WRITE 1,pulse_length.highbyte

'flash when recording occured and finished (max 327ms with 8MHz 5 us resolution 65536 increments)
HIGH led
PAUSE 2000
LOW led

goto start

END 'end of program

dhouston
- 3rd October 2008, 12:31
... can I jump to the pulsin when I detect a low to high change on a pin (using a polling loop or an interrupt)...Yes, it does not look for the leading edge. An interrupt will be more precise but a tight loop works almost as well.

Bruce
- 3rd October 2008, 16:32
I'm pretty sure it does wait for the idle state, and then look for the starting edge to begin
timing, so you might want to test this.

The library routine indicates this, and the manual also states; if the pulse edge
never happens or the width of the pulse is too great to measure, Var is set to zero.



call STATECNT ; Wait for idle state
btfsc STATUS, Z ; If timeout then it's over
goto DONE
call STATECNT ; Wait for starting edge
btfsc STATUS, Z ; If timeout then it's over
goto DONE
call STATECNT ; Do the count

xnihilo
- 4th October 2008, 09:18
Dhouston you think it does not expect a rising edge while Bruce you are pretty sure it does.
When I read the manual info about PULSIN it looks like there is an EDGE detection...

The manual says that it waits for and EDGE, you're right but the I don't know how I am supposed to start PULSIN if I don't know when the EDGE will appear on the line and PULSIN has a timeout.

Something very weird:

To do some experiment, I've tested the code I've posted above (a polling loop). In this configuration, PULSIN will NOT see a rising edge but will start no matter what, so I assume PULSIN begins and runs until it sees a falling edge (which is not the way you tell me PULSIN works) or until the timeout happens because the pulse is too long.
I connected my application circuit to the tespin and I trigger my application circuit where I set the pulse pin HIGH at the begining of the code section for which I want to mesure the execution time then set the pin low when I reach the end of the section. This way, I expect PULSIN to tell me how long it takes to execute a section of a program.

I get a value of 14925~14927.
If I read well PBP manual, as I'm using a PIC16F684 (with DEFINE OSC 8) the resolution should be of 5US per iteration of the PUSLIN internal counter. Which makes 74ms.
What a surprise because in the application circuit in the section of code I'm testing, I use a 80ms pause, so the mesured execution length should be of AT LEAST 80ms...
How is it possible???

dhouston
- 4th October 2008, 11:49
As I wrote, PULSIN does not wait for a leading edge. If the pin is already in the the state of the defined "pulse", it starts counting as soon as PULSIN is called and stops counting when the trailing edge is detected. If the pin is initially in the non-defined state, the count starts at the leading edge. The disparity between your readings and your expectations is just due to the limits of accuracy using this method.

However, you cannot use it to time any execution other than itself as it does not return until it detects the trailing edge.

The manual is ambiguous, referring to an edge but not specifying both edges must be detected. Initially, I interpreted it as you (and Bruce) have but found, through experience, that was not the case. Other PBasic derived dialects for PICs that I've used are explicit about waiting for a leading edge.

@BRUCE: If you look at the NEC RF example i posted to Code Examples, removing the statements that wait until the initial space (trailing the long starting pulse) ends, the loop will detect that first space, giving an invalid code as a result.

xnihilo
- 4th October 2008, 12:15
Dhouston: So if I get you right, you DON'T need a rising edge for PULSIN?

I connected 2 PICS together so the 690 for which I want to time a code chunk sends a pulse to the 684 that will record the pulse length and then display the value to an LCD.
Obviously I cannot use PULSIN the way you thought I do :)

"The disparity between your readings and your expectations is just due to the limits of accuracy using this method."
-> This is not really a problem. Although I'm disapointed by the strange value I get, the method will always be the same so I only want to compare the execution duration of two different chunks of code. I already noticed that the second chunk I'm timing leaves a led on for about 1s which is far beyond the timeout of PULSIN, no wonder it returns a value of 0... This is because I have LCDOUT and WRITE that may take some time to execute.

dhouston
- 4th October 2008, 14:33
You don't need either a rising or falling leading edge for PULSIN depending on the pin state when PULSIN is called.

I didn't read your code so my comments were based purely on the content of your posts. It wasn't clear that you were using separate PICs.

Another way to do this type of measurement is by using a soundcard as an oscilloscope. See...http://davehouston.org/learn.htmWhile the URL deals with IR & RF codes, they're just pulsestreams so the principle is the same.

Bruce
- 4th October 2008, 18:33
If the pin is already in the the state of the defined "pulse", it starts counting as soon as PULSIN is called and stops counting when the trailing edge is detected.
Sorry, but I respectfully dissagree with this.

Try this;


DEFINE OSC 20
DEFINE LOADER_USED 1

PTIME VAR WORD
PTIME2 VAR WORD

SYMBOL PIN_PIN = PORTB.0
TRISB = %11111101

PTIME = 0

MAIN:
WHILE PIN_PIN = 0 ' wait for PIN_PIN to go high
WEND

HIGH 1 ' indicate PULSIN start
PULSIN PIN_PIN,1,PTIME ' this reads the pulse after the pin is already high
LOW 1 ' indicate PULSIN complete

PULSIN PIN_PIN,1,PTIME2 ' this reads it after the rising edge
HSEROUT ["Pulse 1 width = ",DEC PTIME,13,10] ' result = 0
HSEROUT ["Pulse 2 width = ",DEC PTIME2,13,10] ' result = 25419

GOTO MAIN
I have a 12F675 programmed to output a train of pulses. 50mS high with a low period of
250mS between each high pulse.

See the analyzer capture below. P1A is the pulse train being read with PULSIN. P1B is RB1
going high just prior to the 1st PULSIN, and low when the 1st PULSIN completes.

Look at the A & B markers. Now look at the time A-->B: 181.9mS. 50mS of this period is
the 50mS pulse shown by P1A at the top. P1B is the high period RB1 stays high once the
1st PULSIN executes. Subtract 50mS. The remainder is the time-out period at 20MHz.

If PULSIN were not waiting for the leading edge, then it should always return the remainder
of the high time period in PTIME, but it doesn't. It returns zero.

Now if you shorten the low period between each high-going pulse to < the PULSIN time-out
period, it will record the 2nd high-going pulse. Not the first if started when the pin is in
the state to be measured.

So, what I'm seeing is - PULSIN does need to see the leading edge. It will however appear
to work, even if started after the leading edge, but will only record the time of the 2nd
pulse - if it happens prior to the time-out period.

I have tried several variations, and I just can't get any results if I start PULSIN after
a leading-edge transition. Except for it locking onto & recording a 2nd pulse that happens
before the time-out period expires.

Bruce
- 4th October 2008, 18:49
Here's a 2nd graphic showing how PULSIN records the 2nd high-going pulse. Note how P1B
doesn't return low until after the 2nd high pulse.

PULSIN didn't record the 1st because it started after the leading edge. It does grab the 2nd
since it happens before the time-out period. The delay between high pulses was shortened
to the time period shown at B-->C:

xnihilo
- 6th October 2008, 09:31
This is a lot of information, I will read it carefuly tomorrow, thanks a lot.
In, the meantime, I noticed a strange thing (I will also post my code tomorrow):

My routine reads 16 bits signal (PWM at 40KHz and TSOP4840 sensor-demod) through IR link using pulsin (each bit is 600Us either HIGH or LOW followed by a spacer of 600us LOW). The 16 bits are announced by a 2400 us HIGH followed by 600 us low. This header is ignored by the routine that waits for the header to end. The total length of the IR signal is (should be) about 22ms but when timing the routine that reads the signal, it takes (visualy, with a led) about 1 second!!! It is probably related to all the stuff we are talking about in the posts above.

xnihilo
- 7th October 2008, 17:30
Okay, with PIC16F690 with int osc at 8MHz, with PULSIN I have a very long code execution time (about 1S) while it is vital that I have a code execution time of less than 100ms as it is supposed to read IR signals incoming every 100ms.



IF (a.0(0) == 0) THEN
FOR i = 0 to 15 'get a sequence of incoming 16 bits (WITHOUT their prefixes which are 600us pause)
PULSIN PORTA.0,0,ir_pulse[i] ' Read 16 low-going pulses on RA.0, see pbp manual
NEXT i
pin = 0 ' Loop 16 times, at 8MHz record in 5us resolution pulse duration in the word variables array
ENDIF


and



databyte = 0 'reset low byte and high byte of the word variable to %0000000000000000

FOR i = 0 TO 15 ' process all 16 "data" bits out of 16 bits collected

' LCDOUT $fe,1,#i,":",#ir_pulse[i]
' PAUSE 2000

IF ((ir_pulse[i] > 210) && (ir_pulse[i] < 275)) THEN '240*5us resolution at 8MHz = 1200 us (usual length of a zero is about 127 - 145 and 242 to 266 for a one)
databyte.0(15-i) = 1 'clear the bit
goto slip 'bypass
ENDIF
IF ((ir_pulse[i] > 105) && (ir_pulse[i] < 160)) THEN
databyte.0(15-i) = 0 'clear the bit
GOTO slip 'bypass
ENDIF
'ELSE: invalid data
'LCDOUT $fe,1,#i," != ",#ir_pulse[i]
'LCDOUT $fe,$c0,"Invalid"
'PAUSE 500

valid = 0

'PAUSE 3000

'GOTO hop_here 'bypass and abort if one of the 14 bits is off limits
slip:
NEXT i



I seem to be unable to use PULSIN the right way.

I've decided not to use PULSIN but use TIMER 1 to measure the pulse length.
I was expecting either 600 or 1200 us pulses but get pretty different values and I'm wondering why...




'the 2400US header that triggered the int when porta.0 went HIGH->LOW is in progress (LOW going pulse because TSOP4840 pulls the pin low when getting 40KHz mod pulse)
while (porta.0 == 0) : WEND 'while pin is low because of the incoming header LOW pulse
'0->1 (2400US header pulse ended)

'here the signal goes high and will stay high for 600us (spacer between header and first bit)
while (porta.0 == 1) : WEND
'1->0 (600US spacer between header and first bit ended because first bit is starting)

'timer1: max 65536 increments of minimum 0.5US at prescale of 1:1
T1CON = %00011100 '1:2 prescale for 1US increments, timer 1 is stopped
TMR1H = 0 'reset timer high byte
TMR1L = 0 'reset timer low byte
databyte = 0 'word var

'memo:
'recorded ranges for a 600 us pulse: 608-741
'recorded ranges for a 1200 us pulse: 1217-1346


'Get length for 16 bits (1200 or 600 us followed by 600 us spacer)
FOR i = 0 to 15
'Bit has started its LOW going pulse, either 1200 or 600 us long
T1CON.0 = 1 'start TMR1 with prescaler = 1:2, we will have 1US increments
WHILE (porta.0 == 0): WEND 'wait for bit pulse to end (while TMR2 is incremented every us)
'0->1 (spacer)
T1CON.0 = 0 'stop TMR2
pulse_length.highbyte = TMR1H
pulse_length.lowbyte = TMR1L
bit_pulse[i] = pulse_length

IF ((pulse_length > 600) && (pulse_length < 750)) THEN 'about 600 us, it is a '0'
databyte.0(15-i) = 0
GOTO next_bit
ENDIF
IF ((pulse_length > 1200) && (pulse_length < 1350)) THEN 'about 1200 us, it is a '1'
databyte.0(15-i) = 1
GOTO next_bit
ENDIF
'GOTO bad_bit
next_bit:
TMR1H = 0
TMR1L = 0
WHILE (porta.0 = 1) : WEND 'we don't measure length of the spacer
'1->0 the falling edge for the next byte
NEXT i




Where am I loosing all these precious clock cycles???

Ioannis
- 7th October 2008, 19:11
Don't give up on Pulsin command.

Have a look at:

http://www.picbasic.co.uk/support/Article.pdf

I am sure it covers what you need.

Ioannis

xnihilo
- 7th October 2008, 20:46
many thanks.

I will read it. I'm so busy right now because I'm testing the system based on the TIMER1.
It seems to get the bits length right (although there is a significant variation compared to the expected value).
Now I have to check what time it takes to execute my routine.




T1CON = %00011100 '1:2 prescale for 1US increments, timer 1 is stopped
TMR1H = 0 'reset timer high byte
TMR1L = 0 'reset timer low byte
databyte = 0 'word var



'the 2400US header that triggered the int when porta.0 went HIGH->LOW is in progress (LOW going pulse because TSOP4840 pulls the pin low when getting 40KHz mod pulse)
while (porta.0(pin) == 0) : WEND 'while pin is low because of the incoming header LOW pulse
'0->1 (2400US header pulse ended)

'here the signal goes high and will stay high for 600us (spacer between header and first bit)
while (porta.0(pin) == 1) : WEND
'1->0 (600US spacer between header and first bit ended because first bit is starting)

'memo:
'recorded ranges for a 600 us pulse: 608-741
'recorded ranges for a 1200 us pulse: 1217-1346

T1CON.0 = 1 'start TMR1 with prescaler = 1:2, we will have 1US increments

'Get length for 16 bits (1200 or 600 us followed by 600 us spacer)
FOR i = 0 to 13
'Bit has started its LOW going pulse, either 1200 or 600 us long

WHILE (porta.0(pin) == 0): WEND 'wait for bit pulse to end (while TMR2 is incremented every us)
'0->1 (spacer)
T1CON.0 = 0 'stop TMR2

'we have 600us (the bit spacer length) to manage de received bit

pulse_length.highbyte = TMR1H
pulse_length.lowbyte = TMR1L
' bit_pulse[i] = pulse_length

IF ((pulse_length > 600) && (pulse_length < 750)) THEN 'about 600 us, it is a '0'
databyte.0(15-i) = 0
GOTO next_bit
ENDIF
IF ((pulse_length > 1200) && (pulse_length < 1350)) THEN 'about 1200 us, it is a '1'
databyte.0(15-i) = 1
GOTO next_bit
ENDIF

'GOTO bad_bit

next_bit:

IF (i == 13) then exit_loop 'after the 14th bit, we are finished here

TMR1H = 0
TMR1L = 0

WHILE (porta.0(pin) = 1) : WEND 'we don't measure length of the spacer
'1->0 the falling edge for the next byte
T1CON.0 = 1 'start TMR1 with prescaler = 1:2, we will have 1US increments
NEXT i

exit_loop: 'bypass label after 14th bit has been received

'at this step the bit lengths are fine
valid = 1
'now let's see if the bytes have a valid value


'TEST block
LCDOUT $fe,1,#databyte.highbyte," ",#databyte.lowbyte
PAUSE 2000

killer_id = databyte.byte1 'get opponent ID
byte2 = databyte.byte0

bad_bit: 'jump here if one of the bit length is invalid (valid flag/bit is set to 0)

RETURN 'after signal has been processed return from subroutine



I failed programming an auxiliary pic to read the pulse duration.
I raise a pin (connected to the auxiliary pic input) at the begining of a code chunk and lower it at the end of the chunk so the auxiliary pic can record the duration of the pulse so it gives me the duration of the chunk execution... I got abdnormal values so I have no real way of knowing how long it takes to execute my code chunk...

Ioannis
- 7th October 2008, 21:03
Leave alone the timer. The link is exactly what you want!

Ioannis

xnihilo
- 8th October 2008, 00:11
Roger that.