Interrupts and PIC

33 views
Skip to first unread message

Multitrain

unread,
Apr 27, 2022, 3:53:10 AM4/27/22
to jallist
Hello,
For a few days, I've been fighting with interrupts to get my small program working.The aim of the full programi to get an output voltage proportional to the input pulse width. The input pulse width ranges from 1 to 2 ms with a 20ms repetition rate. I choose the PIC16F628A because it has a 4 bit resolution Vref output and because I have a lot of them.  There are few Pic with an analog output , the 12F1572 has a5 bit output but to few pins for my app. remains also the 16F1938 (28pins device!)
Any way, I use the CCP1 module to measure the time width of the input pulse. I use to see what happens  a variable associated with an output: Meas_Time_X = on on the rising edge and Meas_Time_X = off on the falling edge. I get something but a bit weird because, I can  (not always) stabiize the output by resetting the supply, but when I change the input pulse width, the front pulse loose the synchronisation and the pulse time I get seems to be random between 0 and 2ms.
I surely made mistakes in my programm, but I don't see what..
The more I program, the more I discover my weaknesses with programming PIC's! ! ! !
Here the program , the problem stays even with quite all instructions removed.

Patrick

 include 16f628a                    -- target PICmicro
pragma target OSC INTOSC_NOCLKOUT
-- This program assumes the internal oscillator
-- is running at a frequency of 4 MHz.
pragma target clock 4_000_000      -- oscillator frequency
-- configuration memory settings (fuses)
pragma target WDT disabled   --  watchdog
pragma target MCLR internal  -- internal
pragma target CP  DISABLED
pragma target brownout ENABLED

include delay
enable_digital_io()


 portb_direction = all_output
     portb = 0
   pin_b3_direction = input
   pin_a4_direction = output

   alias sig_in is pin_b3    
   alias CD5V is pin_b5
   alias CdRL is pin_b4
   alias Rhyst is pin_a4
   alias Meas_Time_X is pin_b7
   alias led_test is pin_b6
   alias comp1_out is pin_b0

   var word t1
   var word t2
   var word Time_X = 750
   var word Tz = 25
   var word ValTime_X
   RHyst = 0
   enable_digital_io()
   CMCON = 0b0000_0100  ; utilisation de Comp1 pour "BEC"
   T1CON_TMR1ON = on
   INTCON_GIE  = on    ; enable global interrupts
   INTCON_PEIE = on
   T1CON = 0b0001_0101; utilisation du Timer 1 pour mesurer la durée signal
 ; prescaler 2  CK interne et timer enabled
 ; horloge timer à 1MHz/2  1.5 ms correspond à 750 tics de l'horloge de TMR1
 ;  PIE1_TMR1IE = on ; interrupt enabled pour timer1
 ;  PIR1_TMR1IF = off ; raz du flag interruption
    tmr1l = 0
    tmr1h = 0

   CCP1CON = 0b000_0101 ; rising edge interrupt
   PIE1_CCP1IE = on ; enable CCP1 interrupt
   PIE1_TMR1IE = on
   
   procedure zoe_1 is
   pragma interrupt
          ;  CCP1CON = 5 ; rising edge interrupt
 if PIR1_CCP1IF & (CCP1CON == 5) then tmr1l = 0 tmr1h = 0
                                     for 3 loop end loop; to compensate the
                                     ;Time_X reading in the other part of the handler
                                     ;and get the ssme pulse width as the input
                                     ; when stabilized
                                      Meas_Time_X = on
                                      PIR1_CCP1IF = off  ; raz du flag interruption
                                      CCP1CON = 4 ; falling edge interrupt
                                   end if
           ;  CCP1CON = 4 ; falling edge interrupt
  if PIR1_CCP1IF & (CCP1CON == 4)then Time_X = (word(tmr1h))<<8 + word (tmr1l)
                                        Meas_Time_X = off
                                      PIR1_CCP1IF = off  ; raz du flag interruption
                                      CCP1CON = 5 ; rising edge interrupt
                                   end if

    end procedure

    -- main
forever loop
    comp1_out =    CMCON_C1OUT
