| CODE |
;;*************************************** ;;***** RS-232 test on 4114 ************* ;;*************************************** ;Fully interrupt driven ;Strings can come from flash or RAM. .include "c:\users\g&g\4414def.inc" .device AT90S4414 .def temp =r16 ;temporary register .def count =r17 ;a counter to use in message .def savSREG =r18 ;save the status register .def TXbusy =r19 ;transmit busy flag .def RXchar =r20 ;a received character .def xpos =r21 .def ypos =r22 .def ballx=r24 .def bally=r25 .def bdx=r2 .def bdy=r3 .def ly=r26 .def ry=r27 .def ldy=r28 .def rdy=r29 .def return=r23 .def drawchar=r20 .def rightscore=r6 .def leftscore=r5 .equ RIGHTPOINT=1 .equ LEFTPOINT=2 .equ baud =25 ;9600 baud constant for 4Mhz crystal .equ miny=2 .equ maxy=25 .equ minby=2 .equ maxby=19 .equ minx=2 .equ maxx=79 ;************************************** .dseg ;define variable strings to be tranmitted from RAM ss: .byte 128 ;a two digit count + a zero terminate ;************************************** .cseg .org $0000 rjmp RESET ;reset entry vector reti reti reti reti reti reti reti reti reti rjmp TXempty;UART buffer empty reti reti ;define fixed strings to be tranmitted from flash- zero terminated crlf: .db 0x0d, 0x0a, 0x00 ;carrage return/line feed clrscr: .db 27,'c',0x00 RESET: ldi temp, LOW(RAMEND);setup stack pointer out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ;initial conditions clr TXbusy ;start out not busy on TX ;setup UART -- enable TXempty & RXdone int, and RX, TX pins ldi temp, 0b00101000 out UCR, temp ;set baud rate to 9600 ldi temp, baud out UBRR, temp ldi temp,1 out tccr0,temp ;intialize text pointer BEFORE turning on interrupts ;because RESET causes the TX empty flag to be SET set ldi ZL, LOW(clrscr<<1);do shift to convert word-addr to byte ldi ZH, HIGH(clrscr<<1) sei sbi UCR, UDRIE ;enable the TXempty interrupt clr temp out ddrc,temp ; clear global variables clr leftscore clr rightscore ; initialize the screen and loop on the screen update function rcall initscreen mainloop:rcall updatescreen rjmp mainloop ; this is a utility function that starts sending data in ram senddata: ldi ZL,LOW(ss) ldi zh,HIGH(ss) clt sbi UCR, UDRIE ;enable the TXempty interrupt ser txbusy rjmp TXwait ; this is a utility function to move the cursor to ; xpos,ypos ; it actually puts the data in ram (which allows movement and ; screen data to be overlapped in a bulk transfer) movecursor: push temp ; send the begining of the escape code for "move cursor" ldi temp,27 st Z+,temp ldi temp,'[' st Z+,temp mov temp,ypos ; send the row (in ascii, not hex) rcall conv_ascii ; send the row - column separator ldi temp,59 st Z+,temp ; send the column mov temp,xpos rcall conv_ascii ; send the move cursor terminator and null terminate the string in ram ; (in case there is no data after this data) ldi temp,'H' st Z+,temp ldi temp,0 st Z,temp pop temp ret ; this utilility function will put the ascii representation of ; a two digit number in ram conv_ascii: push temp push count cpi temp,10 ; no leading '0' because that messes up the vt100 stuff brlt notens ldi count,'0'-1 ; get the tens digit ten_loop: inc count subi temp,10 brmi donetens rjmp ten_loop donetens: subi temp,-10 st z+,count ; store the tens digit notens: ; get the ones digit, store it, and null terminate subi temp,-'0' st Z+,temp clr temp st z,temp pop count pop temp ret updatescreen: ; erase the old ball (move the cursor to the old position, ; store a ' ', and null terminate ldi Zl,LOW(ss) ldi ZH,HIGH(ss) mov xpos,ballx mov ypos,bally rcall movecursor ldi temp,' ' st Z+,temp clr temp st Z,temp ; update the ball position first ; check for someone getting a point ; note that bounds checking is not completely symmetrical ; because of the available conditional branches clr return ; check the ball position with the left paddle position cpi ballx,minx+1 brge checkrightpoint ldi ballx,minx ; see if this is a bounce or a point ; check left edge cp bally,ly brge checkleftbottom ldi return,RIGHTPOINT rjmp donedraw checkleftbottom: mov temp,ly subi temp,-6 cp temp,bally brge bounceballx ldi return,RIGHTPOINT rjmp donedraw ; check right edge checkrightpoint: cpi ballx,maxx brlt checktopandbottom ldi ballx,maxx cp bally,ry brge checkrightbottom ldi return,LEFTPOINT rjmp donedraw checkrightbottom: mov temp,ry subi temp,-6 cp temp,bally brge bounceballx ldi return,LEFTPOINT rjmp donedraw bounceballx: ; the ball is bouncing in the x direction - negate it's velocity neg bdx ; check top and bottom boundary to see if the ball has hit a wall ; negate the y component of the ball's velocity if necessary checktopandbottom: cpi bally,MAXY brlt checktopball ldi bally,MAXY neg bdy rjmp donebally checktopball: cpi bally,MINY+1 brge donebally ldi bally,MINY neg bdy donebally: add ballx,bdx add bally,bdy mov xpos,ballx mov ypos,bally rcall movecursor ldi temp,'*' st Z+,temp clr temp st z,temp ; now move the paddles if a key is pressed ; the keys are as follows: the buttons on the board are ; connected to port c. each player has four buttons: ; fast and slow motion in both the up and down directions ; with combinations of fast and slow motion possible ; for really fast motion clr ldy sbis PINC,7 subi ldy,-2 sbis PINC,6 subi ldy,-1 sbis PINC,5 subi ldy,1 sbis PINC,4 subi ldy,2 clr rdy sbis PINC,3 subi rdy,-2 sbis PINC,2 subi rdy,-1 sbis PINC,1 subi rdy,1 sbis PINC,0 subi rdy,2 ; move the left bar if buttons are pressed and ; it's not touching a boundary ; the bar is moved by erasing '|' characters at the ; old position and drawing them in the new position add ly,ldy set tst ldy brge nonegldy neg ldy clt nonegldy: breq startrightbar cpi ly,MAXBY brlt checktoply ; fix the motion of the paddle if it's past a wall boundary subi ly,MAXBY sub ldy,ly ldi ly,MAXBY rjmp donefixly checktoply: cpi ly,MINby brge donefixly ldi temp,MINby sub temp,ly sub ldy,temp ldi ly,MINby donefixly: tst ldy breq startrightbar mov count,ldy ldi xpos,1 mov ypos,ly ldi drawchar,'|' clr temp brtc leftwriteloop ldi drawchar,' ' sub ypos,ldy ; this loop draws pipes if moving up and ; spaces to erase if moving down leftwriteloop: rcall movecursor st Z+,drawchar st Z,temp inc ypos dec count brne leftwriteloop ldi xpos,1 mov ypos,ly subi ypos,-6 ldi drawchar,' ' brtc leftclearloop ldi drawchar,'|' sub ypos,ldy ; this loop erases characters if moving up and draws them if moving down leftclearloop: rcall movecursor st Z+,drawchar st Z,temp inc ypos dec ldy brne leftclearloop ;; do the right bar - this is exactly symmetrical with the left bar startrightbar: add ry,rdy set tst rdy brge nonegrdy neg rdy clt nonegrdy: breq donedraw cpi ry,MAXBY brlt checktopry subi ry,MAXBY sub rdy,ry ldi ry,MAXBY rjmp donefixry checktopry: cpi ry,MINby brge donefixry ldi temp,MINby sub temp,ry sub rdy,temp ldi ry,MINby donefixry: tst rdy breq donedraw mov count,rdy ldi xpos,80 mov ypos,ry clr temp ldi drawchar,'|' brtc rightwriteloop ldi drawchar,' ' sub ypos,rdy rightwriteloop: rcall movecursor st Z+,drawchar st Z,temp inc ypos dec count brne rightwriteloop mov ypos,ry subi ypos,-6 ldi drawchar,' ' brtC rightclearloop ldi drawchar,'|' sub ypos,rdy rightclearloop: rcall movecursor st Z+,drawchar st Z,temp inc ypos dec rdy brne rightclearloop donedraw: tst return brne point rjmp senddata ; if a side has gotten a point, update the score and reinitialize the ; screen. If a side has won (gotten 10 points) print a message ; and spin loop point: ldi temp,10 cpi return,RIGHTPOINT brne norightpoint inc rightscore cp rightscore,temp breq rightwins rjmp initscreen norightpoint: inc leftscore cp leftscore,temp breq leftwins rjmp initscreen rightwins: ldi ypos,12 ldi xpos,34 rcall movecursor rcall senddata ldi ZL,LOW(rws<<1) ldi zh,high(rws<<1) set sbi UCR, UDRIE ;enable the TXempty interrupt ser txbusy rcall TXwait rwl: rjmp rwl leftwins: ldi ypos,12 ldi xpos,34 rcall movecursor rcall senddata ldi ZL,LOW(lws<<1) ldi zh,high(lws<<1) set sbi UCR, UDRIE ;enable the TXempty interrupt ser txbusy rcall TXwait lwl: rjmp lwl ; this utility function will print out initial stuff ; including the bars and the scores initscreen: ; clear the screen first set ldi ZL, LOW(clrscr<<1);do shift to convert word-addr to byte ldi ZH, HIGH(clrscr<<1) ser txbusy sbi UCR, UDRIE ;enable the TXempty interrupt ser txbusy rcall TXwait clt ; ss is a string to be printed - use it to store ; the scores and the initial bars ; first print the left score ldi Zl,LOW(ss) ldi ZH,HIGH(ss) ldi xpos,1 ldi ypos,1 rcall movecursor mov temp,leftscore rcall conv_ascii ; then print the right score ldi xpos,80 rcall movecursor mov temp,rightscore rcall conv_ascii ;draw stuff ldi ly,10 ldi ry,10 ldi xpos,1 mov ypos,ly ldi count,6 ; loop to create the bars leftcreateloop: rcall movecursor ldi temp,'|' st Z+,temp clr temp st Z,temp inc ypos dec count brne leftcreateloop ldi xpos,80 mov ypos,ry ldi count,6 rightcreateloop: rcall movecursor ldi temp,'|' st Z+,temp clr temp st Z,temp inc ypos dec count brne rightcreateloop rcall senddata ;; pseudorandomly choose ball direction ; based on the lsb of a free-running timer ldi bally,12 ldi temp,-1 mov bdy,temp in temp,tcnt0 ror temp brcs goright ldi ballx,41 ldi temp,-1 mov bdx,temp ret goright: ldi ballx,40 ldi temp,1 mov bdx,temp ret rws: .db "right wins!",0x00 lws: .db "left wins!",0x00 ;***************************** ;interrupt routines ; UART needs a character TXempty:in savSREG, SREG ;save processor status brtc TXram ;t bit=0:message in flash.t=1: message in ram lpm ;and put it in r0 inc ZL ;get the next char from flash rjmp TXfls TXram: ld r0,Z+ ;get char from mem TXfls: tst r0 ;if char is zero then exit breq TXend out UDR, r0 ;otherwise transmit it rjmp TXexit ;exit until next char TXend: clr TXbusy ;no more chars cbi UCR, UDRIE ;clear the TXempty interrupt TXexit: out SREG, savSREG ;restore proc status reti ;back to pgm ; TX done -- buffer is empty -- unused here TXdone: in savSREG, SREG ;save processor status out SREG, savSREG ;restore proc status reti ;back to pgm ; UART read a character RXdone: in savSREG, SREG ;save processor status in RXchar, UDR ;get the character out SREG, savSREG ;restore proc status reti ;back to pgm ;***************************** ;subroutine TXwait: tst TXbusy ;now wait for the tranmission to finish brne TXwait ret |