PIC programming question - frequency activated relay

Discussion in 'Embedded Systems and Microcontrollers' started by bluebrakes, Sep 16, 2012.

  1. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    I'm building my own CNC milling machine and one of the safety features that they advise you to build is a frequency safety switch (aka charge pump) that activates a relay when there is a constant 8-13KHz signal from the computer.

    I would like to build mine using a pic like the 12C508/P, which I have plenty of spare and eager to make use of/get rid of... :D

    So the circuit is essential one input pin (for the signal 0-5V) and one output pin for the relay)


    I realise that the 555 timers are able to do a similar thing already with 'missing pulse detectors' but i'd like to have the advantage of fine tuning the algorithm to cater for checking the pulse width, etc in the future.

    I'm just struggling to get my head round the code as usual...

    Any ideas or code examples I could use to get started?

    thanks!
     
  2. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    I was working on something similar on a baseline PIC. It's not complete or commented, but it might give you some ideas.

    Code ( (Unknown Language)):
    1.  
    2. test
    3. clrwdt
    4. clrf TMR0
    5. clrf pulse_count
    6.  
    7. wait3
    8. movlw d'200'
    9. subwf TMR0, W
    10. btfsc STATUS, C
    11. goto time_up
    12. btfsc GPIO, 3
    13. goto wait3
    14.  
    15. wait4
    16. movlw d'200'
    17. subwf TMR0, W
    18. btfsc STATUS, C
    19. goto time_up
    20. btfss GPIO, 3
    21. goto wait4
    22. incf pulse_count, F
    23. goto wait3
    24.  
    25.  
    26. time_up
    27. movlw d'3'
    28. subwf pulse_count, W
    29. btfss STATUS, C
    30. goto test
    31.  
    32. movlw d'9'
    33. subwf pulse_count, W
    34. btfsc STATUS, C
    35. goto test
    36.  
     
  3. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
  4. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    thanks guys. both useful information. :)

    interesting about the CCP, as I see the 12F675 has this built-in as well, which I think I have a few somewhere as well.

    So from what I gather about your code (Mark), is that the code counts the number of pulses in order to clear the Watchdog timer?
     
  5. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    clrwdt is a red herring.
    In both the wait3 and wait 4 loops it is checking to see if the TMR0 (linked to internal instruction cycle) has reached 200 to measure an approximate time interval 200-210μs due to the size of the loops.
    The wait3 and wait4 loops also check for changes on GPIO[3] and cycle from wait3 to wait4, increasing pulse_count every time the pin has gone high then low. After the 200-210μs it ends up at the checks at the end to see if between 3 and 9 cycles have been detected.
    It should be fine at 13kHz with modifications to the tests and maybe the prescaler for TMR0. I was using it to detect 36kHz IR remote control carrier and it worked well.
    <ed>If the number of cycles is between 3 and 9 it continues past the last instruction, otherwise it goes back to the start. </ed>
     
    Last edited: Sep 17, 2012
  6. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    thanks mark.
    Supposing I was to use CCP, would something like the below code work?

    I have almost no idea what I'm supposed to be doing with CCP to measure frequency ranges. But it would be nice to learn with some experimentation...


    Code ( (Unknown Language)):
    1. LIST    p=16F628, R=DEC        ;tell assembler what chip we are using
    2.     #include "P16F628.inc"        ;include the defaults for the chip
    3.    
    4.     __config _INTRC_OSC_NOCLKOUT & _LVP_OFF & _WDT_OFF & _PWRITE_ON & _BODEN_ON
    5.  
    6.  
    7.     CBLOCK 0x20
    8.        
    9.         Check_Freq
    10.         d1
    11.         d2
    12.         d3
    13.     ENDC
    14.    
    15.     ;499994 cycles for delay routine
    16.     movlw    0x03
    17.     movwf    d1
    18.     movlw    0x18
    19.     movwf    d2
    20.     movlw    0x02
    21.     movwf    d3
    22.  
    23.    
    24.     #DEFINE    RELAY    PORTB, 0    ; Define the relay on RB0
    25.  
    26.  
    27.     clrf    CCP1CON            ; CCP Module is off
    28.     clrf    TMR1H            ; clear timer1 high byte
    29.     clrf    TMR1L            ; clear timer1 low byte
    30.     clrf    INTCON            ; disable interupts and clear TO1F
    31.     bsf        STATUS,    RP0        ; Bank 0
    32.     bsf        TRISC,    CCP1    ; Make CCP1 an input pin
    33.     clrf    PIE1
    34.     bcf        STATUS,    RP0        ; Bank 0
    35.     clrf    PIR1            ; clear pheripheral interupt flags
    36.     movlw    0x06            ; capture mode every 4th rising edge
    37.     movwf    CCP1CON
    38.     bsf        T1CON,    TMR1ON    ; Timer1 starts
    39.     bcf        RELAY            ; Turn the relay off
    40.  
    41.  
    42. ORG        0x000    ; Program starts here
    43.  
    44.  
    45. Loop call Capture_Event    ; Wait for something to be captured
    46.     call Check_Input
    47.  
    48.  
    49.  
    50. ; Captured Occurred
    51.  
    52.  
    53.  
    54.  
    55. Goto Loop
    56.  
    57.  
    58. Check_Input movwf    Check_Freq    ; Put the result of W into memory
    59.    
    60.     movlw    0x41
    61.     subwf    Check_Freq,    w
    62.     btfsc    STATUS,    Z
    63.     bsf        RELAY        ; Result is good, turn on relay
    64.    
    65.     retlw    0x00
    66.  
    67.  
    68. Capture_Event    ; Wait for something to be captured
    69.     BTFSS    PIR1,    CCP1IF    ; This needs to be done before next compare
    70.     GOTO    Capture_Event
    71.     movf    RCREG, W        ; Store result in W
    72.     retlw    0x00
    73.  
    74.  
    75.  
    76.  
    77. Delay_0
    78.     decfsz    d1, f
    79.     goto    $+2
    80.     decfsz    d2, f
    81.     goto    $+2
    82.     decfsz    d3, f
    83.     goto    Delay_0
    84.  
    85.             ;6 cycles
    86.     goto    $+1
    87.     goto    $+1
    88.     goto    $+1
    89.  
    90.  
    91. END
     
  7. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    thanks mark.
    Supposing I was to use CCP, would something like the below code work?

    I have almost no idea what I'm supposed to be doing with CCP to measure frequency ranges. But it would be nice to learn with some experimentation...


    Code ( (Unknown Language)):
    1. LIST    p=16F628, R=DEC        ;tell assembler what chip we are using
    2.     #include "P16F628.inc"        ;include the defaults for the chip
    3.    
    4.     __config _INTRC_OSC_NOCLKOUT & _LVP_OFF & _WDT_OFF & _PWRITE_ON & _BODEN_ON
    5.  
    6.  
    7.     CBLOCK 0x20
    8.        
    9.         Check_Freq
    10.         d1
    11.         d2
    12.         d3
    13.     ENDC
    14.    
    15.     ;499994 cycles for delay routine
    16.     movlw    0x03
    17.     movwf    d1
    18.     movlw    0x18
    19.     movwf    d2
    20.     movlw    0x02
    21.     movwf    d3
    22.  
    23.    
    24.     #DEFINE    RELAY    PORTB, 0    ; Define the relay on RB0
    25.  
    26.  
    27.     clrf    CCP1CON            ; CCP Module is off
    28.     clrf    TMR1H            ; clear timer1 high byte
    29.     clrf    TMR1L            ; clear timer1 low byte
    30.     clrf    INTCON            ; disable interupts and clear TO1F
    31.     bsf        STATUS,    RP0        ; Bank 0
    32.     bsf        TRISC,    CCP1    ; Make CCP1 an input pin
    33.     clrf    PIE1
    34.     bcf        STATUS,    RP0        ; Bank 0
    35.     clrf    PIR1            ; clear pheripheral interupt flags
    36.     movlw    0x06            ; capture mode every 4th rising edge
    37.     movwf    CCP1CON
    38.     bsf        T1CON,    TMR1ON    ; Timer1 starts
    39.     bcf        RELAY            ; Turn the relay off
    40.  
    41.  
    42. ORG        0x000    ; Program starts here
    43.  
    44.  
    45. Loop call Capture_Event    ; Wait for something to be captured
    46.     call Check_Input
    47.    call Delay_0 ; Let things settle for a bit before checking again
    48.  
    49.  
    50. ; Captured Occurred
    51.  
    52.  
    53.  
    54.  
    55. Goto Loop
    56.  
    57.  
    58. Check_Input movwf    Check_Freq    ; Put the result of W into memory
    59.    
    60.     movlw    0x41
    61.     subwf    Check_Freq,    w
    62.     btfsc    STATUS,    Z
    63.     bsf        RELAY        ; Result is good, turn on relay
    64.    
    65.     retlw    0x00
    66.  
    67.  
    68. Capture_Event    ; Wait for something to be captured
    69.     BTFSS    PIR1,    CCP1IF    ; This needs to be done before next compare
    70.     GOTO    Capture_Event
    71.     movf    RCREG, W        ; Store result in W
    72.     retlw    0x00
    73.  
    74.  
    75.  
    76.  
    77. Delay_0
    78.     decfsz    d1, f
    79.     goto    $+2
    80.     decfsz    d2, f
    81.     goto    $+2
    82.     decfsz    d3, f
    83.     goto    Delay_0
    84.  
    85.             ;6 cycles
    86.     goto    $+1
    87.     goto    $+1
    88.     goto    $+1
    89.  
    90.  
    91. END
     
  8. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    Double posting?
    Without simulating it I'm not sure. There are a couple of things I spotted:
    Use return instead of retlw 0x00, it's messing up one of the functions.
    Set d1, etc at the start of delay_0 or it will only be the right length the first time.
     
  9. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    thanks mark... yeah it was a double post. not sure what happened there.

    Having experimented further with my code and not being to get it to work properly, I think I'm going back to my original decision to code it using something like your code above. Especially as I'm literally measuring a square wave to make sure it's between a certain frequency.
     
  10. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    some updates then....

    I have written some code for the 16f628a, which I just use to experiment with. The code now works perfectly, but clearly a 16f628a is a bit overkill for this simple application. So I would like to tailor the code to work on the 12c508 next if possible.


    How the code works.....

    timer0 is reset followed by an 18ms delay.
    The pic then checks to see if the number of pulses is between 10 and 70 in the time period given. If it is then it adds this to a count.

    If the number of pulses has been correct twice, then activate the relay. Any time the pulses fail to match, then it switches off the relay and resets the count.

    Code ( (Unknown Language)):
    1.     processor 16F628A
    2.     #include <P16F628A.INC>
    3.     __config 0x2118
    4. ;   _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BODEN_OFF & _MCLRE_OFF & _PWRTE_OFF
    5. ;   & _WDT_OFF
    6.  
    7. ; RAM-Variable
    8. LRAM_0x20 equ 0x20
    9. LRAM_0x21 equ 0x21
    10. LRAM_0x22 equ 0x22
    11. LRAM_0x23 equ 0x23
    12. LRAM_0x70 equ 0x70
    13. LRAM_0x7C equ 0x7C
    14. LRAM_0x7D equ 0x7D
    15.  
    16. ; Program
    17.  
    18.     Org 0x0000
    19.  
    20. ;   Reset-Vector
    21.     GOTO INITIALISE
    22.  
    23.     Org 0x0003
    24.  
    25. INITIALISE
    26.     MOVLW 0x0A
    27. ;   Interrupt-Vector
    28.     BCF STATUS,RP0       ; !!Bank Register-Bank(0/1)-Select
    29.     BCF STATUS,RP1       ; !!Bank Register-Bank(2/3)-Select
    30.     MOVWF LRAM_0x23
    31.     MOVLW 0x46
    32.     MOVWF LRAM_0x20
    33.     BSF STATUS,RP0       ; !!Bank Register-Bank(0/1)-Select
    34.     CLRF PORTB           ; !!Bank!! PORTB - TRISB - PORTB - TRISB
    35.     MOVLW 0x80
    36.     MOVWF TMR0           ; !!Bank!! TMR0 - OPTION_REG - TMR0 - OPTION_REG
    37.     BCF STATUS,RP0       ; !!Bank Register-Bank(0/1)-Select
    38.     CLRF PORTA           ; !!Bank!! PORTA - TRISA - Unimplemented - Unimplemented
    39.     MOVLW 0xFF
    40.    
    41.  
    42.     BSF STATUS,RP0       ; !!Bank Register-Bank(0/1)-Select
    43.     MOVWF PORTA          ; !!Bank!! PORTA - TRISA - Unimplemented - Unimplemented
    44.     BCF STATUS,RP0       ; !!Bank Register-Bank(0/1)-Select
    45.     CLRF PORTB           ; !!Bank!! PORTB - TRISB - PORTB - TRISB
    46.     BSF STATUS,RP0       ; !!Bank Register-Bank(0/1)-Select
    47.     BSF TMR0,5           ; !!Bank!! TMR0 - OPTION_REG - TMR0 - OPTION_REG
    48.     BSF TMR0,3           ; !!Bank!! TMR0 - OPTION_REG - TMR0 - OPTION_REG
    49.     BCF STATUS,RP0       ; !!Bank Register-Bank(0/1)-Select
    50.     CLRF TMR0            ; Clear Timer0
    51.  
    52.  
    53. Main_Loop
    54.     CLRF TMR0            ; Clear Timer0
    55.     MOVLW 0x06            
    56.     MOVWF LRAM_0x7C
    57.     MOVLW 0xD7
    58.     MOVWF LRAM_0x7D
    59.  
    60.  
    61.  
    62. LADR_0x001E
    63.     DECFSZ LRAM_0x7D,F
    64.     GOTO LADR_0x001E
    65.     DECFSZ LRAM_0x7C,F
    66.     GOTO LADR_0x001E
    67.     MOVF TMR0,W          ; !!Bank!! TMR0 - OPTION_REG - TMR0 - OPTION_REG
    68.     SUBWF LRAM_0x23,W
    69.     BTFSC STATUS,C
    70.     GOTO LADR_0x003D
    71.     MOVF LRAM_0x20,W
    72.     SUBWF TMR0,W         ; !!Bank!! TMR0 - OPTION_REG - TMR0 - OPTION_REG
    73.     BTFSC STATUS,C
    74.     GOTO LADR_0x003A
    75.     INCF LRAM_0x21,F
    76.     BTFSC STATUS,Z
    77.     INCF LRAM_0x22,F
    78.     MOVLW 0x80
    79.     MOVWF LRAM_0x70
    80.     MOVLW 0x80
    81.     XORWF LRAM_0x22,W
    82.     SUBWF LRAM_0x70,W
    83.     BTFSS STATUS,Z
    84.     GOTO LADR_0x0036
    85.     MOVF LRAM_0x21,W
    86.     SUBLW 0x02
    87.  
    88.  
    89. LADR_0x0036
    90.     BTFSC STATUS,C        
    91.     GOTO LADR_0x0039
    92.     BSF PORTB,0          ; Turn on relay on RB0
    93.  
    94.  
    95. LADR_0x0039
    96.     GOTO LADR_0x003C
    97.  
    98.  
    99. LADR_0x003A
    100.     CLRF LRAM_0x21
    101.     CLRF LRAM_0x22
    102.  
    103. LADR_0x003C
    104.     GOTO BEGINNING
    105.  
    106.  
    107. LADR_0x003D
    108.     BCF PORTB,0          ; Turn off relay on RB0
    109.     CLRF LRAM_0x21
    110.     CLRF LRAM_0x22
    111.  
    112. BEGINNING                  ;LADR_0x0040
    113.     GOTO Main_Loop
    114.  
    115. Endless_Loop
    116.     GOTO Endless_Loop
    117.  
    118.     End
    Unfortunately I didn't use MPLAB to create the code, but Mikrobasic, that I'm currently trialling.
     
  11. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    It's a bit hard to read without meaningful variable names and labels.
    It should be easy enough on 12F508, either do similar to what I posted below or use TMR0 as a counter on the T0CKI pin and have a fixed delay (which is what I'm guessing your recent post does).
    I'd have used the counter but I wanted to use the T0CKI pin as an output.
     
  12. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Since you need to detect a frequency is present but don't know the freq, maybe you could just use a duty cycle detector?

    example;
    Code ( (Unknown Language)):
    1.  
    2. // detect if any freq is present
    3. unsigned int i, d;
    4.  
    5. d = 0;
    6. for(i=0; i<50000; i++)     // test over 0.5 second period
    7. {
    8.   delay_uS(10);
    9.   if(input) d++;           // count a 1 bit
    10. }
    11.  
    12. // now check for freq fail (fail = < 5% or > 95% duty)  
    13. if(d < 2500 || d > 47500) pin_relay = 0;   // relay off  
    14. else                      pin relay = 1;   // relay on
    15.  
     
Loading...