News:

Let's find out together what makes a PIC Tick!

Main Menu

measure High pulse width

Started by hitronics, Dec 28, 2023, 09:37 PM

Previous topic - Next topic

hitronics

I want to use 12F508 to measure high pulse width without using pulsein command then how to do it?

trastikata

#1
Quote from: hitronics on Dec 28, 2023, 09:37 PMI want to use 12F508 to measure high pulse width without using pulsein command then how to do it?

Monitor the pin in a loop, start the TMR0, monitor the pin in a loop, stop TMR0

In any case better to use different MCU.

Pepe

Demo Proteus pulsein

hitronics

Quote from: trastikata on Dec 28, 2023, 10:35 PM
Quote from: hitronics on Dec 28, 2023, 09:37 PMI want to use 12F508 to measure high pulse width without using pulsein command then how to do it?

Monitor the pin in a loop, start the TMR0, monitor the pin in a loop, stop TMR0

In any case better to use different MCU.

pulse width that want to measure range 100us to 30ms, so which MCU you recommend and could you please show me code to test it

trastikata

Quote from: hitronics on Dec 29, 2023, 03:17 AMpulse width that want to measure range 100us to 30ms, so which MCU you recommend and could you please show me code to test it

It depends what you want to do afterwards once the pulse has been measured.

Anyway what you need is a MCU that has Timer Gate Pin functionality.

TGP.jpg

JonW

This can easily be done in a 12F or 10F mcu with very little resources, it depends on the accuracy and resolution you need. If it has to be accurate then use a crystal reference, resolution will generally come down to the max speed you can run the device at. 
Once you know this you can select an mcu and decide how you want to measure the width.

Most basic way woukd be to create a tight loop using timers or delays.  Wait for an edge and start counting.  Stop at the other edge and the result is loop time x counter value.

As mentioned ultimate accuraccy and resolution will always be related to the clock stability and be way better with hardware gating than pure firmware.



hitronics

Quote from: JonW on Dec 29, 2023, 07:27 AMThis can easily be done in a 12F or 10F mcu with very little resources, it depends on the accuracy and resolution you need. If it has to be accurate then use a crystal reference, resolution will generally come down to the max speed you can run the device at. 
Once you know this you can select an mcu and decide how you want to measure the width.

Most basic way woukd be to create a tight loop using timers or delays.  Wait for an edge and start counting.  Stop at the other edge and the result is loop time x counter value.

As mentioned ultimate accuraccy and resolution will always be related to the clock stability and be way better with hardware gating than pure firmware.




let's say xtal as 4MHz then pulse width range want to measure between 200us to 30ms

JonW


hitronics

#8
Quote from: JonW on Dec 29, 2023, 08:36 AMAt what resolution?
how about options for resolution can be?
could you please give me an example?

Stephen Moss

#9
Quote from: hitronics on Dec 29, 2023, 08:06 AMlet's say xtal as 4MHz then pulse width range want to measure between 200us to 30ms
If my calculations are correct then those values will not work very well...
At 4MHz the timer Clock = 1MHz (Fosc/4), with the prescaller set to 8 (highest value that provides an even count then) then counter will get to 25 @ 200uS, but would need to count to 3750 for 30mS.
A 16 bit Timer would be more useful in this case, it is possible with an 8 bit timer but you would have to track the number of times the counter overflows, however to do that you really need a Timer Interrupt to be generated and the device you are considering does not appear to have that. So high resolution but that inevitably results in high count values.

The only prescaller value that would cover that entire range and keep the count within the range of the Timer is 128, at 200uS that would give 1.5 so would probably be read as Timer Count of 1, for 30mS your timer count would be 234 (234.375). The problem is as 200uS/128uS = 1.5 rather then an even value you have a scalling issue because is you use 1 * 200uS = 200uS, then 234 * 200uS = 46800uS or 46.8mS which is some way off 30mS.
If you add a scallig factor so that 1 = 150uS rather than 200uS then 1 = 150uS and 234 * 150uS = 35.1mS, which is a little better but it will be difficult to be accurate at this lower resilution, how relevant that is depends on you appliaction.

As @trastikata mentioned, with out any IOC pins you main program loop would have to be be something like...
START:
Loop until pin state changes (Start of Pulse)
start Timer
Loop until pin state changes (End of Pulse)
Stop Timer
Read Timer Value and determine pulse width
Take appropriate action depenatant upon pulse width
Clear current Timer value (Timer = $00)
Goto Start (repeat indefinately)

