//Receive Unit //refers to the following included speech files //Contains the packed 2-bit codes for syntehsis //Generated by the program Make2code476.m #define grillzillaSize 2110 #define yourMeatIsSize 4120 #define almostSize 1480+1480 #define notSize 1460+1480 #define doneSize 1480 //Includes #include #include #include<.\txrx.c> #include #include #include "grillzilla_8.h" #include "your_8.h" #include "almost_8.h" #include "not_8.h" #include "done_8.h" //LCD initialization #asm .equ __lcd_port=0x15 #endasm #include //definitions #define begin { #define end } #define MAX_RX_LENGTH 32 #define data_buffer 32 #define transmitThreshold 1000 #define stateMachineTrigger 125 #define ID 15 //state machine definitions for buttons #define NoPush 1 #define MaybePush 2 #define Pushed 3 #define MaybeNoPush 4 //state machine definitions for grilling #define Menu 1 #define Grilling 2 #define TimerMenu 6 //button definitions #define but1 16 #define but2 32 #define but3 64 #define but4 128 //if desired temp - current temp < THRESHTEMP //user is told the meat is almost done #define THRESHTEMP 7 //fixed point macros #define int2fix(a) (((int)(a))<<8) //Convert char to fix. a is a char #define fix2int(a) ((signed char)((a)>>8)) //Convert fix to char. a is an int #define divfix(a,b) ((int)((((long)(a))<<8)/((long)(b)))) //divide two fixed # #define float2fix(a) ((int)((a)*256.0)) //Convert float to fix. a is a float //function declarations void stateMachine(void); //run state machine for buttons and menu screens void LCDPrint(void); //prints lcd_buffer's on the led void menuPrint(void); //transfers main menu text to lcd_buffer's void grillPrint(void); //transfers grill menu text to lcd_buffer's void timerPrint(void); //transfers timer menu text to lcd_buffer's char my_rx_data[MAX_RX_LENGTH]; //buffer for received data unsigned char percent; //percent that the meat is done cooking unsigned int time; //keeps track of seconds for self timer and state machine //vars for receiver char k, current_line, last_replaced; //buffers for lcd display char lcd_buffer1[20]; // LCD display buffer char lcd_buffer2[20]; char lcd_buffer3[20]; char lcd_buffer4[20]; //IDs seen by receiver - for debugging char seen_ids[4]; //vars for state machines unsigned char stateMachineTime; unsigned int LEDTime; unsigned char ButState; unsigned int packetID; unsigned char grillState; unsigned char button; //vars for main menu unsigned char menuLine; char meats[6][8]={{"Beef"},{"Veal"},{"Lamb"},{"Pork"},{"Poultry"},{"Fish"}}; char preparation[3][8]= {{"M. Rare"},{"Medium"},{"W. Done"}}; char timerModes[2][4] = {{"N"},{"Y"}}; char range[8] = {"NoRange"}; unsigned char selectedMeat; unsigned char selectedPrep; unsigned char timerMode; unsigned int diff; //boolean flags to trigger speech phrases unsigned char speechFlag; unsigned char almostDoneFlag; unsigned char doneFlag; unsigned char speaking; // Cooking parameters // meatTemps[0] is beef, veal, and lamb // meatTemps[1] is pork // meatTemps[2] is chicken // meatTemps[3] is fish // ------------------------- // meatTemps[X][0] is Medium Rare // meatTemps[X][1] is Medium // meatTemps[X][2] is Well Done //grilling screen vars unsigned char meatTemps[4][3]; //unsigned char buttonFlag; unsigned char currentTemp; unsigned char desiredTemp; unsigned char packetNum; //timer set vars unsigned char m2, m1, s2, s1,h, cursorPos, timingFlag; //speech variables unsigned int outI, tableI; //indexes char out, lastout; //output values char cycle ; //decode phase counter unsigned int endI; //index to end on char packed ; //byte containing 4 2-bit values char p1, p2, p3, p4 ; //hold 4 differentials //reconstruction differentials //flash char PCMvalue[4] = {-78, -16, 16, 78}; flash char PCMvalue[4] = {-20, -4, 4, 20}; unsigned char phrase; unsigned char first; unsigned char almostDoneLock; unsigned char ms; //counts down fractions of a ms //Bruce Land's fast fixed point multiply routine //See instruct1.cit.cornell.edu/courses/ee476/Math/index.html int multfix(int a,int b) begin #asm ;****************************************************************************** ;* ;* FUNCTION ;* muls16x16_24 ;* DECRIPTION ;* Signed multiply of two 16bits numbers with 24bits result. ;* USAGE ;* r31:r30:rxx = r23:r22 * r21:r20 ;****************************************************************************** push r20 push r21 LDD R22,Y+2 ;load a LDD R23,Y+3 LD R20,Y ;load b LDD R21,Y+1 muls r23, r21 ; (signed)ah * (signed)bh mov r31, r0 ;r18, r0 mul r22, r20 ; al * bl mov r30, r1 ;movw r17:r16, r1:r0 ;mov r16, r0 mulsu r23, r20 ; (signed)ah * bl add r30, r0 ;r17, r0 adc r31, r1 ;r18, r1 mulsu r21, r22 ; (signed)bh * al add r30, r0 ;r17, r0 adc r31, r1 ;r18, r1 pop r21 pop r20 #endasm end interrupt [TIM0_OVF] void sgen(void) begin //if not speaking, keep track of time if (!speaking) begin // count down the ticks in a ms if (ms>0) --ms; else begin ms = 63; //if 1 ms has passed, increment time accordingly if(time < transmitThreshold) time++; if(stateMachineTime < stateMachineTrigger) stateMachineTime++; end end //else speak the phrase! else begin //compute next sample cycle = outI%4; if (cycle==0) //do we need to unpack more data? begin if (tableI>6; p2 = (packed & 48)>>4; p3 = (packed & 12)>>2; p4 = (packed & 3); tableI++ ; end //end unpack table entry //compute the output and send to PWM out = lastout + PCMvalue[p1] - lastout>>4 ; end else if (cycle==1) //don't need to unpack yet--just ouput begin out = lastout + PCMvalue[p2] - lastout>>4 ; end else if (cycle==2) begin out = lastout + PCMvalue[p3] - lastout>>4 ; end else if (cycle==3) begin out = lastout + PCMvalue[p4] - lastout>>4 ; end //update outputs OCR0 = out; lastout = out; outI++; //if end of phrase has been reached //either move to second half of phrase //or if (tableI==endI) begin //"grillzilla" phrase if (phrase==0 && !first) begin //set up timer 0 TIMSK=0x01; //turn on timer 0 overflow ISR TCCR0 = 0b00000001; //no prescaler speaking = 0; //speaking flag off //init menu Display and grilling state machine selectedMeat = 0; selectedPrep = 0; timerMode = 0; menuLine = 0; grillState = Menu; menuPrint(); //initialize beef, veal, and lamb temps meatTemps[0][0] = 145; meatTemps[0][1] = 160; meatTemps[0][2] = 170; //initialize pork temps meatTemps[1][0] = 160; meatTemps[1][1] = 160; meatTemps[1][2] = 170; //initialize chicken temps meatTemps[2][0] = 170; meatTemps[2][1] = 170; meatTemps[2][2] = 180; //initialize fish temps meatTemps[3][0] = 145; meatTemps[3][1] = 145; meatTemps[3][2] = 155; end //"your meat is not done" phrase completion else if (phrase==1 && first) begin outI = 0; lastout = 128; tableI = 0; endI = notSize; first--; end //"your meat is done" phrase completion else if (phrase==2 && first) begin outI = 0; lastout = 128; tableI = 0; endI = doneSize; first--; end //"your meat is almost done" phrase completion else if (phrase==3 && first) begin outI = 0; lastout = 128; tableI = 0; endI = almostSize; first--; end //phrase complete - go back to menus else begin //set up timer 0 TIMSK=1; //turn on timer 0 cmp match ISR TCCR0=0b00000001; //if "done" turn off the done flag and back to the menu! if (phrase==2) begin grillState = Menu; menuPrint(); doneFlag = 0; end // almost done, stay in the menu if (phrase==3) begin grillState = Grilling; almostDoneFlag = 0; almostDoneLock = 1; end phrase = 0; speaking = 0; end end end end //********************************************************** //initialization void init() begin //Used for LED array, output DDRB = 0xff; PORTB = 0xff; //starting off //Used for pushbuttons, input DDRA = 0x00; PORTA = 0x00; //PORTD used for TX. //d7 led, d1 TX, d0,d2..6 unused DDRD = 0xff; PORTD.7=0; //turn d7 led on as power-on led //set up timer 0 TIMSK=0x01; //turn on timer 0 overflow ISR TCCR0=0b00000001; //no prescaler //LCD Setup, PORTC lcd_init(20); lcd_clear(); //TXRX init txrx_init(0,1,249,1);//RX only - 4000 baud - led on rx_reset(MAX_RX_LENGTH); //initialize variables seen_ids[0] = 0; seen_ids[1] = 0; seen_ids[2] = 0; seen_ids[3] = 0; time=0; percent=0; current_line=0; last_replaced=1; stateMachineTime = 0; ButState=NoPush; LEDTime = 0; menuLine = 0; cursorPos = 0; doneFlag = 0; almostDoneFlag = 0; speechFlag = 0; speaking = 0; first = 0; phrase = 0; almostDoneLock = 0; //set millisecond var for countdown ms = 63; #asm ("sei"); //Initialization Screen sprintf(lcd_buffer1, " Grillzilla! "); sprintf(lcd_buffer2, " ECE476 Spring 06 "); sprintf(lcd_buffer3, " Matt Bertenthal "); sprintf(lcd_buffer4, " Jeff Guido "); LCDPrint(); //delay_ms(500); //make the chip say GRILLZILLA!!! //make sure state machine and lcd is stopped! // turn on pwm with period= 256*8 cycles = 2048 cycles // (7812 samples/sec) in fast PWM mode. // turn on timer0 overflow ISR to update once per PWM cycle TIMSK = 0b00000001; TCNT0 = 0; OCR0 = 128; TCCR0 = 0b01101010 ; outI = 0; tableI = 0; //init the ouptut value lastout = 128; phrase = 0; speechFlag = 1; endI = grillzillaSize; end //********************************************************** void main() { init(); while(1) { //parse transmission data when not on grilling screen or speaking if(rxdone()==1 && grillState==Grilling && !speaking && !speechFlag) { k=0; init_getrx(); while(rx_empty()!=1) { my_rx_data[k] = get_next_rx_data(); k++; } // 0 - 170 // 1 - start_char // 2 - ID // 3 - length // 4 - number // 5 to x - payload rx_reset(MAX_RX_LENGTH); //ID, length, and number display packetID = decodeOne(my_rx_data[2]); //debug info - transmission ID, Length, and packet number //sprintf(lcd_buffer1,"%-i %-i %-i", decodeOne(my_rx_data[2]), my_rx_data[3], my_rx_data[4]); //payload if (packetID == ID) currentTemp = my_rx_data[5]; else currentTemp = 0; //get packet number packetNum = my_rx_data[4]; } // Debug statements for button presses // if (buttonFlag && !speaking) sprintf(lcd_buffer3, "Button %d pressed!", buttonFlag); // else sprintf(lcd_buffer3, " "); // sprintf(lcd_buffer4, " "); //decrement time if self timing mode is and not speaking //print grilling screen if not speaking if(time==transmitThreshold && !speaking && !speechFlag) { time=0; PORTD.7 = 1; //count down the time accordingly if (timingFlag) begin if (s1==0) begin if (s2!=0) begin s2--; s1 = 9; end else begin if (m1!=0) begin m1--; s2 = 5; s1 = 9; end else begin if (m2!=0) begin m2--; m1 = 9; end else begin if (h!=0) begin h--; m2 = 5; m1 = 9; s2 = 5; s1 = 9; end else begin doneFlag = 1; end end end end end else s1--; end //print the grilling menu screen if (grillState==Grilling) grillPrint(); } //initialize microcontroller for speech if (speechFlag) begin //make sure state machine and lcd is stopped! speaking = 1; TIMSK = 0b00000001; //turn on pwm with period= 256*8 cycles = 2048 cycles // (7812 samples/sec) in fast PWM mode. //Turn on timer0 overflow ISR to update once per PWM cycle TCNT0 = 0; OCR0 = 128; TCCR0 = 0b01101010 ; outI = 0; tableI = 0; //init the ouptut value lastout = 128; if (almostDoneFlag) begin //make sound for meat being almost done endI = yourMeatIsSize; phrase = 3; first = 1; end else if (doneFlag) begin //make sound for meat being done endI = yourMeatIsSize; phrase = 2; first = 1; end else if (grillState==Grilling) begin //make sound to say meat is not done endI = yourMeatIsSize; phrase = 1; first = 1; end speechFlag = 0; end //run state machine for buttons and menus if not speaking if (stateMachineTime==stateMachineTrigger && !speaking && !speechFlag) begin stateMachineTime = 0; stateMachine(); end } //while } //main //state machine for buttons and menus void stateMachine(void) begin //determine what button has been pressed if ((~PINA & but1)==but1) button = 1; else if ((~PINA & but2)==but2) button = 2; else if ((~PINA & but3)==but3) button = 3; else if ((~PINA & but4)==but4) button = 4; else button = 0; //state machine to debounce buttons switch (ButState) begin case NoPush: if (button) begin ButState=MaybePush; end else ButState=NoPush; break; case MaybePush: if (button) begin ButState=Pushed; //buttonFlag=button; end else ButState=NoPush; break; case Pushed: if (button) ButState=Pushed; else ButState=MaybeNoPush; break; case MaybeNoPush: if (button) ButState=Pushed; else begin ButState=NoPush; //buttonFlag=0; end break; end //state machine for menus switch(grillState) begin //main menu case Menu: if (button==1) begin if (menuLine<2) menuLine++; else menuLine = 2; menuPrint(); end else if (button==2) begin if (menuLine > 0) menuLine--; else menuLine = 0; menuPrint(); end else if (button==3) begin if (menuLine==0) begin if (selectedMeat < 5) selectedMeat++; else selectedMeat = 0; end else if (menuLine==1) begin if (selectedPrep < 2) selectedPrep++; else selectedPrep = 0; end else if (menuLine==2) begin if (timerMode) timerMode = 0; else timerMode = 1; end menuPrint(); end else if (button==4) begin if (timerMode) begin grillState = TimerMenu; if (selectedMeat == 1 || selectedMeat == 2) desiredTemp = meatTemps[0][selectedPrep]; else if (selectedMeat>=3) desiredTemp = meatTemps[selectedMeat-2][selectedPrep]; else desiredTemp = meatTemps[0][selectedPrep]; timerPrint(); end else begin if (selectedMeat == 1 || selectedMeat == 2) desiredTemp = meatTemps[0][selectedPrep]; else if (selectedMeat>=3) desiredTemp = meatTemps[selectedMeat-2][selectedPrep]; else desiredTemp = meatTemps[0][selectedPrep]; grillState = Grilling; grillPrint(); end end else grillState = Menu; break; //grilling menu case Grilling: if (currentTemp>=desiredTemp) begin doneFlag = 1; speechFlag = 1; almostDoneFlag = 0; almostDoneLock = 0; end else if (((desiredTemp-currentTemp) <= THRESHTEMP) && !almostDoneLock) begin almostDoneFlag = 1; speechFlag = 1; doneFlag = 0; end else begin almostDoneFlag = 0; doneFlag = 0; end if (button==1) desiredTemp++; else if (button==2) desiredTemp--; else if (button==3) begin speechFlag = 1; end else if (button==4) begin grillState = Menu; menuPrint(); timingFlag = 0; h = 0; m2 = 0; m1 = 0; s2 = 0; s1 = 0; end else grillState = Grilling; break; //self timer settings menu case TimerMenu: if (button==1) begin if (cursorPos==0) cursorPos=2; else if (cursorPos==3) cursorPos = 5; else if (cursorPos==6) cursorPos = 6; else cursorPos++; timerPrint(); end else if (button==2) begin if (cursorPos==0) cursorPos=0; else if (cursorPos==2) cursorPos = 0; else if (cursorPos==5) cursorPos = 3; else cursorPos--; timerPrint(); end else if (button==3) begin if (cursorPos==0) begin if (h==9) h = 0; else h++; end else if (cursorPos==2) begin if (m2==5) m2=0; else m2++; end else if (cursorPos==3) begin if (m1==9) m1=0; else m1++; end else if (cursorPos==5) begin if (s2==5) s2=0; else s2++; end else if (cursorPos==6) begin if (s1==9) s1=0; else s1++; end timerPrint(); end else if (button==4) begin grillState = Grilling; grillPrint(); timingFlag = 1; end else grillState = TimerMenu; break; end end //print lcd screen void LCDPrint(void) begin lcd_gotoxy(0,0); lcd_putsf(" "); lcd_gotoxy(0,0); lcd_puts(lcd_buffer1); lcd_gotoxy(0,1); lcd_putsf(" "); lcd_gotoxy(0,1); lcd_puts(lcd_buffer2); lcd_gotoxy(0,2); lcd_putsf(" "); lcd_gotoxy(0,2); lcd_puts(lcd_buffer3); lcd_gotoxy(0,3); lcd_putsf(" "); lcd_gotoxy(0,3); lcd_puts(lcd_buffer4); end //print main menu void menuPrint(void) begin //turn off the cursor _lcd_ready(); _lcd_write_data(0b1100); sprintf(lcd_buffer1, " Select Meat:%s",meats[selectedMeat] ); sprintf(lcd_buffer2, " Prepatation:%s", preparation[selectedPrep]); sprintf(lcd_buffer3, " Self Timer Mode:%s", timerModes[timerMode]); sprintf(lcd_buffer4, "U:1 D:2 Sel:3 Nxt:4"); LCDPrint(); lcd_gotoxy(0,menuLine); lcd_putchar(0x7E); end //print grilling screen void grillPrint(void) begin //set this to time or progress depending on mode char progString[8]; //turn off the cursor _lcd_ready(); _lcd_write_data(0b1100); if (!timerMode && !doneFlag) begin if (currentTemp > 75) begin diff = float2fix(((float)(currentTemp)/(desiredTemp))); percent = fix2int(multfix(diff,int2fix(100))); sprintf(progString, "%d%%",percent); end else sprintf(progString, "Undef."); end else sprintf(progString,"%d:%d%d:%d%d",h,m2,m1,s2,s1); if (doneFlag) sprintf(progString,"Done!"); sprintf(lcd_buffer1, "Desired Temp:%3d %3d", desiredTemp, packetNum); if (currentTemp==0) sprintf(lcd_buffer2, "Current Temp:%7s", range); else sprintf(lcd_buffer2, "Current Temp:%3d ", currentTemp); if (timerMode) sprintf(lcd_buffer3, "Meat:%7s Time: ", meats[selectedMeat]); else sprintf(lcd_buffer3, "Meat:%7s %% Done:", meats[selectedMeat]); sprintf(lcd_buffer4, "Prep:%7s %7s", preparation[selectedPrep], progString); LCDPrint(); end //print timing screen void timerPrint(void) begin sprintf(lcd_buffer1," Set Cooking Time: "); sprintf(lcd_buffer2," %d:%d%d:%d%d ",h,m2,m1,s2,s1); sprintf(lcd_buffer3," Left:1 Right:2 "); sprintf(lcd_buffer4,"Change:3 Grill!:4 "); LCDPrint(); //set cursor to digit in time that is being set lcd_gotoxy(cursorPos+6,1); //set the cursor to blink underneath the digit _lcd_ready(); _lcd_write_data(0xF); end