АЦП для Raspberry из Arduino NANO

Ziriaell
Offline
Зарегистрирован: 04.10.2018

Доброго времени суток господа! Стояла задача передать данные от датчика на малину по беспроводному каналу. Для решения этой задачи решено использовать два модуля nrf24l01. К малине подключить корректно не удалось - модуль принимал какую-то чушь, но если вмето малины его подключить к ардуинке, то все работает нормально. Поэтому не долго думая была заколхожена следующая схема: RPI <-i2c-nano(nrf24) <- nano(nrf24+датчик). Система работала стабильно, малина раз в 10 секунд читывала данные и отравляла в облако. Со временем потребовалось подключить к малине аналоговый датчик, но ацп под рукой не обнаружилось, а результат требовался здесь и сейчас. Поэтому роль ацп взяла на себя nano c nrf24, благо на борту у нее достаточно аналоговых пинов. Работа происходила по следующему алгоритму: малина отправляет номер порта на ардуино, а ардуино считывает с указанного порта данные и возвращает их малине. Все работает нормально какое то время, но потом выскакивает ошибка "bus.write_byte(SLAVE_ADDRESS, ord(chanel)) OSError: [Errno 121] Remote I/O error" и вместо разных данных с разных портов, малина получает данные одного (выскакивает ошибка). После перезагрузки ардуино все работает нормально какое то время.

Прогаю недавно, прошу тапками не кидаться

Код arduino 

#include <Wire.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h> // https://github.com/maniacbug/RF24

#define SLAVE_ADDRESS 0x04

const uint64_t pipe = 0xF0F1F2F3F4LL; // индитификатор передачи, "труба"
const int sensorPin = A0; //пин подключения датчика
const long interval = 10000; 
//unsigned long previousMillis = 0;
int smoke_level_0 = -1; // CO2 кухня
int flag;
RF24 radio(9, 10); // CE, CSN


void setup(){
  //Serial.begin(9600);
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);
  pinMode(A4, INPUT);
  pinMode(A5, INPUT);
  pinMode(A6, INPUT);
  pinMode(A7, INPUT);
  Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(processMessage);
  Wire.onRequest(sendRadioReading);
  radio.begin();
  delay(2);
  radio.setChannel(9); // канал (0-127)

  // скорость, RF24_250KBPS, RF24_1MBPS или RF24_2MBPS
  // RF24_250KBPS на nRF24L01 (без +) неработает.
  // меньше скорость, выше чувствительность приемника.
  radio.setDataRate(RF24_1MBPS);

  // мощьность передатчика RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_MED=-6dBM,
  radio.setPALevel(RF24_PA_HIGH);

  radio.openReadingPipe(1, pipe); // открываем первую трубу с индитификатором "pipe"
  radio.startListening(); // включаем приемник, начинаем слушать трубу
}

//  radio.stopListening(); // останавливает приём (нужно перед началом передачи)


void loop(){ 
  //unsigned long currentMillis = millis();
  if (radio.available()) { // проверяем не пришло ли чего в буфер.
    radio.read(&smoke_level_0, sizeof(smoke_level_0)); // читаем данные, указываем сколько байт читать
  }
  //if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
   // previousMillis = currentMillis;
   // Serial.write(smoke_level_0);
    //Serial.write(sensorPin);
    
  //}
}
void processMessage(int n)
{
  char message = Wire.read();
  if (message =='0'){
    flag = 0;
  }
  else if (message == '1')
  {
    flag = 1;
  }
  else if (message == '2')
  {
    flag = 2; 
  }
  else if (message == '3')
  {
    flag = 3; 
  }
  else if (message == '4')
  {
    flag = 4; 
  }
  else if (message == '5')
  {
    flag = 5; 
  }
  else if (message == '6')
  {
    flag = 6; 
  }
  else if (message == '7')
  {
    flag = 7; 
  }
  else if (message == '8')
  {
    flag = 8; 
  }
}

void sendRadioReading() {
  if (flag == 8)
  {
    Wire.write(smoke_level_0);
  }
  else if (flag != 8)
  {
    Wire.write(analogRead(flag));
  }
}

 Код малинки 

import smbus
import time

bus = smbus.SMBus(1)
SLAVE_ADDRESS = 0x04

def request_reading(chanel):
    bus.write_byte(SLAVE_ADDRESS, ord(chanel))
    reading = int(bus.read_byte(SLAVE_ADDRESS))
    #print(reading)
    return reading
while True:
    
    x = request_reading('8')
    print(x)
    time.sleep(2)
    x = request_reading('0')
    print(x)
    time.sleep(5)

 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

1. Почему бы вместо строк 65-99 не записать просто

if (message >= '0' && message <= '8') flag = message - '0';

? Это, конечно, "на скорость не влияет", но как-то попроще будет, всё ж одна строка, а не 35.

2. А вот что может влиять. Все переменные, которые используются и в программе, и в обработчике прерывания (наприер, flag, smoke_level_0) хорошо бы объявить "внезапно изменяемыми" - volatile.

Сделайте, а там посмотрим.

Ziriaell
Offline
Зарегистрирован: 04.10.2018

Проблема никуда не ушла

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не вижу кода