Of course the above is based on the assumtion that there will be sufficient time between pulses for the main code to execute and loop back to the start before the next pulse begins, otherwise you will not get the correct pulse count.


david

If the resolution doesn't have to be too flash you could probably do a simple software count of the number of times you can do a DelayuS 50 while the pin is high.  At 4MHz clock the limit is 24uS but if he only needs resolution like 100uS, 200uS, 300uS it may suffice.  Of course the whole show stops until it can exit this timing loop whereas the Timer1 and interrupt can run in the background.  If using a 12F508 I don't think the expectations can be too high.

David

hitronics

all your replies are appreciated
so it is first time I use timer as counter?
the steps want to do as follow:
check pin state if it is high then start timer then when pin state is low then stop timer and put timer value inside a variable
is there any code to test it?

midali

Here's LES code , measuring pulse using Timer1 :

Quote'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate a preprocessor meta-macro to access a Port.Pin directly and read a Timer1 value
' Written for the Positron8 compiler by Les Johnson
'
    Device = 18F25K20
    Declare Xtal = 16
'
' Create variables
'
    Dim MyWord As Word
    Dim wTimer1 As TMR1L.Word
   
'----------------------------------------------------------------------
' Load a variable with the contents of Timer1
' Input     : pInPin holds the Port.Pin to sample
' Output    : pResult holds the value read from Timer1
' Notes     : None

$define Read_Rx(pInPin, pResult) '
    wTimer1 = 0                  '
    Repeat: Until pInPin = 0     '
    Repeat: Until pInPin = 1     '
    T1CONbits_TMR1ON = 1         '
    Repeat: Until pInPin = 0     '
    T1CONbits_TMR1ON = 0         '
    pResult = wTimer1
 
'----------------------------------------------------------------------
' The main program starts here
'
Main: 
    Read_Rx(PORTC.0, MyWord)    ' Read Timer1 into MyWord

midali

'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate a preprocessor meta-macro to access a Port.Pin directly and read a Timer1 value
' Written for the Positron8 compiler by Les Johnson
'
    Device = 18F25K20
    Declare Xtal = 16
'
' Create variables
'
    Dim MyWord As Word
    Dim wTimer1 As TMR1L.Word
   
'----------------------------------------------------------------------
' Load a variable with the contents of Timer1
' Input     : pInPin holds the Port.Pin to sample
' Output    : pResult holds the value read from Timer1
' Notes     : None

$define Read_Rx(pInPin, pResult) '
    wTimer1 = 0                  '
    Repeat: Until pInPin = 0     '
    Repeat: Until pInPin = 1     '
    T1CONbits_TMR1ON = 1         '
    Repeat: Until pInPin = 0     '
    T1CONbits_TMR1ON = 0         '
    pResult = wTimer1
 
'----------------------------------------------------------------------
' The main program starts here
'
Main: 
    Read_Rx(PORTC.0, MyWord)    ' Read Timer1 into MyWord

hitronics

is it possible provide code without macro
I will use 12F675

JonW

#15
This seems work ok from a few us to 32ms

It uses a 16M Clock and can be a TCXO to get very accurate timing.  The resolution is 500ns, without divide/2,  this device also has a gate function, but I think this needs a low to start the clock, so you would have to invert the pulse if you used the gate function.



        Device = 12F675
        Xtal = 16
       
        Declare Create_Coff = On
        Declare RSOut_Pin = GPIO.1
        Declare Serial_Baud = 19200

        Dim TIMER1 As TMR1L.Word
        Dim PULSE_IN As GPIO.0
        Dim TMREN As T1CON.0
        Dim TIME As Word
              
        PinInput GPIO.0           
        PinOutput GPIO.1       
       
        T1CON = 0b00000001        ' TIMER FOSC/4, PRE = 0 


MAIN:   

        While PULSE_IN = 0: Wend    ' WAIT FOR PULSE TO GO HI    
        TIMER1 = 0                            ' CLEAR TIMER AS PULSE IS HI
        While PULSE_IN = 1: Wend    ' WAIT FOR PULSE TO GO LO
        TMREN = 0                   ' STOP THE TIMER (WILL NEED TO RE-ENABLE TO MEASURE ANOTHER PULSE)
        TIME = (TIMER1/2)          '  FORMAT TO 1us TICKS
        RsOut "PULSE WIDTH = ", Dec TIME," us", 13,10     
        Stop

