• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
arduino i2c rpi proszę o pomoc
#1
Witam serdecznie wszystkich.
Arduino i raspberry zajmuje się od niedawna i hobbistycznie i proszę o wyrozumiałość gdyż raczkuje w programowaniu.

Bardzo proszę o pomoc w projekcie.
Na arduino zmontowałem układ z oled lcd, 3x ds18b20 jako 1-wire każdy na poszczególny pin (by łatwo zmieniać czujniki), 1x DHT11.
Całość działa bardzo fajnie ale potrzebuje podpiąć się do raspberry przez i2c i wysyłałć dane z czujników do skryptu w pythjonie. I tu zaczyna sie problem.
Albo wysyła mi jedna daną, jak próbuję wysłać tablicę wysyła mi tylko część.
Oto kody z płytek:

Kod:
#include <DallasTemperature.h>
#include <OneWire.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "DHT.h"
#define DHT11_PIN 7
#define SLAVE_ADDRESS 0x09

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
                         OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

#define ONE_WIRE_BUS1 3
#define ONE_WIRE_BUS2 4
#define ONE_WIRE_BUS3 5
OneWire oneWire1(ONE_WIRE_BUS1);
OneWire oneWire2(ONE_WIRE_BUS2);
OneWire oneWire3(ONE_WIRE_BUS3);
DallasTemperature sensors1(&oneWire1);
DallasTemperature sensors2(&oneWire2);
DallasTemperature sensors3(&oneWire3);
float temp1;
float temp2;
int temp3;
int wil;
DHT dht;

void setup() {
  display.clearDisplay();
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC);
  sensors1.begin();
  sensors1.setResolution(10);
  dht.setup(DHT11_PIN);
  Wire.begin(SLAVE_ADDRESS);
  Wire.onRequest(sendData);
}

void loop() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.println("Temp.");
  display.setCursor(0, 16);
  display.setTextSize(3);
  TM1();
  display.setCursor(40, 40);
  display.setTextSize(3);
  TM2();
  display.setCursor(90, 16);
  display.setTextSize(3);
  TM3();
  display.display();
  delay(10000);

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.println("Wilgot.");
  display.setCursor(0, 25);
  display.setTextSize(3);
  WILG();
  display.setCursor(50, 25);
  display.setTextSize(2);
  display.println(" %RH");
  display.display();
  delay(10000);
}

void TM1() {
  sensors1.requestTemperatures();
  temp1 = sensors1.getTempCByIndex(0);
//  display.println(temp1);
   char tm1[2];
  dtostrf(temp1, 2, 0, tm1);
   display.println(tm1);
}
void TM2() {
  sensors2.requestTemperatures();
  temp2 = sensors2.getTempCByIndex(0);
// display.println(temp2);
  char tm2[2];
  dtostrf(temp2, 2, 0, tm2);
   display.println(tm2);
}
void TM3() {
  sensors3.requestTemperatures();
  temp3 = sensors3.getTempCByIndex(0);
  display.println(temp3);
}

void WILG() {
  wil = dht.getHumidity();
  display.println(wil);
}

char t1[2];
char t2[2];
char wil1[2];
//char wyn[4];
//char t1[3];
//char wil1[3];
char data[] = {t2,wil1};
int index = 0;

// callback for sending data
void sendData() {
//  itoa(temp1, t1, 10);
    itoa(wil, wil1, 10);
    dtostrf(temp1, 2, 0, t1);
    dtostrf(temp2, 2, 0, t2);
//    dtostrf(wil, 2, 1, wil1);
//    strcat(wyn, t1);
//    strcat(wyn, t2);
    Wire.write(data[index]);
    ++index;
    if (index >= 6) {
         index = 0;
    }
}

raspberry:

Kod:
#!/usr/bin/python

import smbus
import time
bus = smbus.SMBus(1)
address = 0x09

while True:
data = ""
for i in range(0, 6):
  data += chr(bus.read_byte(address));
# print data
h1 = data[2:4]
t1 = data[4:6]
print t1,"C,",h1,"%Rh"
break

Obecnie dostaję ciąg: kwadracik kwadracik wynik czujnik DHT11 wynik czujnik t2
Próbowałem już kilka dni by dostać wynik z czujników w formacie: t1t2t3DHT11 czyli przykład: 23251945
Z góry bardzo dziekuję za pomoc.
 
