Стартовый бит и функция контрольной суммы

Maximus
Offline
Зарегистрирован: 24.07.2015

Добрый день!

Я новичек и ни как не пойму какой стартовый бит выбрать?

при моей структуре пакета:

struct packet_arduino_pomp //пакет Arduino nano
{

    char start_byte;//в коротком пакете равен -32
    byte temp_pomp;//температура охлаждения
    byte on_of_pomp;//on-off насоса (1 или 0)
    byte tmp;//пока не трогаем
    byte crv;//пока не трогаем
};

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

Теперь с контрольной суммой. Посоветуйте мне пожалуйста на один байт формулу подчета контрольной суммы? В гуглах что то сложно все.

 

Мой код (прошу о критике):

Мастер:


#include <SoftwareSerial.h>

#define DIR 8 // переключатель прием\передача
#define BUT 49
SoftwareSerial RS485 (7, 6); // RX, TX

struct packet_big //пакет PC
{
    char start_byte;//в длинном пакете равен -12
    byte temp_pomp;//температура охлаждения
    byte on_of_pomp;//on-off насоса (1 или 0)
    byte ex_temp_reactor;//текущая температура в реакторе
    byte current_temp_reactor;//выставленная температура в реакторе
    byte timer_ex;//таймер
    byte tmp;//пока не трогаем
    byte crv;//пока не трогаем
};

struct packet_arduino_pomp //пакет Arduino nano
{

    char start_byte;//в коротком пакете равен -32
    byte temp_pomp;//температура охлаждения
    byte on_of_pomp;//on-off насоса (1 или 0)
    byte tmp;//пока не трогаем
    byte crv;//пока не трогаем
};

packet_big one={'H',0,0,0,0,0,0,0};
packet_arduino_pomp one_pomp = {'C',0,0,0,0};


byte buttonState=0;

void setup()
{
    Serial.begin(9600);//на PC
    RS485.begin(9600); // SoftwareSerial на Arduino nano
    pinMode(BUT, INPUT);
    pinMode(DIR, OUTPUT);

}

void loop()
{
    buttonState = digitalRead(BUT); //кнопка
    digitalWrite(DIR, LOW); // включаем прием
    byte* ptr28 = (byte* )&one;
    byte *ptr_pomp =(byte*)&one_pomp;
    //прием с PC данных всех команд, включая информацию о температуре с реактора
    if (Serial.available()>sizeof(ptr28)) //возможно установить колличество байт
    {
        for (size_t i = 0; i < sizeof(packet_big)-1; i++)
        {
            byte buf_big = Serial.read();
            if (buf_big  == 'H')//это проверяет стартовый байт.
            {
                i = 0;
                ptr28[i] = buf_big ;
                continue;//пропускаем
            }
            ptr28[i] = buf_big ;
        }
    }
    //возможно нужно повторно записать стартовый бит.
    //прием с ардуино nano данных о вкл/ вкл насоса и температуры охлаждения
    if (RS485.available()>sizeof(ptr_pomp)) //возможно установить колличество байт
    {
        for (size_t i = 0; i < sizeof(packet_arduino_pomp)-1; i++)
        {
            byte buf_pump = RS485.read();
            if (buf_pump == 'C')//это проверяет стартовый байт.
            {
                i = 0;
                ptr_pomp[i] = buf_pump;//если да, записываем вначало
                continue;//пропускаем
            }
            ptr_pomp[i] = buf_pump;
        }
    }
    if (buttonState == HIGH) //вкл/выкл от кнопки
    {
        if(one.on_of_pomp==0)//если выключен , то перезаписываем в пакете (включаем)
            one.on_of_pomp=1;
        else if(one.on_of_pomp==1)//если включен, то перезаписываем в пакете (выключаем)
            one.on_of_pomp=0;
    }

// запись данных из пакета от PC в пакет от ардуино и наобарот.
    one.temp_pomp = one_pomp.temp_pomp;
    one_pomp.on_of_pomp = one.on_of_pomp;

    digitalWrite(DIR, HIGH); // включаем передачу
    Serial.write(ptr28,sizeof(packet_big)); //передаем на PC
    RS485.write(ptr_pomp,sizeof(packet_arduino_pomp));//передаем на Arduino nano

}

Слейв:

#include <SoftwareSerial.h>

#define DIR 8 // переключатель прием\передача
#define ON 1 // вкл. насос
#define OFF 0 // вкл. насос

struct packet_arduino_pomp
{
    char start_byte;//в коротком пакете равен -32
    byte temp_pomp;
    byte on_of_pomp;
    byte tmp;//пока не трогаем
    byte crv;//пока не трогаем
};

static packet_arduino_pomp one = {'C',0,0,0,0};;//пакет с данными
byte temp_pomp = 0;//переменная для хранения температуры

SoftwareSerial RS485 (7, 6); // RX, TX

void setup()
{
    Serial.begin(9600);
    RS485.begin(9600); // SoftwareSerial

    pinMode(DIR, OUTPUT);
    pinMode(3, OUTPUT);
}