Ziriaell
Offline
Зарегистрирован: 04.10.2018

Код тот же самый, только с Вашими поправками.

Ардуино

#include <Wire.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h> // https://github.com/maniacbug/RF24

#define SLAVE_ADDRESS 0x04

const uint64_t pipe = 0xF0F1F2F3F4LL; // индитификатор передачи, "труба"
//const int sensorPin = A0; //пин подключения датчика
//const long interval = 10000; 
//unsigned long previousMillis = 0;
volatile int smoke_level_0 = -1; // CO2 кухня
volatile int flag;
RF24 radio(9, 10); // CE, CSN


void setup(){
  //Serial.begin(9600);
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);
  pinMode(A4, INPUT);
  pinMode(A5, INPUT);
  pinMode(A6, INPUT);
  pinMode(A7, INPUT);
  Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(processMessage);
  Wire.onRequest(sendRadioReading);
  radio.begin();
  delay(2);
  radio.setChannel(9); // канал (0-127)

  // скорость, RF24_250KBPS, RF24_1MBPS или RF24_2MBPS
  // RF24_250KBPS на nRF24L01 (без +) неработает.
  // меньше скорость, выше чувствительность приемника.
  radio.setDataRate(RF24_1MBPS);

  // мощьность передатчика RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_MED=-6dBM,
  radio.setPALevel(RF24_PA_HIGH);

  radio.openReadingPipe(1, pipe); // открываем первую трубу с индитификатором "pipe"
  radio.startListening(); // включаем приемник, начинаем слушать трубу
}

//  radio.stopListening(); // останавливает приём (нужно перед началом передачи)


void loop(){ 
  //unsigned long currentMillis = millis();

  //if (currentMillis - previousMillis >= interval) {
   // Serial.write(smoke_level_0);
    //Serial.write(sensorPin);
    
  //}
}
void processMessage(int n)
{
  char message = Wire.read();
  if (message >= '0' && message <= '8'){ flag = message - '0';
  }
}

void sendRadioReading() {
  if (flag == 8)
  {
    if (radio.available()) { // проверяем не пришло ли чего в буфер.
    radio.read(&smoke_level_0, sizeof(smoke_level_0)); // читаем данные, указываем сколько байт читать
    Wire.write(smoke_level_0);
  }
    
  }
  else if (flag == 0)
  {
    Wire.write(analogRead(A0));
  }
    else if (flag == 1)
  {
    Wire.write(analogRead(A1));
  }
    else if (flag == 2)
  {
    Wire.write(analogRead(A2));
  }
    else if (flag == 3)
  {
    Wire.write(analogRead(A3));
  }
    else if (flag == 4)
  {
    Wire.write(analogRead(A4));
  }
    else if (flag == 5)
  {
    Wire.write(analogRead(A5));
  }
    else if (flag == 6)
  {
    Wire.write(analogRead(A6));
  }
}

Малина 

import smbus
import time

bus = smbus.SMBus(1)
SLAVE_ADDRESS = 0x04

def request_reading(chanel):
    bus.write_byte(SLAVE_ADDRESS, ord(chanel))
    time.sleep(1)
    reading = int(bus.read_byte(SLAVE_ADDRESS))
    #print(reading)
    return reading
while True:
    
    x = request_reading('8')
    print(x)
    time.sleep(2)
    x = request_reading('0')
    print(x)
    time.sleep(5)
    

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Т.е. вы предлагаете кроме ардуины еще и с питоновской либой на малине потрахаться чтобы рассказать, где ошибка?

Ziriaell
Offline
Зарегистрирован: 04.10.2018

Уважаемый, я вам ни с чем трахаться не предлагаю. Питоновский код прикреплен здесь только для полноты картины и работает идеально, это проверено длительным промежутком времени на других проектах. Если внимательно прочитать код ошибки, видно, что малина не можеть отправить команду на указаный адрес, т.е., как мне кажется, проблема в ардуино.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ziriaell пишет:

Код тот же самый

Фига-се тот же самый! Как sendRadioReading-то поменялась.

Ну, давайте разбираться.

Во-первых, что у Вас за фигня в строка 74-10. Почему не нписать весто них всех

else Wire.write(analogRead(A0+flag));

Это будет ровно то, что написано у Вас в этой чёртовой уйме строк. Только это неправильно.

Вы читаете analogRead'ом 10-тибитовое число, а передаёте 8-битовое. При таком продходе правильно будет передатваться только значения до 255. А любые значения от 256 и до 1023 будут передаваться неправильно.

Тоже самое в строках 69-70. В строке 69 Вы читаете 2 байта, а в строке 70 - передаёте только один.

Вы это понимаете?

Наконец, на стороне малины. В строках 8 и 10 Вы читаете по 1 байту. Учитывая, что Вы и передаетё по-одному, формально правильно, но на самом деле, Вам надо и передавать и читать по два байта.

Ziriaell
Offline
Зарегистрирован: 04.10.2018

Пока это сложно для меня. Можете показать, как передавать по два байта? какой нибудь простенький пример?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, например, так:

const uint16_t val = analogRead(A0);
Wire.write((uint8_t *)&val, sizeof(val));