EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

Sensing beams in strict timeframes - 8051

Started by mik3ca 5 years ago73 views

I currently made a board in which a 4-sensor unit is multiplexed into one output connected to P3.0 of an AT89C4051 microcontroller. The sensor is selected via P3.4 and P3.5 since they're connected to the select inputs of the same multiplexer. The output pin (P3.1) is connected to an LED which glows bright when P3.1 is low. 

This micro is connected to another micro (call it master) via a port bus and an extra port pin.

I intend to make many of these units for an upcoming lazertag system. 

The idea behind my code is as follows:

If the master makes a request and sends x0xxxxxx to this micro, then a reset is done. This means, the first sensor is selected, the shot status is reset and the counter to the current status we want is reset and the main timer is reset.

If the master makes any other request, then it expects the number of times it has been hit by a remote light beam (from 0 to 15) in the currently selected sensor. The sensor number increments and if it goes beyond 4, then it resets and the next player's data is loaded. Eventually, data from all players will be loaded and the process repeats.

The main timer is used to synchronize everything. Basically each individual sensor is active for a certain amount of time in which a hit can be accepted for it. Once each sensor has a chance to run, then the process repeats and the player's number is incremented (and wraps around if it goes too high). I use this approach to identify which player hit what sensor and I attempt to have the micro log it accordingly as described above and in code.

I can't change the hardware now, but I was wondering, is this the ideal way to go with this? I want to be able to detect shots at high speed and I want to make a remote light beam that goes on and off within the sensor's allowed time frame to count as a shot.

All units in operation will be synchronized the same way to reduce error, and eventually a central server will send the master chips a signal to send x0xxxxxx to these micros to make every player reset their setup simultaneously to minimize error.

If I can further optimize this code I could award that person a "beer" because this part of my project is tough so any help is appreciated.

Also, each sensor should have a limit of about 1ms because I want all players to have a turn to fire a shot (aka make their LED glow bright) within a 100-150mS timeframe.

The input is also inverted as well. I did this because I originally was going to feed the input and output through the 8051 serial interface but then after I thought that would be too slow for my objectives.


SENSH equ 0h ;Sensor timeout - 1ms (I need to change these 2 values)
SENSL equ 0h ;before shot invalid.
MAXPLAYERS equ 18h ;maximum players = 25
OUTHW equ P3   ;output hardware
ISHOT equ P3.0 ;incoming hit
OSHOT equ P3.1 ;shoot (beam) out
OPTION equ P3.3 ;optional feature
;sensor bits (P3.4 and P3.5)
SENS0 equ P3.4
SENS1 equ P3.5
ACK bit P1.7  ;Return acknowledgement
EXEC bit P3.7 ;Remote made execution
D equ P1 ;7-bit data line
WANTSHOT equ 20h.0 ;See if user wants to fire
GOTHIT equ 20h.1 ;Flag to see if we are getting hit
OSHOTB equ 20h.2 ;Instant shot configuration from timer
SENSLOC equ 10h ;Sensor value storage location
PLAYER equ 14h ;current player
HITC equ 30h ;hit counts.
;Memory format: aaaabbbb ccccdddd, aaaabbbb ccccdddd ....
;Start
org 0h
ljmp init
;timer interrupt
org 0Bh
    push PSW ;save C
    mov TH0,#SENSH
    mov TL0,#SENSL
    inc R0 ;move to next sensor (every 1mS)
    cjne R0,#SENSLOC+4,nss
      ;reached end so go to 1st sensor again
      mov R0,#SENSLOC
      ;Reset shot
      setb OSHOTB
      ;Reset hit status
      clr GOTHIT
      ;move to next player
      djnz PLAYER,nominp
        mov PLAYER,#MAXPLAYERS ;wrap around if 0 reached
      nominp:
      ;see if user wanted to make a shot
      jnb WANTSHOT,nostart
        clr OSHOTB   ;set shot
        clr WANTSHOT ;clear request
      nostart:
    nss:
    mov C,OSHOTB  
    mov OUTHW,@R0 ;Set hardware to new sensor
    mov OSHOT,C   ;and set shot accordingly
    pop PSW       ;restore C
