//Stimulator version 2.0 /* Pulse train: 1-255 pulses 0-4 sec pulse duration 0-4 sec pulse spacing 0-4 sec train repeat time 0-30 volt amplitude Pulse output is port D.3 Synch output is port D.4 Trigger is either manual or periodic Manual trigger is port D.2 timer 0 ISR generates pulse timing timer 1 generates PWM for amplitude control on pin OC1A (D.5) continuously so lowpass filter can average it main loop handles parameter setting and rs232 comm */ #include < 90s8515.h> #include < Stdio.h> #include < delay.h> #include < stdlib.h> #include < math.h> #define begin { #define end } //input parameters unsigned char num; //number of pulses unsigned int dur; //pulse duration unsigned long durL; //holds duration string for float convert unsigned int delay; //pulse spacing unsigned long delayL; //holds delay string unsigned int rep; //pulse train repeat time unsigned long repL; //holds repeat time string unsigned int amp; //pulse amplitude 0-255 //state variables unsigned int elapsedT; //running stimulus time unsigned int nextT; //next event time unsigned char mode; //manual or repeat 'm' or 'r' unsigned char pulseon; //state machine variable 1 or 0 unsigned char currentpulse;//current pulse num unsigned char starting; //indicates first time thru ISR unsigned char cmd; //serial command character float Conversion; //converts mSec to units of 64 microSec //#pragma savereg- //******************************************** //timer 0 overflow ISR interrupt [TIM0_OVF] void t0_overflow(void) begin //check for starting and emit synch pulse, reset time if (starting) begin PORTD.4 = 1; //start synch pulse output starting = 0; //on next ISR we won't be starting elapsedT = 0; //relative to pulse train start pulseon = 0; //starts in the off state nextT = delay; //next deadline time currentpulse = 0; //the pulse number PORTD.4 = 0; //end synch pulse end else //not starting begin elapsedT++; //all times are in 't0 ovfl tick units' //at end of pulse train: //check for manual mode and kill timer //otherwise set starting back to 1 for next train if (elapsedT == rep) begin PORTD.3 == 0; //kill the output pulse just in case if (mode == 'r') starting=1; //get ready to restart if (mode == 'm') TCCR0=0; //kill this ISR end else if (elapsedT == nextT) begin //have we putput all of the pulses? if (currentpulse < num) begin if (pulseon) begin //turn off the pulse pulseon = 0; PORTD.3 = 0; nextT = elapsedT + delay; end else begin //turn on the pulse pulseon = 1; PORTD.3 = 1; currentpulse++; //inc the pulse cout nextT = elapsedT + dur; end //pulseon else end else //(currentpulse==num) so the train is done begin PORTD.3 = 0; //kill the last pulse nextT = 0; //impossible time marker so next match is rep end end //if elapsedT end //else not starting end //ISR // //********************************************* //#pragma savereg+ void main(void) begin //serial comm setup (no interrupts) UCR = 0x18 ; UBRR = 51; //25 ; 4 MHz value //putsf("\rStimulator 2.0 copyright Cornell University\r"); //timer 0 setup TIMSK = 0x02 ; //Timer 0 ovfl enable TCCR0 = 0; //Timer 0 is off //timer 1 setup (rest of setup is in ISR) TCCR1B = 0; //Timer 1 is off //port D setup DDRD.2 = 0 ; //port D.2 is trigger input PORTD.2 = 1; //turn on D.2 internal pullup DDRD.5 = 1 ; //port D.5 is PWM output DDRD.3 = 1; //port D.3 is main pulse DDRD.4 = 1; //port D.4 is synch pulse //Convert 10*mSec to units of 64 microSec // 32 Conversion = 1000.0/32.0/10 ; // 1000.0/64.0/10 ; //turn on all interrupts #asm sei #endasm /*main event loop two events: serial command input --s stop --g go --p set parameters number,amplitude,dur,delay,rep --m set mode manual/repeat starting pushbutton in manual mode */ while(1) begin //if manual, check button D.2 for a trigger (active-low) if (mode=='m' && PIND.2==0) begin TCNT0=0; TCCR0=1; starting=1; //debounce the switch and wait for release delay_ms(50); while(PIND.2==0){}; delay_ms(50); end //pushbutton event //check USR for a valid character and get it if (USR.7==1) begin cmd=getchar(); switch (cmd) begin case 's': //to stop, terminate timer ISR and kill any output TCCR0 = 0; //turn off timer 0 PORTD.3 = 0; //and kill any leftover pulse break; case 'g': if (mode=='r') begin TCNT0=0; //zero the clock TCCR0=1; //and start it starting=1; //flag to tell ISR to start new pulse train end //putsf("running\r"); break; case 'p': //putsf("\r\n#, amp, dur, delay, rep\r") ; scanf("%d%d%d%d%d", &num, &, &durL, &delayL, &repL) ; //printf("%d%d%d%d%d\r\n", num,amp,durL,delayL,repL) ; //convert time units dur = floor(durL*Conversion+0.5); delay = floor(delayL*Conversion+0.5); rep = floor(repL*Conversion); OCR1A = 256-amp; //loads PWM duty cycle TCCR1B = 1; //turn on PWM TCCR1A = 0xc1; //8-bit, inverted PWM mode TCNT1 = 0; //start at zero to set phase break; case 'm': mode=getchar(); break; case 'r': mode=getchar(); break; end //switch end //if (USR==1) serial event handler end //while(1) end //main