News:

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

Main Menu

Simple Pwm Detection?

Started by Maxi, Jun 14, 2025, 06:57 AM

Previous topic - Next topic

Maxi

My input signal is 0-5 volt pwm,
How can I detect whether there is a signal (change) at the input end in a simple way?
I can measure frequency, but I need something very simple,
I will get information from the speed sensor of a vehicle, is the car going or stopping?
I just need to make such a simple determination.

So I think there is no need for lines of code when measuring frequency using interrupt.

david

Hi,
You could integrate the pwm through an RC filter and treat it as variable DC which could then be read by an ADC input or if you only want an indication of running or stopping then maybe a Schmitt logic input or comparator may suffice.  Maybe I've misunderstood your application.

Cheers,
David

Maxi

No, no, I think it's a good idea, but the frequency (pwm) that will occur when the vehicle is moving very very slowly may not provide us with enough voltage.
It seems to me that it will happen with a few logic commands, but I haven't managed it yet.

david

Ok.  If the pwm is like a sensor picking up a wheel turn then the frequency is too low to conveniently integrate.

Add a small GPS sensor and use a few lines of code to parse the NMEA sentences-

Dim kph As string*5   'captured string
HRSIn Wait ("VTG,")       'Wait for VTG sentence
        For comma=1 To 6          'Step out 6 fields
          While HRSIn<>",": Wend
        Next comma
        HRSIn kph     'take next 5 char as kph string

Cheers,
David

RGV250

Hi,
Could you not use CCP to capture the pulse width?

Bob

Maxi

Quote from: RGV250 on Jun 14, 2025, 01:51 PMHi,
Could you not use CCP to capture the pulse width?

Bob

I will do that

trastikata

Quote from: Maxi on Jun 14, 2025, 06:57 AMHow can I detect whether there is a signal (change) at the input end in a simple way?


Depending on the PIC, the application and the pin ... keep in mind that IOC flag is always set and can be monitored whether or not the IOC has been enabled.

Pepe

demo proteus and code


Device = 12F629

Config HS_OSC, WDT_ON, PWRTE_OFF, MCLRE_OFF, BODEN_OFF, CP_OFF, CPD_OFF

Declare Xtal = 20
Declare Optimiser_Level = 3
Declare Dead_Code_Remove = 1        ' Remove dead code
Declare Reminders Off
Declare Hints Off
Declare Create_Coff On
Declare Serial_Baud =9600
Declare RSOut_Pin =GPIO.0
Declare RSOut_Mode = 0
Declare Watchdog On


Symbol   LCD_CLR        0x01
Symbol   LINE1          0x80
Symbol   LINE2          0xC0
Symbol   COMMAND        0xFE
Symbol PWM_PIN = GPIO.2
Dim PulsoActual As Word
Dim PulsoAnterior As Word
Dim FlancoSubida As Bit  = 1
Dim flag As Bit
Dim temp As Word
Dim wTimer1 As TMR1L.Word
Dim change As SWord

' Configuración inicial

GPIO = 0x0
TRISIO = 0x04

T1CON = %00000001            ' Timer1 encendido, sin prescaler
INTCON = %10010000           ' Habilitar interrupciones globales y externas
OPTION_REG.6 = 1             ' Interrupción por flanco de subida inicialmente
On_Interrupt GoTo Isr

LCD_Init()

Do
 Clrwdt
 DelayMS 10
 flag = 0
 LCD_COMMAND(LINE1)
     
 change = PulsoActual - PulsoAnterior     ' Comparar valores fuera de la interrupción
       
 If change > 2 Then
                    RsOut "PWM up    "
               ElseIf change < -2 Then
                    RsOut "PWM down  "
               Else
                    RsOut "PWM stable"
 EndIf
 If flag = 0 Then
                   PulsoActual=0
 EndIf                       
 LCD_COMMAND(LINE2)
 RsOut "Pwm: ",Dec1  PulsoActual /25.5 ," %   " 
 PulsoAnterior  =  PulsoActual
Loop

Proc LCD_Init()
    LCD_COMMAND(0xC0) 
    LCD_COMMAND(0x01)
    DelayMS 2
    LCD_COMMAND(0x06)   
    LCD_COMMAND(LCD_CLR)
    DelayMS 200
