PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : RP6 Master-Slave Einstellung



Mac80
13.04.2012, 13:55
Hallo, ich bin auch neu hier und wollte mich schon mal ganz herzlich für die (indirekte) super Unterstützung im Forum bedanken.
Die Suchmaschine habe ich auch schon benutzt...
Mein Set ist: RP6-Base als Slave und RP6 M32 als Master. Es sind 3 SRF08 Sensoren angebaut, welche eingestellt und am ehemals RP6 Base-Master super funktionierten (modifiziertes Example Programm).
Mein Problem:
Die SRF Sensoren werden im Master-Slave Modus nicht korrekt ausgelesen/ angesprochen.
Der Code im Slave:


/*
* ************************************************** **************************
* 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

#define SRF_LEFT_ADR 0xE6
#define SRF_MIDDLE_ADR 0xE4
#define SRF_RIGHT_ADR 0xE2
/************************************************** ***************************/

// 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
#define I2C_REG_SRF_LEFT_ADR 30
#define I2C_REG_SRF_MIDDLE_ADR 31
#define I2C_REG_SRF_RIGHT_ADR 32
uint16_t distance_left = 0;
uint16_t distance_right = 0;
uint16_t distance_middle = 0;

/**
* 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);
I2CTWI_readRegisters[I2C_REG_SRF_LEFT_ADR] = (uint8_t)(distance_left);
I2CTWI_readRegisters[I2C_REG_SRF_MIDDLE_ADR] = (uint8_t)(distance_middle);
I2CTWI_readRegisters[I2C_REG_SRF_RIGHT_ADR] = (uint8_t)(distance_right);
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(500);
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;
}

und der Code im RP6 M32 Master:

/*
* ************************************************** **************************
* RP6 ROBOT SYSTEM - RP6 CONTROL M32 Examples
* ************************************************** **************************
* Example: I2C Master 8 - Lib
* Author(s): Dominik S. Herwald
* ************************************************** **************************
* Description:
* To make it easier to understand, we have put several routines and definitions
* in a seperate file now.
* We made the library like the RP6Lib - all variable names are just the
* same as in the RP6Lib. Also some functions have the same names
* and parameters.
* There are also all the event handlers like the ACS and Bumpers event
* Handler - plus some new ones. In the next example we will add movement
* functions to the library...
*
* This makes it easier to reuse parts of programs written for the RP6Lib on
* RP6-M32.
*
* In this example we do just the same as in the last program, but we also
* output several sensor values on the serial Interface and enable the
* timed watchdog of the slave, which generates an interrupt every 500ms and
* forces the Master to respond. These requests are shown with a second
* blinking character on the LC-Display. If the Master does not respond within
* 3 seconds, the Robot gets stopped.
*
* ################################################## ##########################
* The Robot does NOT move in this example! You can simply put it on a table
* next to your PC and you should connect it to the PC via the USB Interface!
* ################################################## ##########################
* ************************************************** **************************
*/

/************************************************** ***************************/

#include "RP6ControlLib.h" // The RP6 Control Library.
#include "RP6I2CmasterTWI.h" // I2C Master Library
#include "RP6Control_I2CMasterLib.h"

// This Library has a lot of new functions for controlling the Robot Base unit
// with the RP6 CONTROL M32 via the I2C Bus.
// In the next example we will add some more functions to it and let one
// of the more complex example programs of the Robot Base run on it.

/************************************************** ***************************/
#define SRF_LEFT_ADR 0xE6
#define SRF_MIDDLE_ADR 0xE4
#define SRF_RIGHT_ADR 0xE2

#define MEASURE_US_LEFT_LOW 0
#define MEASURE_US_LEFT_HIGH 1
#define MEASURE_US_RIGHT_LOW 2
#define MEASURE_US_RIGHT_HIGH 3
#define MEASURE_US_MIDDLE_LOW 4
#define MEASURE_US_MIDDLE_HIGH 5

/**
* This is just the same as in the last example - but inside of the
* ACS Event Handler that you already know from the Base Unit.
* You can even use the same variables - obstacle_left and obstacle_right!
*/
void acsStateChanged(void)
{
writeString_P("ACS state changed L: ");
if(obstacle_left)
{
writeChar('o');
setCursorPosLCD(1, 12);
writeStringLCD_P("LEFT");
}
else
{
writeChar(' ');
clearPosLCD(1, 12, 4);
}
writeString_P(" | R: ");
if(interrupt_status.obstacleRight)
{
writeChar('o');
setCursorPosLCD(1, 0);
writeStringLCD_P("RIGHT");
}
else
{
writeChar(' ');
clearPosLCD(1, 0, 5);
}
if(obstacle_left && obstacle_right)
{
externalPort.LEDS = 0b0110;
writeString_P(" MIDDLE!");
setCursorPosLCD(1, 7);
writeStringLCD_P("MID");
}
else
{
externalPort.LEDS = 0b0000;
clearPosLCD(1, 7, 3);
}

if(obstacle_left)
externalPort.LED1 = true;
if(obstacle_right)
externalPort.LED4 = true;
outputExt();

if(obstacle_left && obstacle_right)
{
sound(140,10,0);
}
else
{
if(obstacle_left)
sound(100,5,0);
if(obstacle_right)
sound(120,5,0);
}
writeChar('\n');
}

