
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.