EndProc

Proc LCD_COMMAND(cmd As Byte)
RsOut COMMAND,cmd
EndProc

'----------------------------
Isr:
 Context Save

    If INTCON.1 = 1 Then  ' INT0 interrupción
        flag = 1
        If FlancoSubida = 1 Then
           wTimer1 =  0              ' Reinicia temporizador
            OPTION_REG.6 = 0         ' Cambia a flanco de bajada
            FlancoSubida = 0
        Else
            temp = wTimer1
            If temp < 2550 Then
                                PulsoActual = temp
                       
            EndIf                   
            OPTION_REG.6 = 1         ' Vuelve a flanco de subida
            FlancoSubida = 1
        EndIf
        INTCON.1 = 0                 ' Limpia bandera de INT
    EndIf

Context Restore

Fanie

#8
Detecting pulses from automotive pickups can be a pain in the whatsmecallit.  I would do the input detection different.
Set up a down counter.
Set up a flag (bit) for high or low.
every time the main program loop, it counts down.
read the A/D pin
if the A-D input > say 20 you have an input else it will be zero or less than 20 (out of 1024, 10-bit A-D)
if the counter counted out then you did not have vehicle movement
if you get an A/D input and the counter did not count out you have movement.
If the flag changed, and the counter did not count out you have movement
Re-set the counter value

Inductive pickups output very small pulses at low speed because it is a magnet moving past a pickup coil, hence the detection is difficult. 
Same can be used for vehicles like some bee em trouble u's that use a reed switch, input is either high or low, the low voltage read still works and the counter timeout will still detect movement or not.  For this you will use the flag set for high input or low for zero input while the counter counts out.  The input can then be either high or low at no movement.

For the hardware you can use a series resistor and divider clamped by a unipolar transzorb (fast) to prevent the A-D from exceeding power supply, some pics hang up if this happens.

ken_k

Quote from: Maxi on Jun 14, 2025, 06:57 AMMy input signal is 0-5 volt pwm,
How can I detect whether there is a signal (change) at the input end in a simple way?
I can measure frequency, but I need something very simple,
I will get information from the speed sensor of a vehicle, is the car going or stopping?
I just need to make such a simple determination.

So I think there is no need for lines of code when measuring frequency using interrupt.

Do you have an oscilloscope trace of the sensor output of at very low speed? An image taken with a phone camera would be perfect.
I could replicate it in spice and maybe offer another solution.
A description of the waveform at various speeds would be fine. Wave shape, amplitude frequency. Are they a variable reluctance type of sensor?  Are we looking at PWM, frequency, or both.
Do not reply if the task has been resolved.

top204

My thoughts on this, are similar to others.

All PIC devices have the CCP peripherals to do just as you require. i.e. Measure pulses, measure pulse lengths, or measure how many pulses etc... So for a form of hysteresis, detect a few pulses, and it must be a PWM signal and not just a blip on the line.

The same could be done with a simple IOC (Interrupt On Change), or INT0, INT1, or INT2, so if it fires multiple times, it is a pulse waveform. Again, all PIC devices have this facility. Without any hysteresis, just look at the peripheral's flag, and if it is set, the INTx or IOC pin has been pulsed with the correct state. i.e. Low to High, or High to Low.

Maxi

First of all, thank you very much to everyone who wrote a reply, you are all valuable men,
I wish I could be as professional as you in coding.
I saw what you wrote a few days ago and over the weekend, but I couldn't analyse it, now I'll look at all of them.

Now I will tell you a short story
I have a toy truck,
I installed a sensor on the right rear wheel of this truck and the sensor gives us 1 pulse at each turn of the wheel.
(Pulse signal 0-5 volt pwm, not like abs or crank sensor)
(The signal is clean. as I wrote in the first line in my first message)

I put this toy on a long table and slowly push it with my hand.
As the toy truck slowly moves forward,
the wheel turns and the sensor signals us 1 pulse, 2 pulses, 3 pulses, if the wheel turns 10 times, 10 pulses come to our pic input.

I need to know that this vehicle is not moving,
I already read the frequency with the interrupt, but I need to understand that the wheel stops completely, that is,
it does not even make 1 turn, I cannot measure this with frequency, for example, I could not read the frequency below 4-5hz.