/**
* The same as for the ACS Event Handler above applies for the Bumpers
* Event Handler!
*/
void bumpersStateChanged(void)
{
// Bumper status changed, output current state and play sounds:
writeString_P("Bumpers changed: ");
if(bumper_right && bumper_left)
{
writeString_P("MIDDLE!");
sound(200,100,0);
}
else
{
if(bumper_left)
{
writeString_P("LEFT!");
sound(200,50,10);
sound(150,20,0);
}
else if(bumper_right)
{
writeString_P("RIGHT!");
sound(200,50,10);
sound(150,20,0);
}
else
{
writeString_P("FREE!");
}
}
writeChar('\n');
}

/**
* And the RC5 Event Handler is the same as on the Robot Base, too.
*/
void receiveRC5Data(RC5data_t rc5data)
{
// Output the received data:
writeString_P("RC5 Reception --> Toggle Bit:");
writeChar(rc5data.toggle_bit + '0');
writeString_P(" | Device Address:");
writeInteger(rc5data.device, DEC);
writeString_P(" | Key Code:");
writeInteger(rc5data.key_code, DEC);
writeChar('\n');
}

/**
* This is a new Event Handler and it gets called when the Battery Voltage
* is getting low! The Parameter isVoltageLow is true, when the voltage
* is low and false, when the voltage is OK.
*/
void batteryVoltageLow(uint8_t isVoltageLow)
{
if(isVoltageLow)
{
writeString_P("\nBattery Voltage low: ");
// Send Battery voltage to UART:
writeIntegerLength((((adcBat/102.4f)+0.1f)), DEC, 2);
writeChar('.');
writeIntegerLength((((adcBat/1.024f)+10)), DEC, 2);
writeString_P("V\n");
}
else
{
writeString_P("\nBattery Voltage is OK!\n");
}
}

/**
* This function prints out all ADC values and motor parameters:
* power, desired speed, measured speed and driven distance.
*
* It first calls "getAllSensors()" from the library which reads all
* the sensor values we use here from the Slave Controller.
* Then you can use just the same variables as on the RP6Base to get
* the ADC values.
*/
void printAllSensorValues(void)
{
getAllSensors();
writeString_P("\nRead Sensor Values:\n");
writeString_P("PL:");writeIntegerLength(mleft_power,DEC,3);
writeString_P(" | PR:");writeIntegerLength(mright_power,DEC,3);
writeString_P(" | VL:");writeIntegerLength(mleft_speed,DEC,3);
writeString_P(" | VR:");writeIntegerLength(mright_speed,DEC,3);
writeString_P(" | DL:");writeIntegerLength(mleft_des_speed,DEC,3);
writeString_P(" | DR:");writeIntegerLength(mright_des_speed,DEC,3);
writeChar('\n');
writeString_P("DSTL:");writeIntegerLength(mleft_dist,DEC,5);
writeString_P(" | DSTR:");writeIntegerLength(mright_dist,DEC,5);
writeChar('\n');
writeString_P("LSL:");writeIntegerLength(adcLSL,DEC,4);
writeString_P(" | LSR:");writeIntegerLength(adcLSR,DEC,4);
writeString_P(" | MCL:");writeIntegerLength(adcMotorCurrentLeft,DEC,4);
writeString_P(" | MCR:");writeIntegerLength(adcMotorCurrentRight,DEC,4);
writeString_P(" | BAT:");writeIntegerLength(adcBat,DEC,4);
writeString_P(" | AD0:");writeIntegerLength(adc0,DEC,4);
writeString_P(" | AD1:");writeIntegerLength(adc1,DEC,4);
//writeString_P(" | SRF_R:");writeIntegerLength(distance_right, DEC,4);
//writeString_P(" | SRF_M:");writeIntegerLength(distance_middle, DEC,4);
//writeString_P(" | SRF_L:");writeIntegerLength(distance_left, DEC,4);
writeChar('\n');
}

/**
* Heartbeat function
*/
void task_LCDHeartbeat(void)
{
if(getStopwatch1() > 500)
{
static uint8_t heartbeat = false;
if(heartbeat)
{
clearPosLCD(0, 15, 1);
heartbeat = false;
}
else
{
setCursorPosLCD(0, 15);
writeStringLCD_P("*");
heartbeat = true;
printAllSensorValues();
}
setStopwatch1(0);
}
}

/**
* Now we have a second "Heartbeat" display
* which shows if the Controller still reacts on
* the Watchdog requests from the Slave Controller!
* And it also shows if the slave Controller is
* still up and running.
*
* It will blink with a rate of about 2Hz when
* the watchdog requests are still active.
*/
void watchDogRequest(void)
{
static uint8_t heartbeat2 = false;
if(heartbeat2)
{
clearPosLCD(0, 14, 1);
heartbeat2 = false;
}
else
{
setCursorPosLCD(0, 14);
writeStringLCD_P("#");
heartbeat2 = true;
}
}


/************************************************** ***************************/
void task_SRF(void)
{
static uint8_t measureInProgress = false;
static uint8_t channel = 0;
if(!measureInProgress) // Start measurement ONCE only
{
if(TWI_operation == I2CTWI_NO_OPERATION) // If there is no request in progress...
{
if(channel == 0)
I2CTWI_transmit2Bytes(SRF_LEFT_ADR, 0, 81);
else if(channel == 1)
I2CTWI_transmit2Bytes(SRF_RIGHT_ADR, 0, 81);
else if(channel == 2)
I2CTWI_transmit2Bytes(SRF_MIDDLE_ADR, 0, 81);
measureInProgress = true;
setStopwatch2(0);
}
}
else if(getStopwatch2() > 1000) // 1000ms (measurement delay)
{
if(channel == 0)
{
I2CTWI_transmitByte(SRF_LEFT_ADR, 2);
I2CTWI_requestDataFromDevice(SRF_LEFT_ADR, MEASURE_US_LEFT_HIGH, 1);
channel = 1;
}
else if(channel == 1)
{
I2CTWI_transmitByte(SRF_RIGHT_ADR, 2);
I2CTWI_requestDataFromDevice(SRF_RIGHT_ADR, MEASURE_US_RIGHT_HIGH, 1);
channel = 2;
}
else if(channel == 2)
{
I2CTWI_transmitByte(SRF_MIDDLE_ADR, 2);
I2CTWI_requestDataFromDevice(SRF_MIDDLE_ADR, MEASURE_US_MIDDLE_HIGH, 1);
channel = 0;
}
measureInProgress = false;
setStopwatch2(0);
}
}

// I2C Requests:

/**
* The I2C_requestedDataReady Event Handler is now a lot smaller.
* It is free for your own request routines.
* You can put them in the Block of the if condition.
* (similar to the RP6 Base Example programs...)
*/
void I2C_requestedDataReady(uint8_t dataRequestID)
{
// We need to check if this is an INT0 Request from the Robot Base unit.
// The Function call inside the if condition returns true if it was an
// interrupt request, so we have to negate it here and if it was NOT
// an interrupt request from the Robot base we can check any other sensors
// from which you may have requested data...
uint16_t distance_left = 0;
uint16_t distance_right = 0;
uint16_t distance_middle = 0;

uint8_t messageBuf[8]; //------------------- erzeugt Fehler im Terminal,wenn es hier steht
static uint8_t dist_tmp;
switch(dataRequestID)
{
case MEASURE_US_LEFT_HIGH:
I2CTWI_getReceivedData( messageBuf, 2 );
dist_tmp = messageBuf[0];
I2CTWI_transmitByte(SRF_LEFT_ADR, 3);
I2CTWI_requestDataFromDevice(SRF_LEFT_ADR, MEASURE_US_LEFT_LOW, 1);
break;
case MEASURE_US_LEFT_LOW:
I2CTWI_getReceivedData( messageBuf, 2 );
distance_left = messageBuf[0] + (dist_tmp << 8);
writeString_P("DistanceL: ");
writeInteger(distance_left, DEC);
writeString_P(" cm ");
break;
case MEASURE_US_RIGHT_HIGH:
I2CTWI_getReceivedData( messageBuf, 2 );
dist_tmp = messageBuf[0];
I2CTWI_transmitByte(SRF_RIGHT_ADR, 3);
I2CTWI_requestDataFromDevice(SRF_RIGHT_ADR, MEASURE_US_RIGHT_LOW, 1);
break;
case MEASURE_US_RIGHT_LOW:
I2CTWI_getReceivedData( messageBuf, 2 );
distance_right = messageBuf[0] + (dist_tmp << 8);
writeString_P("\t\tDistanceR: ");
writeInteger(distance_right, DEC);
writeString_P(" cm\n");
break;
case MEASURE_US_MIDDLE_HIGH:
I2CTWI_getReceivedData( messageBuf, 2 );
dist_tmp = messageBuf[0];
I2CTWI_transmitByte(SRF_MIDDLE_ADR, 3);
I2CTWI_requestDataFromDevice(SRF_MIDDLE_ADR, MEASURE_US_MIDDLE_LOW, 1);
break;
case MEASURE_US_MIDDLE_LOW:
I2CTWI_getReceivedData( messageBuf, 2 );
distance_middle = messageBuf[0] + (dist_tmp << 8);
writeString_P("\t\tDistanceM: ");
writeInteger(distance_middle, DEC);
writeString_P(" cm\n");
break;
}
if(!checkRP6Status(dataRequestID))
{
// Here you can Check other sensors/microcontrollers with their own
// request IDs - if there are any...

}

}

/************************************************** ***************************/
// I2C Error handler

/**
* This function gets called automatically if there was an I2C Error like
* the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
*/
void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR - TWI STATE: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}

/************************************************** ***************************/
// Main function - The program starts here:

int main(void)
{
initRP6Control();
initLCD();

writeString_P("\n\nRP6 CONTROL M32 I2C Master Example Program!\n");
writeString_P("\nInterrupts - part 2...\n");

// ---------------------------------------
// The Event Handlers can be set the same way as with the
// RP6Lib:
ACS_setStateChangedHandler(acsStateChanged);
BUMPERS_setStateChangedHandler(bumpersStateChanged );
IRCOMM_setRC5DataReadyHandler(receiveRC5Data);
// New LowBat Event Handler:
BATTERY_setLowVoltageHandler(batteryVoltageLow);
// New Watchdog Request Event Handler:
WDT_setRequestHandler(watchDogRequest);

// ---------------------------------------
// Init TWI Interface:
I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);

sound(180,80,25);
sound(220,80,25);

setLEDs(0b1111);

showScreenLCD("################", "################");
mSleep(500);
showScreenLCD("I2C-Master", "Example Program 3");
mSleep(1000);
setLEDs(0b0000);

// ---------------------------------------
// Setup ACS power:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_ACS_POWER, ACS_PWR_MED);
// Enable Watchdog for Interrupt requests:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT, true);
// Enable timed watchdog requests:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT_RQ, true);

showScreenLCD("ACS Status:", "");

startStopwatch1();
startStopwatch2();

while(true)
{
task_SRF();
task_LCDHeartbeat();
task_checkINT0();
task_I2CTWI();
}
return 0;
}



Im Praxisfall macht der RP6 "Sensortests" und je eine Messung mit dem SRF während ein IR Sensor einen Gegenstand detektiert. Nach einiger Zeit kommt eine "RC5 Reception --> Toggle Bit:0 | Device Adresse:0 | Key Code:0" Meldung im Terminal.

Ich schätze mal, das Lesen oder Schreiben von Register in RC5 Bereich falsch laufen.

Kann mir jemand damit helfen, oder zumindest in die richtige Richtung schieben?

Vielen Dank im Voraus.

Mfg, Mac80

Dirk
13.04.2012, 19:10
@Mac80,

grundsätzlich sollte der Slave (Base) alle Dinge erledigen, die mit den SRF08 zu tun haben. Das heißt: In seiner task_update() müßten regelmäßig die neuen Distanzwerte in die Variablen geschrieben werden. Der Master kann sie dann über die Register 30..32 auslesen, wenn er will.
Der Slave kann natürlich auch über Int0 signalisieren, dass Daten der SRF08 anliegen. Das müßte dann in I2C_requestedDataReady() ausgewertet werden.

Hilft das?
Du müßtest also deine Programmlogik noch einmal überdenken ...

Mac80
13.04.2012, 20:15
Vielen Dank für die schnelle Antwort.
Ja, du hast ja recht, das ganze war nur eine Art Notlösung da ich die Funktion "void task_SRF(void)" im RP6 Base so nicht aufrufen konnte (wegen I2CTWI_getReceivedData... usw., die nur in der "RP6I2CmasterTWI.h" vorhanden ist). Das würde bedeuten, dass eine Funktion "void task_SRF(void)" komplett im RP6 Master wegfällt.
Ich glaub, ich steh gerade im Wald.
Wie würde der Slave (RP6 Base) die Messwerte vom SRF08 erhalten, ohne die "RP6I2CmasterTWI.h" zu benutzen?

Gruß
Mac80

Dirk
13.04.2012, 21:00
@Mac80,

ok, vielleicht hatte ich eben dein Problem noch nicht richtig verstanden ...

Das mit dem "Überdenken" hatte ich so gemeint:

1. Du hast ja ein I2C-Bussystem mit einem Master (M32) und 4 Slaves (Base + 3x SRF08 ).
2. Der Master kann mit den 4 Slaves kommunizieren und Daten abfragen.
3. Normalerweise dient die M32 ja dann dazu, als "Gehirn" des Roboters zu funktionieren.
4. Das heißt: Die M32 braucht die SRF08-Daten, um die Base wie gewünscht zu steuern.
5. Das heißt auch: Die Base braucht die Sensordaten eigentlich nicht selbst, denn sie wird ja durch die M32 "ferngesteuert".
6. Das Fernsteuern wird erreicht, indem in der Base das I2C-Slave-Programm läuft und in der M32 ein passender Master.

Davon war ich ausgegangen. Willst du das irgendwie anders machen?

Mac80
14.04.2012, 11:32
Hallo,
ja so hatte ich mir das vorgestellt, dass der I2C-Master alle Daten abfragt. Da die Base ursprünglich die Sensordaten abgefragt hatte (Beispielprogramm), wollte ich das erstmal auch so lassen. Da aber der I2C-Master nun auf dem M32 läuft, musste ich das anpassen. Von der Leistung her sollte das für den M32 kein Problem darstellen.
Mein neuer Ansatz wäre jetzt, auf dem Base (Slave) alle Sensordaten zu entfernen, außer den Definitionen und dem Registeranhang, wenn dies nötig ist. Über die Funktion "void I2C_requestedDataReady(uint8_t dataRequestID)" im M32-Master sollten dann I2C Abfragekollisionen vermieden werden können. Momentan hängen 5 Slaves am I2C Bus (Base, 3x Sensor SRF08 und ein inaktiver TSL2561 Lichtsensor). Wenn die Abfragen der SRF08 Sensoren störungsfrei funktionieren, dann kommt der TSL2561 dazu. Abfragen auch über den Master.
Momentan muss ich nochmal die Ansteuerung der SRF Sensoren überarbeiten, da sei scheinbar nur messen, wenn die IR Sensoren ein Objekt detektieren. Ansonsten wird immer noch der Startwert 0 zugewiesen.


Gruß
Mac80

RolfD
14.04.2012, 15:20
Hallo Mac80
ich gebe folgendes zu bedenken. So lange die Base die Sensoren auslesen soll und keine M32 aufsitzt, müsste alles funktionieren wie geplant. Sobald aber die M32 aufsitzt muss die Base als Slave laufen. Liest die Base aber dabei Sensoren aus, würde sie als Master auf dem Bus agieren und es wäre ein Multimaster System bzw die Base müsste Master und Slave Mode können. Dagegen ist technisch so nichts einzuwenden, jedoch hat die CPU angeblich Hardwareseitig ein Problem bei der Erkennung von Buskollisionen
(http://www.robotroom.com/Atmel-AVR-TWI-I2C-Multi-Master-Problem.html)
und obendrein funktioniert die Busarbitierung mit der RP6Lib Software so nicht und es gibt auch sonst noch ein paar Schwierigkeiten.

Allein ein System mit Base als "dummer" Slave, Slave-Sensoren und M32 als Master ist mit Boardmitteln denkbar aber leider relativ instabil. Mit der M128 lässt sich das entsprechend noch weiter spinnen - wobei die auch nur Funktionen vergleichbar mit der Feury Lib bietet und eher nicht Multimaster tauglich ist. (http://homepage.hispeed.ch/peterfleury/avr-software.html#libs)

Wenn Dich die Hintergründe interssieren:
https://www.roboternetz.de/community/threads/51816-Dicker-Fehler-in-der-RP6I2CmasterTWI-h-der-RP6Lib-Bugfix
Ich habe jedoch die Arbeit daran magels Interesse & Feedback eingestellt. Wenn weiterhin Interesse an einem Multimastersystem besteht, empfehle ich Dir die Libs vom Arduino Projekt, dort insbesondere wire.cpp und twi.c/.h.
Damit ist zumindest ein stabiler Multimasterslave Betrieb möglich.

Leider macht das Gefummel mit den Interrupts in der RP6 Lib ein stabilen Betrieb der Base Slave schwierig - eigentlich bräuchte man auf der Base ein stabiles Core System wenn man mit der M32 anfängt zu experimentieren. Ich habe diesbezüglich mal mit Nano OS (http://sourceforge.net/projects/nanoos/ und http://www.mikrocontroller.net/topic/190388) experimentiert, aber bin bisher nicht zu vorzeigbaren Ergebnissen gekommen. Leider konnte ich auch noch niemand dazu bewegen, das als Team gemeinsam anzugehen und um das allein zu machen issses mir zu Aufwendig. Das I2C aber allgemein beim RP6 problematisch ist, erfährst du schon wenn du hier nach i2c suchst. Echte Lösungen findet man aber kaum - nur Minimallkompromisse und Provisorien.
LG Rolf

Mac80
15.04.2012, 18:05
Hallo Rolf,
ich habe jetzt das Erweiterungsmodul M32 stillgelegt, bis bei mir da eine bessere Lösung funktioniert. Bis dahin verwende ich nur das RP6 Base als Master, womit auch alle SRF Sensoren funktionieren.
Da ich schon mit dem Arduino Mega 2560 die einzelnen Bauteile getestet hatte und mit Wire.h gut zu rande kam, stellten sich schon die ersten Probleme mit der I2C Umstellung beim RP6 ein.
Wobei mich da jetzt das nächste Problem einholt. Mit dem Arduino konnte ich den TSL2561 ganz gut ansprechen, aber mit der jetzigen Lib (RP6I2CmasterTWI.h) habe ich so meine Probleme.

Der (Beispiel) Code im Arduino:


#include <Wire.h>

void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial communication at 9600bps
}

int reading = 0;

void loop()
{
Wire.beginTransmission(115);
Wire.write(byte(0x00));
Wire.write(byte(0x51));
Wire.endTransmission();
delay(70);
Wire.beginTransmission(115);
Wire.write(byte(0x02));
Wire.endTransmission();
Wire.requestFrom(115, 2);

if(2 <= Wire.available()) // if two bytes were received
{
reading = Wire.read();
reading = reading << 8;
reading |= Wire.read();
Serial.println(reading);
}

delay(500);
}




Übertragung (Kurzform) auf RP6I2CmasterTWI.h im RP6 Base:



#include "RP6RobotBaseLib.h"
#include "RP6I2CmasterTWI.h"

#define SRF_LEFT_ADR 0xE6
#define SRF_MIDDLE_ADR 0xE4
#define SRF_RIGHT_ADR 0xE2
#define TSL_2561_ADR 0x39

#define MEASURE_US_LEFT_LOW 0
#define MEASURE_US_LEFT_HIGH 1
#define MEASURE_US_RIGHT_LOW 2
#define MEASURE_US_RIGHT_HIGH 3
#define MEASURE_US_MIDDLE_LOW 4
#define MEASURE_US_MIDDLE_HIGH 5
#define MEASURE_TSL_DATA_LOW 6
#define MEASURE_TSL_DATA_HIGH 7

uint16_t distance_left = 0;
uint16_t distance_right = 0;
uint16_t distance_middle = 0;
uint16_t lux = 0;

//I2C Bus Werteabfrage auf Adressen
void I2C_requestedDataReady(uint8_t dataRequestID)
{
uint8_t messageBuf[8];
static uint8_t dist_tmp;
switch(dataRequestID)
{
case MEASURE_US_LEFT_HIGH:
I2CTWI_getReceivedData( messageBuf, 2 );
dist_tmp = messageBuf[0];
I2CTWI_transmitByte(SRF_LEFT_ADR, 3);
I2CTWI_requestDataFromDevice(SRF_LEFT_ADR, MEASURE_US_LEFT_LOW, 1);
break;
case MEASURE_US_LEFT_LOW:
I2CTWI_getReceivedData( messageBuf, 2 );
distance_left = messageBuf[0] + (dist_tmp << 8);
writeString_P("SRF_L: ");
writeInteger(distance_left, DEC);
writeString_P(" cm ");
break;
case MEASURE_US_RIGHT_HIGH:
I2CTWI_getReceivedData( messageBuf, 2 );
dist_tmp = messageBuf[0];
I2CTWI_transmitByte(SRF_RIGHT_ADR, 3);
I2CTWI_requestDataFromDevice(SRF_RIGHT_ADR, MEASURE_US_RIGHT_LOW, 1);
break;
case MEASURE_US_RIGHT_LOW:
I2CTWI_getReceivedData( messageBuf, 2 );
distance_right = messageBuf[0] + (dist_tmp << 8);
writeString_P("\tSRF_R: ");
writeInteger(distance_right, DEC);
writeString_P(" cm");
break;
case MEASURE_US_MIDDLE_HIGH:
I2CTWI_getReceivedData( messageBuf, 2 );
dist_tmp = messageBuf[0];
I2CTWI_transmitByte(SRF_MIDDLE_ADR, 3);
I2CTWI_requestDataFromDevice(SRF_MIDDLE_ADR, MEASURE_US_MIDDLE_LOW, 1);
break;
case MEASURE_US_MIDDLE_LOW:
I2CTWI_getReceivedData( messageBuf, 2 );
distance_middle = messageBuf[0] + (dist_tmp << 8);
writeString_P("\tSRF_M: ");
writeInteger(distance_middle, DEC);
writeString_P(" cm\n");
break;
case MEASURE_TSL_DATA_HIGH:
I2CTWI_getReceivedData( messageBuf, 2 );
dist_tmp = messageBuf[0];
I2CTWI_transmitByte(TSL_2561_ADR, 3);
I2CTWI_requestDataFromDevice(TSL_2561_ADR, MEASURE_TSL_DATA_LOW, 1);
case MEASURE_TSL_DATA_LOW:
I2CTWI_getReceivedData( messageBuf, 2 );
lux = messageBuf[0] + (dist_tmp << 8); //
writeString_P("\tTSL: ");
writeInteger(lux, DEC);
writeString_P(" lux\n");
break;
}
}

//I2C Bus Fehlerausgabe
void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR --> TWI STATE IS: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}

//SRF08 Sensorenfunktion
void task_SRF(void)
{
static uint8_t measureInProgress = false;
static uint8_t channel = 0;
if(!measureInProgress) // Start measurement ONCE only
{
if(TWI_operation == I2CTWI_NO_OPERATION) // Busverkehrüberwachung, freie Transfermöglichkeit
{
if(channel == 0)
I2CTWI_transmit2Bytes(SRF_LEFT_ADR, 0, 81);
else if(channel == 1)
I2CTWI_transmit2Bytes(SRF_RIGHT_ADR, 0, 81);
else if(channel == 2)
I2CTWI_transmit2Bytes(SRF_MIDDLE_ADR, 0, 81);
measureInProgress = true;
setStopwatch1(0);
}
}
else if(getStopwatch1() > 500) // 500ms Messverzögerung
{
if(channel == 0)
{
I2CTWI_transmitByte(SRF_LEFT_ADR, 2);
I2CTWI_requestDataFromDevice(SRF_LEFT_ADR, MEASURE_US_LEFT_HIGH, 1);
channel = 1;
}
else if(channel == 1)
{
I2CTWI_transmitByte(SRF_RIGHT_ADR, 2);
I2CTWI_requestDataFromDevice(SRF_RIGHT_ADR, MEASURE_US_RIGHT_HIGH, 1);
channel = 2;
}
else if(channel == 2)
{
I2CTWI_transmitByte(SRF_MIDDLE_ADR, 2);
I2CTWI_requestDataFromDevice(SRF_MIDDLE_ADR, MEASURE_US_MIDDLE_HIGH, 1);
channel = 0;
}
measureInProgress = false;
setStopwatch1(0);
}
}

int task_TSL()
{
static uint8_t measureInProgress = false;
static uint8_t channel = 0;
uint8_t DataLow = 0;
uint8_t DataHigh = 0;
uint8_t Channel3 = 0;

if(!measureInProgress)
{
if(TWI_operation == I2CTWI_NO_OPERATION)
{
if(channel == 3)
I2CTWI_transmit2Bytes(TSL_2561_ADR, 140, DataLow);
I2CTWI_transmit2Bytes(TSL_2561_ADR, 141, DataHigh);
measureInProgress = true;
setStopwatch2(0);
}
else if(getStopwatch2() >500)
I2CTWI_transmitByte(TSL_2561_ADR, 2);
I2CTWI_requestDataFromDevice(TSL_2561_ADR, MEASURE_TSL_DATA_HIGH, 1);
}
measureInProgress = false;
setStopwatch2(0);
Channel3 = DataHigh*256+DataLow;
return(Channel3);
}



int main(void)
{
initRobotBase();

I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);

setLEDs(0b111111);
mSleep(500);
setLEDs(0b000000);

powerON();


startStopwatch1(); //SRF
startStopwatch2(); //TSL2561
startStopwatch3();

while(true)
{
task_TSL(); //kommt noch...
task_SRF();
task_I2CTWI();
task_RP6System();
}
return 0;
}