;; limitation pour grand écart:
;              if Time_X <= 490 then Time_X = 490 end if
;              if Time_X >= 1010 then Time_X = 1010 end if
;; en position centrale, pas de tension fixe "7V"
;             if 750 - Tz <  Time_X < 750 + Tz then CD5V = off VRCON=224 end if
;; Commande inversion par relais avant d'avoir le "7V"
;              if Time_X < (750 - Tz<<1) then CDRL = on end if
 ;             if Time_X > (750 + Tz<<1) then CDRL = off  end if
; variation de 7 à 15V en sortie pour fonctionnement moteur
 ;             if Time_X > (750 + Tz) then  CD5V = on  ValTime_X = (Time_X -(750 + Tz))/15
 ;                     VRCON = (224) + byte (ValTime_X)     end if
 ;             if Time_X < (750 - Tz) then  CD5V = on  ValTime_X = ((750-Tz)-Time_X)/15
;                      VRCON = (224) + byte (ValTime_X)     end if    

  _usec_delay(05_000) ; mise à jours info ttes les 15ms  20ms

;  led_test = !led_test

 end loop


Rob CJ

unread,
Apr 27, 2022, 5:17:46 AM4/27/22
to jal...@googlegroups.com
Hi Patrick,

I do not exactly understand your problem, can you clarify this a bit more?

I do have a suggestion - which will not solve the problem but makes your program a bit simpler - and that is that there is also a tmr1 as a word defined in the device file.

This means that you can replace:

tmr1l = 0 tmr1h = 0​ --> tmr1 = 0
and
Time_X = (word(tmr1h))<<8 + word (tmr1l) --> Time_X = tmr1

Kind regards,

Rob



Van: jal...@googlegroups.com <jal...@googlegroups.com> namens Multitrain <patfr...@gmail.com>
Verzonden: woensdag 27 april 2022 09:53
Aan: jallist <jal...@googlegroups.com>
Onderwerp: [jallist] Interrupts and PIC
 
--
You received this message because you are subscribed to the Google Groups "jallist" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jallist+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jallist/17cce5b0-cf5d-49f2-8b16-48a3850d24a8n%40googlegroups.com.

Rob CJ

unread,
Apr 27, 2022, 10:00:00 AM4/27/22
to jal...@googlegroups.com
Hi Patrick,

I had a closer look. If your pulse has some jitter then things may go wrong since both statements in the interrupt routine could be 'activated'. You added some delay in the interrupt routine which is not a good practice and from that I conclude that your input signal is not stable (but I may be wrong).

It is then better to restructure your interrupt routine. For example as follows:

procedure zoe_1 is
   pragma interrupt

   if PIR1_CCP1IF then 
      if (CCP1CON == 5) then 
         tmr1 = 0
         for 3 loop end loop ; to compensate the
                             ; Time_X reading in the other part of the handler
                             ; and get the ssme pulse width as the input
                             ; when stabilized
         Meas_Time_X = on
         CCP1CON = 4 ; falling edge interrupt
      elsif (CCP1CON == 4) then 
         Time_X = tmr1
         Meas_Time_X = off
         CCP1CON = 5 ; rising edge interrupt
      end if
      PIR1_CCP1IF = off  ; raz du flag interruption
   end if 

end procedure


Kind regards,

Rob


Van: jal...@googlegroups.com <jal...@googlegroups.com> namens Rob CJ <rob...@hotmail.com>
Verzonden: woensdag 27 april 2022 11:17
Aan: jal...@googlegroups.com <jal...@googlegroups.com>
Onderwerp: Re: [jallist] Interrupts and PIC
 

Patrick FROUCHT

unread,
Apr 29, 2022, 4:19:22 PM4/29/22
to jal...@googlegroups.com
Hello,

I solved the problem with another strategy.

I use Timer 1 and wait until Something happens on the input pin. with:
T1CON = 0b0000_0100 ; timer1 is deasabled
while (Sig_in == 0) loop  end loop
When Sig_in changes, I clear Timer1 registers
 tmr1l = 0 tmr1h = 0 ; reset timer1 counters
Then timer 1 is enabled
  T1CON = 0b0000_0101 ; timer1 is enabled
Then do nothing while Input is on (the counter counts)
while (Sig_in == 1) loop end loop
When the input changes again to "0" the program leaves the loop and
stops the timer 
T1CON = 0b0000_0100 ; timer1 is disabled
then  the program reads the value.
Time_TMR1 = (word(tmr1h))*256 + word (tmr1l); read timer1 value

here the program which can be put in the main or in a procedure
  Time_TMR1  is a declared as a word

