Actions

AVR Code

From Just in Time

Revision as of 10:31, 1 April 2012 by Danny (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

<source lang="cpp"> /*

* pendule.c
*
*  Created on: 2 mrt. 2012
*      Author: Vincent
*/
  1. include <avr/io.h>
  2. include <util/delay.h>
  3. include <avr/interrupt.h>
  4. include <avr/wdt.h>
  5. include <avr/eeprom.h>
  1. define HALFSTEPS

//#define waitTime 43200 // 12 * 3600 //#define waitTime 43380 // 12 * 3600 + 3 * 60

  1. define waitTime 40

// define delays that are caused by mechanical construction // it takes about 30 seconds from starting the stop-action before the pendulum has actually stopped

  1. define stopDelay 30 // in seconds
  2. define startDelay 3 // in seconds
  1. define soft_reset() \

do \ { \

   wdt_enable(WDTO_15MS);  \
   for(;;)                 \
   {                       \
   }                       \

} while(0)


// Function Prototype to reset wdt on startup void wdt_init(void) __attribute__((naked)) __attribute__((section(".init3")));

// Function Implementation void wdt_init(void) {

   MCUSR = 0;
   wdt_disable();
   return;

}

volatile uint16_t secondsPassed; volatile uint8_t secondsPassedReset;

  1. define ORG (1<<PC2)
  2. define YEL (1<<PC3)
  3. define PIK (1<<PC4)
  4. define BLU (1<<PC5)
  1. define leftSwitch (1<<PD3)
  2. define rightSwitch (1<<PD2)
  3. define switchPort PIND
  1. define LEFT 1
  2. define RIGHT 2
  1. ifdef HALFSTEPS

#define almostStop 412 #define totalStop 160 #define stopSpeed 200

  1. else

#define almostStop 825 #define totalStop 350 #define stopSpeed 100

  1. endif
  1. define stepDelay 3

uint8_t steps[8];

uint8_t currentStep = 0; uint8_t side = 0; // 1 = left, 2 = right uint16_t stopWaitTime;

uint16_t totalSteps;

void clear_eeprom() { uint8_t *addr; for(uint16_t i=0;i<=E2END;i++) { addr = (uint8_t *)i; eeprom_write_byte(addr,0xff); } }

void write_eeprom(uint8_t oscVal) { uint8_t *addr; addr = (uint8_t *)0x1ff; eeprom_write_byte(addr,oscVal); }

void write_totalSteps() { uint16_t *addr; addr = (uint16_t *)0x1f0; eeprom_write_word(addr,totalSteps); }

uint8_t read_eeprom() { uint8_t *addr; addr = (uint8_t *)0x1ff; uint8_t tByte = eeprom_read_byte(addr); return(tByte); }

void checkSwitches() { if(!(PIND & rightSwitch) && !(PIND & leftSwitch)) { write_eeprom(side); soft_reset(); } }

