-         

Ergebnis 1 bis 3 von 3

Thema: RP6Base_I2CSlave.c Frage

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied Avatar von Thorben W
    Registriert seit
    17.02.2012
    Ort
    Niedersachsen
    Beiträge
    108

    RP6Base_I2CSlave.c Frage

    Anzeige

    Hallo,
    als ich mir gerade das Programm RP6Base_I2CSlave.c ansah, kam ich zu der Funktion task_update:
    Code:
    uint16_t uBat_measure = 720;
    uint8_t  uBat_count = 0;        
            
    /**
     * This function needs to be called frequently in the main loop. It updates
     * some values (currently only Battery Voltage and Motor status, but this may
     * be expanded in future). 
     */ 
    void task_update(void)
    {
        if(getStopwatch4() > 250)
        {
            uBat_measure += adcBat;
            uBat_measure /= 2;
            uBat_count++;
            setStopwatch2(0);
        }
        if(uBat_count > 5)
        {
            if(!interrupt_status.batLow && uBat_measure < 560)
            {
                interrupt_status.batLow = true;
                signalInterrupt();
            }
            else if(interrupt_status.batLow && uBat_measure > 580)
            {
                interrupt_status.batLow = false;
                signalInterrupt();
            }
            uBat_count = 0;
        }
            
        drive_status.motorsOn = (mleft_power || mright_power);
        drive_status.direction = getDirection();
     }
    und fragte mich wieso in der Zeile 16 setStopwatch2(0); steht ich finde setStopwatch4(0); sinnvoller, weil sonst die Funktion immer ausgefürt wird nicht nur nach den die Zeit abgelaufen ist. Oder verstehe ich das Falsch?

    Hier noch mal der Komplette Quellcode:
    Code:
    /* 
     * ****************************************************************************
     * RP6 ROBOT SYSTEM - ROBOT BASE EXAMPLES
     * ****************************************************************************
     * Example: I2C Slave
     * Author(s): Dominik S. Herwald
     * ****************************************************************************
     * Description:
     *
     * A very common thing that many users will want to do with their RP6 is 
     * to control it with a second controller which has more free resources. 
     * (more free memory, free I/O Ports and ADCs, faster, etc. pp.
     * for example the RP6-M32 expansion Module)
     * 
     * This programs allows you to control the Robot Base Unit completely via
     * I2C-Bus as a slave device!
     * 
     * Also have a look at the RP6 CONTROL M32 example programs which can also
     * be found on this CD-ROM - there you get examples of how to use
     * this program! 
     *  
     * ****************************************************************************
     */
    
    /*****************************************************************************/
    // Includes:
    
    #include "RP6RobotBaseLib.h"     
    
    #include "RP6I2CslaveTWI.h"     // Include the I²C-Bus Slave Library
    
    /*****************************************************************************/
    
    // The Slave Address on the I2C Bus can be specified here:
    #define RP6BASE_I2C_SLAVE_ADR 10
    
    /*****************************************************************************/
    
    // This bitfield contains the main interrupt event status bits. This can be
    // read out and any Master devices can react on the specific events.
    union {
         uint8_t byte;
        struct {
            uint8_t batLow:1;
            uint8_t bumperLeft:1;
            uint8_t bumperRight:1;
            uint8_t RC5reception:1;
            uint8_t RC5transmitReady:1;
            uint8_t obstacleLeft:1;
            uint8_t obstacleRight:1;
            uint8_t driveSystemChange:1;
        };
    } interrupt_status;
    
    // Some status bits with current settings and other things.
    union {
         uint8_t byte;
        struct {
            uint8_t powerOn:1;
            uint8_t ACSactive:1;
            uint8_t watchDogTimer:1;
            uint8_t wdtRequest:1;
            uint8_t wdtRequestEnable:1;
            uint8_t unused:3;
        };
    } status;
    
    // Drive Status register contains information about current movements. 
    // You can check if movements are complete, if the motors are turned
    // on, if there were overcurrent events and for direction.
    union {
         uint8_t byte;
        struct {
            uint8_t movementComplete:1;
            uint8_t motorsOn:1;
            uint8_t motorOvercurrent:1;
            uint8_t direction:2;
            uint8_t unused:3;
        };
    } drive_status;
    
    
    RC5data_t lastRC5Reception;
    
    /*****************************************************************************/
    
    /**
     * Generates Interrupt Signal and starts Software Watchdog
     */ 
    void signalInterrupt(void)
    {
        I2CTWI_dataWasRead = 0;
        extIntON();
        if(status.watchDogTimer)
            startStopwatch2();
    }
    
    /**
     * Clears Interrupt
     */ 
    void clearInterrupt(void)
    {
        stopStopwatch2();
        setStopwatch2(0);
        status.wdtRequest = false;
        interrupt_status.RC5reception = false;
        interrupt_status.driveSystemChange = false;
        extIntOFF();
    }
    
    /**
     * ACS Event Handler 
     */ 
    void acsStateChanged(void)
    {
        interrupt_status.obstacleLeft = obstacle_left;
        interrupt_status.obstacleRight = obstacle_right;
        signalInterrupt();
    }
    
    /**
     * Bumpers Event Handler
     */ 
    void bumpersStateChanged(void)
    {
        interrupt_status.bumperLeft = bumper_left;
        if(bumper_right)
            interrupt_status.bumperRight = true;
        else
            interrupt_status.bumperRight = false;
        signalInterrupt();
    }
    
    /**
     * RC5 Event Handler
     */ 
    void receiveRC5Data(RC5data_t rc5data)
    {
        lastRC5Reception.toggle_bit = rc5data.toggle_bit;
        lastRC5Reception.device = rc5data.device;
        lastRC5Reception.key_code = rc5data.key_code;
        interrupt_status.RC5reception = true;
        signalInterrupt();
    }    
    
    /**
     * Motion Control Event Handler
     */ 
    void motionControlStateChanged(void)
    {
        drive_status.movementComplete = isMovementComplete();
        drive_status.motorOvercurrent = motion_status.overcurrent;
        interrupt_status.driveSystemChange = true;
        signalInterrupt();
    }
    
    
    uint16_t uBat_measure = 720;
    uint8_t  uBat_count = 0;        
            
    /**
     * This function needs to be called frequently in the main loop. It updates
     * some values (currently only Battery Voltage and Motor status, but this may
     * be expanded in future). 
     */ 
    void task_update(void)
    {
        if(getStopwatch4() > 250)
        {
            uBat_measure += adcBat;
            uBat_measure /= 2;
            uBat_count++;
            setStopwatch2(0);
        }
        if(uBat_count > 5)
        {
            if(!interrupt_status.batLow && uBat_measure < 560)
            {
                interrupt_status.batLow = true;
                signalInterrupt();
            }
            else if(interrupt_status.batLow && uBat_measure > 580)
            {
                interrupt_status.batLow = false;
                signalInterrupt();
            }
            uBat_count = 0;
        }
            
        drive_status.motorsOn = (mleft_power || mright_power);
        drive_status.direction = getDirection();
    }
    
    /*****************************************************************************/
    // I2C Registers that can be read by the Master. Their names should 
    // be self-explanatory and directly relate to the equivalent variables/functions 
    // in the RP6Library
    
    #define I2C_REG_STATUS1          0
    #define I2C_REG_STATUS2          1
    #define I2C_REG_MOTION_STATUS      2
    #define I2C_REG_POWER_LEFT          3
    #define I2C_REG_POWER_RIGHT      4
    #define I2C_REG_SPEED_LEFT          5
    #define I2C_REG_SPEED_RIGHT      6
    #define I2C_REG_DES_SPEED_LEFT      7
    #define I2C_REG_DES_SPEED_RIGHT  8
    #define I2C_REG_DIST_LEFT_L      9
    #define I2C_REG_DIST_LEFT_H      10
    #define I2C_REG_DIST_RIGHT_L     11
    #define I2C_REG_DIST_RIGHT_H      12
    #define I2C_REG_ADC_LSL_L          13
    #define I2C_REG_ADC_LSL_H          14
    #define I2C_REG_ADC_LSR_L          15
    #define I2C_REG_ADC_LSR_H          16
    #define I2C_REG_ADC_MOTOR_CURL_L 17
    #define I2C_REG_ADC_MOTOR_CURL_H 18
    #define I2C_REG_ADC_MOTOR_CURR_L 19
    #define I2C_REG_ADC_MOTOR_CURR_H 20
    #define I2C_REG_ADC_UBAT_L          21
    #define I2C_REG_ADC_UBAT_H          22
    #define I2C_REG_ADC_ADC0_L          23
    #define I2C_REG_ADC_ADC0_H          24
    #define I2C_REG_ADC_ADC1_L          25
    #define I2C_REG_ADC_ADC1_H          26
    #define I2C_REG_RC5_ADR              27
    #define I2C_REG_RC5_DATA          28
    #define I2C_REG_LEDS              29
    
    
    /**
     * This very important function updates ALL registers that the Master can read.
     * It is called frequently out of the Main loop. 
     */
    void task_updateRegisters(void)
    {
        if(!I2CTWI_readBusy) 
        {
            I2CTWI_readRegisters[I2C_REG_STATUS1] =          (uint8_t)(interrupt_status.byte);
            I2CTWI_readRegisters[I2C_REG_STATUS2] =          (uint8_t)(status.byte);
            I2CTWI_readRegisters[I2C_REG_MOTION_STATUS] =      (uint8_t)(drive_status.byte);
            I2CTWI_readRegisters[I2C_REG_POWER_LEFT] =          (uint8_t)(mleft_power);
            I2CTWI_readRegisters[I2C_REG_POWER_RIGHT] =      (uint8_t)(mright_power);
            I2CTWI_readRegisters[I2C_REG_SPEED_LEFT] =          (uint8_t)(getLeftSpeed());
            I2CTWI_readRegisters[I2C_REG_SPEED_RIGHT] =      (uint8_t)(getRightSpeed());
            I2CTWI_readRegisters[I2C_REG_DES_SPEED_LEFT] =      (uint8_t)(getDesSpeedLeft());
            I2CTWI_readRegisters[I2C_REG_DES_SPEED_RIGHT] =  (uint8_t)(getDesSpeedRight());
            I2CTWI_readRegisters[I2C_REG_DIST_LEFT_L] =      (uint8_t)(getLeftDistance());
            I2CTWI_readRegisters[I2C_REG_DIST_LEFT_H] =      (uint8_t)(getLeftDistance()>>8);
            I2CTWI_readRegisters[I2C_REG_DIST_RIGHT_L] =      (uint8_t)(getRightDistance());
            I2CTWI_readRegisters[I2C_REG_DIST_RIGHT_H] =      (uint8_t)(getRightDistance()>>8);
            I2CTWI_readRegisters[I2C_REG_ADC_LSL_L] =          (uint8_t)(adcLSL);
            I2CTWI_readRegisters[I2C_REG_ADC_LSL_H] =          (uint8_t)(adcLSL>>8);
            I2CTWI_readRegisters[I2C_REG_ADC_LSR_L] =          (uint8_t)(adcLSR);
            I2CTWI_readRegisters[I2C_REG_ADC_LSR_H] =          (uint8_t)(adcLSR>>8);
            I2CTWI_readRegisters[I2C_REG_ADC_MOTOR_CURL_L] = (uint8_t)(adcMotorCurrentLeft);
            I2CTWI_readRegisters[I2C_REG_ADC_MOTOR_CURL_H] = (uint8_t)(adcMotorCurrentLeft>>8);
            I2CTWI_readRegisters[I2C_REG_ADC_MOTOR_CURR_L] = (uint8_t)(adcMotorCurrentRight);
            I2CTWI_readRegisters[I2C_REG_ADC_MOTOR_CURR_H] = (uint8_t)(adcMotorCurrentRight>>8);
            I2CTWI_readRegisters[I2C_REG_ADC_UBAT_L] =          (uint8_t)(adcBat);
            I2CTWI_readRegisters[I2C_REG_ADC_UBAT_H] =          (uint8_t)(adcBat>>8);
            I2CTWI_readRegisters[I2C_REG_ADC_ADC0_L] =          (uint8_t)(adc0);
            I2CTWI_readRegisters[I2C_REG_ADC_ADC0_H] =          (uint8_t)(adc0>>8);
            I2CTWI_readRegisters[I2C_REG_ADC_ADC1_L] =          (uint8_t)(adc1);
            I2CTWI_readRegisters[I2C_REG_ADC_ADC1_H] =          (uint8_t)(adc1>>8);
            I2CTWI_readRegisters[I2C_REG_LEDS] =              (uint8_t)(statusLEDs.byte);
            I2CTWI_readRegisters[I2C_REG_RC5_ADR] =          (uint8_t)((lastRC5Reception.device)|(lastRC5Reception.toggle_bit<<5));
            I2CTWI_readRegisters[I2C_REG_RC5_DATA] =          (uint8_t)(lastRC5Reception.key_code);
            if(I2CTWI_dataWasRead && I2CTWI_dataReadFromReg == 0)
                clearInterrupt();
        }
    }
    
    /*****************************************************************************/
    // Command Registers - these can be written by the Master.
    // The other registers (read registers) can NOT be written to. The only way to
    // communicate with the Robot is via specific commands. 
    // Of course you can also add more registers if you like...
    
    // ----------------------
    
    #define I2C_REGW_CMD 0
    #define I2C_REGW_CMD_PARAM1 1
    #define I2C_REGW_CMD_PARAM2 2
    #define I2C_REGW_CMD_PARAM3 3
    #define I2C_REGW_CMD_PARAM4 4
    #define I2C_REGW_CMD_PARAM5 5
    #define I2C_REGW_CMD_PARAM6 6
    
    // ----------------------
    
    uint8_t cmd;
    uint8_t param1;
    uint8_t param2;
    uint8_t param3;
    uint8_t param4;
    uint8_t param5;
    uint8_t param6;
    
    /**
     * Checks if a new Command has been received and also reads all 
     * paramters associated with this command.
     * It returns true if a new command has been received.
     */
    uint8_t getCommand(void)
    {
        if(I2CTWI_writeRegisters[I2C_REGW_CMD] && !I2CTWI_writeBusy) 
        {
            cmd = I2CTWI_writeRegisters[I2C_REGW_CMD]; // store command register
            I2CTWI_writeRegisters[I2C_REGW_CMD] = 0; // clear command register (!!!)
            param1 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM1]; // parameters 1-6...
            param2 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM2];
            param3 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM3];
            param4 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM4];
            param5 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM5];
            param6 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM6];
            return true;
        }
        return false;
    }
    
    /*****************************************************************************/
    // Command processor:
    
    
    uint8_t leds = 1;
    
    // Commands:
    #define CMD_POWER_OFF         0
    #define CMD_POWER_ON         1
    #define CMD_CONFIG             2
    #define CMD_SETLEDS         3
    #define CMD_STOP               4
    #define CMD_MOVE_AT_SPEED   5
    #define CMD_CHANGE_DIR        6
    #define CMD_MOVE             7
    #define CMD_ROTATE             8
    #define CMD_SET_ACS_POWER    9 
    #define CMD_SEND_RC5        10 
    #define CMD_SET_WDT            11 
    #define CMD_SET_WDT_RQ        12
    
    // Parameters for CMD_SET_ACS_POWER:
    #define ACS_PWR_OFF  0
    #define ACS_PWR_LOW  1
    #define ACS_PWR_MED  2
    #define ACS_PWR_HIGH 3
    
    /**
     * This function checks if commands have been received and processes them.
     */ 
    void task_commandProcessor(void)
    {
        if(getCommand()) 
        {
            switch(cmd) 
            {
                case CMD_POWER_OFF:    powerOFF(); status.powerOn = false; break;
                case CMD_POWER_ON:  powerON(); status.powerOn = true; break;
                case CMD_CONFIG: break;
                case CMD_SETLEDS: setLEDs(param1); break;
                case CMD_STOP: stop(); break;
                case CMD_MOVE_AT_SPEED: moveAtSpeed(param1, param2); break;
                case CMD_CHANGE_DIR: changeDirection(param1); break;
                case CMD_MOVE: move(param1, param2, ((param3<<8)+param4), false); break;
                case CMD_ROTATE: rotate(param1, param2, ((param3<<8)+param4), false); break;
                case CMD_SET_ACS_POWER: 
                    switch(param1)
                    {
                        case ACS_PWR_OFF: 
                            disableACS(); setACSPwrOff(); status.ACSactive = false; 
                        break;
                        case ACS_PWR_LOW: 
                            enableACS(); setACSPwrLow();  status.ACSactive = true; 
                        break;
                        case ACS_PWR_MED: 
                            enableACS(); setACSPwrMed();  status.ACSactive = true; 
                        break;
                        case ACS_PWR_HIGH: 
                            enableACS(); setACSPwrHigh(); status.ACSactive = true; 
                        break;
                    }
                break;
                case CMD_SEND_RC5: IRCOMM_sendRC5(param1, param2); break;
                case CMD_SET_WDT: status.watchDogTimer = param1 ? true : false; break;
                case CMD_SET_WDT_RQ: status.wdtRequestEnable = param1 ? true : false; break;
            }
        }
    }
    
    /**
     * This is the Software watchdog function. After any interrupt event, a timer is
     * stated and if a certain amount of time has passed by with no reaction from
     * the Master, the Robot is stopped to prevent any damages. Usually the Master
     * program has errors or is locked up if it does not react, so this it is
     * very good idea to stop moving.
     */
    void task_MasterTimeout(void)
    {
        if(status.watchDogTimer)
        {
            if( getStopwatch2() > 3000)  // 3 seconds timeout for the master to react on
            {                            // our interrupt events - if he does not react, we 
                                        // stop all operations!
                cli();
                IRCOMM_OFF();
                setACSPwrOff();
                OCR1AL = 0;
                OCR1BL = 0;
                TCCR1A = 0;
                powerOFF();
                writeString_P("\n\n##### EMERGENCY SHUTDOWN #####\n");
                writeString_P("##### ALL OPERATIONS STOPPED TO PREVENT ANY DAMAGE! #####\n\n");
                writeString_P("The Master Controller did not respond to the interrupt requests\n");
                writeString_P("within the defined timeout! Maybe he's locked up!\n");
                writeString_P("\nThe Robot needs to be resetted now.\n\n");
                while(true) // Rest In Peace
                {
                    setLEDs(0b100010);
                    uint8_t dly;
                    for(dly = 10; dly; dly--)
                        delayCycles(32768);
                    setLEDs(0b010100);
                    for(dly = 10; dly; dly--)
                        delayCycles(32768);
                }
            }
            else if(getStopwatch3() > 250)
            {
                status.wdtRequest = true;
                signalInterrupt();
                setStopwatch3(0);
            }
        }
    }
    
    /*****************************************************************************/
    // Main - The program starts here:
    
    int16_t main(void)
    {
        initRobotBase();
        
        setLEDs(0b111111);
        mSleep(100);       
        setLEDs(0b000000);
    
        I2CTWI_initSlave(RP6BASE_I2C_SLAVE_ADR);
        
        ACS_setStateChangedHandler(acsStateChanged);
        BUMPERS_setStateChangedHandler(bumpersStateChanged);
        IRCOMM_setRC5DataReadyHandler(receiveRC5Data);
        MOTIONCONTROL_setStateChangedHandler(motionControlStateChanged);
    
        powerON();
    
        startStopwatch1();
    
        disableACS();
        setACSPwrOff();
        
        status.byte = 0;
        interrupt_status.byte = 0;
        drive_status.byte = 0;
        
        status.watchDogTimer = false;
        status.wdtRequestEnable = false;
        
        startStopwatch3();
        startStopwatch4();
        
        while(true) 
        {
            task_commandProcessor();
            task_update();
            task_updateRegisters();
            task_RP6System();
            task_MasterTimeout();
        }
        return 0;
    }
    Danke schon mal für eure Antworten.
    Thorben W

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von Dirk
    Registriert seit
    30.04.2004
    Ort
    NRW
    Beiträge
    3.791
    Hi Thorben,
    wir hatten schon mal hier darüber diskutiert:
    Ohne wirkliches Ergebnis.
    Der Slave scheint aber so gut zu funktionieren.

    Meine Meinung: setStopwatch4(0) macht wirklich mehr Sinn, zumal mit setStopwatch2(0) der Watchdog-Timer gestört wird.
    Gruß
    Dirk

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied Avatar von Thorben W
    Registriert seit
    17.02.2012
    Ort
    Niedersachsen
    Beiträge
    108
    Ich habe die Slave Datei für eine neue Motorsteuerung umgeschrieben und fragte mich deshalb was das soll.
    Danke für deine Antwort.
    Thorben W

Ähnliche Themen

  1. Antworten: 2
    Letzter Beitrag: 28.08.2011, 18:37
  2. .:Anfänger Frage zu Sensoren:.(Neu! Frage zu meinem 1. Progr
    Von oceans94 im Forum Sensoren / Sensorik
    Antworten: 22
    Letzter Beitrag: 06.05.2008, 07:54

Berechtigungen

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