.include "m16def.inc" #define SIMULATOR 1 ; set to 1 when running on the simulator to deactivate the UART and the delay ; ********************************************************************* ; Command headers ; ********************************************************************* .equ PROD_HEADER = 0x40 .equ COIN_HEADER = 0x00 .equ DISPLAY_HEADER = 0x80 ; ********************************************************************* ; Registers symbolic name ; ********************************************************************* .def cmd = r17 ; command, used in all the UART operation .def tmp1 = r18 ; Temp register .def tmp2 = r16 ; Temp register .def coinVal = r19 .def creditTmp = r20 ; ********************************************************************* ; UART parameter ; ********************************************************************* .equ F_CPU = 1000000 ; Systemtakt in Hz .equ BAUD = 9600 ; Baudrate ; Berechnungen .equ UBRR_VAL = ((2*F_CPU+BAUD*8)/(BAUD*16)-1) ; clever runden .equ BAUD_REAL = (2*F_CPU/(16*(UBRR_VAL+1))) ; Reale Baudrate .equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000) ; Fehler in Promille .if ((BAUD_ERROR>10) || (BAUD_ERROR<-10)) ; max. +/-10 Promille Fehler .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!" .endif ; ********************************************************************* ; RAM allocation: current credit, and products' price ; ********************************************************************* .dseg .org 0x00060 CREDIT: .byte 1 ; allocate RAM for CREDIT PRICE: .byte 64 ; allocate RAM for PRICE _RAM_: ; to mark the end of the allocated ram: DO NOT CHANGE IT! .cseg .org 0000 rjmp main_init ; ********************************************************************* ; Constants in PROGRAM memory ; ********************************************************************* .org 0x0030 ; Products price array. It is possible to add values or change the existing ones const_PP: .db 15, 12, 10, 30, 35, 8; _PP_end_: ; to mark the end of the array main_init: ldi r17, high(_RAM_) out SPH, r17 ldi r17, low(_RAM_) out SPL, r17 clr r17 ldi r19, (_RAM_-CREDIT+1) __clear_ram: push r17 dec r19 brne __clear_ram ldi XL, low(PRICE) ldi XH, high(PRICE) ldi ZL, low(const_PP<<1) ldi ZH, high(const_PP<<1) ldi r19, (_PP_end_-const_PP) __init__ram: lpm r17, Z ; first byte ori ZL, 0x01 lpm r18, Z+ ; second byte st X+, r17 st X+, r18 dec r19 brne __init__ram ; Baudrate einstellen ldi tmp1, HIGH(UBRR_VAL) out UBRRH, tmp1 ldi tmp1, LOW(UBRR_VAL) out UBRRL, tmp1 ; Frame-Format: 8 Bit ldi tmp1, (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0) out UCSRC, tmp1 sbi UCSRA, U2X sbi UCSRB, TXEN ; TX aktivieren sbi UCSRB, RXEN ; RX aktivieren ; TODO: Stackpointer initialisieren ldi tmp1, high(RAMEND) out SPH, tmp1 ldi tmp1, low(RAMEND) out SPL, tmp1 ; TODO: setze das Display auf 0 ldi cmd, (1<<7) call serout main: call serin sbrc cmd, 7 rjmp main ; decode the command sbrs cmd, 6 call coin sbrc cmd, 6 call product rjmp main ; end main ; ********************************************************************* ; COIN ; ; Decode, update the CREDIT ; ********************************************************************* coin: ldi YL, low(CREDIT) ldi YH, high(CREDIT) ld creditTmp, Y ; load the credit value sbrc cmd, 5 rjmp coins_back ; eject all coins (bit 5 is set) ; decode coin value call decode_coin ; get coinVal from cmd ; check new credit add creditTmp, coinVal ; add coin to credit cpi creditTmp, 100 ; compare with 100 (represents 10,0 Euro) brsh last_coin_back ; more than allowed? -> return last coin ; update CREDIT st Y, creditTmp ; save credit value to RAM call display_update ; update the display ret coins_back: call change_back call display_update ; update the display ret last_coin_back: call serout ; cmd is still the coin command ret decode_coin: clr coinVal ; ready to store the coin value ; 10 Cent sbrc cmd, 0 ldi coinVal, 1 ; 20 Cent sbrc cmd, 1 ldi coinVal, 2 ; 50 Cent sbrc cmd, 2 ldi coinVal, 5 ; 1 Euro sbrc cmd, 3 ldi coinVal, 10 ; 2 Euro sbrc cmd, 4 ldi coinVal, 20 ret ; ********************************************************************* ; PRODUCT ; ; Decode, lookup price, release or show the price ; ********************************************************************* product: ldi XL, low(PRICE) ldi XH, high(PRICE) andi cmd, 0b00111111 ; remove the first two bits (2 MSB) add XL, cmd clr tmp1 adc XH, tmp1 ; TODO: pre-decrement or not? ; is the first product 0b00000001? ; ld tmp1, -X ; load the price ld tmp1, X ; load the price tst tmp1 brne product_ret ldi YL, low(CREDIT) ldi YH, high(CREDIT) ld creditTmp, Y ; load the credit value sub creditTmp, tmp1 ; substract the price from the credits brmi display_blink ; not enough credits ; output the product call serout ; cmd is still the command of the requested product st Y, creditTmp ; save the new credits call change_back ; return the change call display_update ret display_blink: mov cmd, tmp1 ori cmd, (1<<7) call serout ; output price call delay_500ms call delay_500ms ser cmd ; set cmd to $FF (display off) call serout call delay_500ms mov cmd, tmp1 ori cmd, (1<<7) call serout ; output price call delay_500ms call delay_500ms call display_update product_ret: ret ; ********************************************************************* ; Give CHANGE back ; ; Return the change minimizing the number of returned coins ; ********************************************************************* change_back: push cmd push YL push YH ldi YL, low(CREDIT) ldi YH, high(CREDIT) ld creditTmp, Y ; load the credit value ldi cmd, (1<<4) ; set cmd to highest coin change_loop: tst creditTmp breq change_end ; is credit empty? call decode_coin ; get coin value sub creditTmp, coinVal ; substract! ; maybe brmi? brlo next_coin ; next coin? call serout ; return that coin rjmp change_loop next_coin: lsr cmd add creditTmp, coinVal rjmp change_loop change_end: clr creditTmp st Y, creditTmp pop YH pop YL pop cmd ret ; ********************************************************************* ; Display Update ; ; Update the display, based on the current CREDIT ; ********************************************************************* display_update: push cmd ld creditTmp, Y ; load the credit value mov cmd, creditTmp ori cmd, (1<<7) ; set the display bit call serout pop cmd ret ; ********************************************************************* ; Delay routine ; ********************************************************************* .equ N1 = 234 .equ N2 = 255 delay_500ms: #if !SIMULATOR ; prevent the simulator by executing the actual delay. push tmp1 push tmp2 ldi tmp2, N1 _delay_loop1: dec tmp2 breq _delay_return ldi tmp1, N2 _delay_loop2: nop nop nop nop nop nop nop dec tmp1 brne _delay_loop2 nop rjmp _delay_loop1 _delay_return: pop tmp2 pop tmp1 #endif ret serout: #if !SIMULATOR sbis UCSRA, UDRE rjmp serout out UDR, cmd #endif ret serin: #if !SIMULATOR sbis UCSRA, RXC rjmp serin ; loop back in cmd, UDR ; else get received byte in cmd #endif ret
Comments