In fact,
the car is a real 4x4 offroad vehicle and
I am making a circuit to its 4-wheel drive system and the vehicle must be completely stopped when switching to the 4th stage.
I have an old 16F88, I will use it, I am afraid of filling up the memory, so I am looking for a simple code with few lines.

You don't need much to detect the movement (so it seems to me)
I can think of something like this, let me start a counter

Dim Cnt as byte
if portB.1=1 inc Cnt

Let this counter count upwards every time the wheel turns.
(it will start from zero again when it is already 255)
then I will add a simple comparison
>if counting upwards continues, do not take action
>if there is no counting, you can pull the relay.

Now, how can I make a simple comparison here?

See_Mos

What type of sensor have you used?  How many pulses per revolution does it give? What PIC are you using?  Answers to these will give us a better understanding of what you need.

If you only want to know if the truck is moving then the interrupt on change that Les suggested would work very well.

If the PIC has nothing else to do then the same thing can be done without using interrupts.


See_Mos

I think this will do what you want, but nothing else.  The sensor is checked one hundred times a second and if it has not changed after 2.55 seconds the relay is turned on.

Dim Sensor As Bit
Dim CNT As Byte
Dim Relay As PORTB.2

    Low Relay                          ' start with relay off and reset CNT to 0
    CNT = 0

    Do
        Sensor = PORTB.1                ' check the sensor
        DelayMS 100                    ' total time  = 2.55 seconds
        Inc CNT                        ' add 1 to CNT
        If CNT = 255 Then
            High Relay                  ' turn on relay
        Else
            Low Relay
        EndIf
       
        If Sensor <> PORTB.1 Then      ' has sensor changed
            CNT = 0                    ' yes so reset counter
            Sensor = PORTB.1            ' save sensor condition to compare
        EndIf   
    Loop

Maxi

Shall we forget about the car, the wheel, the sensor?

There's a madman here, he keeps coming round and pressing the doorbell. Beep beep beep beep beep beep always like this.

I want to detect that it does not press the bell.
If portb.0=0 then I cannot say because sometimes it presses continuously.

I can count the number of times he pressed the button with interrupt, but I couldn't find what to do when he doesn't press it.
Because when he doesn't press the button, the processor doesn't go through the ISR interrupt routine.

I think @Pepe's code is correct, but I can't quite figure it out, I'm working on it.

Here is the code
ISR occurs when there is a signal at the input, of course
I need to know how to detect when the interrupt does not occur.

@See_Mos I saw your message just as I was writing and I am looking at it immediately.

Device = 16F88
Declare Xtal=8
OSCCON =%01111110

@CONFIG_REQ
@__CONFIG _CONFIG1, INTRC_IO & WDT_OFF & PWRTE_ON & MCLR_OFF & BODEN_ON & LVP_OFF & WRT_PROTECT_OFF & CP_ALL & CPD_ON & DEBUG_OFF
Config2 FCMEN_OFF, IESO_OFF

TRISB  = %00000001
Dim Cnt1 As Byte

'------------------------------------------------
Symbol INTEDG = OPTION_REG.6 'int rise edge
Symbol GIE = INTCON.7 ' Global Interrupt Enable
'------------EXT RB0 INTERRUPT-------------------
Symbol INT0IE = INTCON.4
Symbol INT0IF = INTCON.1
INTEDG=1
                                             
On_Interrupt GoTo Isr                                             
INT0IE=1
GIE=1


Do:

Toggle PORTB.7 'led
DelayMS 500

Loop

Isr:'-----------------------
Context Save

If INT0IF=1 Then
Inc Cnt1
EndIf
'----------
INT0IF = 0
Context Restore

top204

I had a very similar mechanism to do a few years ago, so that a move could be detected if it is still moving or stopped, and very quickly detect it. I could not use the CCP peripherals because they were being used for PWM. So I used Timer0, with its clock source as an external pin (T0CKI), so every time the pin is toggled, the Timer increments.

