Menu

DoEvery function

2020-06-22
2020-06-23
  • stan cartwright

    stan cartwright - 2020-06-22

    I just wrote this doevery function for 3 events
    It's only for mega328 but if you change the 1ms interrupt to your pic it would be the same.
    I scoped it and it's working.
    Only 1ms resolution and 3 events.
    tim1event=how often tim1go called in ms
    tim1even2=how often tim2go called in ms
    tim1even3=how often tim3go called in ms

    first draft. Chris Roper is working on a proper version of this. This is just the idea I think. My version.

    #chip mega328p,16
    #option Explicit
    dir portc.2 out
    dir portc.3 out
    dir portc.4 out
    
    dim millis as long
    dim tim1event,tim1tmp as long
    dim tim2event,tim2tmp as long
    dim tim3event,tim3tmp as long
    
    tim1event=1000 ;every second
    tim2event=2 'every 2ms
    tim3event=20 ;every 20ms
    
    millis a long variable but will overflow after ???
    
    millis=0
    tim1tmp=millis:tim2tmp=millis:tim3tmp=millis
    ;start 1ms interrupt isr
        On Interrupt Timer0Match1 Call isr
        Dim OCR0  AS byte alias OCR0A
        Dim TCCR0 AS  byte alias TCCR0B
        WGM01 = 1
        OCR0 = 62 ;1ms
        TCCR0 = 0x28
        TCCR0 = TCCR0 or 0x03
    '---------------
    do
    loop
    ;
    sub tim1go ;every 1 s
      portc.2 = not portc.2
    end sub
    ;
    sub tim2go ;every 2ms
      portc.3 = not portc.3
    end sub
    ;
    sub tim3go ;every 20ms
      portc.4 = not portc.4
    end sub
    ;
    sub isr
      millis=millis + 1
      if millis-tim1tmp=tim1event then tim1go:tim1tmp=millis
      if millis-tim2tmp=tim2event then tim2go:tim2tmp=millis
      if millis-tim3tmp=tim3event then tim3go:tim3tmp=millis
    end sub
    
     
  • jackjames

    jackjames - 2020-06-23

    I think the interrupt routine should be as small as possible.
    The best thing would be to set flags during the check in the interrupt routine and check the flags and act accordingly during the main loop.

     
    • Chris Roper

      Chris Roper - 2020-06-23

      DoEvery is a fire and forget function.

      You give it a period, an Interrupt routine address and it runs forever.

      The routine that is called must be short, as you have correctly pointed out, and in effect Stan is just setting a flag, in this case his flags are Port Pins todrive Servo Motors, but still only use as much code as setting any flag.

      It is good to draw attention to interrupts, their use, abuse and limitations to try and get some discussion and education going, as the next release of GCBASIC will include some Timer Based User Interrupt hooks inspired by Stan's DoEvery idea.

      Look for more to come on this subject in the weeks ahead as several other functions will be available to use what I am starting to think of as “The System Timer” - Timer0.

      The release version will not need Stans Setup code or ISR and it will be fully portable.
      Something like this is envisaged:

      #chip mega328p,16
      #option Explicit
      #include <Tardis.h>
      
      #DoEvery0   1000, portc.2 = not portc.2 ' Every Second
      #DoEvery1      2, portc.3 = not portc.3 ' Every 2 mS
      #DoEvery2     20, portc.4 = not portc.4 ' Every 20 mS
      Init_Timers()
      
      dir portc.2 out
      dir portc.3 out
      dir portc.4 out
      
      Start_Timers()
      
      do
      loop
      
      End
      
       
    • stan cartwright

      stan cartwright - 2020-06-23

      @jackjames. Hi. Yes, the interrupt code must be shorter than the interrupt period.
      Here is a sub that is called from a 2ms interrupt every 2ms.
      It looks a lot of code so I timed it by set portc.3 on at the start
      and set portc.3 off at the end and scoping portc.3 which gave a pulse hovering around 8us.
      You would think it would take longer.

      sub motors
      set portc.3 on
      ;left motor
        if l_mot_dir=stop then
          set portd.0 off:set portd.1 off:set portd.2 off:set portd.3 off
        else if l_mot_dir=forward then
          l_mot_pos++
          if l_mot_pos=5 then
            l_mot_pos=1
          end if
        else
          l_mot_pos---
          if l_mot_pos=0 then
            l_mot_pos=4
          end if
        end if
      ;
        select case l_mot_pos
          case 4
            set portd.0 on:set portd.1 on:set portd.2 off:set portd.3 off
          case 3
            set portd.0 off:set portd.1 on:set portd.2 on:set portd.3 off
          case 2
            set portd.0 off:set portd.1 off:set portd.2 on:set portd.3 on
          case 1
            set portd.0 on:set portd.1 off:set portd.2 off:set portd.3 on
      
        end select
      ;
      ;right motor
        if r_mot_dir=stop then
          set portd.4 off:set portd.5 off:set portd.6 off:set portd.7 off
        else if r_mot_dir=forward then
          r_mot_pos++
          if r_mot_pos=5 then
            r_mot_pos=1
          end if
        else
          r_mot_pos---
          if r_mot_pos=0 then
            r_mot_pos=4
          end if
        end if
      ;
       select case r_mot_pos
        case 4
          set portd.4 on:set portd.5 off:set portd.6 off:set portd.7 on
        case 3
          set portd.4 off:set portd.5 off:set portd.6 on:set portd.7 on
        case 2
          set portd.4 off:set portd.5 on:set portd.6 on:set portd.7 off
        case 1
          set portd.4 on:set portd.5 on:set portd.6 off:set portd.7 off
       end select
      set portc.3 off
      end sub
      

      I also call another sub from the same isr every 20ms.
      This uses pulseout to generate pulses between 7800us to 2200us

      sub servo
        pulseout servopin,servopos us
      end sub
      

      The isr drives the motors and the servo with no apparent problems.

       
  • Chris Roper

    Chris Roper - 2020-06-23

    millis a long variable but will overflow after ???

    A long variable is 32 bits so has a total count of 2^32
    which is 4,294,967,296.00 mS
    or 4,294,967.29600 Seconds
    or 71,582.7882667 Minutes
    or 1,193.04647111 Hours
    or 49 Days, 17 hours, 2 Minutes and 47.296 Seconds

    But if you are just interested in an elapsed time then subtracting the Start time from the time now will ensure that the rollover is canceled out mathematically .

    The System version of DoEvery will not be using Millis() as it is an independent countdown timer and so not affected by the rollover either.

     

    Last edit: Chris Roper 2020-06-23
  • stan cartwright

    stan cartwright - 2020-06-23

    Looking forward to the final release Chris.
    Without the gcb interrupt demos, I would have no idea how to code an interrupt.
    There are only a few demos so it encourages you to try the timercalc program to get interrupts at different frequencies.

     
  • stan cartwright

    stan cartwright - 2020-06-23

    Here is a thought.
    event 1 every 2ms takes 10us
    event 2 every 20ms takes 2200us max using pulseout,pin
    so event 2 could start and in the 2200us it could run for, event 1 starts.
    in the application, this must happen but I see no effects showing.
    maybe pulseout stops interrupts?? and is why it works.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.