void loop()
{

    byte* ptr28 = (byte* )&one;
    digitalWrite(DIR, LOW); // включаем прием
    delay(100);
    if (RS485.available()>sizeof(ptr28))
    {
        Serial.println("ON");
        for (size_t i = 0; i < sizeof(packet_arduino_pomp); i++)
        {
            byte buf = RS485.read();
            if (buf == 'C')//это проверяет стартовый байт.
            {
                i = 0;// если да, обнуляем счетчик
                ptr28[i] = buf;
                Serial.println(ptr28[i]);
                continue;//пропускаем
            }
            ptr28[i] = buf;
            Serial.println(ptr28[i]);
        }
        Serial.println("END");
    }
    if(one.on_of_pomp==ON) // включим клапан
    {
        digitalWrite(3, HIGH); //  включим клапан
    }
    else if (one.on_of_pomp==OFF)
        digitalWrite(3, LOW);

    //тут обработка датчика температуры вместо random
    // temp_pomp = 55;

    one.temp_pomp=55;//записываем значение температуры охлаждения в пакет на отправку

    digitalWrite(DIR, HIGH); // включаем передачу
    RS485.write(ptr28,sizeof(packet_arduino_pomp)); //отправляем
}

Пока плохо работает, поэтому подумал начать со структуры пакета.

Суть такая: Один пакет (большой, который несет всю информацию) будет между Ардуино Мега и PC(написана программа на Qt), второй пакет маленький , между Ардуино нано и Мега ( несет информацию о включение-выключение насоса и температуре с датчика). Пока хочу сделать чтобы мега управляла нано ( с кнопки отправляла сигнал о включении насоса), а нано в ответку отправляла данные о температуре. Дальше мега собирает все данные , записывает в пакет для PC и отправляет. А PC читает, и если изменения какие то внесены с PC, заполняет этот же пакет и отправляет обратно... мега читает, расчленяет его и отправлет нано ...и т.д.

Тоесть мастером будет Pc, но если его отлючить от Меги, хочу чтобы она самостоятельная была( позже сделать экранчик с кнопаками).

Посмотрите , может какие то грубые ошибки найдете, я только учусь)

 

Заранее спасибо!

b707
Offline
Зарегистрирован: 26.05.2017

определитесь с терминами.

Бит не может быть ни отрицательным, ни "больше 400". Бит - это только 0 или 1. Судя по контексту у вас имеется в виду байт. Так вот, байт тоже не может быть более 400, его максимальное значение 255.

Насчет того, может ли char быть отрицательными - недавно была огромная дискуссия. Я не хочу вызвать флейм вновь, но советовал бы вам рассматривать char как синоним byte - то есть с диапазоном 0-255

Самая простая контрольная сумма - просто 8-битное побайтное сложение всех данных в пакете, за исключением самой суммы.

Код не смотрел, если с ним у вас проблемы - формулируйте вопросы яснее.

Maximus
Offline
Зарегистрирован: 24.07.2015

Да, пардон, всегда путаюсь -бит-байт.

Смысл считать данные всего пакета, если пакет меняется. Нужно же статичное значение ?

b707
Offline
Зарегистрирован: 26.05.2017

Еще одно небольшое добавление - разберитесь, как компьютер представляет отрицательные числа.  Знаковое -32 и беззнаковое 223 в двоичном коде выглядят одинаково, так что если вы пытаетесь с помощью отрицательных чисел задать "уникальное" значение стартового байта - затея обречена на провал.  Ничего "уникального" в значении -32 для компьютера нет.

b707
Offline
Зарегистрирован: 26.05.2017

Maximus пишет:

Смысл считать данные всего пакета, если пакет меняется. Нужно же статичное значение ?

Контрольная сумма используется, как раз чтобы отследить изменение данных в пакете. 

Maximus
Offline
Зарегистрирован: 24.07.2015

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Maximus пишет:

Да, пардон, всегда путаюсь -бит-байт.


не путайся. Бит это байт минус налоги.

b707
Offline
Зарегистрирован: 26.05.2017

Maximus пишет:

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

Можно и больше. Я так понимаю, что для вас главное, чтобы получившаяся последовательность не встречалась в данных. Иногда для этого приходится дополнительно кодировать данные, чтобы исключить появление в них управляющих кодов, типа заголовка пакета.

Maximus
Offline
Зарегистрирован: 24.07.2015

Типо стартовый байт =210, а все данные делим на 2, а про приему умножаем? Но как же потяря точности ? Делим, получается с запятой значение, оно в байтовой переменной обрязается, а когда умножается, полчается другое значение?

b707
Offline
Зарегистрирован: 26.05.2017

Maximus пишет:

Типо стартовый байт =210, а все данные делим на 2, а про приему умножаем? Но как же потяря точности ? Делим, получается с запятой значение, оно в байтовой переменной обрязается, а когда умножается, полчается другое значение?

Это не единственный метод.  Как вариант - все данные, кроме 210, передаем как есть, а 210 заменяем на пару байт 210-210.  Тогда при приеме одинарный 210 - это заголовок пакета, а двойной - это данные. (правда, надо следить, чтобы второй байт пакета не был 210 - но это обычно проще, чем перекодировать все данные)

Maximus
Offline
Зарегистрирован: 24.07.2015

Ничего не понял, псевдокод можите набросать пожалуйста?

b707
Offline
Зарегистрирован: 26.05.2017

Смысл в том, что вы перекодируете не все данные в пакете, а только значение 210. 

Или вообще его исключаете.  Например, возьмем стартовый байт 255. Значения в пакете в диапазоне 0-254 передаются как есть, а вместо 255 передаем 254. Потеря точности мизерна, стартовый байт уникален.

Если все еще непонятно, псевдокод пусть кто другой накропает - я на работе, знаете ли, нет времени :)

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Зачем такие сложности при таком простом обмене? Реализуйте подобие интерфейса общения и все. Т.е. сначала идет команда и ждете ответа, сравниваете црц. Например, отправляете с меги на нано 0х10, нано получается байт и переходит в режим ожидания пакета известного размера. Все последующие байты считаются данными. Когда все получено считаем црц. Мега так же сидит и ждет команды, нано выдает 0х10 мега переходит в режим приема данных и т.д. Даже если размер структуры будет не известен (а у вас он известен) то можно первым байтом выдавать размер.

Maximus
Offline
Зарегистрирован: 24.07.2015

Пока набросал с двумя стартовыми битами. Не думаю что высока вероятность попадания  подряд таких чиселю. Посмотрите коД, я правильно мыслю?

Это Слейв.

#include <SoftwareSerial.h>

#define DIR 8 // переключатель прием\передача
#define ON 1 // вкл. насос
#define OFF 0 // вкл. насос

struct packet_arduino_pomp //пакет Arduino nano
{

    byte start_byte_one;//в коротком пакете равен 212
    byte start_byte_two;//в коротком пакете равен 211
    byte temp_pomp;//температура охлаждения
    byte on_of_pomp;//on-off насоса (1 или 0)
    byte tmp;//пока не трогаем
    byte crv;//пока не трогаем
};


static packet_arduino_pomp one = {212,211,0,0,0,0};//пакет с данными
byte temp_pomp = 0;//переменная для хранения температуры

SoftwareSerial RS485 (7, 6); // RX, TX

void setup()
{
    Serial.begin(9600);
    RS485.begin(9600); // SoftwareSerial

    pinMode(DIR, OUTPUT);
    pinMode(3, OUTPUT);
}

void loop()
{

    byte* ptr28 = (byte* )&one;
    digitalWrite(DIR, LOW); // включаем прием
    delay(100);

    if (RS485.available()>sizeof(ptr28))
    {
        Serial.println("ON");
        byte buf_pump = RS485.read();
        if (buf_pump  == 212)
        {
            buf_pump = RS485.read();
            if (buf_pump  == 211)
            {
                ptr28[0] = 212;
                ptr28[1] = buf_pump;
                Serial.println(ptr28[0]);
                Serial.println(ptr28[1);
                               for (size_t i = 2; i < sizeof(packet_arduino_pomp)-1; i++)
                {
                    buf_pump = RS485.read();
                    ptr28[i] = buf_pump;
                    Serial.println(ptr28[i]);
                }
                Serial.println("END");
            }
        }
        /*for (size_t i = 0; i < sizeof(packet_arduino_pomp); i++)
        {
            byte buf = RS485.read();
            if (buf == 'C')//это проверяет стартовый байт.
            {
                i = 0;// если да, обнуляем счетчик
                ptr28[i] = buf;
                Serial.println(ptr28[i]);
                continue;//пропускаем
            }
            ptr28[i] = buf;
            Serial.println(ptr28[i]);
        }
        Serial.println("END");*/
    }
    if(one.on_of_pomp==ON) // включим клапан
    {
        digitalWrite(3, HIGH); //  включим клапан
    }
    else if (one.on_of_pomp==OFF)
        digitalWrite(3, LOW);

    //тут обработка датчика температуры вместо random
    // temp_pomp = 55;

    one.temp_pomp=55;//записываем значение температуры охлаждения в пакет на отправку

    digitalWrite(DIR, HIGH); // включаем передачу
    RS485.write(ptr28,sizeof(packet_arduino_pomp)); //отправляем
}

 

Maximus
Offline
Зарегистрирован: 24.07.2015

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Для посчета контрольной суммы структура пакета должна быть такой.

struct packet_arduino_pomp {//пакет Arduino nano
  byte start_byte_one;//в коротком пакете равен 212
  byte start_byte_two;//в коротком пакете равен 211
  byte temp_pomp;//температура охлаждения
  byte on_of_pomp;//on-off насоса (1 или 0)
  byte tmp;//пока не трогаем
  byte crv;//пока не трогаем
  //--
  byte  CRC8;//контрольная сумма
  byte get_CRC() {
    byte  CRC = 0;
    /*подсчитать конрольную сумму*/
    CRC8 = CRC;
    return CRC;
  }
};

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

а глобальная CRC8 нахрена?

и вапще, откройте для себя avr\crc16.h  там всё есть

Maximus
Offline
Зарегистрирован: 24.07.2015

Как я понял это член структуры, а дальше метод. Хорошо спасибо) По стартовым битам не совсем уродски я сделал?

Maximus
Offline
Зарегистрирован: 24.07.2015

