7Khz hört man halt - aber als Nachteil finde ich das nicht. Ich fänd's cool, wenn er proportional zur Geschwindigkeit brummen tät. Irgendwas mit Prescaler 64 und Fast PWM oder so..Bei meiner 10 bit Variante hört man die Motoren manchmal leise piepsen
Code:/********************************************************************* N I B O B E E Feste Zykluszeit für Mainloop und zyklische (Sensor) Ein- und (LED) Ausgabe Version 1.07 für alternative Nibobee C Bib von s.frings 20100411 Birger Töpelmann *********************************************************************/ #ifndef _ZYKLUS_H_ #define _ZYKLUS_H_ // Folgende Zeile auskommentieren für "normalen" NiboBee #define _LED6_MUX_ // 6 LEDs an PB0..PB2; PB3 ist frei /*-------------------------------------------------------------------- - PB2 -|100R|-->(x) es leuchtet pro Takt immer nur eine LED; - PB1 -|100R|-->(y) ein PIN ist Plus, ein PIN Minus, ein Pin offen - PB0 -|100R|-->(z) LED (Vor-)Widerstand 2 x 100R LED_Pattern Bit Anode - Kathode DDRB PORTB 0 DUO links grün (y) - (z) ..110 ..010 1 DUO links rot (x) - (z) ..101 ..001 2 DUO rechts grün (z) - (y) ..110 ..100 3 DUO rechts rot (x) - (y) ..011 ..001 4 ROTAUGE links (z) - (x) ..011 ..010 5 ROTAUGE rechts (y) - (x) ..101 ..100 Zuordnung LED_Pattern Bit# und LED anpassbar in led_ausgabe(): case 0:{ ddr = 0x06; pin = 0x02;} break; // DUO links grün case 1:{ ddr = 0x05; pin = 0x01;} break; // DUO links rot case 2:{ ddr = 0x06; pin = 0x04;} break; // DUO rechts grün case 3:{ ddr = 0x03; pin = 0x01;} break; // DUO rechts rot case 4:{ ddr = 0x03; pin = 0x02;} break; // ROTAUGE links case 5:{ ddr = 0x05; pin = 0x04;} break; // ROTAUGE rechts --------------------------------------------------------------------*/ //#include "nibobee.h" // s.frings Bibliothek #include "zyklus.h" // also includes "nibobee.h" #include <stdio.h> #include <avr/interrupt.h> #include <util/atomic.h> #include <util/delay.h> /******************************************* ZYKLUS & CLOCK ***********/ // zählt bis 1000 (1s) in 1ms Schritten volatile uint16_t takt_ms; // zählt die Sekunden seit dem Systemstart volatile uint32_t takt_sec; // Zyklustimer wird in ISR inkrementiert und in Zyklus() volatile uint8_t zyklus_ms; // überwacht und genullt // bremst die Hauptschleife auf feste Zykluszeit (Zzeit in ms) // organisert LED Ausgabe und Sensoren Eingabe mit Flankenerkennung uint8_t Zyklus(uint8_t Zzeit); /****************************************** Sensoren ******************/ volatile uint8_t Sensors; // Aktueller Eingabestatus volatile uint8_t SensSFL; // Steigende Flanke erkannt volatile uint8_t SensFFL; // Fallende Flanke erkannt /*--------------------------------------------------------------------- Flankenerkennung (Trigger): 0101 Bitmuster vorher 0011 Bitmuster aktuell 0010 Bitmuster steigende Flanke 0100 Bitmuster fallende Flanke ----------------------------------------------------------------------*/ void sens_eingabe(); // SensorPins lesen/Flankenerkennung #define SENS_SW1_1 readBit(Sensors,4) #define SENS_SW2_1 readBit(Sensors,5) #define SENS_SW3_1 readBit(Sensors,7) #define SENS_SW4_1 readBit(Sensors,6) #define SENS_SW1_S readBit(SensSFL,4) #define SENS_SW2_S readBit(SensSFL,5) #define SENS_SW3_S readBit(SensSFL,7) #define SENS_SW4_S readBit(SensSFL,6) #define SENS_SW1_F readBit(SensFFL,4) #define SENS_SW2_F readBit(SensFFL,5) #define SENS_SW3_F readBit(SensFFL,7) #define SENS_SW4_F readBit(SensFFL,6) /***************************************** LED MULTIPLEX **************/ volatile uint8_t LED_Pattern; // LED Ausgabemuster volatile uint8_t LED_PattSFL; volatile uint8_t LED_PattFFL; volatile uint8_t LED_Blinker; // gesetztes Bit lässt LED blinken #ifdef _LED6_MUX_ // umgebauter NiboBee // Kompatibilität zu s.frings: entsprechendes Bit in Pattern setzen #define set_LED0(value) writeBit(LED_Pattern,1,value) #define set_LED1(value) writeBit(LED_Pattern,4,value) #define set_LED2(value) writeBit(LED_Pattern,5,value) #define set_LED3(value) writeBit(LED_Pattern,3,value) // Returns 1, if the LED is on #define LED0 readBit(LED_Pattern,1) #define LED1 readBit(LED_Pattern,4) #define LED2 readBit(LED_Pattern,5) #define LED3 readBit(LED_Pattern,3) #else // normaler NiboBee // Kompatibilität zu s.frings: entsprechendes Bit in Pattern setzen #define set_LED0(value) writeBit(LED_Pattern,0,value) #define set_LED1(value) writeBit(LED_Pattern,1,value) #define set_LED2(value) writeBit(LED_Pattern,2,value) #define set_LED3(value) writeBit(LED_Pattern,3,value) // Returns 1, if the LED is on #define LED0 readBit(LED_Pattern,0) #define LED1 readBit(LED_Pattern,1) #define LED2 readBit(LED_Pattern,2) #define LED3 readBit(LED_Pattern,3) #endif //_LED6_MUX_ // meine LED Makros basieren auf LED Nummer #define LED_EIN(NR) LED_Pattern |= (1 << NR); #define LED_AUS(NR) LED_Pattern &= ~(1 << NR); LED_Blinker &= ~(1 << NR); #define LED_BLINK(NR) LED_Pattern |= (1 << NR); LED_Blinker |= (1 << NR); #define LED_TOGGLE(NR) LED_Pattern ^= (1 << NR); void led_ausgabe(); // LED Multiplex Ausgabe // Debughilfen: vordere LED links/rechts bei ea==0 aus-, // sonst einschalten, !! schaltet jew. die andere LED aus void augeL(uint8_t ea); void augeR(uint8_t ea); /***************************************** LED MULTIPLEX **************/ #endif // _ZYKLUS_H_
Und soweit bin ich bisher mit der Main() von s.frings gekommen: hier sind noch etliche Anpassungen nötig; _delay_ms(), while{} oder blockierende Funktionen sind eigentlich No Gos. Aber ich verspreche mir davon, dass mehrere "prozesse" quasi gleichzeitig bearbeitet werden können.Code:/********************************************************************* N I B O B E E Feste Zykluszeit für Mainloop und zyklische (Sensor) Ein- und (LED) Ausgabe Version 1.07 für alternative Nibobee C Bib von s.frings 20100411 Birger Töpelmann *********************************************************************/ #include "zyklus.h" #include <stdio.h> #include <avr/interrupt.h> #include <util/atomic.h> #include <util/delay.h> /***************************************** CLOCK & MOTPID ***********/ volatile uint16_t takt_ms; volatile uint32_t takt_sec; //#define Zykluszeit 1 // Zykluszeit der Hauptschleife in ms volatile uint8_t zyklus_ms; // Zyklustimer wird in ISR inkrementiert // und in Zyklus() überwacht und genullt /************************************************* SENS *************/ volatile uint8_t Sensors = 0; // Aktueller Eingabestatus volatile uint8_t SensSFL = 0; // Steigende Flanke erkannt volatile uint8_t SensFFL = 0; // Fallende Flanke erkannt void sens_eingabe() { SensSFL = ~Sensors; // vorherigen Zustand merken für Flankenerkennung SensFFL = Sensors; Sensors ^= Sensors; // bits nullen für neuen Zustand Sensors |= ~(PINC & 0xf0); // 1 == Sensor aktiv // Hier Eingänge von Ext-Ports Pins verOdern SensSFL &= Sensors; // Steigende Flanke erkennen SensFFL &= ~Sensors; // Fallende Flanke erkennen } /************************************************* LED **************/ /* #define LED_EIN(NR) LED_Pattern |= (1 << NR); #define LED_AUS(NR) LED_Pattern &= ~(1 << NR); LED_Blinker &= ~(1 << NR); #define LED_BLINK(NR) LED_Pattern |= (1 << NR); LED_Blinker |= (1 << NR); #define LED_TOGGLE(NR) LED_Pattern ^= (1 << NR); */ volatile uint8_t LED_Pattern = 0; volatile uint8_t LED_Blinker = 0; void led_ausgabe() { static uint16_t tmux = 0; if (0 == tmux--) tmux = 640; // !Wert = vielfaches von 8 uint8_t leds = LED_Pattern; // Pattern für Ausgabe if (tmux < 400) leds &= ~LED_Blinker; // Blinkbits #ifdef _LED6_MUX_ // umgebauter NiboBee uint8_t ddr = 0; uint8_t pin = 0; if ((1 << (tmux & 0x07)) & leds) // welche LED soll leuchten? { switch((tmux & 0x07)) { case 0:{ ddr = 0x06; pin = 0x02;} break; // DUO links grün case 1:{ ddr = 0x05; pin = 0x01;} break; // DUO links rot case 2:{ ddr = 0x06; pin = 0x04;} break; // DUO rechts grün case 3:{ ddr = 0x03; pin = 0x01;} break; // DUO rechts rot case 4:{ ddr = 0x03; pin = 0x02;} break; // ROTAUGE links case 5:{ ddr = 0x05; pin = 0x04;} break; // ROTAUGE rechts // case 6:{ ddr = 0x00; pin = 0x00;} break; // case 7:{ ddr = 0x00; pin = 0x00;} break; } } DDRB = (DDRB & ~0x07) | ddr; // zwei PINS als Ausgang PORTB = (PORTB & ~0x07) | pin; // ein Pin = 1, Rest = 0 #else // nicht umgebauter NiboBee // Auch hier wird immer nur eine LED eingeschaltet // 1 * Zykluszeit Ein; 3 * Zykluszeit Aus PORTB = (PORTB & ~0x0f) | (leds & (1 << (tmux & 3))); #endif //_LED6_MUX_ } /* // Debughilfen void augeL(uint8_t ea) { uint8_t ddr = 0; uint8_t pin = 0; if(ea){ ddr = 0x03; pin = 0x02;} // ROTAUGE links DDRB = (DDRB & ~0x07) | ddr; // zwei PINS als Ausgang PORTB = (PORTB & ~0x07) | pin; // ein Pin = 1, Rest = 0 } void augeR(uint8_t ea) { uint8_t ddr = 0; uint8_t pin = 0; if(ea){ ddr = 0x05; pin = 0x04;} // ROTAUGE rechts DDRB = (DDRB & ~0x07) | ddr; // zwei PINS als Ausgang PORTB = (PORTB & ~0x07) | pin; // ein Pin = 1, Rest = 0 } */ /******************************* TIMER 1 CONFIG PWM & TAKT **********/ // s.frings setup: // Initialize the motor PWM // Mode 2 = phase correct 10 bit PWM, // channel A+B outputs are set on compare match when upcounting // and cleared on compare match when downcounting. // TCCR1A = PWM invertiert + + 10bit PWM Betrieb // TCCR1A = (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11); | (1<<WGM10); // Original nibobee (springob) setup // TCCR1A = PWM invertiert + + 9bit PWM Betrieb // TCCR1A = (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11); // Use I/O clock without prescaling // TCCR1B = (1<<CS10); // Overflow Interrupt enable // TIMSK |= (1<<TOIE1); // F_CPU = 15 Mhz // Prescale = 1 // Frequenz bei 10 bit 15000000/(2*1023)= 7.331 kHz ; OVF alle 136 uS // Frequenz bei 9 bit 15000000/(2* 511)=14.677 kHz ; OVF alle 68 uS #define T1PERIODE 136 // Periodendauer zwischen Overflows in uS /************************************* TIMER 1 OVERFLOW ISR **********/ ISR(TIMER1_OVF_vect) { static uint16_t takt_us=0; takt_us += T1PERIODE; if (takt_us >= 1000) { takt_us -= 1000; takt_ms++; zyklus_ms++; } if (takt_ms >= 1000) { takt_ms -= 1000; takt_sec++; } } /**************************************** ZYKLUS & WATCHDOG **********/ uint8_t Zyklus(uint8_t Zzeit) { if(Zzeit == 0) // Zyklustimer Reset / Init { // Timer 1 Overflow Interrupt freigeben, damit die Uhr tickt #ifdef TIMSK1 // ATmega644 TIMSK1 |= (1<<TOIE1); #else // ATmega16 TIMSK |= (1<<TOIE1); #endif zyklus_ms = 0; return(0); } sei(); // Interrupts freigeben led_ausgabe(); // Ausgänge aktualisieren uint8_t zms = zyklus_ms; // aktuelle Zykluszeit merken while(zyklus_ms < Zzeit){}; // Zykluszeit abwarten sens_eingabe(); // Eingänge lesen // -------------------- WATCHDOG --------------------------- // es wird kein Reset/Neustart ausgelöst -> Endlosschleife // LED blinken im Binär Muster der erfassten Zykluszeit if(zyklus_ms > Zzeit) // Zykluszeit überschritten ? { uint8_t zyt = 0; // alternativ Zyklustimer (Blinken) if (zms > 15) zms = 15; // Zykluszeit >= 15 -> alle LED ein while(1==1) // Fehlerfalle Zykluszeit überschritten { _delay_ms(10); // Klassische Verzögerung if(zyt-- == 0) zyt = 70;// Blinktakt 700ms if(zyt > 50) { LED_Pattern = zms; // Ist-Zykluszeit Binär ausgeben } else { LED_Pattern = 0; // LED aus für Blinklicht } led_ausgabe(); // LED Muster am Port ausgeben } }//-------------------------------------------------------- else zyklus_ms = 0; // Zykluszeit Timer Reset return(zms); // Interessant bei Zykluszeit > 1: // Wie lang war der Zyklus tatsächlich }
Oder ich weiß nicht - liege ich mit meiner Vorstellung einer Controllerprogrammierung total daneben? Dann geb' ich's auf und bastel mir 'ne Logo oder zwei auf Räder...Code:/********************************************************************* N I B O B E E Projekt Alternative s.frings und Birger.T zum Selberbasteln und Ändern Ver.20100411 *********************************************************************/ #define Zykluszeit 1 // Hauptschleife Zykluszeit in ms #define USE_SERIAL 0 #include "nibobee.h" #include "zyklus.h" uint16_t previousSpeed; // Display battery status on the 4 led's // LED0 = >4.1V // LED1 = >4.3V // LED2 = >4.5V // LED3 = >4.7V void battery_check() { set_AREF(REF_256); for (uint8_t i=0; i<10; i++) { // _delay_ms(50); for (uint8_t t=0; t<50; t++) { _delay_ms(1); led_ausgabe(); } set_LED0(analog(VBAT)>(410*2)); set_LED1(analog(VBAT)>(430*2)); set_LED2(analog(VBAT)>(450*2)); set_LED3(analog(VBAT)>(470*2)); // _delay_ms(50); for (uint8_t t=0; t<50; t++) { _delay_ms(1); led_ausgabe(); } set_LED0(0); set_LED1(0); set_LED2(0); set_LED3(0); } set_AREF(REF_VCC); _delay_ms(50); } // Wait for start signal (touch any sensor) // While waiting, display debug information from sensors: // LED0: Left odometer sensor // LED3: Right odometer sensor // LED1: System timer // LED2: Center line sensor void wait_for_start() { while (!(SENS_SW1 || SENS_SW2 || SENS_SW3 || SENS_SW4)) { // Display status of odometry sensors while waiting set_LED0(ODO_L); set_LED3(ODO_R); // Display system timer (flashes every second) set_LED1((system_time() % 1000) < 20); // Display line sensor set_LED2(analog(LINE_C)>600); _delay_ms(1); led_ausgabe(); } set_LED0(0); set_LED3(0); _delay_ms(10); while ((SENS_SW1 || SENS_SW2 || SENS_SW3 || SENS_SW4)) {} _delay_ms(400); } #define FORWARD 1 #define BACKWARD 0 volatile uint8_t running = 0; // Drive forward or backward. // Accellerate or decellerate softly to the maxSpeed. // The distance is measured in 1/20 wheel rotations. // LED0 or LED3 light if a which motor runs too fast. uint8_t drive(uint8_t direction, uint16_t distance, uint16_t maxSpeed) { static uint16_t speed= 0; static uint32_t lastTime=0; if(!running){ if (direction) { set_DIR_L(1); set_DIR_R(0); } else { set_DIR_L(0); set_DIR_R(1); } // Start with the previous speed // uint16_t speed=previousSpeed; // uint32_t lastTime=system_time(); speed=previousSpeed; lastTime=system_time(); reset_odometer(); running = 1; } // while (odometer_left()<distance || odometer_right()<distance) { if(!(odometer_left()<distance || odometer_right()<distance)) running = 0; // Ziel erreicht else{ int16_t diff=odometer_left()-odometer_right(); // If left motor is too fast if (diff>0) { set_LED0(1); PWM_L=speed/2; PWM_R=speed; } // If right motor is too fast else if (diff<0) { set_LED3(1); PWM_R=speed/2; PWM_L=speed; } // Speed of both motors is equal else { set_LED0(0); set_LED3(0); PWM_L=speed; PWM_R=speed; } // If a millisecond has elapsed, increase or decrease the speed // a little until the maxSpeed has been reached. uint32_t currentTime=system_time(); if (currentTime>lastTime) { if (speed<maxSpeed) speed++; else if (speed>maxSpeed) speed--; lastTime=currentTime; } } // vom while previousSpeed=speed; return(running); } // Stop driving. void stop() { PWM_L=0; PWM_R=0; previousSpeed=0; running = 0; } // Main program int main() { uint8_t tour = 0; // Merker für den Fahrtabschnitt uint16_t warten = 0; // nibobee_init(); // Display battery status battery_check(); // Wait for a start signal before start driving wait_for_start(); // Drive forward and backward repeatedly, to demonstrate // that the drive() function keeps straight on properly. Zyklus(0); //Zyklustimer Reset / Init while(1) { // deactivate_output_bit(IO_LINE_EN); // Front IR Leds aus writeBit(PORTB,PB5,0); Zyklus(Zykluszeit); // Zykluszeit abwarten // activate_output_bit(IO_LINE_EN); // Front IR LEDs blitzen im Zyklustakt für // Zeitmessung per IR Transistor und Oszi writeBit(PORTB,PB5,1); // Kollision (oder an die Fühler getippt) = Stop if(SENS_SW2_S || SENS_SW3_S) { tour = 100; stop(); } // Neustart bei Sensor nach vorne tippen und loslassen if((tour == 100) && (SENS_SW1_F || SENS_SW4_F)) tour = 0; // Drive forward 2 meters, accellerating up to nearly maximum speed if((tour == 0) && !drive(FORWARD,2000/6,900)) tour = 10; // Drive forward 30cm, decellerating down to the minimum speed if((tour == 10) && !drive(FORWARD,300/6,200)){ stop(); tour = 20; warten = 500; } // _delay_ms(500); if((tour == 20) && !warten--) tour = 30; // Drive backward 2 meters, accellerating up to nearly maximum speed if((tour == 30) && !drive(BACKWARD,2000/6,900)) tour = 40; // Drive backward 30cm, decellerating down to the minimum speed if((tour == 40) && !drive(BACKWARD,300/6,200)) { stop(); tour = 50; warten = 500; } // _delay_ms(500); if((tour == 50) && !warten--) tour = 0; } return 0; }![]()
Eigentlich wollte ich noch ein Foto machen: Meine Erfahrung LiPos halten so lange, bis man sie dann mal braucht.. bis zum WE.







Zitieren

Lesezeichen