void stepLeft() { currentStep++; currentStep = currentStep%8; PORTC = steps[currentStep]; _delay_ms(stepDelay); checkSwitches(); // PORTC = 0x00; }

void setSide(uint8_t sid) { side = sid; }

void stopStep() { PORTC = 0x00; }

void returnLeft() { while(PIND & leftSwitch) { stepLeft(); } stopStep(); side = LEFT; }

void stepRight() { currentStep--; currentStep = currentStep%8; PORTC = steps[currentStep]; _delay_ms(stepDelay); checkSwitches(); // PORTC = 0x00; }

void returnRight() { while(PIND & rightSwitch) { stepRight(); } stopStep(); side = RIGHT; }

void stopTime() { // this function stops the Pendulum if(side == LEFT) { for(uint16_t q=0;q<almostStop;q++) // bring to almostStop position from left side { stepRight(); } for(uint16_t q=0;q<totalStop;q++) { stepRight(); _delay_ms(stopSpeed); } returnLeft(); } if(side == RIGHT) { for(uint16_t q=0;q<almostStop;q++) // bring to almostStop position from right side { stepLeft(); } for(uint16_t q=0;q<totalStop;q++) { stepLeft(); _delay_ms(stopSpeed); } returnRight(); } }

void startTime() { // start the pendulum with stepper if(side == LEFT) { returnRight(); } else if(side == RIGHT) { returnLeft(); } }

void waitForSecondsPassedReset() { // wait until the ISR has reset the secondsPassed bool to avoid premature triggering while(!secondsPassedReset); secondsPassedReset = 0; }


void waitForStartTijd() { while(secondsPassed < waitTime - startDelay) { checkSwitches(); } waitForSecondsPassedReset(); // if the ISR hasn't reset the bool, the next phase would trigger immediately }

void waitForStopTijd() { while(secondsPassed < waitTime - stopDelay) { checkSwitches(); } waitForSecondsPassedReset(); // if the ISR hasn't reset the bool, the next phase would trigger immediately }

void test() { while(1) { returnLeft(); returnRight(); } }

void countSteps() { while(PIND & leftSwitch) { stepLeft(); } setSide(LEFT);

totalSteps = 0;

while(PIND & rightSwitch) { stepRight(); totalSteps++; } setSide(RIGHT);

write_totalSteps(); }

void defineSteps() {

  1. ifdef HALFSTEPS

steps[0] = ORG; steps[1] = YEL; steps[2] = PIK; steps[3] = BLU; steps[4] = ORG; steps[5] = YEL; steps[6] = PIK; steps[7] = BLU;

  1. else

steps[0] = ORG; steps[1] = ORG | YEL; steps[2] = YEL; steps[3] = YEL | PIK; steps[4] = PIK; steps[5] = PIK | BLU; steps[6] = BLU; steps[7] = BLU | ORG;

  1. endif

}

int main() { //define steps for stepper defineSteps(); // set DDR for blinkled on OC2A DDRB = (1 << PB3); // set output for stepper PORTC = 0; DDRC = (ORG | YEL | PIK | BLU);

// init timer atmega8

  1. ifdef _atmega8

TIMSK &= ~(1 << TOIE2); TIMSK &= ~(1 << OCIE2); ASSR |= (1 << AS2); // set async mode (crystal nodig) OCR2 = 31; // prescaler 1024 with OCR 32 is 1 interrupt per sec. TCNT2 = 0; // reset counter voor de zekerheid TCCR2 = (1 << WGM21) | (1 << COM20) | 7; // set in normal mode with prescaler 1024 // we turn on OCR2 toggle, to make it possible to have a led on the programming header while(ASSR & (1 << TCN2UB)); // wait voor TCN ready while(ASSR & (1 << OCR2UB)); // wait voor OCR ready while(ASSR & (1 << TCR2UB)); // wait voor TCR ready

TIFR = 0; // clear interrupt flags

// nu kunnen de interrupts aan.. TIMSK |= (1 << OCIE2); sei();

  1. else

// init timer atmega88 TIMSK2 &= ~(1 << TOIE2); TIMSK2 &= ~(1 << OCIE2A); ASSR |= (1 << AS2); // set async mode (crystal) OCR2A = 31; // prescaler 1024 with OCR 32 for 1 interrupt per sec. TCNT2 = 0; // reset counter TCCR2A = 0; TCCR2A = (1 << WGM21); // we turn on OCR2 toggle, to make it possible to have a led on the programming header TCCR2B = 7; // prescaler 256 while(ASSR & (1 << TCN2UB)); // wait voor TCN ready while(ASSR & (1 << OCR2AUB)); // wait voor OCR ready while(ASSR & (1 << TCR2AUB)); // wait voor TCR ready

TIFR2 = 0; // clear interrupt flags

// turn on interrupts TIMSK2 |= (1 << OCIE2A);

  1. endif

DDRD = 0x00; // set all D as inputs PORTD = 0xff; // pullups on

// test();

// check if both switches are pressed; this is a user reset // since in this case we can't determine which side the arm is we get the position from eeprom if(!(PIND & rightSwitch) && !(PIND & leftSwitch)) { side = read_eeprom(); } else { if(!(PIND & leftSwitch)) // arm is left in rest { side = LEFT; } if(!(PIND & rightSwitch)) // arm is right in rest { side = RIGHT; }

if(side == 0) // arm neither left nor right, turn to right rest position { returnRight(); } }


// startTime(); stopTime(); secondsPassed = 23; sei();

while(1) { waitForStartTijd(); startTime(); waitForStopTijd(); stopTime(); } }

ISR( TIMER2_COMPA_vect) { secondsPassed++; if(secondsPassed > waitTime) { secondsPassed = 1; secondsPassedReset = 1; } PORTB ^= (1 << PB3); //stub to check if interrupts work }

</source>