А по контрольной сумме я правильно понимаю, приходит пакет, я его считываю, потом подставляю в ту же формулу данные которые я принял и сверяю с принятой контрольной суммой, если они разные , этот пакет пропускаю, жду другого ? Правильно?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Где вы видите глобальную CRC8. Она же лежит в пакете . Не нравится CRC8 пусть будет CRC16. Немного аналогии. К вам домой пришла посылка. Вопрос как проверить вскрывали посылку или нет. Разумеется проверить упаковку. Упаковка , как это знучит не странно, приходит с посылкой, а не лежит глобально на почте. Вот контрольная сумма это и есть упаковка. Если она верна, то пакет верен. Итак привожу итоги. В любом пакете должна быть сама информация , контрольная сумма и две функции упаковать (подсчитать и записать контрольную сумму) и проверка самой контрольной суммы.  Если в пакет перед отправкой вы засунули информацию, то должны дать команду упаковать. А если получили свежий пакет, то проверить упаковку. Если упаковка "вскрыта", то требуйте новый пакет.

ПС:упрощенно где то так 

struct pasket {
  byte data1;
  byte data2;
  byte data3;
  //---
  byte CRC8;//контрольная сумма
  /*упаковать*/
  void pask() {
    CRC8 = data1 + data2 + data3;
  }
  /*проверка упаковки*/
  bool test pask() {
    if (CRC8 == (data1 + data2 + data3)) return 0; //ОК
    return -1; // ошибка
  }
};

 

Maximus
Offline
Зарегистрирован: 24.07.2015

Товарищи, танцевал с бубном весь вечер. Нано принемает пакеты и читает их от Меги, но проблема в том, что когда нано прочитала, она отправляет обратно пакет с внесенными изменениями. И в Мастере(Мега) не хочет читаться ничего. Прошу помочь, сам не вижу ошибки.

Мастер (Аржуино Мега):




#include <SoftwareSerial.h>

#define DIR 8 // переключатель прием\передача
#define BUT 49
SoftwareSerial RS485 (7, 6); // RX, TX

struct packet_big //пакет PC
{
    byte start_byte_one;//в длинном пакете равен 254
    byte start_byte_two;//в длинном пакете равен 232
    byte temp_pomp;//температура охлаждения
    byte on_of_pomp;//on-off насоса (1 или 0)
    byte ex_temp_reactor;//текущая температура в реакторе
    byte current_temp_reactor;//выставленная температура в реакторе
    byte timer_ex;//таймер
    byte tmp;//пока не трогаем
    byte crv;//пока не трогаем
};

struct packet_arduino_pomp //пакет Arduino nano
{

    byte start_byte_one;//в коротком пакете равен 212
    byte start_byte_two;//в коротком пакете равен 211
    byte temp_pomp;//температура охлаждения
    byte on_of_pomp;//on-off насоса (1 или 0)
    byte tmp;//пока не трогаем
    byte CRC8;//пока не трогаем
    /*упаковать*/
    void pask()
    {
        CRC8 = (start_byte_one + start_byte_two + temp_pomp+on_of_pomp+tmp)/10;
    }
    /*проверка упаковки*/
    bool test_pask()
    {
        if (CRC8 == (start_byte_one + start_byte_two + temp_pomp+on_of_pomp+tmp)/10) return 0; //ОК
        return -1; // ошибка
    }
};

packet_big one= {254,232,0,0,0,0,0,0,0};
packet_arduino_pomp one_pomp = {212,211,0,0,0,0};


byte buttonState=0;

void setup()
{
    Serial.begin(9600);//на PC
    RS485.begin(9600); // SoftwareSerial на Arduino nano
    pinMode(BUT, INPUT);
    pinMode(DIR, OUTPUT);

}

void loop()
{
    buttonState = digitalRead(BUT); //кнопка
    byte* ptr28 = (byte* )&one;
    byte *ptr_pomp =(byte*)&one_pomp;
    
    if (buttonState == HIGH) //вкл/выкл от кнопки
    {
        if(one.on_of_pomp==0)//если выключен , то перезаписываем в пакете (включаем)
            one.on_of_pomp=1;
        else if(one.on_of_pomp==1)//если включен, то перезаписываем в пакете (выключаем)
            one.on_of_pomp=0;
    }
    
    one_pomp.on_of_pomp = one.on_of_pomp;
    
    digitalWrite(DIR, HIGH); // включаем передачу
    // Serial.write(ptr28,sizeof(packet_big)); //передаем на PC
    one_pomp.pask();
    RS485.write(ptr_pomp,sizeof(packet_arduino_pomp));//передаем на Arduino nano
    delay(200);



    digitalWrite(DIR, LOW); // включаем прием
    //прием с PC данных всех команд, включая информацию о температуре с реактора
    if (Serial.available()>sizeof(packet_big)) //возможно установить колличество байт
    {
        byte buf_big = Serial.read();
        if (buf_big  == 254)
        {
            buf_big = Serial.read();
            if (buf_big  == 232)
            {
                ptr28[0] = 254;
                ptr28[1] = buf_big;
                for (size_t i = 2; i < sizeof(packet_big); i++)
                {
                    buf_big = Serial.read();
                    ptr28[i] = buf_big ;
                }
            }
        }
    }
    //возможно нужно повторно записать стартовый бит.
    //прием с ардуино nano данных о вкл/ вкл насоса и температуры охлаждения
    if (RS485.available()) //возможно установить колличество байт
    {

        byte buf_pump = RS485.read();
        if (buf_pump  == 212)
        {
            buf_pump = RS485.read();
            if (buf_pump  == 211)
            {
              Serial.println('a');
                for (size_t i = 2; i < sizeof(packet_arduino_pomp); i++)
                {
                    buf_pump = RS485.read();
                    ptr_pomp[i] = buf_pump;
                    if(i==sizeof(packet_arduino_pomp)-1)
                    {
                        if(one_pomp.test_pask())
                        {
                            i=0;
                        }

                    }
                }
            }
        }
    }
  /*  Serial.println("ON");
    for(size_t i = 0; i < sizeof(packet_arduino_pomp); i++)
    {
        Serial.println(ptr_pomp[i]);
    }
    Serial.println("END");*/

// запись данных из пакета от PC в пакет от ардуино и наобарот.
   // one.temp_pomp = one_pomp.temp_pomp;


}