Odpowiedź
#2
Zacznij od sprawdzenia analizatorem logicznym lub oscyloskopem, czy arduino nie wysyła wszystkich danych czy RPi nie wszystko odczytuje. Stawiam na arduino bo w loop widzę delay. Ponadto  w loop masz operacje 1-Wire, które zawieszają przerwania (A NIE MUSZĄ!) i odpowiedź slave I2C nie jest realizowana  (jest przerywana).
Wywal delay na rzecz choćby niedoskonałego millis a bezwzględnie użyj biblioteki 1-Wire, która nie zawiesza przerwań.To samo z DHT. jak i wszystkimi rozwiązaniami blokującymi przerwania na czas dłuższy niż pojedyncze mikrosekundy jak obsługa WS2812 i setki innych arduinowych wynalazków pod tytułem:
- Blokuj przerwania kiedy tylko masz na to ochotę.
- Nie używaj sprzętu choć go masz lepiej "machaj pinem" blokując przy okazji przerwania.
- Używaj float nawet tam gdzie to jest niepotrzebne (to chyba wyniesione z "lekcji" firmy u$ (M$) , której beznadziejnym produktem był Basic, zwłaszcza Basic dla C-64. Nic dziwnego, że Commodore padło skoro kupowało soft od u$.

Widzę też potencjalny problem obsługi OLED na I2C i SLAVE I2C. Jak to niby działa na jednym I2C? Czy używane biblioteki zapewniają mechanizmy umożliwiające taki tryb pracy? Jak znam arduino, to nie. Biblioteki arduino nie są pisane pod kątem wielozadaniowości, podobnie jak Gwindow$. Jak działa jedna funkcja, to nie działa druga. Jak chcesz wielozadaniowości to do każdego zadania użyj osobnego CPU.
 
Odpowiedź
#3
Dziękuje za podpowiedź.
Oled mam podpięty po SPI.
Lepiej jest zamieniać float na char czy int na char?
 
Odpowiedź
#4
Cytat:Lepiej jest zamieniać float na char czy int na char?
Po takim pytaniu odpowiedź może być tylko jedna: zacznij od kursu C/C++. Następnie kurs arduino.
Niestety kurs arduino nie rozwiąże problemu zawieszania przerwań na czas operacji 1-wire i DHT bo opiera się o gotowe biblioteki. Będziesz musiał napisać własne, porządne biblioteki więc kurs AVR, chyba, że lubisz mnożyć płytki i dodasz kolejną, która zajmie się odczytem 1-Wire a komunikacja pomiędzy płytkami będzie odbywać się z małą prędkością po UART lub z większa po interfejsie synchronicznym. I2C masz już użyte więc pozostaje SPI ale pod SPI masz OLED. SPI w Oled pracuje pewnie z zegarem 8MHz, więc będziesz musiał na czas komunikacji z drugą płytką  prędkość zmniejszać, bo AVR nie ma szans, (slave SPI) odbierać dane 8MHz. Bajt pojawia się co 1us a tyle zajmie pewnie wejście w przerwanie i odłożenia danych na stos. Na AVR obsługa przerwania krótsza niż kilka us jest raczej niewykonalna, (chyba, że tylko zmieniasz w przerwaniu stan GPIO) ponadto 1-wire i DHT zawiesza przerwania i to na dość długo. SPI musi więc pracować z zegarem rzędu kHz.

Projekt, który chcesz zrealizować jest banalny ale padłeś ofiarą kiepskich bibliotek arduino. Zakładam, że własnych nie napiszesz. Z SPI też pewnie będzie problem. Widzę tylko możliwość użycia 2 płytek arduino, komunikacja I2C. Płytka połączona z RPi, tak jak teraz, sprzętowo obsługuje slave I2C. I2C master realizujesz programowo. Na drugiej sprzętowe I2C slave. Jaką prędkość wybrać? Przy 100kHz bajt jest transmitowany w 90us. 1-wire zawiesza przerwania na max 64us więc masz rezerwę. Mam nadzieję, że reset 1-wire nie zawiesza przerwań tak samo jak oczekiwanie na presence, jeśli tak, to prędkość I2C musisz zmniejszyć do 10kHz.

Może się wydawać, że ESP32 rozwiąże problem (2 rdzenie). Pytanie czy poradzisz sobie z tym? Biblioteki 1-wire i DHT dla ESP są tak samo źle napisane jak i na AVR i jedynym ratunkiem jest wykonanie obsługi 1-wire przez drugi rdzeń, który zajmuje się obsługą Wi-Fi ale czy to nie zaburzy działania Wi-Fi? Jeśli tak, to 1-Wire i oled obsługujesz jak zwykle a drugi rdzeń Wi-Fi i I2C slave.


Dlaczego wszystkich zadań nie realizujesz przez RPi?
 
Odpowiedź
#5
RPI chce zastosować jako główny kloce bazę do sms-ów i powiadomień. Termometry na arduino chciałem użyć jako modułowe, z możliwością komunikacji z RPI. A w razie po odpięciu RPI w celu(przeróbki, zmiany, itp) by termometry dalej pokazywały temperaturę na oled w warsztacie, kolejne płytka z oled w nowym adresem i2c w piwnicy, kolejna w kotłowni.
 
Odpowiedź
#6
(11-09-2019, 11:39)krusnik napisał(a): w warsztacie, kolejne płytka z oled w nowym adresem i2c w piwnicy, kolejna w kotłowni.
Chcesz użyć I2C na duże odległości. Jak to chcesz zrobić? Bezpośrednio się nie da. Spodziewać należy się też problemu pętli masy, różnicy potencjałów pomiędzy urządzeniami.
 
Odpowiedź
#7
Funkcja Wire.Write wysyła 1bajt, z tablicy dwuelementowej, indeksem lecisz do 6 (do siódmego elementu). Kurs Arduino znajdziesz tu: https://forbot.pl/blog//kurs-arduino-pod...rsu-id5290. Dane do wysłania możesz poukładać w strukturę (są tu przykładowe kody przy okazji komunikacji NRF24L01), na raz da się wysłać około 30 bajtów.
Pan S. (witam ponownie BTW) wrzucał tu darmowe książki o C, poszukaj w postach ES2.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości