-         

Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 25

Thema: NIBObee: Hier ist eine alternative C Library

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    19.03.2010
    Beiträge
    161

    NIBObee: Hier ist eine alternative C Library

    Anzeige

    Hallo Moderator: Kannst Du vielleicht für den NIBObee ein eigenes Unterforum anlegen?

    Ich hatte ein wenig Schwierigkeiten, die Quelltexte der originalen C Library zu verstehen. Da passieren einige Dinge, die mit unnötig aufwendig erscheinen, manches ist wohl auch etwas konfus umgesetzt.

    Zum Beispiel die PWM Steuerung: Wenn man die Fahrtrichtung ändert, wird der Motor zuerst gestoppt und erst beim nächsten Interrupt die neue Fahrtrichtung und Geschwindigkeit eingestellt. Das klingt ja erstmal sinnvoll, aber beim nächsten Interrupt steht der Motor noch lange nicht. Also muss man entweder viel länger warten oder man lässt es ganz bleiben.

    Irgendwie nervt mich auch, dass die eigentlich winzigen Funktionen über mehrere include-Files und mehrere (nicht gleich lautende) Libraries (*.a files) verstreut sind.

    Und ich vermisse, dass der serielle Port als standart Eingabe und Ausgabe für stdio.h eingerichtet wird, so dass Befehle wie fgets, puts, prinf, etc.funktionieren.

    Kurzum, ich habe meine eigene Library geschrieben. Sie ist kleiner, einfacher, und ganz sicher nicht weniger funktional. Ihr dürft sie gerne kopieren, ändern und benutzen.

    nibobee.h:
    Code:
    // This file contains macros, definitions and function to access the NIBObee
    // hardware.
    
    // Autor: Stefan Frings <stefan@meinemullemaus.de>
    // Date: 06.04.2010
    
    #ifndef _HARDWARE_H_
    #define _HARDWARE_H_
    
    #include <stdint.h>
    #include <avr/io.h>
    
    
    
    
    //===========================================================================
    // Serial port
    //===========================================================================
    // To enable use of the serial port as stdin and stdout, set four definitions
    // as compiler options in your Makefile:
    //
    // -DUSE_SERIAL=1 -DBAUD=115200 -DTERMINAL_MODE=1 -DSERIAL_ECHO=1
    //
    // To disable use of the serial port only one settings is required:
    //
    // -DUSE_SERIAL=0
    //
    // The terminal mode enables support for line breaks in old DOS format, which
    // is the default in most terminal programs.
    
    
    
    
    //===========================================================================
    // Access to single port bits
    //===========================================================================
    // These macros have been primarily designed to access single I/O lines,
    // but they can also be used with registers and variables. These macros are
    // optimized pretty good by the compiler, so don't hesitate to use them
    // wherever it makes the source code better readable. Examples:
    // writeBit(PORTB,3,1);
    // uint8_t portC7=readBit(PINC,7);
    
    // Set a bit to high if the value is >0, otherwise set the bit to low.
    #define writeBit(port,bit,value)   { if ((value)>0) (port) |= (1<<bit); else (port) &= ~(1<<bit); }
    
    // Read a single bit. The result is alwas either 0 or 1.
    #define readBit(port,bit)          (((port) >> (bit)) & 1)
    
    
    
    
    //===========================================================================
    // Analog channels
    //===========================================================================
    // The analog channels are sampled in background (interrupt driven), and their
    // values are internally stored in an array, which can be read using the
    // analog() function. Each channel is sampled twice: with PB4=high and with
    // PB4=low, that switches the line sensor light on and off.
    //
    // Line sensors should be read with VCC as reference (which is the default).
    // Their value is usually below 600 for dark surfaces and above 600 for bright
    // surfaces.
    //
    // To get meaningful values from the battery channel, you must use the 2.56V
    // reference instead.
    
    // Analog channels, PB4=low (line sensor light on)
    #define AN0 0
    #define AN1 1
    #define AN2 2
    #define AN3 3
    #define VBAT 4
    #define LINE_L 5
    #define LINE_C 6
    #define LINE_R 7
    
    // Analog channels, PB4=high (line sensor light off)
    #define _AN0 8
    #define _AN1 9
    #define _AN2 10
    #define _AN3 11
    #define _VBAT 12
    #define _LINE_L 13
    #define _LINE_C 14
    #define _LINE_R 15
    
    // Read values from the ADC (see above for possible channels values).
    uint16_t analog(uint8_t channel);
    
    // Analog reference inputs (VCC or 2.56V)
    #define REF_VCC (1<<REFS0)
    #define REF_256 ((1<<REFS0) | (1<<REFS1))
    
    // Change the reference input of ADC (see above for possible input values).
    // After changing, you must wait a while (e.g. 100ms) to load C16.
    void set_AREF(uint8_t input);
    
    
    
    
    //===========================================================================
    // Sensor switches
    //===========================================================================
    // These macros returns 1 if the switch is pressed
    
    #define SENS_SW1 !readBit(PINC,4)
    #define SENS_SW2 !readBit(PINC,5)
    #define SENS_SW3 !readBit(PINC,7)
    #define SENS_SW4 !readBit(PINC,6)
    #define SENS_L1 !readBit(PINC,4)
    #define SENS_L2 !readBit(PINC,5)
    #define SENS_R1 !readBit(PINC,6)
    #define SENS_R2 !readBit(PINC,7)
    
    
    
    
    //===========================================================================
    // Status Led's
    //===========================================================================
    // The status LED's are free programmable for whatever you like.
    
    // The LED goes on if the value is >0.
    #define set_LED0(value) writeBit(PORTB,0,value)
    #define set_LED1(value) writeBit(PORTB,1,value)
    #define set_LED2(value) writeBit(PORTB,2,value)
    #define set_LED3(value) writeBit(PORTB,3,value)
    
    // Returns 1, if the LED is on
    #define LED0 readBit(PINB,0)
    #define LED1 readBit(PINB,1)
    #define LED2 readBit(PINB,2)
    #define LED3 readBit(PINB,3)
    
    
    
    
    //===========================================================================
    // Motor control
    //===========================================================================
    // The motor direction is controlled by one port pin for each side. The motor
    // speed is controlled by Timer1 which generates a 10bit PWM signal. With
    // good batteries on a plain surface, the robotr starts moving at value 200.
    
    // Motor direction
    // 0=clockwise, 1=counter-clockwise
    #define set_DIR_L(value) writeBit(PORTD,6,value)
    #define set_DIR_R(value) writeBit(PORTD,7,value)
    #define DIR_L readBit(PIND,6)
    #define DIR_R readBit(PIND,7)
    
    // Motor speed
    // 0=stop, 1023=maximum speed.
    #define PWM_L OCR1A
    #define PWM_R OCR1B
    
    
    
    
    //===========================================================================
    // Odometer sensors
    //===========================================================================
    // The odometry sensors count interrupts that are generated by photo sensors
    // in the gears. They measure the distance of movement. Keep in mind that the
    // wheels may slip, specially when the robot accelerates or decellerates too
    // quickly. When the wheels slip, the odometry counters contain false
    // information.
    // The odometer sensors generate on counter tick per 6 millimeters (with the
    // original wheels that I got).
    
    // Odometer photo sensors
    #define ODO_L readBit(PIND,2)
    #define ODO_R readBit(PIND,3)
    
    // Reset odometer counters
    void reset_odometer();
    
    // Get left odometer counter
    uint32_t odometer_left();
    
    // Get right odometer counter
    uint32_t odometer_right();
    
    
    
    
    //===========================================================================
    // System timer
    //===========================================================================
    // The system timer is interrupt driven from Timer0. It counts the number of
    // milliseconds since last reset.
    
    // Get system time in milliseconds
    uint32_t system_time();
    
    
    
    
    #endif // _HARDWARE_H_
    nibobee.c:
    Code:
    #include "nibobee.h"
    #include <stdio.h>
    #include <avr/interrupt.h>
    #include <util/atomic.h>
    #include <util/setbaud.h>
    
    
    // Autor: Stefan Frings <stefan@meinemullemaus.de>
    // Date: 06.04.2010
    
    
    // Values from ADC
    // Index 0-7 are channel 0-7 captured while PB4=low
    // Index 8-15 are channel 0-7 captured while PB4=high
    static uint16_t analog_values[16];
    
    
    // Odometry counters
    static uint32_t odometry_left;
    static uint32_t odometry_right;
    
    
    // System time counter (in milliseconds)
    static uint32_t system_timer;
    
    
    // System timer prescaler. Counts Timer0 interrupts.
    static uint8_t system_timer_prescaler;
    
    
    // The following code binds the serial port to standard input and output of stdio.h
    #if USE_SERIAL
        static int serial_write(char, FILE *);
        static int serial_read(FILE *);
        static FILE serialPort = FDEV_SETUP_STREAM(serial_write, serial_read, _FDEV_SETUP_RW);
    
       // Write a character to the serial port
        static int serial_write(char c, FILE *f) {
            #if TERMINAL_MODE
                if (c=='\n') {
                   loop_until_bit_is_set(UCSRA, UDRE);
                   UDR='\r';
               }
            #endif /* TERMINAL_MODE */
            loop_until_bit_is_set(UCSRA, UDRE);
            UDR = c;
            return 0;
        }
    
    
        // Read a character from serial port
        static int serial_read(FILE *f) {
            loop_until_bit_is_set(UCSRA, RXC);
            char c=UDR;
            #if SERIAL_ECHO
                loop_until_bit_is_set(UCSRA, UDRE);
               UDR = c;
            #endif /* SERIAL_ECHO */
            #if TERMINAL_MODE
                if (c=='\r') {
                    c='\n';
                    #ifdef SERIAL_ECHO
                        loop_until_bit_is_set(UCSRA, UDRE);
                        UDR = c;
                    #endif /* SERIAL_ECHO */
                }
            #endif /* TERMINAL_MODE */
            return c;
        }
    
    
        // Initialize the serial port
        void initserial(void) {
            // set baudrate
            UBRRH = UBRRH_VALUE;
            UBRRL = UBRRL_VALUE;
            #if USE_2X
                UCSRA |= (1 << U2X);
            #else
                UCSRA &= ~(1 << U2X);
            #endif
            // enable receiver and transmitter
            UCSRB = (1<<RXEN) | (1<<TXEN);
            // framing format 8N1
            UCSRC = (1<<UCSZ1) | (1<<UCSZ0);
            // Bind stdout and stdin to the serial port
            stdout = &serialPort;
            stdin = &serialPort;
        }
    #endif /* USE_SERIAL */
    
    
    // Interrupt from the ADC
    ISR(ADC_vect) {
        uint16_t value = ADC;
        uint8_t channel = ADMUX & 7;
        uint8_t pb4 = readBit(PORTB,4);
        analog_values[channel+(pb4<<3)]=value;
        // Increment channel number as 3 bit counter
        // and toggle PB4 on every overflow
        if (++channel > 7) {
            PORTB ^= (1<<4);
            channel=0;
        }
        // switch to next channel
        ADMUX=(ADMUX & ~7) | channel;
        // start next conversion
        ADCSRA |= (1<<ADSC); 
    }
    
    
    // Read values from the ADC
    uint16_t analog(uint8_t channel) {
        ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
            return analog_values[channel];
        }
        return 0; // will never be reached
    }
    
    
    // Change the reference input of ADC
    void set_AREF(uint8_t input) {
        ADMUX=(ADMUX & ~((1<<REFS0) | (1<<REFS1))) | input;
    }
    
    
    // Interrupt from left odometry sensor
    ISR(INT0_vect) {
        odometry_left++; 
    }
    
    
    // Interrupt from right odometry sensor
    ISR(INT1_vect) {
        odometry_right++;
    }
    
    
    // Timer 0 overflow interrupt, generates a 1khz system clock (not exactly).
    // Is called with a rate of 100khz
    ISR(TIMER0_COMP_vect) {
        system_timer_prescaler++;
        if (system_timer_prescaler==100) {
            system_timer_prescaler=0;
            system_timer++;
        }
    }
    
    
    // get clock counter
    uint32_t system_time() {
        ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
            return system_timer;
        }
        return 0; // will never be executed
    }
    
    
    // reset odometer counters
    void reset_odometer() {
        ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
            odometry_left = 0;
            odometry_right = 0;
        }
    }
    
    
    // get left odometer counter
    uint32_t odometer_left() {
        ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
            return odometry_left;
        }
        return 0; // will never be executed
    }
    
    
    // get right odometer counter
    uint32_t odometer_right() {
        ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
            return odometry_right;
        }
        return 0; // will never be executed
    }
    
    
    // Install the nibobee_init() procedure in the startup code section 5
    void nibobee_init() __attribute__ ((naked))  __attribute__ ((section (".init5")));
    
    
    // Initialize the hardware
    void nibobee_init() {
        
        // Set output pins direction 
        DDRB |= 1+2+4+8+16; // LED0-3 and LINE_EN are outputs
        DDRD |= 16+32+64+128; // PWM_R, PWM_L, DIR_L and DIR_R are outputs
        PORTC |= 16+32+64+128; // Enable Pull-ups for sensor switches
    
        // Initial drive direction is forward
        set_DIR_L(1); // Left motor counter-clockwise
        set_DIR_R(0); // Right motor clockwise
        
        // Initialize the serial port
        #if USE_SERIAL
            initserial();
        #endif /* USE_SERIAL */
        
        // 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 = (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11) | (1<<WGM10);
        // Use I/O clock without prescaling
        TCCR1B = (1<<CS10);
    
        
        // Initialize odometry counters
        // Trigger interrupts on rising edge of INT0 and INT1 pins.
        // Enable interrupts for input INT0 and INT1.    
        #ifdef EICRA
            // ATmega644
            EICRA |= (1<<ISC11) | (1<<ISC10) | (1<<ISC01) | (1<<ISC00);
            EIMSK |= (1<<INT1) |  (1<<INT0);
        #else
            // ATmega16
            MCUCR |= (1<<ISC11) | (1<<ISC10) | (1<<ISC01) | (1<<ISC00);
            GICR |= (1<<INT1) |  (1<<INT0);
        #endif
        odometry_left = 0;
        odometry_right = 0;
        
        
        // Initialize the ADC
        // Enable ADC in single conversion mode with 117khz clock rate (F_CPU/128)
        // Which defines a performance of approx. 1000 samples/sec each of the 16 channels
        ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0) | (1<<ADIE) | (1<<ADSC); 
        // Use AVCC as reference
        ADMUX = REF_VCC;
    
       
        // Initialize system timer
        // Divide clock by 150 (=100khz)
        // Mode: Clear Timer On Compare, no clk prescaler
        // Enable interrupt on compare match
        #ifdef TIMSK0
            // ATmega644
            OCR0A = 150;
            TCCR0A = (1<<WGM1) | (1<<CS00);
            TIMSK0 |= (1<<TOIE0);
        #else
            // ATmega16
            OCR0 = 150;
            TCCR0 = (1<<WGM01) | (1<<CS00);
            TIMSK |= (1<<OCIE0);
        #endif
    
    
        // Enable interrupts
        sei();
    }
    Beispiel main.c:
    Code:
    #include "nibobee.h"
    #include <util/delay.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);
            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);
            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)==0);
            // Display line sensor
            set_LED2(analog(LINE_C)>600);
        }
        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
    // 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.
    void drive(uint8_t direction, uint16_t distance, uint16_t maxSpeed) {
        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();
        reset_odometer();
        while (odometer_left()<distance || odometer_right()<distance) {
            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;
            }
        }
        previousSpeed=speed;
    }
    
    
    // Stop driving.
    int stop() {
        PWM_L=0;
        PWM_R=0;
        previousSpeed=0;
    }
    
    
    // Main program
    int main() {
        // 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.
        while(1) {
            // Drive forward 2 meters, accellerating up to nearly maximum speed
            drive(FORWARD,2000/6,900);
            // Drive forward 30cm, decellerating down to the minimum speed
            drive(FORWARD,300/6,200);
            stop();
            _delay_ms(500);
            // Drive backward 2 meters, accellerating up to nearly maximum speed
            drive(BACKWARD,2000/6,900);
            // Drive backward 30cm, decellerating down to the minimum speed
            drive(BACKWARD,300/6,200);
            stop();
            _delay_ms(500);
        }
        return 0;
    }

  2. #2
    Erfahrener Benutzer Roboter Genie Avatar von Rabenauge
    Registriert seit
    13.10.2007
    Ort
    Osterzgebirge
    Alter
    49
    Beiträge
    1.245
    Mal als Zwischenfrage (ich komme heute zu nix mehr, nachher geht es raus, Roboter hin, NIBOBee her): fährt deine Biene bei einem PWM-Wert von 200 wirklich schon zuverlässig?
    Meine muss ich da regelrecht betteln, sicher wirds erst so ab 270.
    Ich frage, weil ich als nächstes eine Fahrregelung (irgendwann muss ich anfangen, mich da durchzubeissen) programmieren will, um so exakt wie nur möglich manövrieren zu können.
    Ohne die ist schliesslich die beste Odometrie nix wert.

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    19.03.2010
    Beiträge
    161
    Ab 200 bewegt er sich, aber nur unter idealen Bedingungen: Glatter Laminat-Boden, Batterien einigermaßen voll.

    Mit fast leeren Batterien (4,2 Volt) muss der Wert schon mindestens 300 sein.

    Ich habe das Getriebe mit ein wenig Vaseline eingefettet, vielleicht spielt das eine Rolle.

  4. #4
    Neuer Benutzer Öfters hier
    Registriert seit
    26.02.2010
    Ort
    Kreuzung BAB3 und B470
    Beiträge
    25
    Hi s.frings; sieht erstmal gut aus; =D>

    ich bin mit den Original Bibs und deren Enbindung ins AVR-Studio auch nicht so ganz glücklich. Deshalb habe ich mir sämtliche headers in eine nibobee.h und alle Sourcen in eine nibobee.c zusammen kopiert, in denen ich jetzt meine Anpassungen vornehme.

    Aber ich war gerade auf Sourcefourge - die Nibobeelib ist mittlerweile Revision 29 vom 2.4.'10. Ein Terminalmode und eine Motorenregellung sind hinzugekommen. (Aber die Lösungen sehen wieder viiel komplizierter aus, als Deine "Links_zu_schnell_dann_Links_ Stopp" Methode. Die neuen Sourcen sind noch nicht released, sondern in einem Ordner "trunk" unter der Rubrik develop versteckelt.

    Die Original Sourcen sind es wert, verfolgt zu werden - "Again what learned" denk ich mir.

    Der Timer 1 macht ja nicht nur die beiden PWM Ausgänge, mit dem OVF wird auch eine Systemuhr gebildet (clock.c), deren Initialisierung in der motpid.c codiert war. Bei mir ist sie nach motpwm.c gewandert. Dadurch dass ich jetzt eine Systemzeit habe, kann ich generell auf delay() verzichten. Meine Hauptschleife wird (noch) im ms-Takt (Zykluszeit) abgearbeitet; wenn ich eine Zeitverzögerung brauche, wird einfache eine Variable auf die Zeit gestellt und dann zyklisch dekrementiert. Solange die Variable > 0 ist wird der zu verzögernde Programmteil halt nicht ausgeführt, aber alles andere dann trotzdem.
    Während ich auf die volle ms warte, kann ich ja mal eben eine gemultiplexte LED Ausgabe machen, und mir mal den Sensorstatus in eine Variable einlesen nachdem ich mir den Vorherstand für eine Flankenerkennung gemerkt habe.

    Tja dann wollte ich mir einen weiteren PWM-Ausgang für eine Analoganzeige einrichten. Aber der OC0 ist mit LED3 und der OC2 mit DIR_R belegt. Also jetzt fliegen erstmal die Original LEDs und Widerstände (die leider mit Masse und nicht mit den Pins verbunden sind). Der PB3 wird dann extra PWM Ausgang vom Timer 0 und mit PB0..PB2 werden dann 6 LEDs gemuxt.

    Sorry, dass ich jetzt hier soviel reingeschrieben habe, aber mich stört immer Verwendung von delay(), das direkte Setzen und Abfragen der IO-Pins innerhalb der Mainloop. und ausserdem fehlt in der nibobee.h "B" bei "#define ODO_L readit(PORTD,2)"

  5. #5
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    19.03.2010
    Beiträge
    161
    Ich habe zur obigen Library noch einen System-Timer hinzugefügt, die Inline-Doku verbessert und ein besseres Beispielprogramm eingefügt. Leider ist die Nachricht nun zu groß, das Makefile passt nicht mehr rein. Darum reiche ich es hier nach:

    Code:
    # Makefile for this AVR project
    
    # make          Compiles the source code into hex files.
    # make fuses    Program fuses
    # make program  Program flash and eeprom
    
    # make list     Create generated code listing
    # make clean    Delete all generated files
    
    
    # Parameters for avrdude
    AVRDUDE_HW = -c usbasp -P USB
    
    # Source files, separated by space.
    SRC = main.c nibobee.c
    
    # Microcontroller
    # The code is designed for atmega16 or atmega644
    MCU = atmega16
    F_CPU = 15000000
    
    # Serial port settings
    # Set TERMINAL_MODE = 1 to support terminal programs that send and
    # expect line breaks in old MS-DOS format.
    # Set SERIAL_ECHO = 1 to enable sending back an echo of all incoming
    # characters.
    USE_SERIAL = 0
    BAUD = 115200
    TERMINAL_MODE = 1
    SERIAL_ECHO = 1
    
    # Fuses
    HFUSE = 0xd1
    LFUSE = 0xef
    #EFUSE = 0xff
    
    # Binaries to be used
    # You may add the path to them if they are not in the PATH variable.
    CC      = avr-gcc
    OBJCOPY = avr-objcopy
    OBJDUMP = avr-objdump
    AVRDUDE = avrdude
    
    # Name of the program without extension
    PRG = nibobee
    
    # Do we need to write Eeprom? (yes/no)
    EEPROM = no
    
    # Libraries
    #LIBS = -L ../nibobee-lib/lib -lnibobee_base -lnibobee_usart -lnibobee_utils
    
    # Includes
    #INCLUDES = -I../nibobee-lib/include
    
    # Compiler options for all c source files
    CFLAGS = -std=c99 -Os -Wall -mmcu=$(MCU) -DF_CPU=$(F_CPU) $(INCLUDES)
    CFLAGS += -DUSE_SERIAL=$(USE_SERIAL) -DBAUD=$(BAUD) -DTERMINAL_MODE=$(TERMINAL_MODE) -DSERIAL_ECHO=$(SERIAL_ECHO)
    
    # Linker options 
    LDFLAGS = -Wl,-Map,$(PRG).map 
    
    # Enable floating-point support in printf
    #LDFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm
    
    # Collect fuse operations for avrdude
    ifdef FUSE
      FUSES += -U fuse:w:$(FUSE):m
    endif
    ifdef LFUSE
      FUSES += -U lfuse:w:$(LFUSE):m
    endif
    ifdef HFUSE
      FUSES += -U hfuse:w:$(HFUSE):m
    endif
    ifdef EFUSE
      FUSES += -U efuse:w:$(EFUSE):m
    endif
    
    # Default sections
    ifeq ($(EEPROM),yes)
    all: code eeprom
    else
    all: code
    endif
    
    # Program code
    code: $(PRG).hex
    
    # Eeprom content
    eeprom: $(PRG)_eeprom.hex
    
    # Generated code listing
    list: $(PRG).lst
    
    # Remove all generated files
    clean:
    	rm -f *.o $(PRG).hex $(PRG).elf $(PRG).lst $(PRG).map $(PRG)_eeprom.hex
    
    # Program flash memory with or without eeprom
    ifeq ($(EEPROM),yes)
    program: code eeprom
    	$(AVRDUDE) -p $(MCU) $(AVRDUDE_HW) -U flash:w:$(PRG).hex:i -U eeprom:w:$(PRG)_eeprom.hex:i 
    else
    program: code 
    	$(AVRDUDE) -p $(MCU) $(AVRDUDE_HW) -U flash:w:$(PRG).hex:i 
    endif
    
    # Program fuses
    fuses:
    	$(AVRDUDE) -p $(MCU) $(AVRDUDE_HW) $(FUSES)
    
    $(PRG).elf: $(SRC:.c=.o)
    	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
    
    %.lst: %.elf
    	$(OBJDUMP) -h -S $< > $@
    
    %.hex: %.elf
    	$(OBJCOPY) -j .text -j .data -O ihex $< $@
    
    %_eeprom.hex: %.elf
    	$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@

  6. #6
    Neuer Benutzer Öfters hier
    Registriert seit
    26.02.2010
    Ort
    Kreuzung BAB3 und B470
    Beiträge
    25
    Ja Supi, hier ist einer aktiv..

    Ich werde dann wohl auf s.frings Bibliothek umsteigen und damit weitermachen.

    Btw. Ich habe mir jetzt den PB3 frei geschaufelt. Da wo vorher die gelben LEDs waren sind jetzt DUO Leds und die beiden vorderen roten habe ich durch 2 rote 10mm Leds "ersetzt*".

    *Eigentlich sind anstelle der LEDs jetzt 100 Ohm Widerstände drin, und dort wo vorher die 180 Ohm Widerstände drin waren, stecken die LEDs (in zusätzlichen Bohrungen).

    Der Timer 1 muß ja sowieso für die Motren initialisiert werden, warum denn nicht den gleich den OVF Interrupt freigeben, und damit den Systemtimer realisieren? So wie es in der Original Bibliothek motpid.c und clock.c gemacht wurde. Ich hatte nämlich mit Timer 0 und OC0 was anderes vor. Analoganzeige oder PiezoPieper..

  7. #7
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    19.03.2010
    Beiträge
    161
    Ich habe Timer0 für den Systemtimer verwendet, um auf exakte Millisekunden zu kommen. Mit Timer 1 wäre das nicht möglich, jedenfalls nicht ohne komplizierte Mathematik. An exakte Millisekunden Zähler habe ich mich inzwischen sehr gewöhnt (vom PC her). Darauf möchte ich nicht verzichten.

    Piepen kann man auch mit den Motoren und Timer1, wenn das Fahrzeug steht.

    Du könntest Timer 2 statt Timer 0 für den Millisekunden-Zähler benutzen.

  8. #8
    Hi BirgerT!

    Hast Du irgendwelche weiteren Infos über den Terminalmode - hat ja anscheind was mit dem BGX1 zu tun - da find ich aber nix zu

    Bei sourceforge gibt es nur ne H-Datei:
    http://nibobeelib.svn.sourceforge.ne...29&view=markup

  9. #9
    Neuer Benutzer Öfters hier
    Registriert seit
    26.02.2010
    Ort
    Kreuzung BAB3 und B470
    Beiträge
    25
    Weitere Infos zum BGX1 habe ich nicht wirklich; hier heisst's wohl abwarten und beobachten; ist alles develop und noch kein release.

    Ich vermute das hiermit etwas geplant ist;
    http://shop.nicai-systems.de/shop.php?view=2&id=25
    aber dafür ist womöglich extra Hardware erforderlich (I2C Porterweiterung o.ä.)

    Nur die h-Datei gefunden?! schau mal hier: http://nibobeelib.svn.sourceforge.ne...vc/nibobeelib/

    Rabenauge und Pinsel120866 haben Bilder- und Videolinks gepostet. Demnach haben sie schon 2-zeilige LCD und Taster am NiboBee in Betrieb.


    Mit Timer 1 wäre das nicht möglich, jedenfalls nicht ohne komplizierte Mathematik
    Also Timer1 läuft bei s.frings Alternativ Bib im 10bit Mode das sind dann 15000000/(2*1023) = 7331 Hz, der OVF Interupt kommt folglich alle 1/7331 Sek. = 136uS.
    In der Original Bib läuft der Timer im 9 Bit Mode; Overflow alle 68uS..
    In der ISR(Timer1_OVF_vect) werden also immer 136 bzw. 68 auf den uint16_t takt_us addiert, ist dieser >1000, werden wieder 1000 abgezogen und der uint16_t takt_ms inkrementiert...

    Ich habe drei Varianten ausprobiert PWM 9 bit, PWM 10bit und Timer0. nach jeder ms den PB5 geXodert und ein Scope drangehängt: Ergebnis ist (ver)gleich(bar); das 1KHz (halt, eigentlich 500Hz 1ms H, 1ms L) Signal jittert bei allen drei Varianten, ob's am Billig-Scope liegt oder am Signal ?!

    Was ist für die Motorenansteuerung eigentlich besser, hohe oder niedrigere PWM Frequenz?

  10. #10
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    19.03.2010
    Beiträge
    161
    Diese Zählmethode ist einfach und einleuchtend. Komisch, dass ich nicht selbst drauf gekommen bin.

    Wegen dem Jitter: Der Timer jittert, weil eben keine Millisekunden gezählt werden und auch nicht ein genaues Vielfaches davon. Im Durchschnitt passt es zwar, aber wenn man wirklich Millisekunden braucht, ist das störend.

    Wegen dem PWM: Das wüsste ich auch gerne. Bei meiner 10 bit Variante hört man die Motoren manchmal leise piepsen. Das empfinde ich als als gerinfügigen Nachteil. Andererseits dachte mir, warum nicht alle 10 bit Nutzen, wenn sie zur Verfügung stehen?

Seite 1 von 3 123 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •