Probleme I2C entre RPI et Arduino

Bonsoir,

Je reviens vers vous suite à un post précédent concernant mon projet de lecture de sondes de température et autres sur arduino et envoi des données sur rpi qui les envoie ensuite sur une page web via tornado web socket. Je l' ai amélioré depuis mon post précédent, principalement une interface pour commande vocale sur base de Yana et controle d un moteur PWM... Bref je ne vais pas entrer dans les details mais depuis que je suis passé sur rpi 3, je ne suis pas sur que ca soit le probleme car ca marchait il y a quelques jours, mais je ne sais pas pourquoi maintenant j ai un probleme avec le bus I2C et je ne me souviens pas avoir modifié tellement le code. En gros sur le rpi une routine tourne pour recevoir en continu les données des sondes sur l arduino en I2C, par un read_i2c_block_data Sur l arduino le code se charge d envoyer les donnees sur le bus pour le read du prog python via Wire.onRequest(sendData); et en meme temps il attend de recevoir des données provenant dur rpi par le bus I2C pour commander le moteur PWM et la telecommande IR. Ceci est fait par un simple wire.read dans la function Wire.onReceive(receiveData) sur l arduino et c est un simple byte. Mais maintenant [u]si j active Wire.onReceive(receiveData) plus rien ne fonctionne[/u] ca n envoie ni ne recoit plus rien sur le bus I2C, et je ne trouve pas la raison, histoire de timerss ou autres je ne sais pas du tout. Je poste mon code en esperant votre aide

Je vous remercie pour vos idees.

Fabrice

Arduino:

#include <IRremote.h>
#include <IRremoteInt.h>
#include <ir_Lego_PF_BitStreamEncoder.h>
#include <NewPing.h>
#include <Wire.h>
#define SLAVE_ADDRESS 0x04
#define FLOATS_SENT 3
#define MOTOR_CONTROL 1
// which analog pin to connect
#define THERMISTORPIN 0
// resistance at 25 degrees C
#define THERMISTORNOMINAL 4540
// temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL 24
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES 5
#define NUMSAMPLESLight 5
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT 3950
// the value of the 'other' resistor
#define SERIESRESISTOR 10000

// These constants, define values needed for the LDR readings and ADC
#define LDR_PIN                   1
#define MAX_ADC_READING           1023
#define ADC_REF_VOLTAGE           5
#define REF_RESISTANCE            5000  // measure this for best results
#define LUX_CALC_SCALAR           12518931
#define LUX_CALC_EXPONENT         -1.405
#define PWMPIN 5

#define TRIGGER_PIN  12  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     11  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
const int RECV_PIN = 9;
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
IRsend irsend;
IRrecv irrecv(RECV_PIN);
decode_results results;
float temperature = 0.00;
float luminosity = 0.00;
float data[FLOATS_SENT];
int motor_action[MOTOR_CONTROL];
int photocellPin = 1;     // the cell and 10K pulldown are connected to a1
int photocellReading;     // the analog reading from the analog resistor divider

int samples[NUMSAMPLES];
int samplesLight[NUMSAMPLESLight];

const float threshold = 30.50;
float tempArduino;
int state = 0;
uint8_t numberchaine = 0;
uint8_t vitesseMoteur = 0;
int pwmValue = 0;
unsigned long IRPartHIGH;
unsigned long IRPartLOW;
unsigned long IRPartLOW2 = 3072;
int togglebit = 1;
uint8_t i;
float average;
int   ldrRawData;
float resistorVoltage, ldrVoltage;
float ldrResistance;
float ldrLux;
float steinhart;
uint8_t ii;
float averageLight;


void setup(void) {
  Serial.begin(9600); // Open serial monitor at 115200 baud to see ping results.
  analogReference(EXTERNAL);
  analogWrite(PWMPIN, pwmValue);
  pinMode(PWMPIN, OUTPUT);
  // initialize i2c as slave
  Wire.begin(SLAVE_ADDRESS);
  // define callbacks for i2c communication
  Wire.onRequest(sendData);
  //******************************************************************************
  // Si j active OnReceive ca ne fonctionne plus !!!
    //******************************************************************************
  //Wire.onReceive(receiveData);
  irrecv.enableIRIn(); // Start the receiver
}