Слейв:


#include <SoftwareSerial.h>

#define DIR 8 // переключатель прием\передача
#define ON 1 // вкл. насос
#define OFF 0 // вкл. насос

struct packet_arduino_pomp //пакет Arduino nano
{

    byte start_byte_one;//в коротком пакете равен 212
    byte start_byte_two;//в коротком пакете равен 211
    byte temp_pomp;//температура охлаждения
    byte on_of_pomp;//on-off насоса (1 или 0)
    byte tmp;//пока не трогаем
    byte CRC8;//пока не трогаем
    /*упаковать*/
    void pask()
    {
        CRC8 = (start_byte_one + start_byte_two + temp_pomp+on_of_pomp+tmp)/10;
    }
    /*проверка упаковки*/
    bool test_pask()
    {
        if (CRC8 == (start_byte_one + start_byte_two + temp_pomp+on_of_pomp+tmp)/10) return 0; //ОК
        return -1; // ошибка
    }
};


static packet_arduino_pomp one = {212,211,0,0,0,0};//пакет с данными
byte temp_pomp = 0;//переменная для хранения температуры

SoftwareSerial RS485 (2, 6); // RX, TX

void setup()
{
    Serial.begin(9600);
    RS485.begin(9600); // SoftwareSerial

    pinMode(DIR, OUTPUT);
    pinMode(3, OUTPUT);
}

void loop()
{

    byte* ptr28 = (byte* )&one;
    digitalWrite(DIR, LOW); // включаем прием
    delay(200);
    if (RS485.available())
    {
        byte buf_pump = RS485.read();
        if (buf_pump  == 212)
        {
            buf_pump = RS485.read();
            if (buf_pump  == 211)
            {
                ptr28[0] = 212;
                ptr28[1] = buf_pump;
                for (size_t i = 2; i < sizeof(packet_arduino_pomp); i++)
                {
                    buf_pump = RS485.read();
                    ptr28[i] = buf_pump;
                    if(i==sizeof(packet_arduino_pomp)-1)
                    {
                        if(one.test_pask())
                        {
                            i=0;
                        }

                    }
                }
            }
        }
            Serial.println("ON");
    for(size_t i = 0; i < sizeof(packet_arduino_pomp); i++)
    {
        Serial.println(ptr28[i]);
    }
    Serial.println("END");
    }
      one.temp_pomp=55;//записываем значение температуры охлаждения в пакет на отправку

    if(one.on_of_pomp==ON) // включим клапан
    {
        digitalWrite(3, HIGH); //  включим клапан
    }
    else if (one.on_of_pomp==OFF)
        digitalWrite(3, LOW);

    //тут обработка датчика температуры вместо random
    // temp_pomp = 55;

  
    digitalWrite(DIR, HIGH); // включаем передачу
    RS485.write(ptr28,sizeof(packet_arduino_pomp)); //отправляем
}
sim31
sim31 аватар
Offline
Зарегистрирован: 26.07.2017

Вместо CRC8 CRC16 вполне можно было ограничится просто суммой 8 или 16 битной, там на несколько процентов ухудшается распознование ошибок, а код проще намного. В DCON так сделано.

И это не CRC (она сложнее), а просто контрольная сумма

CRC8 = data1 + data2 + data3 +...

 

Maximus
Offline
Зарегистрирован: 24.07.2015

Не могу понять принцип , в том плане, где ставить delay. Может в этом причина. То ли нано не отправляет пакет, потому что в меге в if:

if (Serial.available()>sizeof(packet_big))

не входит. Я убирал условие, все равно ни одного байта не приходит. А отправляет он исправно, нано исправно принимает.....

Может есть какие то идеи или я что то грубо не вижу и не знаю.....

sadman41
Онлайн
Зарегистрирован: 19.10.2016

delay в таких вещах вообще нигде не нужен. Забудетесь, начнете в код с SoftSerial делеи лепить и порастеряете все, что вам шлют.

Самый простой способ упорядочить в голове этот алгоритм в данном случае - использовать "машину состояний". Она отлично справляется с анализом входящего пакета на лету.

А так.. вы же сами понимаете, где ошибки - комментируете даже:

    bool test_pask()
    {
        ...
        return -1; // ошибка
    }

 

Maximus
Offline
Зарегистрирован: 24.07.2015

Типо написать Case конечный автомат, с несколькими состаяними : Прием пакета, первый стартовый бит, второй стартовый бит, принятие информации, проверка контрольной суммы? По образу :http://www.devexp.ru/2011/02/konechnye-avtomaty-v-c/