Then, within the main loop of the program, have a previous value and a current value for the timer's value, and if the current value is not the same as the previous value, the item is moving, but if they are the same, there is no movement, because the timer has not incremented. No interrupts and no time constraints required, as long as the delay in the difference checking is long enough to make sure the timer should have incremented, even if a few ticks. If longer times are required, or faster pulses to detect, alter the Timer's prescaler.

Below is a simple implementation of the above mechanism, running on a PIC18F26K22 device, but can be changed to work on any device that has a Timer0 peripheral. Or use Timer1 if more suitable. The code can be enhanced to suit the requirements, because it is so simple in principle, and can use any Timer that has an external clock source:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate detecting a pulse on the Timer0 T0CKI pin, to detect movement from a rotation sensor attached to it.
' Written by Les Johnson for the Positron8 compiler.
' https://sites.google.com/view/rosetta-tech/home
'
    Device = 18F26K22                                   ' Tell the compiler what device to compile for
    Declare Xtal = 16                                   ' Tell the compiler what frequency the device will be operating at (in MHz)
    Declare Auto_Heap_Arrays = On                       ' Make all arrays "Heap" types, so they always get placed after standard variables
    Declare Auto_Heap_Strings = On                      ' Make all Strings "Heap" types, so they always get placed after standard variables
    Declare Auto_Variable_Bank_Cross = On               ' Make sure all multi-byte variables remain within a single RAM bank
'
' Setup USART1 (for debugging)
'
    Declare Hserial1_Baud = 9600
    Declare HSerout_Pin = PORTB.6
'
' Create some global variables for the demo program
'
    Dim wTimerVal As Word                               ' Holds the current Timer0 value
    Dim wPrev_TimerVal As Word                          ' Holds the previous Timer0 value

    Dim wTimer0_SFR As TMR0L.Word                       ' Create a 16-bit SFR from the TMR0L and TMR0H SFRs
   
'-------------------------------------------------------------------------------------------
' The main program starts here.
' Detect a pulse on the T0CKI pin, and if there is one, indicate it on a serial terminal.
'
Main:
    Setup()                                             ' Setup the program and any peripherals
    Do                                                  ' Create a loop
        If Movement_Detect() = 1 Then                   ' Is there any movement detected via the T0CKI pin?
            HRSOutLn "Moving"                           ' Yes. So indicate that there is movement, on the serial terminal
        Else                                            ' Otherwise... No movement has been detected...
            HRSOutLn "Not Moving"                       ' So... Indicate that there is no movement, on the serial terminal
        EndIf
        DelayMS 1                                       ' A small delay in the main loop. To make sure enough pulses are allowed to increment the timer0
    Loop                                                ' Do it forever

'------------------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    Timer0_Init()                                       ' Initialise Timer0 to count pulses on the T0CKI pin
    wPrev_TimerVal = 0                                  ' Pre-load the previous Timer0 value
EndProc   

'------------------------------------------------------------------------------------------------
' Detect movement by checking the Timer0 value
' Input     : None
' Output    : Returns 1 if there is movement, 0 if no movement
' Notes     : Checks if the current Timer0 value is the same as the previous Timer0 value
'             And if it is, then there have been no pulses on the Timer0 pin, so no movement.
'
Proc Movement_Detect(), Bit
    wTimerVal = wTimer0_SFR                             ' Make a copy of the TMR0L\H SFRs
    Result = 0                                          ' Default to no movement detected
    If wTimerVal <> wPrev_TimerVal Then                 ' Is the previous value of Timer0 the same as the current value?
        wPrev_TimerVal = wTimerVal                      ' No. So save the current Timer0 value as the previous value
        Result = 1                                      ' Indicate that there are pulses on the T0CKI pin
    EndIf
EndProc

'------------------------------------------------------------------------------------------------
' Setup Timer0 so that it increments on pulses received on the T0CKI pin
' Input     : None
' Output    : None
' Notes     : This setup is for a PIC18F26K22 device
'
Proc Timer0_Init()
    wTimer0_SFR = 0                                     ' Clear the TMR0L\H SFRs
    T0CON = %10101000                                   ' Prescaler is 1:2. 16-bit mode. Increment on low to high. T0CKI pin is source. Timer0 enabled
EndProc