void loop(void) {

  for (ii = 0; ii < NUMSAMPLESLight; ii++) {
    samplesLight[ii] = analogRead(photocellPin);
    delay(10);
  }
  // average all the samples out
  averageLight = 0;
  for (ii = 0; ii < NUMSAMPLESLight; ii++) {
    averageLight += samplesLight[ii];
  }
  averageLight /= NUMSAMPLESLight;
  photocellReading = averageLight;
  /// Perform the analog to digital conversion
  ldrRawData = averageLight;

  // RESISTOR VOLTAGE_CONVERSION
  // Convert the raw digital data back to the voltage that was measured on the analog pin
  resistorVoltage = (float)ldrRawData / MAX_ADC_READING * ADC_REF_VOLTAGE;

  // voltage across the LDR is the 5V supply minus the 5k resistor voltage
  ldrVoltage = ADC_REF_VOLTAGE - resistorVoltage;

  // LDR_RESISTANCE_CONVERSION
  // resistance that the LDR would have for that voltage
  ldrResistance = ldrVoltage / resistorVoltage * REF_RESISTANCE;

  // LDR_LUX
  // Change the code below to the proper conversion from ldrResistance to
  // ldrLux
  ldrLux = LUX_CALC_SCALAR * pow(ldrResistance, LUX_CALC_EXPONENT);


  for (i = 0; i < NUMSAMPLES; i++) {
    samples[i] = analogRead(THERMISTORPIN);
    delay(10);
  }
  // average all the samples out
  average = 0;
  for (i = 0; i < NUMSAMPLES; i++) {
    average += samples[i];
  }
  average /= NUMSAMPLES;
  // convert the value to resistance
  average = 1023 / average - 1;
  average = SERIESRESISTOR / average;
  steinhart = average / THERMISTORNOMINAL;     // (R/Ro)
  steinhart = log(steinhart);                  // ln(R/Ro)
  steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
  steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart = 1.0 / steinhart;                 // Invert
  steinhart -= 273.15;                         // convert to C
  data[0] = steinhart;
  data[1] = ldrLux;
  data[2] = sonar.ping_cm();
  // Envoi PWM moteur sur D9
  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    if (results.value == 0xA82 || results.value == 0x282) {
      pwmValue = 0;
      analogWrite(PWMPIN, pwmValue);
    }
    if (results.value == 0xA83 || results.value == 0x283) {
      pwmValue = 127;
      analogWrite(PWMPIN, pwmValue);
    }
    if (results.value == 0xA85 || results.value == 0x285) {
      pwmValue = 255;
      analogWrite(PWMPIN, pwmValue);
    }
    irrecv.resume();
  }
}
//******************************************************************************
// Ca ne marche plus pour ecrire sur le bus I2C !!!
//******************************************************************************
void receiveData(int byteCount) {

  int numbermax;
  int numbermin;
  //IRPartHIGH = 0;
  Serial.print("byteCount ");
  Serial.println(byteCount);
  Serial.print("test ");
  Serial.println(numberchaine);
  while (Wire.available()) {
  numberchaine = Wire.read();
  Serial.println(numberchaine);
  // Ici il y avait un irsend pour envoyer le code IR reçu sur le bus I2C, mais je l ai enleve car de toute facon ca ne fonctionne pas ca plante deja au n
  if (numberchaine == 98) {
    pwmValue = 0;
    analogWrite(PWMPIN, pwmValue);

  }
  if (numberchaine == 99) {
    pwmValue = 127;
    analogWrite(PWMPIN, pwmValue);

  }
  if (numberchaine == 100) {
    pwmValue = 255;
    analogWrite(PWMPIN, pwmValue);
  }
  delay(100);
  }
} 
void sendData() {

  Serial.println("transmit temp,lux,dist");
  //Wire.beginTransmission(SLAVE_ADDRESS);
  Serial.println(numberchaine);
  //Wire.write(number);
  Wire.write((byte*) &data, FLOATS_SENT * sizeof(float));
  //Wire.endTransmission();
  Serial.print("Treshold ");
  Serial.println(threshold);
  Serial.print("Temperature ");
  Serial.print(steinhart);
  // Serial.print(data[0]);
  Serial.println(" *C");
  Serial.print("TemperatureArduino ");
  Serial.print(tempArduino);
  Serial.println(" *C");
  Serial.print(data[1]);
  Serial.println("Lux");
  // delay(29);                     // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.

  Serial.print("Ping: ");
  Serial.print(data[2]); // Send ping, get distance in cm and print result (0 = outside set distance range)
  Serial.println("cm");
  //delay(1000);
}

// Get the internal temperature of the arduino
double GetTemp(void)
{
  unsigned int wADC;
  double t;
  ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
  ADCSRA |= _BV(ADEN); // enable the ADC
  delay(20); // wait for voltages to become stable.
  ADCSRA |= _BV(ADSC); // Start the ADC
  while (bit_is_set(ADCSRA, ADSC));
  wADC = ADCW;
  t = (wADC - 324.31 ) / 1.22;
  return (t);
}