А по поводу проверки контрольной суммы, у меня вообще стоит:

if(one.test_pask())
                        {
                            i=0;
                        }

Если меняю на 

if(!one.test_pask())
                        {
                            i=0;
                        }

То ересь начинает приходить и прием спатыкаться начинает. 

Вопрос то в другом, почему мега ничего не принемает, вообще ничего.

Maximus
Offline
Зарегистрирован: 24.07.2015

А если delay убрать, то нано вообще ничего не принемает. Короче я в отчаянии, мне еще Мегу надо к Qt проге подрубить, которая уже есть.....  

Просто по логике, вроде все просто. Мега шлет пакет, нано ждет пакет, принемает его. Делает действия в зависимости от содержания пакета, записывает в него свои данные и отправляет. В это время Мега ждет приема, принемает, записывает значения в пакет для Pc и отправляет.

И зачем конечный автомат , тут же пакет коротки и не проще ли его так как я сделал прочитать, в цикле?

 

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

У вас на слэйве 51й строкой открывается if и закрывается на 81 (код из поста 20) а потом вы смотрите что там с клапанами в пакете, который возможно даже не получили. Потом передаете пакет и возвращаетесь в начало луп где снова задаете указатель на структуру ждете 200мс и по кругу. Это так и задумано? )

Maximus
Offline
Зарегистрирован: 24.07.2015

То что не проверил получил ли я пакет или нет, да, исправлю, внесу это в if который начинается на 51 строке. А дальше что не так? Вы хотите сказать что этот указатель глабально надо обьявить?

sim31
sim31 аватар
Offline
Зарегистрирован: 26.07.2017

Maximus пишет:

А если delay убрать, то нано вообще ничего не принемает.

Очень странно, данные не должны пропадать, они лежат в буфере пока не считают их... то же самое с передачей данных.

Maximus
Offline
Зарегистрирован: 24.07.2015

Почему Мега ни чего не принимает , вот в чем вопрос. Все красивости я допилю потом(конечне автоматы и т.д.), когда будет более менее работать код. А на данный момент подозрения что я не в том порядке что то делаю и канал занимается мегой, но на отправку, а нано не успевает запихнуть ничего в него. Возможно такое?

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Сейчас для интереса попробовал мега+уно. Сначала с софтверными сериала и там затыки были периодически, на аппаратных сериалах все четко идет. Зачем вы на меге используете софтверный порт когда там 4ре аппаратных, ну и на нано можно использовать аппаратный, а отлаживаться по софтверному или через мегу отлаживаться.

Maximus
Offline
Зарегистрирован: 24.07.2015

Вечером попробую контакты перекинуть! Спасибо большое!

Maximus
Offline
Зарегистрирован: 24.07.2015

Я просто думал что какаяразница и сделал на софтверном сериале. Но не первый раз слышу что разница есть....

Да и тем более я не на те пины закинул:

Среди известных ограничений библиотеки SoftwareSerial можно перечислить следующие:

  • При использовании нескольких последовательных портов, в каждый момент времени только один из них может получать данные.
  • На платах Arduino Mega и Mega2560 некоторые выводы не поддерживают прерывания, возникающие при изменении уровня сигнала. В силу этого, на данных платах в качестве вывода RX могут использоваться только следующие выводы: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69).
  • На Arduino Leonardo некоторые выводы не поддерживают прерывания, возникающие при изменении уровня сигнала. Поэтому, на этой плате в качестве вывода RX могут использоваться только следующие выводы: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI).
qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Это не танцы с бубном, а клоуны в цирке. Изучите как устроена Сетевая модель OSI. Вы решаете на Канальном уровне то что должно решаться на Сетевом уровне. Проще говоря у вас нет Сетевого уровня. От туда все проблемы.

Maximus
Offline
Зарегистрирован: 24.07.2015

А можно поконкретнее...

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Я немного перепутал.  Прикладной уровень- это вы программе пишете строчку похожую Serial.print("sdsfsf"), или Led.ON():  И так далее. Представительский уровень это все упаковывается в пакет в котором откуда, куда, что передать(что сделать), время отправления и контрольная сумма. Сеансовый уровень это отправка пакета через посредников получателю(почта - отдел работы с клиентом) Общение с клентом служебными пакетами и получение , отправление главного пакета. Транспортный , сетевой ,канальный скорее объедены тоже самое но обмен идет через посредников минуя клиентов. Прикладной это уже железо и работа с ним. 

sim31
sim31 аватар
Offline
Зарегистрирован: 26.07.2017

qwone пишет:
Проще говоря у вас нет Сетевого уровня. От туда все проблемы.

Это вообще не по теме. Человек контакты перепутал, а вы читаете громоздкий академический курс по сетевой модели, который кроме университетов никому даром не нужен, так как далек от жизни. Все равно что начать с того что гравитация Луны притягивает электроны сильнее, чем гравитация Марса и это нужно точно расчитать :)

Обычно упрощают всё до нижнего уровня (железо) и верхнего уровня (программа), тут этого достаточно.

Даже в Википедии есть упоминание:

Пока комитеты ISO спорили о своих стандартах, за их спиной менялась вся концепция организации сетей и по всему миру внедрялся протокол TCP/IP.