reti
;initialization: Set almost everything to NULL
init:
  clr A
  mov P1,A
  mov SP,#070h
  mov R0,#7Fh
  clrall:
    mov @R0,A
  djnz R0,clrall
  mov PSW,A
  mov TCON,A
  dec A
  mov OUTHW,A
  ;Put FFh, EFh, DFh and CFh into 10h-13h memory locations
  mov SENSLOC,A
  mov SENSLOC+1,#0EFh
  mov SENSLOC+2,#0DFh
  mov SENSLOC+3,#0CFh
  ;Setup hardware and pointer to no-fire and sensor location 0.
  mov R0,#SENSLOC
  mov OUTHW,#SENSLOC
  ;set player to highest number
  mov PLAYER,#MAXPLAYERS
  mov TMOD,#11h
  setb TF0      ;overflow timer so it sets timeout for us
  setb TR0
  mov IE,#82h   ;Run timer interrupt
;Main loop that runs forever
main:
    jb ISHOT,ns1
      ;ISHOT GPIO pin low detected
      jb GOTHIT,ns1
      ;Its falling edge so assume start of valid shot
      setb GOTHIT
    ns1:
    jnb ISHOT,ns2
      ;ISHOT GPIO pin high detected
      jnb GOTHIT,ns2
      clr GOTHIT
      ;Its rising edge. Shot complete
      mov A,R0 ;Identify sensor
      swap A   ;Swap so values are at lowest bits
      rrc A    ;Take lowest bit
      mov B,A  ;Save remainder
      ;Get Address of storage based on opponent #
      mov A,PLAYER 
      rl A     
      addc A,#HITC ;C=1=one bit of sensor set so use next memory location
      mov R1,A  ;R1=memory location
      mov A,@R1 ;Get data
      jnb B.0,noaddt1 ;See what nibble we increment based on sensor bit set
        inc A
        sjmp nadd
      noaddt1:
      add A,#10h
      nadd:
      mov @R1,A ;update value
    ns2:
;See what remote micro wants.
;Remote micro sends data to P1 then lowers EXEC to start request
;ACK (P1.7) is lowered when request is done
    jb EXEC,noexec
    mov A,D ;Here request is started and loaded into A
    jbc ACC.6,noreset
      ;Here we reset stuff because incoming value is x0xxxxxx
      clr TR0 ;Stop timer so no one else messes up values
      mov R7,#(MAXPLAYERS*4)    ;reset player pointers
      mov PLAYER,#MAXPLAYERS
      mov R0,#SENSLOC           ;reset sensor location
      setb TF0                  ;overflow timer
      clr ACK                   ;tell remote were ready
      setb TR0                  ;start clock
      ajmp noexec               ;were done
    noreset:
    ;Incoming value is not x0xxxxxx so load next sensor count
    djnz R7,nreset
      mov R7,#(MAXPLAYERS*4) ;wrap-around if sensor count reaches start
    nreset:
    mov A,R7 ;Get sensor counter number
    rrc A    ;divide by 2 and take fragment number
    mov PART,C
    add A,#HITC ;load our pointer accordingly
    mov R1,A    
    mov A,@R1   ;load value from our pointer to A and B
    mov B,A  
    ;make nibble of wanted part = 0 in memory
    jnb PART,sw1
      anl B,#0F0h
    sw1:
    jb PART,nosw
      anl B,#00Fh
      swap A
    nosw:
    ;Store remaining unwanted part plus a nibble of 0 in memory
    mov @R1,B
    ;format result to 0000xxxx where x=part
    anl A,#0Fh
    ;send it out (automatically gives ACK signal)
    mov D,A
    noexec:
;Remote micro sends FFh to P1, waits a bit, picks up result
;then raises EXEC to complete request
    jnb EXEC,execend
      ;Here, we tristate P1 to complete request
      mov D,#0FFh
    execend:
;and repeat loop
ajmp main

any suggestions on code improvement?

P.S. I've been head-banging trying to come up with working code. Forgive me if you see any obvious mistakes.

The 2024 Embedded Online Conference