AVR Assembler Source Blog

Ремонт частотных преобразователей AVR Assembler Source Blog: Input_from_port

Saturday, October 5, 2013


ремонт автоматики
                              ; Test 2: Learn to more about the board: Input from a port
                              ; What to learn here:
                              ; - to read input from a port
                              ; - call subroutines and setup the stack
                              ; - Binary math operations like AND, OR, ROL, etc.
                              ; - Conditional branches (commands SBIx, BRxx)
                              ; This is the replacement for the malfunctioning .DEVICE directive again:
.INCLUDE "8515def.inc"
                              ; Define a universal register:
.DEF mp=R16
                              ; The jump-command on adress 0 again:
 rjmp main
                              ; The main program starts here
       ldi mp,LOW(RAMEND)     ;Initiate Stackpointer
       out SPL,mp
       ldi mp,HIGH(RAMEND)
       out SPH,mp
                              ; These commands initiate the stack in the build in SRAM. Stack operations
                              ; are always necessary when subroutines or interrupts are called.
                              ; By calling the subroutine or interrupt handling routine the actual adress
                              ; is written to the stack in order to later jump back to the code where the
                              ; interrupt or call occurred. The stack is located at the upper end of the
                              ; build in SRAM. The upper end of the SRAM is called RAMEND and is defined
                              ; in the file "xxxxdef.inc" for the respective processor type, so we do not
                              ; have to care about its real value.
                              ; If a byte is disposed on the stack it is written to the SRAM location and the
                              ; stack pointer at adress SPH:SPL (a 16 bit value) is decremented to the next
                              ; lower stack location. Further disposing bytes brings this pointer nearer
                              ; to the beginning of the SRAM. If a byte is taken from the stack then the
                              ; stackpointer is incremented first and then the value is read.
                              ; The last value put on the stack is read first when the stack is read, called
                              ; a Last-In-First-Out structure.
                              ; As the program counter and the adress structure requires 16 bits and
                              ; all registers and the SRAM are 8 bits wide, every adress on stack requires
                              ; two write/read operations to process the 16 bits. The SRAM adress is 16
                              ; bits wide, so the port SPL holds the lower 8 bits and the port SPH holds
                              ; the upper eight bits of the stack adress. Togeter we get the pointer SPH:SPL
                              ; as a 16 bit pointer to the stack adress.
                              ; The operations LOW and HIGH provide the opportunity to commincate to
                              ; the assembler that the lower or upper byte of RAMEND is meant when
                              ; we set up the stack pointer ports with the RAMEND value.
                              ; Port D is connected to the eight switches on the board. In order to
                              ; read these switches these pins have to have a zero in their data direction
                              ; register
       ldi mp,0x00            ; 8 zeros in universal register
       out DDRD,mp            ; to data direction register
                              ; The switches connect the inputs of port D with GND. In order to provide
                              ; a clear logical 1 when the key is open pull-up resistors have to be added.
                              ; This is already done on the STK200 by external resistors, so we wouldn't
                              ; need to use the internal resistors.Those internal resistors are build on
                              ; the chip, so we can switch them on by software action. This is done by
                              ; writing ones to the port register:
       ldi mp,0xFF            ; 8 Ones into the universal register
       out PORTD,mp           ; and to port D (these are the pull-ups now!)
                              ; Port B connected to the LEDs is again output, so we need to set its direction
                              ; register. On startup we want the LEDs to be all off, so we need to write ones
                              ; to the port output registers, too.
       ldi mp,0xFF            ; 8 Ones to the universal register
       out DDRB,mp            ; and to the data direction register
       out PORTB,mp           ; and to the outputregisters.
                              ; Clicking the keys 0 and 1 should switch on the corresponding LEDs,
                              ; the keys 2 to 6 all the other LEDs. Clicking key 7 swiches all LEDs off.
                              ; Within the main loop the switches are read and, if the different conditions
                              ; are met, branched to the different subroutines.
                              ; Reading switch 0 (very easy first)
                              ; The first command (SBIS) reads port D (PIND) and tests if the bit 0 is
                              ; one. If so, the next command is skipped. This is the case, if the switch
                              ; is open and the input pin is pulled to one by the pull-up. If the switch
                              ; is on, the pin reports zero and the condition for branching is not fulfilled.
                              ; So the next command after SBIS must be a single byte command that
                              ; branches to the routine that sets LED 0 on. This must be a subroutine,
                              ; as it has to come back after execution, because we have to process the
                              ; other switches as well.
                              ; This subroutine is further down in the source code, the assembler cares
                              ; about the displacement for the RCALL command. The RCALL pushes the
                              ; current adress on stack, so the subroutine can come back to the next
                              ; byte to be processed. The RCALL is used here, because it is a single
                              ; byte command, while a normal CALL command, also implemented in the
                              ; AVRs, is a 2-byte-command and would not fit.
       sbis PIND,0            ; Jump if bit 0 in port D input is one
       rcall Lampe0           ; Relative call to the subroutine named Lampe0
                              ; After processing the subroutine and by jumping over that call command
                              ; the next command is processed.
                              ; Reading switch 1 (a little bit exotic)
                              ; The ports are mirrored into the adress space of the SRAM. The SRAM
                              ; adress is 32 bytes higher than the respective port adress (add hex 20).
                              ; So we can use SRAM read commands to access the port. For our
                              ; convenience we give that adress a new name:
.EQU d_in_spiegel=PIND+$20
                              ; With the register pair R27:R26 we define a pointer that points to that input
                              ; port. With the LoaD-command we read the port input to a register as if it
                              ; were a SRAM byte.
       ldi R26,LOW(d_in_spiegel); define lower pointer in R26
       ldi R27,HIGH(d_in_spiegel); define upper pointer in R27
       ld mp,X                ; Laad register mp from pointer adress (PIND)
                              ; Isolate Pin1 (the switch 1) using mit AND-command and test for all zeros
andi mp,0b00000010            ; AND Bit 1
                              ; Branch over all following commands if the result of the AND command is
                              ; not zero (switch was off, input was one). The jump command BRNE (branch
                              ; if not equal) branches to a lable up- or downwards and is not limited to
                              ; a single byte command to follow. Use it for bigger jumps (here we don't).
       brne weiter            ; branch to lablel weiter, if not zero
       rcall Lampe1           ; Relative call to subroutine Lampe1
                              ; Switches 2 to 6
                              ; Read the ports D into a register, mask the switches 0, 1 and 7 with the
                              ; OR command and isolate the switches 2 to 6, if all are ones skip the next
                              ; commands with the BREQ command to the label sw7, otherwise read the
                              ; current status of the LEDs on port B (PINB), set all pins from 2 to 7 to zeros
                              ; and send this to the port B output.
       in mp,PIND             ; Read port D
       ori mp,0b10000011      ; mask switches 0, 1 und 7
       cpi mp,0b11111111      ; any one switch on?
       breq sw7               ; branch to label sw7, if not (= $FF)
       in mp,PINB             ; read current LED-status
       andi mp,0b00000011     ; switch on lamps 2 bis 7
       out PORTB,mp           ; to LED-port
       in mp,PIND             ; read port with the switches
       rol mp                 ; shift the seventh bit into the carry-flag
       brcs endloop           ; 7th bit is 1 (BRanch if carry is set)
       ldi mp,0xFF            ; All LEDs off
       out PORTB,mp
       rjmp loop
                              ; Subroutine Lampe0
                              ; switches LED 0 on.
       in mp,PINB             ; Read current status on port B
       andi mp,0b11111110     ; Whatever the other LEDs might be, this is 0
       out PORTB,mp           ; write back the result to the LED port
       ret                    ; get the return adress from the stack and return where you came from.
                              ; Subroutine Lampe1
                              ; switches LED1 on (a little bit different than Lampe0)
       in mp,PINB             ; read status of port B
       cbr mp,0b00000010      ; set bit 2 to zero with the CBR command
       out PORTB,mp           ; write back the result to the LEDs
       ret                    ; return adress from stack and return

No comments:

Post a Comment