Klappt noch nicht.

Nach dem Chip Hersteller soll man die Struktur beachten:
Read ADC Channels Using Read Byte Protocol

Address = 0x39 //Slave addr − also 0x29 or 0x49
Command = 0x8C //Address the Ch0 lower data register
ReadByte (Address, Command, DataLow) //Result returned in DataLow
Command = 0x8D //Address the Ch0 upper data register
ReadByte (Address, Command, DataHigh) //Result returned in DataHigh
Channel0 = 256 * DataHigh + DataLow //Shift DataHigh to upper byte
Command = 0x8E //Address the Ch1 lower data register
ReadByte (Address, Command, DataLow) //Result returned in DataLow
Command = 0x8F //Address the Ch1 upper data register
ReadByte (Address, Command, DataHigh) //Result returned in DataHigh
Channel1 = 256 * DataHigh + DataLow //Shift DataHigh to upper byte


Da bräuchte ich Hilfe.

Gruß
Mac80

RolfD
16.04.2012, 03:46
Da Du mit der Arduino Software vertraut bist sollte es dir möglich sein, die TWI funktionen aus der RP6 Lib rauszuwerfen (oder einfach nicht zu includieren) und statt dessen die Arduino Funktionen zu portieren.. das ist etwas arbeit aber es lohnt sich. Die twi.c/.h müsste man fast komplett so übernehmen können, evtl. auf sowas wie Frequenzen achten und so... die wire.c ist zwar in c++ geschrieben aber recht simpel - eigentlich ist es nicht kompliziert sie in ein normalen c code zu übertragen. Da könnte auch der gcc präprozessor bzw. g++ helfen. Ich halte es auch für machbar, einen Wrapper zu schreiben der die Aufrufe aus den Demoprogrammen gegen die RP6 TWI Libs austauscht gegen Aufrufe der Arduino Lib - so das man dann die noramlen RP6Lib Aufrufe weiter verwenden kann. Das wär aber dann schon Schritt 2.
Dann wird jedenfalls auch dein TSL2561 und die Srfs wieder so funktionieren wie getestet. Ich habe diese Woche leider keine Zeit am Source zu arbeiten aber ich bin an den Ergebnissen interssiert und werde mich nächste Woche evtl. mal mit dran setzen.
LG Rolf

SlyD
16.04.2012, 13:44
@Mac80:
Zu dem TSL Code.
Erstmal glaube ich das da ein paar Klammern in Deiner task_TSL nicht so ganz richtig gesetzt sind.
Eine if Bedingung ohne klammer führt nur genau EINE direkt darauf folgende Zeile aus.
Die Einrückung spielt in C anders als in Python keine Rolle ;)

Und was if(channel == 3) da überhaupt zu suchen hat ist mir auch nicht ganz klar.

Also strukturier es doch zunächst etwas einfacher und versuch erst danach es so zu machen
wie es für die SRFs gelöst wurde.

Du musst ja nicht die requestedDataReady Funktion verwenden.
Das ist nur um mehr Dinge nebenläufig erledigen zu können eingeführt worden.
Es geht auch normal blockierend.

Im Beispiel RP6Base_I2CMaster_04.c siehst Du wie man beide Arten auch miteinander mischen kann.

Dann reduziert sich ein Zugriff auf so einen Sensor z.B. auf




#define PCF8591_4LDRS_ADR 0x90

/**
* Read 4x PCF8591 LDRs - we do not take advantage of the method we use for
* the SRF Sensors above!
*/
void task_ext_LDRs(void)
{
if(getStopwatch2() > 200)
{
I2CTWI_transmitByte(PCF8591_4LDRS_ADR, 0b01000100 ); // 64 + 4);

uint8_t results[6];
I2CTWI_readBytes(PCF8591_4LDRS_ADR,results,5);
// Byte 0 contains last conversion result - thus we skip it and
// begin with results[1]:
writeString_P(" | LDR1:"); writeInteger(results[1], DEC);
writeString_P(" | LDR2:"); writeInteger(results[2], DEC);
writeString_P(" | LDR3:"); writeInteger(results[3], DEC);
writeString_P(" | LDR4:"); writeInteger(results[4], DEC);
writeChar('\n');
setStopwatch2(0);
}
}



Hier ein PCF8591 4 Kanal ADC auslesen - musst Du natürlich noch an den Sensor anpassen.
Probiers doch erstmal so.

MfG,
SlyD

SlyD
16.04.2012, 14:13
Jetzt noch kurz eine Vermutung warum Du oben mit der Lib auf dem M32 Probleme hast.
Du hast da einfach nicht bedacht das die RP6Control_I2CMasterLib mit eingebunden ist.
Der Code gehört natürlich mit zum Programm!

#define INT0_STATUS_CHECK 0

und


#define MEASURE_US_LEFT_LOW 0

sind hier beide auf derselben Request ID.
--> Schlecht.
Also bitte alle Deine eigenen request IDs um 1 erhöhen.


Dann noch folgendes aus einem der Beispielprogramme lesen:




/**
* The I2C_requestedDataReady Event Handler is now a lot smaller.
* It is free for your own request routines.
* You can put them in the Block of the if condition.
* (similar to the RP6 Base Example programs...)
*/
void I2C_requestedDataReady(uint8_t dataRequestID)
{
// We need to check if this is an INT0 Request from the Robot Base unit.
// The Function call inside the if condition returns true if it was an
// interrupt request, so we have to negate it here and if it was NOT
// an interrupt request from the Robot base we can check any other sensors
// from which you may have requested data...

if(!checkRP6Status(dataRequestID))
{
// Here you can Check other sensors/microcontrollers with their own
// request IDs - if there are any...
}
}





Dein Code gehört also eigentlich in die If Bedingung rein.
Nicht davor.
Das alleine wäre aber nicht so schlimm, problematischer
ist da schon das mit der doppelt belegten request ID.

Das kommt sich natürlich in die Quere da ja beides gleichzeitig läuft...



Ob das das einzige Problem ist oder noch an anderer Stelle irgendwas nicht stimmt habe ich jetzt nicht genauer untersucht.
Aber ändere erstmal das und teste es dann nochmal.

Hattest Du am Slave Code von der RP6Base irgendwas geändert?
(Ich frage nur weil Du den Code hier gepostet hattest, auf den ersten blick sieht der unverändert aus)

MfG,
SlyD

Mac80
16.04.2012, 21:26
@SlyD

Ja, der Slave Code ist nur um ein paar Zeilen erweitert worden und evtl. waren da noch die Reste vom Test Code (SRF im Slave auslesen - das habe ich ja nun verworfen).
Danke - die "Request ID 0" Doppeltvergabe habe ich übersehen. Das werde ich nochmal testen und bescheid geben ob es daran lag. Die if-Bedingung ist mir leider nicht so gut gelungen (garnicht), da ich ein wenig von den Herstellangaben irritiert war. Ich habe die nächsten Tage noch mal vor, eine abgespeckte Version vom I2C Slave Read (nur der TSL2561) zu schreiben, in der Hoffnung ein paar Daten zu erhalten.

Das macht mir jetzt wieder Hoffnung.