Below is a simulation of the above code listing, operating from a 1uS pulse on the T0CKI pin. When the button is pressed, the pulses are sent, as if the sensor is detecting them, then when the button is released, there are no pulses, as if the sensor is not detecting them, because there are none:

Timer0_Pulse_Detector.jpg

Pepe

At a frequency of 1 Hz, it says that there is movement and that there is no movement.

Pepe

#17
By modifying time, the detection time base can be expanded or reduced; it is currently set to 1 second.

;-------------------------------------------------------------------------------
;**** Added by Fuse Configurator ****
; Use the Fuse Configurator plug-in to change these settings

Device = 16F88

Config1 INTRC_IO, WDT_OFF, PWRTE_OFF, MCLR_OFF, CP_OFF, CPD_OFF, BODEN_OFF, IESO_OFF, FCMEN_OFF, LVP_OFF, DEBUG_OFF

;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------
Declare Xtal=8
OSCCON =%01111110


Declare Create_Coff On
Declare Optimiser_Level = 3
Declare Watchdog Off



Symbol GIEL = INTCON.6   ' Peripheral Interrupt Enable
Symbol GIEH = INTCON.7   ' Global Interrupt Enable

Symbol TMR0IE = INTCON.5 ' TMR0 Overflow Interrupt Enable
Symbol TMR0IF = INTCON.2 ' TMR0 Overflow Interrupt Flag

Symbol INTIF =  INTCON.1' INT2 External Interrupt Flag
Symbol INTIE =  INTCON.4' INT2 External Interrupt Enable

Declare Hserial1_Baud = 9600
Declare HSerout_Pin = PORTB.5


Symbol PERIOD       1000.0       ; 100 us
Symbol Xtl          8000000    ; crystal frequency - 20MHz
Symbol ICLK         (Xtl/4)     ; crystal is divided by four
Symbol SCALE        32           ; prescale by 32 - check for overflow!

Symbol PRELOAD      257-(PERIOD*ICLK/SCALE)/1000000
 
Symbol time 1000      '1 seg base time


Dim timer As Word
Dim motion As Bit

   
OPTION_REG = 0xC4

TMR0IE = 1
 
On_Hardware_Interrupt GoTo Isr
                   
INTIE = 1 
timer = time           
GIEL = 1   
GIEH = 1
 
DelayMS 1000 
 
Do
 If motion <> 0 Then
                     HRSOutLn "moving"
                Else
                     HRSOutLn "not moving"
 EndIf
Loop

   
Isr:

 Context Save
 
 If TMR0IF = 1 Then
                    TMR0 = PRELOAD
                   
                    If timer = 0 Then
                                      motion = 0
                                 Else
                                      Dec timer     
                    End If                 
                   
                    TMR0IF = 0                 
 End If
 
 If INTIF = 1 Then
                    INTIF = 0
                    motion = 1
                    timer = time
 End If
 
Context Restore





demo proteus

Fanie

#18
What happened to handbrakes on trucks ?  Get two bricks to put front and back of the wheels and use the pic for making lip sounds when you push it instead, it will keep spit off the truck.
For easy movement detection an easy way would be to use a disk with slots and a gapped opto coupler.  This way any small movement will already be detected.  The opto can switch a FET which switches a latching relay to run a claxon siren.
https://www.youtube.com/watch?v=W_9KR3mYkUo

For the guy repeated pressing the doorbell, install a eyepiece small PIR.  If the PIR see someone then ring the bell once and disable doorbell for 30 seconds.
Or install a metal vandal proof push button and a car coil on an oscillator that will zap the living daylights out of the villain.  Once the bad habit wears off, switch back to the old doorbell.

Or combine the door and the truck.  If the claxon siren goes it's either the doorbell ringer or the truck moving.  Make sure the claxon siren plays on the outside of the door.

ricardourio

Does this engine use electronic fuel injection ? If yes, you problably have a speed sensor on it. If not, one tooth wheel will not be good, and depending of sensor type, like an active inductive sensor, can be used to measure how much time time tooth will be in front of sensor. With passive inductive sensor it is not possible. Anyway, to detect a non-moving vehicle will need a time counter. You can use signals from NEUTRAL and BRAKE lights to enable 4WD change. One more solution, but need some considerations, is to add an accelerometer sensor.

Ricardo Urio