//sched2 modified to include NON-BLOCKING serial code //used as an example in the program organization doc. #include <90s8515.h> #include //for debugging using printf, etc //timeout values for each task #define t1 60 #define t2 250 #define t3 50 //I like these definitions #define begin { #define end } //timer 1 constants #define prescale1 1 #define clear_on_match 8 //the subroutines void task1(void); //test for button press void task2(void); //increment note to be played void task3(void); //check the serial line for commands void initialize(void); //all the usual mcu stuff unsigned char reload; //timer 0 reload to set 1 mSec unsigned char time1, time2, time3; //task scheduleing timeout counters unsigned char cmd_ready; //set when command is received unsigned char cmd; //'p'=play 's'=stop unsigned char note; //current note to be played... //task 1 sets note to 0 to start song //**************************************************** //table of periods for 1 cycle of each musical note in 1/4 microsec ticks // // note freq period in // Hz 1/4 microsec // // C4 262 15267 // D4 294 13605 // E4 330 12121 // F4 349 11461 // G4 392 10204 // A4 440 9090 // B4 494 8097 // C5 523 7648 // put the notes in flash to save RAM flash int notetable[8]={15267/2, 13605/2, 12121/2, 11461/2, 10204/2, 9090/2, 8097/2, 7648/2}; //********************************************************** //timer 0 overflow ISR interrupt [TIM0_OVF] void timer0_overflow(void) begin //reload to force 1 mSec overflow TCNT0=reload; //Decrement the three times if they are not already zero if (time1>0) --time1; if (time2>0) --time2; if (time3>0) --time3; end //********************************************************** //timer 1 compare-match A ISR interrupt [TIM1_COMPA] void cmpA_overflow(void) begin PORTC = ~PORTC ; //toggle the port to make a sound end //********************************************************** //Entry point and task scheduler loop void main(void) begin initialize(); //main task scheduler loop -- never exits! while(1) begin if (time1==0) task1(); if (time2==0) task2(); if (time3==0) task3(); end end //********************************************************** //Task 1 -- detect a pusbutton void task1(void) begin time1=t1; //reset the task timer //turn on the scale if (~PIND == 0x01 || (cmd_ready && cmd=='p') ) begin note=0; //check for button push or 'p' PORTB=0xfe; //turn on the LED cmd_ready=0; end //kill it if (~PIND == 0x02 || (cmd_ready && cmd=='s')) begin note=8; //check for button push or 's' TCCR1B = 0; //and turn off timer 1 PORTB=0xfd; //turn on the LED cmd_ready=0; end //LEDs off if (~PIND == 0x00) begin PORTB=0xff; //turn off the LEDs end end //********************************************************** //Task 2 -- detect start/end of scale and increment the note void task2(void) begin time2=t2; //reset the task timer if (note < 8) //play a note? or are we done? begin TCNT1=0; OCR1A=notetable[note]; //and load the correct time out for timer 1 ++note ; //play the next note when task 2 enters again TCCR1B = prescale1 + clear_on_match ; //start timer 2 end else TCCR1B=0; //turn off timer 1 end //********************************************************** //Task 3 -- non-blocking keyboard check every 50 mSec void task3(void) begin time3=t3; if (USR.7) //RX done bit begin cmd=getchar(); putchar(cmd); putsf("\r\n"); cmd_ready=1; end end //********************************************************** //Set it all up void initialize(void) begin //set up the ports DDRD=0x00; // PORT D is an input DDRC=0xff; // PORT C is an ouput DDRB=0xff; //PORT B is an output for leds PORTC=0; PORTB=0xff; //all LEDs off //serial setop for debugging using printf, etc. UCR = 0x10 + 0x08 ; UBRR = 25 ; //set up timer 0 //62.5 x (64x.25) microSec = 1.0 mSec, so prescale 64, and count 62 times. reload=256-62; //value for 1 Msec TCNT0=reload; //preload timer 1 so that is interrupts after 1 mSec. TCCR0=3; //prescalar to 64 TIMSK=2; //turn on timer 0 overflow ISR //set up timer 1 TIMSK=TIMSK | 0x40; //turn on timer 1 compare match interrupt TCCR1B = 0; //disable timer 1 until song starts TCNT1 = 0; //and zero the timer //init the task timers time1=t1; time2=t2; //init the current note 8 => all done //song starts when task 1 sets note to 0 note=8; //crank up the ISRs #asm sei #endasm end