И вот, когда протоколы ISO были наконец реализованы, выявился целый ряд проблем:

  • эти протоколы основывались на концепциях, не имеющих в современных сетях никакого смысла;
  • их спецификации были в некоторых случаях неполными;
  • по своим функциональным возможностям они уступали другим протоколам;
  • наличие многочисленных уровней сделало эти протоколы медлительными и трудными для реализации.

Сейчас даже самые ярые сторонники этих протоколов признают, что OSI постепенно движется к тому, чтобы стать маленькой сноской на страницах истории компьютеров. — Эви Нэмет

 

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Maximus пишет:
И зачем конечный автомат , тут же пакет коротки и не проще ли его так как я сделал прочитать, в цикле?

Он поможет вам привести мысли в порядок. А то bool функция, возвращающая -1 попахивает неэвклидовой геометрией.  

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

sim31 пишет:
Сейчас даже самые ярые сторонники этих протоколов признают, что OSI постепенно движется к тому, чтобы стать маленькой сноской на страницах истории компьютеров. — Эви Нэмет

Понятно,тупеет народ, а тупому быдлу фундаментальные знания ни к чему. Сеть она многослойная. И разумеется терминология расплывчатая. 

sim31
sim31 аватар
Offline
Зарегистрирован: 26.07.2017

qwone пишет:
Понятно,тупеет народ, а тупому быдлу фундаментальные знания ни к чему. Сеть она многослойная. И разумеется терминология расплывчатая.

Или наоборот, умнее, и народ сходу отсекает демагогию. Практик сделал устройство, с телефона управляет поливом теплицы и всё работает. Тут приходит демагог и начинает, где у вас прикладной уровень, а где представительский? :)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Знаем мы таких практиков. Каждый раз новая тема :помогите новичку , ему нужно сделать миньет  написать скетч . Он блин практик, а демагогии в виде ,как писать код ему не нужны, даже если у него скеч спизженый на просторах инета не работает.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

qwone пишет:

у него скеч спизженый на просторах инета не работает.

я же запретил пиздить нерабочие скетчи. ¯\_(ツ)_/¯

Maximus
Offline
Зарегистрирован: 24.07.2015

Поменял пины на меге, все равно не пашет. Нано принемает все хорошо, а вот мега принемать ни единого пакета не хочет. Еще раз приведу код, я там кое что изменил. 

qwone- я  таких спецов как Вы , на "Х.. вертел", код не ворованый, в том то и дело. Если какашки лезут, прошу какашки извергать в других темах или лучше у себя дома.

Возвращаясь к теме,  не могу понять нано не отправляет или мега не принемает. Без delay не работает, прием в штопор уходит.

 

Мега:


#include <SoftwareSerial.h>

#define DIR 8 // переключатель прием\передача
#define BUT 49


struct packet_big //пакет PC
{
  byte start_byte_one;//в длинном пакете равен 254
  byte start_byte_two;//в длинном пакете равен 232
  byte temp_pomp;//температура охлаждения
  byte on_of_pomp;//on-off насоса (1 или 0)
  byte ex_temp_reactor;//текущая температура в реакторе
  byte current_temp_reactor;//выставленная температура в реакторе
  byte timer_ex;//таймер
  byte tmp;//пока не трогаем
  byte crv;//пока не трогаем
};

struct packet_arduino_pomp //пакет Arduino nano
{

  byte start_byte_one;//в коротком пакете равен 212
  byte start_byte_two;//в коротком пакете равен 211
  byte temp_pomp;//температура охлаждения
  byte on_of_pomp;//on-off насоса (1 или 0)
  byte tmp;//пока не трогаем
  byte CRC8;//пока не трогаем
  /*упаковать*/
  void pask()
  {
    CRC8 = (start_byte_one + start_byte_two + temp_pomp + on_of_pomp + tmp) / 10;
  }
  /*проверка упаковки*/
  bool test_pask()
  {
    if (CRC8 == (start_byte_one + start_byte_two + temp_pomp + on_of_pomp + tmp) / 10) return 0; //ОК
    return -1; // ошибка
  }
};

packet_big one = {254, 232, 0, 0, 0, 0, 0, 0, 0};
packet_arduino_pomp one_pomp = {212, 211, 0, 0, 0, 0};


byte buttonState = 0;

void setup()
{
  Serial.begin(9600);//на PC
  Serial2.begin(9600); // SoftwareSerial на Arduino nano
  pinMode(BUT, INPUT);
  pinMode(DIR, OUTPUT);
}

void loop()
{
  digitalWrite(DIR, HIGH); // включаем передачу
  buttonState = digitalRead(BUT); //кнопка
  byte* ptr28 = (byte* )&one;
  byte *ptr_pomp = (byte*)&one_pomp;

  if (buttonState == HIGH) //вкл/выкл от кнопки
  {
    if (one.on_of_pomp == 0) //если выключен , то перезаписываем в пакете (включаем)
      one.on_of_pomp = 1;
    else if (one.on_of_pomp == 1) //если включен, то перезаписываем в пакете (выключаем)
      one.on_of_pomp = 0;
  }

  one_pomp.on_of_pomp = one.on_of_pomp;

  // Serial.write(ptr28,sizeof(packet_big)); //передаем на PC
  one_pomp.pask();
  Serial2.write(ptr_pomp, sizeof(packet_arduino_pomp)); //передаем на Arduino nano
  delay(100);
  digitalWrite(DIR, LOW); // включаем прием
  //прием с PC данных всех команд, включая информацию о температуре с реактора
  if (Serial.available() > sizeof(packet_big)) //возможно установить колличество байт
  {
    byte buf_big = Serial.read();
    if (buf_big  == 254)
    {
      buf_big = Serial.read();
      if (buf_big  == 232)
      {
        ptr28[0] = 254;
        ptr28[1] = buf_big;
        for (size_t i = 2; i < sizeof(packet_big); i++)
        {
          buf_big = Serial.read();
          ptr28[i] = buf_big ;
        }
      }
    }
  }
  //возможно нужно повторно записать стартовый бит.
  //прием с ардуино nano данных о вкл/ вкл насоса и температуры охлаждения

  if (Serial2.available() >= sizeof(packet_arduino_pomp))
  {

    byte buf_pump = 0;
    for (size_t i = 0; i < sizeof(packet_arduino_pomp); i++)
    {
      Serial.println("1");
      if (i == 0 && (buf_pump = Serial2.read()) != 212)
      {
        Serial.println("2");
        i = 0;
        continue;
      }
      if (i == 1 && (buf_pump = Serial2.read()) != 211)
      {
        Serial.println("3");
        i = 0;
        continue;
      }
      if (i >= 2)
      {
        Serial.println("4");
        buf_pump = Serial2.read();
        ptr_pomp[i] = buf_pump;
        if (i == sizeof(packet_arduino_pomp) - 1)
        {
          Serial.println("5");
          if (one_pomp.test_pask()) //проверяем контрольную сумму
          {
            Serial.println("6");
            i = 0;
            continue;
          }
        }

      }
    }
    Serial.println("ON");
    for (size_t i = 0; i < sizeof(packet_arduino_pomp); i++)
    {
      Serial.println( ptr_pomp[i]);
    }
    Serial.println("END");

  }

  // запись данных из пакета от PC в пакет от ардуино и наобарот.
  // one.temp_pomp = one_pomp.temp_pomp;


}

Нано:

#include <SoftwareSerial.h>

#define DIR 8 // переключатель прием\передача
#define ON 1 // вкл. клапан
#define OFF 0 // вкл. клапан

struct packet_arduino_pomp //пакет Arduino nano
{

    byte start_byte_one;//в коротком пакете равен 212
    byte start_byte_two;//в коротком пакете равен 211
    byte temp_pomp;//температура охлаждения
    byte on_of_pomp;//on-off насоса (1 или 0)
    byte tmp;//пока не трогаем
    byte CRC8;//пока не трогаем
    /*упаковать*/
    void pask()
    {
        CRC8 = (start_byte_one + start_byte_two + temp_pomp+on_of_pomp+tmp)/10;
    }
    /*проверка упаковки*/
    bool test_pask()
    {
        if (CRC8 == (start_byte_one + start_byte_two + temp_pomp+on_of_pomp+tmp)/10) return 0; //ОК
        return -1; // ошибка
    }
};


static packet_arduino_pomp one = {212,211,0,0,0,0};//пакет с данными
byte temp_pomp = 0;//переменная для хранения температуры

SoftwareSerial RS485 (2, 6); // RX, TX

void setup()
{
    Serial.begin(9600);
    RS485.begin(9600); // SoftwareSerial

    pinMode(DIR, OUTPUT);
    pinMode(3, OUTPUT);
}

void loop()
{

    byte* ptr28 = (byte* )&one;
    digitalWrite(DIR, LOW); // включаем прием
    if (RS485.available()>= sizeof(packet_arduino_pomp))
    {


        byte buf_pump=0;
        for (size_t i = 0; i < sizeof(packet_arduino_pomp); i++)
        {
          Serial.println("1");
            if(i==0&&(buf_pump = RS485.read())!=212)
            {
              Serial.println("2");
                i=0;
                continue;
            }
            if(i==1&&(buf_pump = RS485.read())!=211)
            {
              Serial.println("3");
                i=0;
                continue;
            }
            if(i>=2)
            {
              Serial.println("4");
                buf_pump = RS485.read();
                ptr28[i] = buf_pump;
                if(i==sizeof(packet_arduino_pomp)-1)
                {
                  Serial.println("5");
                    if(one.test_pask())//проверяем контрольную сумму
                    {
                      Serial.println("6");
                        i=0;
                        continue;
                    }
                }

            }
        }
        Serial.println("ON");
        for(size_t i = 0; i < sizeof(packet_arduino_pomp); i++)
        {
            Serial.println(ptr28[i]);
        }
        Serial.println("END");
        if(one.on_of_pomp==ON) // включим клапан  
        {
            digitalWrite(3, HIGH); //  включим клапан
        }
        else if (one.on_of_pomp==OFF)
            digitalWrite(3, LOW);
    }
    one.temp_pomp = 55;//записываем значение температуры охлаждения в пакет на отправку
    one.pask();//формируем контрольную сумму
    digitalWrite(DIR, HIGH); // включаем передачу
 RS485.write(ptr28,sizeof(packet_arduino_pomp));
}

 

Maximus
Offline
Зарегистрирован: 24.07.2015

Все заработало, после плясками с delay, расставил , все ок.