PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] RP6Base_I2CSlave.c Frage



Thorben W
16.03.2014, 14:50
Hallo,
als ich mir gerade das Programm RP6Base_I2CSlave.c ansah, kam ich zu der Funktion task_update:
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:
/*
* ************************************************** **************************
* 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)|(lastRC5Recept ion.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(motionControl StateChanged);

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

Dirk
16.03.2014, 15:19
Hi Thorben,
wir hatten schon mal hier (https://www.roboternetz.de/community/threads/59178-RP6Control-M32-Projekt-I2C-Slave) 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.

Thorben W
16.03.2014, 17:03
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