Config FOSC_EC, WDTE_OFF, PWRTE_OFF, MCLRE_OFF, BOREN_ON, CP_OFF, CPD_OFF

hitronics

#16
Quote from: JonW on Dec 30, 2023, 09:27 AMThis seems work ok from a few us to 32ms

It uses a 16M Clock and can be a TCXO to get very accurate timing.  The resolution is 500ns, without divide/2,  this device also has a gate function, but I think this needs a low to start the clock, so you would have to invert the pulse if you used the gate function.



        Device = 12F675
        Xtal = 16
       
        Declare Create_Coff = On
        Declare RSOut_Pin = GPIO.1
        Declare Serial_Baud = 19200

        Dim TIMER1 As TMR1L.Word
        Dim PULSE_IN As GPIO.0
        Dim TMREN As T1CON.0
        Dim TIME As Word
              
        PinInput GPIO.0           
        PinOutput GPIO.1       
       
        T1CON = 0b00000001        ' TIMER FOSC/4, PRE = 0 


MAIN:   

        While PULSE_IN = 0: Wend    ' WAIT FOR PULSE TO GO HI    
        TIMER1 = 0                            ' CLEAR TIMER AS PULSE IS HI
        While PULSE_IN = 1: Wend    ' WAIT FOR PULSE TO GO LO
        TMREN = 0                   ' STOP THE TIMER (WILL NEED TO RE-ENABLE TO MEASURE ANOTHER PULSE)
        TIME = (TIMER1/2)          '  FORMAT TO 1us TICKS
        RsOut "PULSE WIDTH = ", Dec TIME," us", 13,10     
        Stop

Config FOSC_EC, WDTE_OFF, PWRTE_OFF, MCLRE_OFF, BOREN_ON, CP_OFF, CPD_OFF


thanks, JonW
I will use internal Rc 4MHz
is there any modifications in the code?
what is the meaning of this line:
Dim TIMER1 As TMR1L.Word

JonW

#17
Why use the internal RC OSC at a much lower frequency? You clearly don't require any precision or accuracy in the measurement.
You must change the config for the internal oscillator and work out the TIME value to scale the result to the lower clock frequency to get the result in microseconds

Dim TIMER1 As TMR1L.Word

This instruction combines the two Timer1 8-bit registers as a single 16-bit register.  Look in the manual p36 to p37.  It just simplifies the code structure and saves time accessing both registers of Timer1

hitronics

Quote from: JonW on Dec 30, 2023, 01:41 PMWhy use the internal RC OSC at a much lower frequency? You clearly don't require any precision or accuracy in the measurement.
You must change the config for the internal oscillator and work out the TIME value to scale the result to the lower clock frequency to get the result in microseconds



I tested before measuring pulses with internal RC using PULSEIN command and got accurate readings but this time no need to use pulsein command just timer
what is the meaning of this line:
Dim TIMER1 As TMR1L.Word
 

JonW

#19
Read the above message again.

RC osc will reduce resolution and will vary with temperature and device.

I looked back at some of your previous posts; you should study the basic architecture of an MCU and how the peripherals function.  Also, read the manual before asking for code all the time, it is exceptionally well written and WILL improve your coding  Asking others to write your code will not further your knowledge or help debug any problems that arise.

        Device = 12F675
        Xtal = 4
       
        Declare Create_Coff = On
        Declare RSOut_Pin = GPIO.1
        Declare Serial_Baud = 19200


        Dim TIMER1 As TMR1L.Word
        Dim PULSE_IN As GPIO.0
        Dim TMROFF As T1CON.0
        Dim TIME As Word
       
       
        PinInput GPIO.0
        PinOutput GPIO.1       


       
        T1CON = 0b00000001         ' TIMER FOSC/4, PRE = 0 

MAIN:   
        While PULSE_IN = 0:Wend     ' WAIT FOR PULSE HI    
        TIMER1 = 0                  ' CLEAR TIMER 1
        While PULSE_IN = 1: Wend    ' WAIT FOR PULSE LO
        TMROFF = 1                  ' STOP TIMER
        TIME = (TIMER1 * 2)           ' NUMBER OF 1us
        RsOut "PULSER WIDTH = ", Dec TIME," us", 13,10     
        Stop

Config FOSC_INTRCCLK, WDTE_OFF, PWRTE_OFF, MCLRE_OFF, BOREN_ON, CP_OFF, CPD_OFF