di3011.txt ;******************************************************************************************************* ; ; LISTING 1 - MOTOR-CONTROL C LISTING ; ; "AVR microcontroller makes improved motor controller," EDN, October 17, 2002, pg 98 ; ;******************************************************************************************************* #include #include #include unsigned char c17; //Used to indicate the present direction of motion. unsigned short s23; //Used to hold the 16 bit Timer 1 count. SIGNAL(SIG_INTERRUPT4) { volatile unsigned char ptr; unsigned char lower_byte; unsigned char upper_byte; lower_byte = 0; //Clear bytes in anticipation of receiving upper_byte = 0; //new data. c17 |= 0x04; //Set global for control is with receiver. ptr = inp(EICR); //Get present state of EICR. if ((ptr & 0x01) == 0) //If falling edge capture enabled, then ... { c17 |= 0x08; //Indicate arithmetic operation can proceed lower_byte = inp(TCNT1L); //Move low part of count to low byte. upper_byte = inp(TCNT1H); //Move high part to high byte. s23 = upper_byte; //Create 16 bit word that represents period s23 <<= 8; //of pulse. s23 += lower_byte; } else //If rising edge capture enabled, then ... { c17 &= 0xF7; //Indicate arithmetic operation should wait outp(0,TCNT1H); //Reset timer counter register. outp(0,TCNT1L); //When writing to 16 bit timer, must write } //to upper register first. ptr = inp(EICR); //Change state of last bit of EICR ptr ^= 1; //in order to be able to trap on the outp(ptr,EICR); //opposite edge. } int initialize(void); int receiver_cntrl(void); int main(void) { initialize(); //Call initialize in order to set //up registers and peripherals. s23 = 0; //Initialize useful variables, c17 = 0; //some that are global and some //that are local to main. while (1) { receiver_cntrl(); } } int initialize(void) { //Timer 0 Setup Code outp(0x61,TCCR0); //No prescale to clk, enable PWM, clear PWM output outp(0,OCR0); //Set output compare register to 0. outp(0,TCNT0); //Set timer counter to 0. //Timer 1 Setup Code outp(0,TCCR1A); //Set clk source as clk/8, compare timer to overflow outp(0x0A, TCCR1B); //Set output compare register to 0xFF00. outp(0xFF, OCR1AH); //Not used, however. outp(0,OCR1AL); //Set output compare register to 0. outp(0,TCNT1H); //Set timer 1 counter to 0. outp(0,TCNT1L); outp(0x10,TIMSK); //Enable timer overflow interrupt. //Timer 2 Setup Code outp(0x61,TCCR2); //No prescale to clk, enable PWM, clear PWM output outp(0,OCR2); //Set output compare register to 0. outp(0,TCNT2); //Set timer counter to 0. //External Interrupts Setup Code outp(0x10,EIMSK); //Enable interrupts for externals 0 through 4. outp(0x03,EICR); //The rising edge between two samples of INT4 //generates an interrupt. outp(0x80,ACSR); //Disable comparator. //Port B Setup Code outp(0xff,DDRB); //Set initial direction of port pins to output. outp(0,PORTB); //Set initial state of pins. //Port D Setup Code outp(0x0,DDRD); //Set initial direction of port pins to input. outp(0xff,PORTD); //Set initial state of pins. //Port E Setup Code outp(0,DDRE); //Set initial direction of port pins to input. outp(0,PORTE); //Set initial state of pins. sei(); //Globally enable all active interrupts. return(0); } int receiver_cntrl(void) { volatile unsigned char ptr; c17 &= 0xF7; //Enable receiver mode s23 -= 0x01EE; //Set up map range if ((s23 >= 0xF0) && (s23 <= 0x110)) //See if s23 is in the deadband. { //If so, then stop the motor. ptr = inp(PORTB); //Get present state of output drivers. ptr &= 0xDB; //Block movement by setting PB:2 and PB:5 to 0 outp(ptr,PORTB); //Update state of driver. outp(0,OCR0); //Set PWM0 to 0% disabling forward. outp(0,OCR2); //Set PWM2 to 0% disabling reverse. c17 &= 0xFC; //Modify global to indicate direction is stop. } else if ((s23 > 0x110) && (s23 <= 0x1FF)) //See if s23 is in fwd range { //If so, then proceed with fwd. if ((c17 | 0xFD) == 0xFD) //If global indicates present { //direction is not reverse. then ... outp(0,OCR2); //Block reverse by shutting down PWM2. ptr = inp(PORTB); //Get present value of port B. ptr &= 0xDF; //Stop reverse by setting driver to 0. outp(ptr, PORTB); //Update value of port B. ptr = (volatile unsigned char)s23; //Assign movement to ptr. outp(ptr, OCR0); //Assign PWM to new movement value. ptr = inp(PORTB); //Get present state of port B. ptr |= 0x04; //Indicate that the direction is forward. outp(ptr,PORTB); //Update the value of the port. c17 |= 0x01; //Set global bit to indicate forward. c17 &= 0xFD; //Set global bit to not indicate reverse. } } else if ((s23 >= 0) && (s23 < 0xF0)) //See if s23 is in rev range { //If so, then proceed with rev. if ((c17 | 0xFE) == 0xFE) //If global indicates present { //direction is not forward, then ... outp(0,OCR0); //Block forward by shutting down PWM0. ptr = inp(PORTB); //Get present value of port B. ptr &= 0xFB; //Stop forward by setting driver to 0. outp(ptr,PORTB); //Update value of port B. ptr = -(volatile unsigned char)s23;//Assign movement to ptr. outp(ptr, OCR2); //Assign PWM to new movement value. ptr = inp(PORTB); //Get present state of port B. ptr |= 0x20; //Indicate that the direction is forward. outp(ptr,PORTB); //Update the value of the port. c17 |= 0x02; //Set global bit to indicate reverse. c17 &= 0xFE; //Set global bit to not indicate reverse. } } return(0); }