Menu

setting port

Help
2020-06-17
2020-06-20
  • stan cartwright

    stan cartwright - 2020-06-17

    Hi. I used portd=portd and 0b11110011 instead of set portd.0 on:set portd.1 on:set portd.2 off:set portd.3 off
    but it doesn't work. Flash hex works.
    You can see the commented out code that worked.
    Trying to set port in one go instead of setting bits.

      select case l_mot_pos
        case 4
          portd=portd and 0b11110011 ;set portd.0 on:set portd.1 on:set portd.2 off:set portd.3 off
        case 3
          portd=portd and 0b11110110 ;set portd.0 off:set portd.1 on:set portd.2 on:set portd.3 off
        case 2
          portd=portd and 0b11111100 ;set portd.0 off:set portd.1 off:set portd.2 on:set portd.3 on
        case 1
          portd=portd and 0b11111001 'set portd.0 on:set portd.1 off:set portd.2 off:set portd.3 on
      end select
    
      select case r_mot_pos
        case 4
          portd=portd and 0b10011111 ;set portd.4 on:set portd.5 off:set portd.6 off:set portd.7 on
        case 3
          portd=portd and 0b11001111 ;set portd.4 off:set portd.5 off:set portd.6 on:set portd.7 on
        case 2
          portd=portd and 0b01101111 ;set portd.4 off:set portd.5 on:set portd.6 on:set portd.7 off
        case 1
          portd=portd and 0b00111111 ;set portd.4 on:set portd.5 on:set portd.6 off:set portd.7 off
      end select
    end sub
    

    can a port be set like this?
    if I can use portd=portd and var I could just rotate var left / right instead of case.
    edit portd=portd and 0b00111111 would not set the bits to change
    I got to change a nibble?

     

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

    Chris Roper - 2020-06-17

    Most ports have several registers, the generic names in GCBASIC being Port, LAT, and TRIS.

    This is to prevent the "Read, Modify, Write" issue (Look it up - too complex to explain here) so whilst PortD = PortD AND 0b11110011 may have worked in ASM on eralyer AVR or PIC devices it is no longer supported by the hardware or the compiler.

    Writing to PortD will actually write to LatD so your statement translates to:

    LatD = PortD and 0b11110011

    if any of the Port pins are pulled lower than 2.5V at the time of reading PortB then that bit in LatB will be set to Zero.

     
    • stan cartwright

      stan cartwright - 2020-06-18

      Thanks. I'll leave the code as is.
      Setting bits works ok but thought it looked inefficient.
      I could not find how to set a port in help so should have guessed it was not possible and anyway you can not rotate 4 bits.

       
  • Anobium

    Anobium - 2020-06-18

    Stan. Of course you can rotate four bits within a byte - but, it the key reading the byte variable/register, mask the bits you are not interested in, rotate and merge back. It may take more code to do this than a direct write (based on a case etc.).

    But, it is doable.

     
    • Anobium

      Anobium - 2020-06-18

      @Stan... before you ask - working code. It is full of serial debug for you. This will not be perfect but is shows how to mask etc.

        dim DeviceID as byte
        dim DeviceIDMask as byte
        do
      
          'Initial value - my assumption is that 0b11----11 where the 1 should not chang we rotate in the -'s
      
      
          DeviceID = 0b11000111  'this is same as DeviceID.2 = 1
      
          HSerPrintCRLF
          HSerPrint "BitWise Rotate"
          HSerPrintCRLF
          wait 100 ms
      
          Do
      
           'reset rotatation mask
            If DeviceIDMask.6 = 1 then
              DeviceID = ( DeviceID & 0b11000011 ) or 0b00000100
              HSerPrintCRLF 2
            end if
      
      
            HSerPrintCRLF
            HSerPrint ByteToBin( DeviceID )
            DeviceIDMask = DeviceID & 60 'same as 0b00111100
            Set C off
            Rotate DeviceIDMask Left
            DeviceID = ( DeviceID & 0b11000011 ) or DeviceIDMask
      
          Loop
      
        loop
      

      Enjoy

       

      Last edit: Anobium 2020-06-18
      • stan cartwright

        stan cartwright - 2020-06-19

        Thanks.. but if I can't set a port in one command then I would still be setting bits.
        I think you could do it in picaxe.Probably thinking of when I used that.
        Here is a problem with using and.
        The interrupt is every 1ms and the sub increments a counter and when it gets to 20 resets and calls servo, which works
        but the if millis and 1 = 0 then motors which I am using to test if millis is an even number ie 0,2,4,6,8,10 to 20 ie every 2ms
        but motors does not get called.

        dim millis as byte : millis = 0
            On Interrupt Timer0Match1 Call isr
            Dim OCR0  AS byte alias OCR0A
            Dim TCCR0 AS  byte alias TCCR0B
            WGM01 = 1
            OCR0 = 249 ;1ms
            TCCR0 = 0x28
            TCCR0 = TCCR0 or 0x03
        
        ;program
        
        sub isr
          millis++
          if millis and 1 = 0 then motors ;every 2ms
          if millis = 20 then millis = 0 : servo ;every 20ms
        end sub
        
         
        • Anobium

          Anobium - 2020-06-19

          Stan ... the code is not real code. is it?

          millis++ will throw an error
          if millis and 1 = 0 then motors ;every 2ms not sure what this does or what the intent is
          calling motors which may be a long running sub during the interrupt is bad practice. As the interrupt is now blocked.
          servo will be called every interrupt.

          So, not sure this code does anything meaningful. But, change to set flags in your main code to call motors and potentially servo.

           
  • Chris Roper

    Chris Roper - 2020-06-19

    Why are you reinvrenting the wheel and not using the millis.h library?

     
    • Anobium

      Anobium - 2020-06-19

      @Chris... that explains things... I assumed that Stan was using millis library.... hence, I was getting the error during millis++

      The ISR wil fail the way is it structured. So, a rethink is required.

      :-)

       
  • stan cartwright

    stan cartwright - 2020-06-19

    Anobium and Chris. The interrpt is from gcb demos, 1ms. timer 0 match.
    Anobium, I have the robot working with Chris Roper's millis BUT Chris has given me a modified version to test and is now working but Chris is a perfectionist and doesn't want it discussed until tested and finalised.
    So I am trying to do the same with 1 interrupt.
    the interruppt is every 1ms.
    the motors sub I set a port bit on at the start of the sub and turned the port bit off at the end and scoped the port bit and measured the pulse width. It hovered around 8us.
    the servo sub is just pulseout 220ms maximum.

    Anobium,
    "if millis and 1 = 0 then motors ;every 2ms not sure what this does or what the intent is"
    It was to test if bit 0 of millis was 0 or 1.
    If it was 0 then it is an even number ie 2,4,6...18,20 ms...millis increases by 1 every 1ms.
    so every even number call motors
    when millis gets to 20 it would call motors as it's an even number and reset to 0 and call servo after 20 1ms interrupts ie 20ms.

    Anyway I got it to work by using an every 2ms interrupt and changing the isr sub.
    so the motors not working previously must be if millis and 1 = 0 then motors.
    I feel chuffed I got it working. Chris, it works the same as using your millis.h but I cannot post code
    using that so "re-invented"your wheel :)
    The robot uses a V53L0X rangefinder and I tweaked the obtacle avoidance code from old code and added a last_turn variable.

    sub isr ,every 2ms
      motors
      mills = mills + 2
      if mills = 20 then mills = 0 : servo ;every 10 x 2 ms
    end sub
    
     

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

      Chris Roper - 2020-06-19

      I have no objection to you posting or discussing the millis() function or code that uses it.

      I was only asking that you don't publish code using the experimental DoEvery Statement.
      I appreciate you beta testing it for me but, as I am still testing and optimising memory use on a range of devices so the syntax and use of DoEvery may change before I publish.

      To show examples now may indirectly lock uys into a restrictive version in the future.

       

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

        stan cartwright - 2020-06-19

        Chris , I worked out my own doevery equivelant so I could post the code for the robot.
        It is interchangeable, just comment out your doevery and use the interrupt or comment out the interrupt and use doevery.

         
  • stan cartwright

    stan cartwright - 2020-06-19

    Anobium, please explain pulseout 2200 us.
    It's software so the program stops for at least 2200us...yes?
    So if I use an every 20ms interrupt no problem...yes?
    If I also calling another event every 2ms ie within the pulseout 2200us what happens to the program flow.
    It doesn't "seem" to be causing a problem.
    Chris, this applies to using your code to.
    Cheers stan

     
    • Anobium

      Anobium - 2020-06-19

      PulseOut is a macro.

      macro Pulseout (Pin, Time)
        Set Pin On
        Wait Time
        Set Pin Off
      end macro
      

      You can use every 20ms but ensure your interrupt does not use Wait as this will mess this up.
      As Pulseout and therefore WAIT counts clock cycles (based on frequency) an interrupt of X cycles will impact PulseOut. The total number of clock cycles will be ( PulseOut cycles + X cycles in the interrupt ).

      You will get 20 ms 'worth' of PulseOut clock transitions. So, this may be way is it working.

       

      Last edit: Anobium 2020-06-19
  • stan cartwright

    stan cartwright - 2020-06-19

    Here's a video of the robot using 2ms interrupt. https://youtu.be/Y_ai0tc_rek

     
  • stan cartwright

    stan cartwright - 2020-06-19

    Here's the program code. You can see it's working in the youtube video.
    You can also see Chris Roper's millis doevery commented out. It looks promising doesn't it?
    Chris has lost sleep working on this.
    I was up until 2.30am thinking what would I do if I was the robot and an obstacle appeared...and coding the thoughts :)
    Please check the motors sub. It looks a lot but take around 8us to execute....no way..
    but I only got a Hantek 6022BE.
    Just got a £8 salae clone logic analyser, as someone on the forum suggested from ebay. may be more accurate.
    Ok if I post as a project with reference to Chris's millis removed?

    ;fullwave stepper V53L0X robot
    #chip mega328p,16
    #option Explicit
    '#include "millis.h"
    
    dir portc.0 out ;servo
    dir portd.0 out:dir portd.1 out:dir portd.2 out:dir portd.3 out
    dir portd.4 out:dir portd.5 out:dir portd.6 out:dir portd.7 out
    ;set up V53L0X
    #define HI2C_DATA PORTC.5 ;sda portc.4 for nano portc.5 for uno
    #define HI2C_CLOCK PORTC.4 ;scl portc.5 for nano portc.4 for uno
    #define HI2C_BAUD_RATE 400
    HI2CMode Master
    ;
    ;v53l0x software restart
    HI2CStart
    HI2CSend(0x52)
    HI2CSend(0x89)
    HI2CSend(0x01)
    HI2CStop
    wait 200 ms
    ;
    dim l_mot_pos,r_mot_pos as byte
    dim l_mot_dir,r_mot_dir as byte
    dim servopos as Word
    dim servodir,distance_lo,distance_hi,mindist,last_turn as Byte
    ;
    #define distance distance_hi*256 + distance_lo ;v53l0x distance
    #define forward 1   ;|
    #define reverse 255 ;|--motor direction
    #define stop 0      ;|
    #define servopin portc.0
    #define wasleft 1
    #define wasright 0
    ;
    last_turn = random and 1 ;0 or 1
    servopos=1500 ;1.5ms servo mid position
    servodir=1 ;servo rotation direction
    mindist=200 ;minimum distance before avoiding
    l_mot_pos=1:r_mot_pos=1
    l_mot_dir=forward:r_mot_dir=forward
    ;
    ;set up interrupts
    dim mills as byte : mills = 0
        On Interrupt Timer0Match1 Call isr
        Dim OCR0  AS byte alias OCR0A
        Dim TCCR0 AS  byte alias TCCR0B
        WGM01 = 1
    ;    OCR0 = 249 ;1ms
    ;    TCCR0 = 0x28
    ;    TCCR0 = TCCR0 or 0x03
    
        OCR0 = 124 ;2ms
        TCCR0 = 0x28
        TCCR0 = TCCR0 or 0x04
    
    '#define DoEvery0  2, motors ;step motors every 2ms
    '#define DoEvery1  20, servo  ; pulseout portc.0,servopos us ;50Hz servo 'refresh
    'StartDoTimers
    ;
    do ;main program
    ;check for objects and avoid
      getdistance ;any object too close?
      if distance <> 20 then ;20 means out of range so skip distance test
    ;distance to obstacle test
        if servopos > 1300 then ;not pointing right
          if servopos < 1700 then ;not pointing left
            mindist = 200 ;pointing forward min distance
          end if
        else
          mindist = 250 ; left and right min distance
        end if
    ;
        if distance < mindist then ;object close
          l_mot_dir=stop:r_mot_dir=stop ;stop motors
    ;
          if servopos > 1700 then
            turnright_until_clear ;object left
            last_turn = wasright
          else if servopos < 1300 then
            turnleft_until_clear ;object right
            last_turn = wasleft
          else ;obstacle forward
            if last_turn = wasright then ;turn right again
              turnright_until_clear
            else ;turn left again
              turnleft_until_clear
            end if
          end if
          l_mot_dir=forward:r_mot_dir=forward ;go forward
        end if
      end if
    ;
    ;rotate servo left-right
      if servodir = 1 then
        servopos = servopos +80
        if servopos = 2220 then
          servodir = 0
        end if
      else
        servopos = servopos - 80
        if servopos = 780 then
          servodir = 1
        end if
      end if
      wait 30 ms
    loop
    ;end of main
    ;-----------------------------------------
    sub isr
      motors
      mills = mills + 2
      if mills = 20 then mills = 0 : servo
    end sub
    ;-------------------------
    sub getdistance
      HI2CStart ;Sys V53L0X Range Start
      HI2CSend(0x52)
      HI2CSend(0x00)
      HI2CSend(0x01)
      HI2CStop
    
      HI2CStart ;read distance
      HI2CSend(0x52)
      HI2CSend(0x1e)
      HI2CReStart
      HI2CSend(0x53) ;set the read flag
      HI2CReceive(distance_hi)
      HI2CReceive(distance_lo, NACK) ;read one byte and conclude
      HI2CStop
    end sub
    ;-----------------------
    sub turnleft_until_clear
      do
       l_mot_dir=reverse:r_mot_dir=forward ;rotate anti clockwise
       wait 20 ms
       l_mot_dir=stop:r_mot_dir=stop
       getdistance
      loop until distance > mindist ;rotate left until clear
    end sub
    ;-----------------------
    sub turnright_until_clear
      do
       l_mot_dir=forward:r_mot_dir=reverse ;rotate clockwise
       wait 20 ms
       l_mot_dir=stop:r_mot_dir=stop
       getdistance
      loop until distance > mindist ;rotate right until clear
    end sub
    ;-----------------------
    sub motors
    ;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
    end sub
    ;----------------------------
    sub servo
      pulseout servopin,servopos us
    end sub
    
     
  • stan cartwright

    stan cartwright - 2020-06-19

    The idea that
    sub isr
    motors
    mills = mills + 2
    if mills = 20 then mills = 0 : servo
    end sub
    works was inspired by Chris Ropers's doevery a la amstrad basic I suggested to him.
    I can see how he is doing it but not from his code which I find difficult to understand.
    The sub isr could have various counters to different timed subs....groovy

     
  • Chris Roper

    Chris Roper - 2020-06-19

    What is needed here is the second User Interrupt function in the Do suite that I have been working on:

    Set Pin On
    DoAfter 20 Set Pin Off

    Would perform the same function as

    Pulseout (Pin, 20 ms)

    But it would not use the Wait command and be 100% compatible with other interrupts as it is itself an interrupt.

    BUT, that is part of the Library I am working on so is not yet ready for testing, hang in there Stan, the more I understand of your needs the more I can refine my thinking.

    I will give it priority and try and get you some test code in the next couple of days.

     
    • stan cartwright

      stan cartwright - 2020-06-19

      Chris , you are making me feel guilty.
      I have a hardware solution if I want from Mr Kent..very complicated but nice offered.
      I don't get using wait..the interrupt still works.
      That's how I use the robot- r_mot_left=forward : wait 200ms and the motors still turn.

      Set Pin On
      DoAfter 20 Set Pin Off

      Would perform the same function as

      Pulseout (Pin, 20 ms)

      But it would not use the Wait command and be 100% compatible with other interrupts as it is itself an interrupt.

      It's pulseout pin,2ms and would be variable from 500 us to 2500 us. 1500us centres a servo.
      I think to simulate pulseout would need a every 10us interrupt.
      I've used a servo interrupt before and a stepper motor interrupt before but not together
      off 1 interrupt before. smug

       
  • stan cartwright

    stan cartwright - 2020-06-19

    Chris, I don't know why a servo needs pulseing it's position every 20msjust what I found researching.
    I think it's for like if the servo is under strain eg a model plane's rudder driven by a servo and the wind resistance.
    In my robot code the servo is not under stress so I removed the call to servo in the every 2ms isr
    and pasted the contents of the servo sub at the end off the only code that controls the servo and
    it is all working fine as before. The every 2ms interrupt is still needed for the motors to perform at peak speed and torque.

    ;rotate servo left-right
      if servodir = 1 then
        servopos = servopos +80
        if servopos = 2220 then
          servodir = 0
        end if
      else
        servopos = servopos - 80
        if servopos = 780 then
          servodir = 1
        end if
      end if
      pulseout servopin,servopos us ;this WAS interrupt driven every 20ms
      wait 30 ms 'to allow servo to move slower and not overheat and getdistance to work
    

    Hope your millis is working to plan.
    would doafter be
    get millis store as mil1
    do event
    is after=millis-mil1
    checked in an interrupt often

     
    • Chris Roper

      Chris Roper - 2020-06-20

      To avoid further confusion:

      Millis() is working fine and it has been working and included in GCBASIC for a few years now.
      Millis() Uses Timer0 and a Long Variable to count the number of milliseconds since a device reset.

      You were looking for an easy way to have user based timer interrupts, but as Timer0 was already used by the Millis any code that tried to use Timer0 would disrupt Millis.

      What I have been working on is a way to share Timer0 between the existing Millis() function and the new requirement for a user based timer interrupt. As "millis.h" already has all of the code to set up Timer0 on all of the supported devices I used that initialisation code as the basis of the new user interrupts.

      The new system is NOT using the millis() function nor does it alter the millis() function in any way you, and anybody else, can continue to use millis() in their code exactly as they always have. The Modified millis.h that I sent you just give an extra hook into the interrupt to allow DoEvery and millis() to coexist without conflicting over timer0.

      The help and the example libraries along with any Arduino Documentation contain info on the use of millis().

      The new functions are taking time because they have to be designed to work on many different devices and minimise the amount or RAM use, that takes time to design, test and rework the retest for several devices. They are NOT based on Millis() they are independent Methods.

      The original Beta code I sent you was specific to your need - the resultant library will be generic.

      So the bottom line is that I am NOT working on or with millis - this is a totally separate project to millis but will coexist with millis so that they can share Timer0.

      So please USE millis(), do NOT try to create your own millis() function, millis() works now, it has worked for a few years and it has been extensively tested on hundreds of different devices.

      DO NOT reinvent the wheel - the DoEvent Library, for want of a better name, is what I am working on, NOT millis() and as the wise man said “if it ain't broke, don't fix it”.

       
  • stan cartwright

    stan cartwright - 2020-06-20

    Chris-It's just a hobby. I can wait for for your ideas to be published.
    More I experiment,more I learn. So... sorry. I will keep on experimenting with interrupt driven events for my own interests on a 328p or a 18f25k22, all I use.
    Your doevery will be useful for making interrupts easier.
    Hope the project works out.

     

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.