Sur le rpi pour recevoir les donnes de l arduino sur le bus:

#!/usr/bin/env python
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import os
import sys
import smbus as smbus
import time
import struct
import RPi.GPIO as GPIO
# for RPI version 1, use "bus = smbus.SMBus(0)"
bus = smbus.SMBus(1)

# This is the address we setup in the Arduino Program
address = 0x04

wss =[]
class WSHandler(tornado.websocket.WebSocketHandler):
  def check_origin(self, origin):
	return True
  def open(self):
    print 'New user is connected.\n' 
    if self not in wss:
      wss.append(self)
  def on_close(self):
    print 'connection closed\n'
    if self in wss:
      wss.remove(self)

application = tornado.web.Application([(r'/ws', WSHandler),])

if __name__ == "__main__":
  os.system('modprobe w1-gpio')
  #os.system('modprobe w1-therm')
  interval_msec = 2000
  
  def get_data():
	return bus.read_i2c_block_data(address, 0, 12);

  def get_float(data, index):
	bytes = data[4*index:(index+1)*4]
	return struct.unpack('f', "".join(map(chr, bytes)))[0]

  def wsSend(message):
    for ws in wss:
      if not ws.ws_connection.stream.socket:
        print "Web socket does not exist anymore!!!"
        wss.remove(ws)
      else:
        ws.write_message(message)

  def read_temp():
   
    try:
		print "start"
		#bus.write_byte(address,10)
		#bus.write_quick(address)
		data = get_data()
		print data
		#temp = get_float(data, 0)
		#print '%.2f' % temp
		Lux = get_float(data, 1)
		#print Lux
		temp = ('%.2f' % get_float(data, 0))
		#dist = ('%.2f' % get_float(data, 2))
		dist = get_float(data, 2)
		#temp = temp.replace('.',',')
		print dist 
		file2 = open('/home/pi/ProgRPI/temp.txt', 'w')
		file2.write(temp)
		#read temp. onboard sensor    
		file = open('/sys/class/thermal/thermal_zone0/temp','r')
		lines = file.readlines()
		tempcpu = float(lines[0])/1000
		tempcpu = ('%.2f' % tempcpu)
		#tempcpu = tempcpu.replace('.',',')
		#print tempcpu
		#print "--------"   
		#file2.write(tempcpu)
		file2.close()
		#temp += ';' + str(float(lines[0])/1000)
		temp += ';' + str(tempcpu)
		temp += ';' + str(Lux)
		temp += ';' + str(dist)
		file.close()
		print temp
		wsSend(temp)
		GPIO.setmode(GPIO.BCM)
		GPIO.setwarnings(False)
		
		GPIO.setup(23,GPIO.OUT)
		if (dist <= 40 and dist >0) :
			print ("Presence")
			GPIO.output(23,GPIO.HIGH)
		else :
			print ("Absence")
			GPIO.output(23,GPIO.LOW)
			
    except:
	wsSend("-;-")

  http_server = tornado.httpserver.HTTPServer(application)
  http_server.listen(8888)
    
  main_loop = tornado.ioloop.IOLoop.instance()
  sched_temp = tornado.ioloop.PeriodicCallback(read_temp, interval_msec,   io_loop = main_loop)

  sched_temp.start()
  main_loop.start()

Un prog python sur le rpi pour envoyer une commande a l arduino:

#!/usr/bin/env python
import smbus
import time
import struct
bus = smbus.SMBus(1)

address = 0x04
tempsign = unichr(176)
def get_data():
    return bus.read_i2c_block_data(address, 0);

def get_float(data, index):
    bytes = data[4*index:(index+1)*4]
    return struct.unpack('f', "".join(map(chr, bytes)))[0]

#print "envoi de la valeur 100"
bus.write_byte(address,100)

personne pour m aider?

c'est la même version de Raspbian sur la version qui marche et celle qui marche pas?

Oui je pense, enfin je fais regulierement les updates

sudo apt-get update && sudo apt-get upgrade && sudo apt-get dist-upgrade && sudo apt-get autoremove && sudo BRANCH=next rpi-update

ou sudo rpi-update si je tourne sur le carte SD sinon c est je boot sur une clé usb d ou le branch=next mais c est la meme image a la base.

Linux yanapi 4.4.27-v7+ #918 SMP Tue Oct 25 16:42:04 BST 2016 armv7l GNU/Linux