| CODE |
; Jonathan Roffman and Theresa Thomas ; EE 476 ; March 29, 1999 ; Lab 6 .include "c:\users\jonther\8535def.inc" .device AT90S8535; specifies to the assembler which chip we are using .def save =r16 ;SREG temp reg .def temp =r17 ;temporary register .def key =r18;temp register for key press value .def butnum =r19;hold button press value .def abc =r20;hold abc value .def letter =r21;register to hold ascii value of input letter .def led =r22;register to hold LED values .def inpuzzle=r23;register to tell whether guess is in puzzle or not ;***** global variables for lcd2 code .def timeout =R24 ;Timeout value passed to subroutine .def lcdstat =R25 ;LCD busy/wait status .def longtime=R26 ;Long timer for powerup .def charcnt =r27 ;Char position on the display .equ azero ='0' ;0x30 ascii '0' .equ prescal =2 ;value to prescale clock to get 2us per tick ;***** Other equates .equ lcdrs =PD6 ;LCD rs pin connected to PD6 .equ lcdrw =PD5 ;LCD r/w pin connected to PD5 .equ lcde =PD4 ;LCD enable pin connected to PD4 ; Timer/Counter prescaler values .equ TSTOP =0 ;Stop Timer/Counter .equ TCK1 =1 ;Timer/Counter runs from CK .equ TCK8 =2 ;Timer/Counter runs from CK / 8 .equ TCK64 =3 ;Timer/Counter runs from CK / 64 .equ TCK256 =4 ;Timer/Counter runs from CK / 256 .equ TCK1024 =5 ;Timer/Counter runs from CK / 1024 .equ TEXF =6 ;Timer/Counter runs from external falling edge .equ TEXR =7 ;Timer/Counter runs from external rising edge ;***** Initialization ;************************************** .cseg .org $0000 rjmp RESET ;reset entry vector reti reti reti rjmp t2int ;timer 2 interrupt for songs reti reti reti reti rjmp t0int ;timer0 interrupt :timer 0 interrupt for lcd stuff reti reti reti reti reti reti reti ;The following table is used to convert raw button-press high/low ;values to a sequence number. Invalid codes caused by multiple ;button presses are ignored. keytbl: .db 0b11101110, 0b11101101, 0b11101011, 0b11100111 .db 0b11011110, 0b11011101, 0b11011011, 0b11010111 .db 0b10111110, 0b10111101, 0b10111011, 0b10110111 .db 0b01111110, 0b01111101, 0b01111011, 0b01110111 RESET: ;***setup stack pointer*** ldi temp, LOW(RAMEND) out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp clr r31 clr butnum ;***start timer1 for randomization routine**** ldi temp, 0b00000001 ;prescale timer 1 by 1 for randomization out TCCR1B, temp clr temp ;***setup for lcd*** ldi temp,TSTOP ;Timer 0 off (just in case) out TCCR0,temp ;Stop timer ldi temp, 0b01000001 ; enable capture interrupt and timer0 interrupt out TIMSK, temp sei ;enable all interrupts **power down the LCD*** ldi temp, 0xff ;LCD power connection out DDRA, temp ;power it down after reset ldi temp, 0x00 out PORTA,temp ldi longtime,100 ; then Wait 1.5 second with LCD power off ldi timeout,0 ;Delay 15 mS offwait:rcall delay dec longtime brne offwait ;***now power up LCD*** ldi temp, 0xff out PORTA, temp ldi longtime,100 ;Wait 1.5 second for LCD power up ldi timeout,0 ;Delay 15 mS puwait: rcall delay dec longtime brne puwait ;***hopefully by now the LCD has rebooted, so initialize and clear*** main: rcall lcdinit ;Initialize LCD module rcall lcdclr ;Clear LCD screen ;***scan the keyboard for a button press*** keybd: clr butnum clr letter ldi temp, 0x0f ;set lower four lines to output out DDRC, temp ldi temp, 0xf0 ;and turn on the pullups on the inputs out PORTC, temp nop ;Need some time for the pullups to nop ;charge the port pins nop nop in temp, PINC ;read the high nibble mov key, temp ;and store it (with zeros in the low nibble) ldi temp, 0xf0 ;set upper four lines to outputs out DDRC, temp ldi temp, 0x0f ;and turn on pullups on the inputs out PORTC, temp nop ;As before wait for the pin to charge nop nop nop in temp, PINC ;read the low nibble or key, temp ;combine to make key code ;At the point the raw key code should have exactly one zero each in ;the lower and upper nibbles. Any other number of zeros indicates ;either no-button pressed or multiple-button pressed. ;Now search the table for a match to the raw key code ;and exit with a button number ldi ZL, low(keytbl*2) ;table pointer in FLASH ldi ZH, high(keytbl*2) ;so convert from word to byte addr tbllp: lpm ;get the table entry cp key, r0 ;match? breq foundit inc butnum ;if not, have we exhaused the cpi butnum, 0x10 ;table breq illegal adiw ZL, 1 ;if not, get the next table entry rjmp tbllp foundit:cpi butnum, 0 ;User presses '1' key to start a new game breq newgame cpi butnum, 12;at end of game, wait until new game button is pressed breq keybd cpi butnum, 1;abc key breq two1 cpi butnum, 2;def key breq three1 cpi butnum, 3;A shift key breq alpha1 cpi butnum, 4;ghi key breq four1 cpi butnum, 5;jkl key breq five1 cpi butnum, 6;mno key breq six1 cpi butnum, 7 :B shift key breq beta1 cpi butnum, 8;prs key breq seven1 cpi butnum, 9;tuv key breq eight1 cpi butnum, 10;wxy key breq nine1 cpi butnum, 11;C shift key breq gamma1 cpi butnum, 13;q and z key breq ten1 rjmp keybd illegal:ser temp ;no table match means show clr butnum rjmp keybd alpha1: rjmp alpha ;jumps because rjmps were out of reach beta1: rjmp beta gamma1: rjmp gamma two1: rjmp two three1: rjmp three four1: rjmp four five1: rjmp five six1: rjmp six seven1: rjmp seven eight1: rjmp eight nine1: rjmp nine ten1: rjmp ten newgame:rcall lcdclr ;clear the lcd clr charcnt ;clear character count ser abc ;set the shift tracker to reset it ser led ;clear the led's out DDRB,led;make port b output to led's out PORTB,led ldi ZH,high(message*2) ;load pointer to first puzzle ldi ZL,low(message*2) in butnum, TCNT1L ;get a random number (lower byte) by reading counter1 lsr butnum ;shift the byte add ZL, butnum ;add it to the lower pointer in butnum, TCNT1H ;get the upper byte of counter 1 add ZL, butnum ;add to lower pointer for further randomization andi butnum, 0b00000011 ;take only lower two bits of upper nibble counter adc ZH, butnum ;add that to high byte of pointer findzero: lpm ; check for new word adiw ZL, 1 ; by looking for trailing zero tst r0 brne findzero ;******Now read the random word****; once we reach trailing zero, get entire word nextchar:lpm ;Get next character from ROM push r0 ;push it on to stack tst r0 ;See if at end of message breq savelength ;If so save letters to reg 1-15 adiw ZL,1 ;Increment Z-pointer inc charcnt ;keep track of chars on display rjmp nextchar ;Loop for more savelength:mov inpuzzle,charcnt ;save character count into another register inc charcnt ;inc character count to point to highest register mov YL, charcnt ;move into Y pointer to start storing into reg 1-15 clr YH ;clear high byte of pointer loadlet:cpi charcnt, 0 ;see if character count is down to zero breq restore ;if so, branch to restore character count pop temp ;pop letter one at a time st Y, temp ;and store it into registers sbiw YL,1 ;inc register pointer dec charcnt ;dec character count to count letters in word rjmp loadlet ;keep loading letters restore: mov charcnt, inpuzzle ;restore the character count printdash:clr r0 ;clear r0 again: cp charcnt,r0 ;check to see if the pointer is at the end of word breq restlength ;if so, then go to automatically guessing a space ldi temp, 8 ;check to see if need to readdress the lcd cp r0, temp brne not8 ;if not, continue writing ldi temp,0xC0 ;Set address to last 8 chars rcall lcdcmd not8: inc r0 ;go to next letter ldi temp, 0b01011111 ;value for underscore rcall lcdput ;put it on lcd rjmp again ;keep going through puzzle jump1: rjmp keybd restlength:mov charcnt,inpuzzle ldi letter, 0x20 ;automatically guess "space" character before starting game rjmp updatelcd alpha: ldi abc, 0 ;first shift key, choses first letter on number key rjmp keybd beta: ldi abc,1 ;second shift key, choses second letter on number key rjmp keybd gamma: ldi abc,2 ;third shift key, choses third letter on number key rjmp keybd two: cpi abc, 0xff ;if abc is not set, go back to keyboard poll breq jump1 ldi letter, 'a' ;load first letter of number key add letter, abc ;and increment according to what shift key was pressed rjmp updatelcd ;update lcd three: cpi abc, 0xff ;same as above for each key breq jump1 ldi letter, 'd' add letter, abc rjmp updatelcd four: cpi abc, 0xff breq jump1 ldi letter, 'g' add letter, abc rjmp updatelcd five: cpi abc, 0xff breq jump1 ldi letter, 'j' add letter, abc rjmp updatelcd six: cpi abc, 0xff breq jump1 ldi letter, 'm' add letter, abc rjmp updatelcd seven: cpi abc, 0xff breq jump1 cpi abc, 0 breq letterp inc abc letterp:ldi letter, 'p' add letter, abc rjmp updatelcd eight: cpi abc, 0xff breq jump1 ldi letter, 't' add letter, abc rjmp updatelcd nine: cpi abc, 0xff breq jump1 ldi letter, 'w' add letter, abc rjmp updatelcd ten: cpi abc, 0xff ;this is for q and z breq jump1 cpi abc, 1 brne letterz ldi letter, 'q' rjmp updatelcd letterz:ldi letter, 'z' rjmp updatelcd updatelcd:ser abc ;set abc to clear it clr YL ;clear the Y pointer clr YH clr inpuzzle ldi temp,0x80 ;Set LCD address to 0 rcall lcdcmd adiw YL,1 ;increment the pointer nextl: ld temp, Y cpi temp, 0 ;are we at end of the word? breq testin ;if so, jump to code which checks if letter ever appeared in puzzle cpi YL, 9 ;do we need to readdress lcd? brne hop ;jump if characters 0-7, otherwise, need to set lcd to address last 8 chars ldi temp,0xC0 ;Set address to last 8 chars rcall lcdcmd hop: ld temp, Y ;get Y pointer cp temp, letter ;check to see if letter guessed is in the word brne skip ;if letter not a match, skip over space on lcd mov temp, letter ;else, found a correct letter, so write it rcall lcdput ser inpuzzle ;set inpuzzle to mark a correct guess adiw YL, 1 ;increment Y pointer dec charcnt ;decrement character count to keep track of legth of word rjmp nextl skip: ldi temp, 0b00010100 ;value to move cursor right by 1 without overwriting rcall lcdcmd adiw YL, 1 ;increment Y pointer rjmp nextl testin: cpi letter, 0x20 ; check if this is the beggining of a game (guessed "space" character) brne reglet ;if not, go to regular letter check ldi inpuzzle, 1 ;if yes, space was guessed, so play game start tone. reglet: cpi inpuzzle, 0 ;was the letter in the puzzle brne wingame ;if so, check to see if they won the game lsl led ;if not, light another led out PORTB, led ldi ZH,high(wrong*2) ;"wrong" guess tone addr to Z-ptr ldi ZL,low(wrong*2) rcall playgo ;call the play song code cpi led,0 ;if no more led's left, then go to lose game breq losegame rjmp keybd ;otherwise, wait for another letter guess wingame:cpi charcnt,0 ;is it at the end of the word breq won ;if so, then they won ldi ZH,high(right*2) ;"right" guess tone addr to Z-ptr ldi ZL,low(right*2) rcall playgo ;call code to play song rjmp keybd ;then go back to keyboard so user can start a new game won: ldi ZH,high(winsong*2) ;winsong addr to Z-ptr ldi ZL,low(winsong*2) rcall playgo ;code to play song ldi key, 0b01111110 ;set key to blank key rjmp keybd ;goto keyboard losegame:clr YL ;clear Y pointer to print out puzzle they didn't guess clr YH adiw YL, 1 ;inc Y pointer ldi temp,0x80 ;Set LCD address to 0 rcall lcdcmd nextlet:ld temp, Y ;load letter into temp cpi temp, 0 ;check to see if at end of word breq playlose ;if so, play losing song cpi YL, 9 ;see if need to readdress lcd brne hop1 ;jump if characters 0-7, otherwise, need to set lcd to address last 8 chars ldi temp,0xC0 ;Set address to last 8 chars rcall lcdcmd hop1: ld temp, Y ;write next letter rcall lcdput adiw YL, 1 ;inc Y pointer rjmp nextlet playlose:ldi ZH,high(losesong*2) ;losesong addr to Z-ptr ldi ZL,low(losesong*2) rcall playgo ;code for playing song ldi key, 0b01111110 ;set key to blank key rjmp keybd ;go to keyboard poll jump: rjmp jump1 playgo: ldi temp, 0b00000100 ;prescale timer2 by 64 for playing notes out TCCR2, temp lpm ;load song or tone adiw ZL, 1 ;increment program memory tst r0 ;are we at the end of the song? breq end ;if so, end mov save, r0 ;if not, move note into save cpi save, 0x75 ;this is a low tone for "wrong" brne notwrong ldi temp, 0x83 ;load in appropriate number of interrupts for each tone into temp rjmp wait notwrong:cpi save, 0x01 ;lowest note brne notlow ldi temp, 61 rjmp wait notlow: cpi save, 0x03 ;low b brne notb0 ldi temp, 62 rjmp wait notb0: cpi save, 0x10 ;low c brne notc0 ldi temp, 65 rjmp wait notc0: cpi save, 0x2a ;low d brne notd0 ldi temp, 73 rjmp wait notd0: cpi save, 0x42 ;low e brne note0 ldi temp, 83 rjmp wait note0: cpi save, 0x4c ;low f brne notb1 ldi temp, 87 rjmp wait notb1: cpi save, 0x89 ;C? brne notc2 ldi temp, 0x83 ;131 interrupts rjmp wait notc2: cpi save, 0x95 ;D? brne notd2 ldi temp, 0x93 ;147 interrupt rjmp wait notd2: cpi save, 0xa1 ;E? brne note2 ldi temp, 0xa6 ;166 interrupts rjmp wait note2: cpi save, 0xa6 ;F? brne notf2 ldi temp, 0xb0 ;176 interrupts rjmp wait notf2: cpi save, 0xb0 ;G? brne notg2 ldi temp, 0xc6 ;198 interrupts rjmp wait notg2: cpi save, 0xb9 ;A? brne nota2 ldi temp, 0xdc ;220 interrupts rjmp wait nota2: cpi save, 0xc1 ;B? brne wait ldi temp, 0xf8 ;248 interrupts wait: cpi temp, 0 ;wait for tone to be finished playing brne wait rjmp playgo end: ldi temp, 0 ;clr temp to stop timer out TCCR2, temp ret ;and return to code =============================================== ; Clear entire LCD and delay for a bit lcdclr: ldi temp,1 ;Clear LCD command rcall lcdcmd ldi timeout,256 ;Delay 15 mS for clear command rcall delay ret ================================================ ; Initialize LCD module lcdinit: ldi temp,0 ;Setup port pins out PORTD,temp ;Pull all pins low ldi temp,0xff ;All pins are outputs out DDRD,temp ldi timeout,256 ;Wait at least 15 mS at power up rcall delay ;LCD specs call for 3 repetitions as follows ldi temp,3 ;Function set out PORTD,temp ;to 8-bit mode nop ;nop is data setup time sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi timeout,256 ;Wait at least 15 mS rcall delay ldi temp,3 ;Function set out PORTD,temp nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi timeout,256 ;Wait at least 15 ms rcall delay ldi temp,3 ;Function set out PORTD,temp nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi timeout,256 ;Wait at least 15 ms rcall delay ldi temp,2 ;Function set, 4 line interface out PORTD,temp nop ; rcall strobe ;Toggle enable line sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi temp,0b11110000;Make 4 data lines inputs out DDRD,temp ;Finally, ;At this point, the normal 4 wire command routine can be used ldi temp,0b00100000;Function set, 4 wire, 1 line, 5x7 font rcall lcdcmd ldi temp,0b00001100;Display on, no cursor, no blink rcall lcdcmd ldi temp,0b00000110;Address increment, no scrolling rcall lcdcmd ret ============================================ ; Wait for LCD to go unbusy lcdwait: ldi temp,0xF0 ;Make 4 data lines inputs out DDRD,temp sbi PORTD,lcdrw ;Set r/w pin to read cbi PORTD,lcdrs ;Set register select to command waitloop: sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde in lcdstat,PIND ;Read busy flag ;Read, and ignore lower nibble sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde sbrc lcdstat,3 ;Loop until done rjmp waitloop ret ============================================= ; Send command in temp to LCD lcdcmd: push temp ;Save character rcall lcdwait ;Wait for LCD to be ready ldi temp,0xFF ;Make all port D pins outputs out DDRD,temp pop temp ;Get character back push temp ;Save another copy swap temp ;Get upper nibble andi temp,0x0F ;Strip off upper bits out PORTD,temp ;Put on port nop ;wait for data setup time sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde pop temp ;Recall character andi temp,0x0F ;Strip off upper bits out PORTD,temp ;Put on port nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi temp,0xF0 ;Make 4 data lines inputs out DDRD,temp ret ============================================= ; Send character data in temp to LCD lcdput: push temp ;Save character rcall lcdwait ;Wait for LCD to be ready ldi temp,0xFF ;Make all port D pins outputs out DDRD,temp pop temp ;Get character back push temp ;Save another copy swap temp ;Get upper nibble andi temp,0x0F ;Strip off upper bits out PORTD,temp ;Put on port sbi PORTD,lcdrs ;Register select set for data nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde pop temp ;Recall character andi temp,0x0F ;Strip off upper bits out PORTD,temp ;Put on port sbi PORTD,lcdrs ;Register select set for data nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ;cbi PORTD,lcdrs ;-- ldi temp,0xF0 ;Make 4 data lines inputs out DDRD,temp ret ============================================= ;***************************** ;interrupt routines ;***** Timer 0 overflow interrupt handler t0int: set ;Set T flag ldi save,TSTOP ;Timer 0 off out TCCR0,save ;Stop timer reti ;Done, return ;***** Timer 2 overflow interrupt handler t2int: in save,SREG ldi key, 0xff cp r0, key ;dont' toggle if value is 0xff breq notone sbic PINA, 6 ;skip if PINA6 is low rjmp setlo1 ;if not low, jump to set low ldi butnum, 0b11000000 out PORTA, butnum ;set PIND6 to high rjmp load1 ;jump to load setlo1: ldi butnum, 0b10000000 out PORTA, butnum;set PIND6 to low load1: out TCNT2, r0 ;set timer reload to set freq out SREG, save notone: dec temp reti ;***** Delay n*64 microseconds using timer 0, delay time passed in timeout ; weird construction, interrupt is called like a subroutine delay: in save,SREG ;Save status register push save out TCNT0,timeout clt ;Clear T ldi save,TCK256 ;Timer 0 prescaler, CK / 256 out TCCR0,save ;Run timer dwait: brtc dwait ;Wait for timer 0 interrupt to set T pop save ;Restore status register out SREG,save ret ============================================= ; text data winsong: .db 0xb0, 0xff, 0x89, 0xff, 0x42, 0xff, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xff, 0x89, 0xff,0xb0,0xff,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0xff,0x4d,0xff,0x42,0xff,0x89,0x00 losesong: .db 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, 0x4c, 0x4c, 0xff, 0x42, 0xff, 0x2a, 0x2a, 0xff, 0x10, 0xff, 0x03, 0x03, 0xff, 0x01, 0xff, 0x10, 0x10, 0x10, 0x00 wrong: .db 0x75, 0x00 right: .db 0xc1, 0x00 message: .db 0x00, "robot", 0x00, "hamburger", 0x00, "store", 0x00, "hydroxide", 0x00, "smell", 0x00 .db "tower", 0x00, "hangman", 0x00, "super man",0x00, "cat", 0x00, "rain", 0x00, "dog", 0x00 .db "snow", 0x00, "significant", 0x00, "university", 0x00, "home run", 0x00, "computer", 0x00 .db "cornell", 0x00, "graduate", 0x00, "bake sale", 0x00, "curious", 0x00, "cat in the hat", 0x00 .db "brownie", 0x00, "hard drive", 0x00, "sunburn", 0x00, "barbecue", 0x00, "friends", 0x00 .db "football", 0x00, "children", 0x00, "die hard", 0x00, "talking heads", 0x00, "terminate", 0x00 .db "door", 0x00, "shirt", 0x00, "helping hands", 0x00, "america", 0x00, "paper doll", 0x00 .db "enter key", 0x00, "aggrivate", 0x00, "roof top", 0x00, "once upon a time", 0x00, "philadelphia", 0x00 .db "california", 0x00, "radio shack", 0x00, "happy birthday", 0x00, "new york", 0x00, "talk", 0x00 .db "hello world", 0x00, "one two three", 0x00, "microsoft sucks", 0x00, "macintosh sucks", 0x00 .db "bruce land", 0x00, "clarinet", 0x00, "trumpet", 0x00, "saxiphone", 0x00, "telephone", 0x00 .db "television", 0x00, "hollywood video", 0x00, "star wars", 0x00, "les miserables", 0x00, "broadway", 0x00 .db "hollywood", 0x00, "windowshade", 0x00, "cable", 0x00, "hair dryer", 0x00, "dishwasher", 0x00 .db "knight rider", 0x00, "ruloffs", 0x00, "clubhouse", 0x00, "chapter", 0x00, "indiana jones", 0x00 .db "cameron diaz", 0x00, "brooke shields", 0x00, "harrison ford", 0x00, "hangover", 0x00 .db "tequila sunrise", 0x00, "sex on a beach", 0x00, "sesame street", 0x00, "whiskey sour", 0x00 .db "teletubbies", 0x00, "butter", 0x00, "girl scouts",0x00,"star trek",0x00,"pentium",0x00 .db "nectarine",0x00,"tangerine",0x00,"photosynthesis",0x00,"black and white", 0x00, "black and blue", 0x00 .db "merry go round", 0x00, "snoop doggy dog", 0x00, "austin powers",0x00,"notebook",0x00,"psychedelic",0x00 .db "blue sky",0x00,"wheres the beef",0x00,"dominos",0x00,"pizza",0x00,"chinese takeout",0x00 .db "tortellini",0x00,"sunglasses",0x00,"neptune",0x00,"bathing suit",0x00,"beach ball",0x00, "volleyball", 0x00 .db "baseball",0x00,"basketball", 0x00, "hockey stick",0x00, "miss america",0x00,"engineering",0x00 .db "workbench",0x00,"capitalism",0x00,"democracy",0x00, "smart", 0x00, "goodbye", 0x00 |