; start "no edge"
T1CON = 0b0000_0100 ; timer1 is deasabled
while (input_pin == 0) loop  end loop
;asm clrwdt ; if pin_in = 0 more than 1 sec, Reset with WDT
; input_pin goes to 1
 tmr1l = 0 tmr1h = 0 ; reset timer1 counters
  T1CON = 0b0000_0101 ; timer1 is enabled
; start with the rising edge
while (input_pin == 1) loop end loop
;asm clrwdt ; if pin_in = 1 more than 1 sec, Reset with WDT
; input_pin goes again at 0
T1CON = 0b0000_0100 ; timer1 is deasabled

Time_TMR1 = (word(tmr1h))*256 + word (tmr1l); read timer1 value

An other trick to read value  inside a program with an oscilloscope:
put in your program

alias  Meas_Time_Xis pin_XY

 Meas_Time_X = on
 delay_10us(value) ; or  value/10
 Meas_Time_X = off

The number representing the time in x*10µs  is the same as the value, or if the value is big enough you use value/10.
Remember if the variable is a word, you need to use byte(value)  or byte of value/10 or 100 or more to get a byte value <= at 255.

Note about the shift function, >> or << . I used it to multiply or divide by 2,4,8,16....it works fine for byte but not to make a word with two bytes
Time_TMR1 = (word(tmr1h))<<8 + word (tmr1l);  doesn't work at all, use
Time_TMR1 = (word(tmr1h))*256 + word (tmr1l); is ok

Patrick



Patrick FROUCHT

unread,
May 11, 2022, 2:19:24 AM5/11/22
to jal...@googlegroups.com
Hello Rob

Sorry but your help came directly in the spam file. I discovered it only yesterday evening.
I changed in my program  Time_TMR1 =TMR1,
Tomeseare the pulse width I wanted to use the PIC tricks document DS41214A TIP #3 page 8.
But I did not get any result with my program because I used " Time_TMR1 = (word(tmr1h))<<8 + word (tmr1l) " witch doesn't work at all.
Then I used the other program with Timer1 and "while (Sig_in == 0) loop  end loop" algorithm. It did not work until I discovered the above failure (use of <<8) and used instead  the " *256 ".
I did no tcame back to the CCP1 use because I inserted at the end of  "while (Sig_in == 0) loop  end loop"and  "while (Sig_in == 1) loop  end loop" an asm CLWDT which in case of any long input "0" or "1" resets the programm and put it in neutral behaviour.
The pulse width measuring and "reset" program
 
 ; start "no edge"
   T1CON = 0b0000_0100 ; timer1 is deasabled
   while (input_pin == 0) loop  end loop
   asm clrwdt ; if pin_in = 0 more than 2 sec, Reset with WDT
; input_pin goes to 1
  TMR1 = 0 ; reset timer1 counters

;
   T1CON = 0b0000_0101 ; timer1 is enabled
; start with the rising edge
   while (input_pin == 1) loop end loop
   asm clrwdt ; if pin_in = 1 more than 2 sec, Reset with WDT

; input_pin goes again at 0
   T1CON = 0b0000_0100 ; timer1 is disabled
;mesure de la durée de l'impulsion d'entrée
   Time_TMR1 = TMR1; lecture du compteur timer1

You are right  " If your pulse has some jitter then things may go wrong since both statements in the interrupt routine could be 'activated'"
The jitter is not a problem because in my new program I have a sliding mean of 16 sample integration for the Time_X, but bounces may cause trouble.
To prevent it I'll put my entry on a free A port input which are all with Schmitt trigger with a low pass filter of 10 to 100µs time constant.

If you want more information about the full system i'm building, contact me
 Again thanks

Patrick

Rob CJ

unread,
May 11, 2022, 12:58:07 PM5/11/22
to jal...@googlegroups.com
Hi Patrick,

No problem. Strange that (word(tmr1h))<<8 + word (tmr1l) did not work. I would expect it to work.

Maybe something I need to verify.

Kind regards,

Rob


Van: jal...@googlegroups.com <jal...@googlegroups.com> namens Patrick FROUCHT <patfr...@gmail.com>
Verzonden: woensdag 11 mei 2022 08:19

Aan: jal...@googlegroups.com <jal...@googlegroups.com>
Onderwerp: Re: [jallist] Interrupts and PIC
Reply all
Reply to author
Forward
0 new messages