@RolfD
Ich habe testweise schon mal probiert die Libs von Arduino zu verwenden. Da muss man jede Menge Header Dateien mit einbinden, um einen Haufen Fehlermeldungen zu verarbeiten. Das Beste in diesem Fall wäre, alle Libs von Arduino in das entsprechende Verzeichnis zu kopieren. Da gibt es auch ein paar doppelte Definierungen eines Typs und ein Haufen anderer Fehlermeldungen. Das ist aber ein lohnendes Ziel, die Libs von Arduino zu importieren. Das werde ich mal am Wochenende austesten.

Vorzugsweise werde ich den TSL in das schon vorhandene Gerüst im RP6 ein zu binden versuchen. Danach geht es Schritt für Schritt weiter.

Ich danke euch beiden.

Gruß
Mac80

Mac80
20.04.2012, 20:58
@SlyD

Hallo, du hattest recht. Als ich die ID angepasst hatte, funktionierte der Ablauf absturzfrei. Die SRF Anweisung habe ich dann noch in die if Bedingung gesetzt und siehe da: Es funktionierte, wie es wohl sollte.
Ich habe weiterhin noch die requestedDataReady Funktion verwendet. Hier noch ein kurzer Auszug von der Terminalausgabe:

Read Sensor Values:
PL:000 | PR:000 | VL:000 | VR:000 | DL:000 | DR:000
DSTL:00001 | DSTR:00001
LSL:0971 | LSR:0963 | MCL:0000 | MCR:0000 | BAT:0748 | AD0:0956 | AD1:0949
| SRF_M: 146 cm |
SRF_L: 34 cm

Read Sensor Values:
PL:000 | PR:000 | VL:000 | VR:000 | DL:000 | DR:000
DSTL:00001 | DSTR:00001
LSL:0967 | LSR:0960 | MCL:0000 | MCR:0000 | BAT:0748 | AD0:0953 | AD1:0946
|tSRF_R: 53 cm | | SRF_M: 146 cm |

Read Sensor Values:
PL:000 | PR:000 | VL:000 | VR:000 | DL:000 | DR:000
DSTL:00001 | DSTR:00001
LSL:0967 | LSR:0960 | MCL:0000 | MCR:0000 | BAT:0748 | AD0:0953 | AD1:0946
SRF_L: 28 cm |tSRF_R: 53 cm |

Read Sensor Values:
PL:000 | PR:000 | VL:000 | VR:000 | DL:000 | DR:000
DSTL:00001 | DSTR:00001
LSL:0980 | LSR:0968 | MCL:0000 | MCR:0000 | BAT:0748 | AD0:0960 | AD1:0953
| SRF_M: 146 cm |
SRF_L: 33 cm

Read Sensor Values:
PL:000 | PR:000 | VL:000 | VR:000 | DL:000 | DR:000
DSTL:00001 | DSTR:00001
LSL:0893 | LSR:0894 | MCL:0000 | MCR:0000 | BAT:0748 | AD0:0888 | AD1:0882
|tSRF_R: 53 cm | | SRF_M: 14 cm |

[RP6BOOT]

[READY]


Wie man sieht, werden die Messergebnisse nur alle 2 Aufrufe von "Read Sensor values" mitgeliefert. Da könnte man noch eine Pause integrieren, ist aber nicht so schlimm. Aber was hier definitiv fehlt sind die ACS Ausgaben, welche ich eigentlich auch bekommen sollte.
Der Slave Code ist diesmal der original Code ohne Erweiterungen und der Master Code nur etwas erweitert/ korrigiert.

Das sollte ich aber hoffentlich dieses Wochenende geklärt haben.

Gruß
Mac80

Filou89
06.08.2012, 14:51
Hallo zusammen,
Ich schliesse mich nun mal diesem Thema an, da es auch um I2C Master-Slave Einstellungen geht.
Dazu mal die Hardware:
1 RP6 Base, 1 RP6 M32, 1 PR6 M256, 1 Atmega8, 1 Attiny44

Idee:
Am Attiny44 sind 2 Servos und ein Sharp angeschlossen. Diese dienen als 3D- Distanz-Scanner. Siehe hier (http://www.nibo-roboter.de/wiki/NDS3)
Der Atmega8 steuert einen Schrittmotor, Display eine serielle Schnittstelle. Zudem kann er Helligkeit und Temperatur messen.
Die M32 steuert nebst Beeper einige Servos an und liest ein ADC-Tastenfeld aus.
Die M256 sollte das Gehirn (Master) bilden und alle infos sammeln und übertragen / auf die SD-Karte speichern.
RP6 Base ist das Fahrgestell von alldem.

Als Bus möchte ich den I2C verwenden.

Fragen:
Gibt es zur M32 eine bestehende I2C Slave Bibliothek?
Würde es Probleme verursachen, die M32 und M256 mit den vorhandenen LIB's als Master zu betreiben?
Muss ich noch irgendwo Pull-Up's anbringen?

Für eure Antworten dankt euch
Filou :-)

RolfD
06.08.2012, 15:42
Hallo Filou,
zu deinen Fragen...
Es gibt im Projekt RP6 Remotrol 1.3 unter RP6 Remotrol 1.3\Firmware\M128 - Master\ ein M32 Slave.
Ja es würde Probleme machen 2 Master auf dem i2c gleichzeitig laufen zu lassen da hier für eine Vorrangsteuerung bzw. Busarbitierung nötig ist, die in der RP6Lib so nicht implementiert ist. Je einen der beiden wirst du aber als Master zum Laufen bekommen.
Nein du brauchst keine Pullups... die Prozessoren bringen schon Pullups mit und auf dem Baseboard sind auch welche. Siehe auch i2c Spezifikation bei NPX oder für TWI bei Amtel.
LG Rolf