Связь nano и pro mini по RX-TX - проблема

M a x
Offline
Зарегистрирован: 20.06.2016

Не смог найти ответа на свою проблему в недрах Интернета.

Проблема в следующем - для проекта нужна связь между двумя клонами Ардуино - nano 328, 16 Mhz и pro mini 328, 16 Mhz. 

Скетч уже более 2000 строк, но суть передать с nano на pro mini до 5 байт информации с разной переодичностью.

В начала проекта, особо не обращал внимания на правильность и аккуратность и в итоге, после небольшой серии экспериментов зараьботало так:

- на передающей ардуине стоит скорость 9600, байты передаются из программы каждый с помощью Serial.write (byte), то 1, то 2-3, то все 5 с периодичностью от 100 мс до нескольких секунд.

- На принимающей стоит скорость 19200 (!!!) и байты принимаются 5 раз Serial.read(), как только становятся доступными if (Serial.available() > 0), байты неполученные получались как 255

Все работало и я как то не озадачивался почему это работает в таком виде.

Настал момент причесывания и все пошло наперекосяк. На скорости на обоих ардуинах 9600 или 19200 - не работает в принципе - вместо посланных байтов доходят не те. Вернул разные скорости, написал функцию, где послыка идет строго 5 байт и прием идет строго по количеству байт в буфере -  работает нестабильно, постоянно проскакивают неконятные байты. Добавил Serial.flush () после пяти посылов байт Serial.write() - так же нестабильно. Или вообще мусор или ноль проскакивает или 255.

 

Никто не сталкивался? Или кинте ссылкой где почитать о похожей проблеме.

есть одно НО - на nano выгорел диод B2 от неправильного включения и она питается только от VCC. Не думаю, что это как то влияет, но все же.

Буду очень признателен за помощь. Ниже - куски кода

 

Передающая:

  Serial.begin (9600); 
 

.......

  sendToLED (boardNum, 0, 0, 0, 0);

......................

  sendToLED (0, 0, 0, 'T', '*');

.........

void sendToLED (byte s1, byte s2, byte s3, byte s4, byte s5) {
  Serial.write (s1);
  Serial.write (s2);
  Serial.write (s3);
  Serial.write (s4);
  Serial.write (s5);
  Serial.flush (); 
}
 
 
Принимающая:
  Serial.begin (19200);
......................
 
  num1 = Serial.available();
  if (num1 > 0) {
    switch (num1) {
      case 1:
        num = Serial.read ();
        spd = 0;
        spdD = 0;
        symb1 = 0;
        symb2 = 0;
 //       Serial.flush();
        break;
      case 2:
.................... 
      case 3:
...................
      case 5:
        num = Serial.read ();
        spd = Serial.read ();
        spdD = Serial.read ();
        symb1 = Serial.read ();
        symb2 = Serial.read ();
        break;
      default:
        break;
    }
..............................
 
vde69
Offline
Зарегистрирован: 10.01.2016

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

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

vde69 пишет:

какую...

какую?

vde69
Offline
Зарегистрирован: 10.01.2016

да хоть вот эту :)

#ifndef BUS_RS485_H        
#define BUS_RS485_H

#include <Arduino.h> 
#include <inttypes.h>
#include <Print.h>
#include <wiring_private.h>

// буфер Serial может хранить 64 байта или 16, заголовок пакета 8 байт, по этому размер буфера дополнительных данных 
// 56 или 8 байт, такой малый размер буфера надо учитывать !!! 
// Рекомендуемый размер дополнительных данных не более 24 байта (2 полных кадра в буфере)
// данная библиотека не будет работать с малым размером буфера для шины RS485, пин управления будет отключен !!!
#if (RAMEND < 1000)
  #define MAX_BUFFER 8
#else
  #define MAX_BUFFER 56
#endif


// описание пакета, данные передаются и принимаются именно в такой последовательности, 
// длина заголовка пакета всегда 8 байт
// длина дополнительных данных от 0 до 24 байт
typedef struct {
  uint8_t Mark;             // маркер начала кадра  
  uint8_t Id_Destination;   // ID получателя пакета
  uint8_t Id_Source;        // ID отправителя пакета
  uint16_t Control_1;       // Два байта контроля пакета (сделано побайтно для удобства применения битовых операций), состав:
  uint16_t Control_2;       //   1...4 - 4 бита, номер команды
                            //   5...8 - 4 бита, всего кадров (пакетов) в команде
                            //   1...4 - 4 бита, номер текущего кадра (пакета) в команде 
                            //   5 - 1 бит, ошибка
                            //   6 - 1 бит, ожидание
                            //   7 - 1 бит, повтор
                            //   8 - 1 бит, подтверждение
                            
  uint8_t SizeDate;         // Размер дополнительных данных пакета
  uint8_t CRC_Data;         // CRC дополнительных данных пакета
  uint8_t CRC_Head;         // CRC заголовка, служит для определения корректности заголовка и выделения кадра из потока данных
  uint8_t Data[MAX_BUFFER]; // дополнительные данные, рекомендуемый размер не более 24 байт, максимальный размер 56 байт
} 
BusRS485_Pack;

// описание параметров ожидаемого пакета, используется для фильтрации пакетов
typedef struct {
  boolean OnReply;          // ожидаем, или нет, ответный пакет
  int TimeOut;              // время которое будем ожидать ответный пакет
  unsigned long StartTime;  // время начала ожидания ответного пакета
  uint8_t Id_Destination;   // ID получателя пакета
  uint8_t Id_Source;        // ID отправителя пакета
  uint8_t Control_1;        // Номер команды и количество кадров в команде
  uint8_t Control_2;        // Номер пакета (младшие 4 бита)
  voidFuncPtr Reply_OnStep; // Пользовательское событие возникающее при получении ответного пакета
} 
Reply_Pack;

class BusRS485 {
private:
  // -------------------------------------------------------------- 
  // данные класса
  HardwareSerial *port;       // указатель на Serial class 
  uint8_t        Id_Unit;     // 0=master, 1..240=slave, 247=резерв
  uint8_t        MaskRW;      // маска потра для получения и отправки данных
  unsigned int   PauseWrite;  // синхро пауза после перехода в режим write и до начала передачи первого байта
  BusRS485_Pack  InPack;      // входящий пакет
  Reply_Pack     Reply;       // ожидаемые данные и правила их обработки
  voidFuncPtr    OnSlave;     // Пользовательское событие возникающее при получении не ожидаемых данных слейвом от мастера
  uint8_t        Echo;        // Вариант эхо входящих данных
                              //   0 - нет эхо
                              //   1 - эхо всех считаных байт
                              //   2 - эхо всех распознаных пакетов
                              //   3 - эхо только пакетов предназначеных для устройства
  
  uint8_t        FInPack;     // флаг входящего пакета 
                              //    0-ждем заголовок 
                              //    1-ждем дополнительные данные 
                              //    2-пакет загружен валиден 
                              //    3-пакет загружен, но не валиден
                              
  uint8_t        FStatus;     // битовый флаг статуса контроллера RS485
                              //    0 - не верный ID 
                              //    1 - слишком маленький буфер 
                              //    2 - конфликт ID в сети 
                              //    3 - выключен RS-485 
                              //    4 - <свободно> 
                              //    5 - <свободно>
                              //    6 - прочая не критическая ошибка 
                              //    7 - прочая критическая ошибка
                              
  // -------------------------------------------------------------- 
  // локальные процедуры
  uint8_t CRC(uint8_t, uint8_t);
  
  // возвращает true если данные отправлены, и false если ошибка
  boolean send(uint8_t,       // ID получателя
               uint8_t,       // номер функции
               uint8_t,       // номер кадра в команде
               uint8_t,       // всего кадров в команде
               boolean,       // флаг ошибки
               boolean,       // флаг ожидания
               boolean,       // флаг повтора
               boolean,       // флаг подтверждения
               uint8_t,       // размер дополнительных данных
               uint8_t *);    // указатель на буфер дополнительных данных 
               
public:
  // -------------------------------------------------------------- 
  // конструктор и процедуры инициализации класса

  BusRS485(uint8_t,            // номер порта Uart, =0, для Меги доступны =0, =1, =2, =3
           uint8_t,            // пин контрольного тригера получения данных интерфейса RS485
           uint8_t);           // пин контрольного тригера отправки данных интерфейса RS485

  void InitEnd(void);   
  void InitMaster(long Speed);
  void InitSlave(long,         // скорость порта 
                 uint8_t,      // Id слейва 
                 void (*)());  // пользовательская функция для обработки получения неожидаемого пакета от мастера
  void SetEcho(uint8_t);       // устанавливает режим эхо
  
  // -------------------------------------------------------------- 
  // публикуемые "свойства" класса

  uint8_t Id (void);
  uint8_t Status (void);
  
  // -------------------------------------------------------------- 
  // публикуемые "свойства" ожидаемого пакета
  
  boolean       OnReply (void);          
  boolean       OnReply (boolean);    
  uint8_t       ReplyId (void);    
  uint8_t       ReplyNumFunc (void);
  int           TimeOut (void);         
  unsigned long StartTime (void);  
  
  // -------------------------------------------------------------- 
  // публикуемые "свойства" входящего пакета
  
  uint8_t Id_Destination (void);
  uint8_t Id_Source (void);
  uint8_t SizeDate (void);
  uint8_t *Date (void);
  
  uint8_t NumFunc (void);
  uint8_t NumCadr (void);
  uint8_t CountCadr (void);
  boolean FError (void);
  boolean FWait (void);
  boolean FRetry (void);
  boolean FValidate (void);

  // -------------------------------------------------------------- 
  // доступные процедуры класса

  void poll();                 // процедура запуска обработки получения данных
  void onRead();               // включение шины на прием
  void onWrite();              // включение шины на передачу
  void off();                  // выключение шины 
  uint8_t Read();              // чтение с UART контроллера 1 байта, с учетом включеного/выключеного эха
  
                 
  // простая команда из одного пакета без ожидания ответа
  // вызывается только на мастере
  void Command(uint8_t,        // Id получателя пакета
               uint8_t,        // номер функции
               uint8_t,        // размер дополнительных данных, не более 24 
               uint8_t *);     // указатель на буфер дополнительных данных 
               
  // начало команды из нескольких пакетов
  // вызывается только на мастере
  void Command(uint8_t,        // Id получателя пакета
               uint8_t,        // номер функции
               uint8_t,        // всего кадров в команде
               uint8_t,        // размер дополнительных данных первого пакета
               uint8_t *,      // указатель на буфер дополнительных данных первого пакета
               int,            // время в которое будем ожидать ответ на первый пакет
               unsigned long,  // время начала ожидания ответного пакета
               void (*)());    // процедура вызываемая при получения ответа
               
  // пакеты из сложной команды 
  // вызывается и на мастере и на слейве из обработчиков получения ответов
  void Command(uint8_t,        // Id получателя пакета
               uint8_t,        // номер функции
               uint8_t,        // номер кадра в команде
               uint8_t,        // всего кадров в команде
               boolean,        // флаг ошибки
               boolean,        // флаг ожидания
               boolean,        // флаг повтора
               boolean,        // флаг подтверждения
               uint8_t,        // размер дополнительных данных первого пакета
               uint8_t *,      // указатель на буфер дополнительных данных первого пакета
               int,            // время в которое будем ожидать ответ на первый пакет
               unsigned long,  // время начала ожидания ответного пакета
               void (*)());    // процедура вызываемая при получения ответа
  
  
};


#endif 

 

#include "BusRS485.h"

// размер буфера дополнительных данных
// размер 24 выбран для размещения в стандартном буфере двух полных пакетов 
// что бы уменьшить потери при задержках в обработки поступившего пакета
#define MIN_BUFFER 24 

// маркер начала кадра (введен для стабильности распознования кадров), всегда $ED, B11101101, 237  
#define MARK 237

//-------------------PUBLIC FUNCTIONS------------------------------------------

// конструктор для мастера
BusRS485::BusRS485(uint8_t PortNum, uint8_t CPinRx, uint8_t CPinTx) {
  FStatus = 0;
  this->Echo = 0;
  if (MAX_BUFFER < MIN_BUFFER) {
    FStatus = FStatus  | B00000010;
  }
 
  switch( PortNum ) {
  #if defined(UBRR1H)
  case 1:
    port = &Serial1;
    break;
  #endif

  #if defined(UBRR2H)
  case 2:
    port = &Serial2;
    break;
  #endif

  #if defined(UBRR3H)
  case 3:
    port = &Serial3;
    break;
  #endif
  case 0:
  default:
    port = &Serial;
    break;
  }
  
  MaskRW = 0;
//  MaskRWI = 0;

  if (CPinRx > 1 && CPinRx < 7) { 
    pinMode(CPinRx, OUTPUT); 
    bitSet(MaskRW, CPinRx);
  }
  if (CPinTx > 1 && CPinTx < 7) { 
    pinMode(CPinTx, OUTPUT); 
    bitSet(MaskRW, CPinTx);
  }
  if (CPinRx > 1 && CPinRx < 7 && CPinTx > 1 && CPinTx < 7 && CPinTx != CPinRx) {;}
  
}

void BusRS485::InitEnd(){         
  // закрытие соединения
  off();
  port->flush();
  port->end();
  FInPack = 0;
}


void BusRS485::InitMaster(long Speed){     // скорость порта
  // это мастер !!!!

  PauseWrite =   (10000.0 / 9600 * 1000)   // это время на отправку 10 бит эха в порт USB со скоростью 9600, 
                                           // нужна в случае включенного эха на устройствах для которых предназначена передача 
                                           // это время через которое устройства шины перейдут из режима Write в режим Read
               + (10000.0 / Speed * 1000); // это время на отправку 10 бит в порт 485 с установленой скоростью, 
                                           // такая пауза обеспечивает синхронизацию на физическом уровне (удаление ложного бита начала посылки)
  
  Id_Unit = 0;    
  port->begin(Speed);
  port->flush();
  onRead();
  delay(100);
  FInPack = 0;
}

void BusRS485::InitSlave(long Speed,           // скорость порта 
                         uint8_t Id,           // Id слейва 
                         void (*_OnSlave)()){  // пользовательская функция для обработки получения неожидаемого пакета от мастера
                         
  PauseWrite =   (10000.0 / 9600 * 1000)   // это время на отправку 10 бит эха в порт USB со скоростью 9600, 
                                           // нужна в случае включенного эха на устройствах для которых предназначена передача 
                                           // это время через которое устройства шины перейдут из режима Write в режим Read
               + (10000.0 / Speed * 1000); // это время на отправку 10 бит в порт 485 с установленой скоростью, 
                                           // такая пауза обеспечивает синхронизацию на физическом уровне (удаление ложного бита начала посылки)
  

  if (Id <= 0 || Id > 240) { // ошибочный ID 
    FStatus = FStatus | B00000001;
    this->Id_Unit = 241;    
  }
  else {
    this->Id_Unit = Id;    
  }
  
  OnSlave = _OnSlave;
  port->begin(Speed);
  port->flush();
  onRead();
  delay(100);
  FInPack = 0;
}

//------------------------------------------------------------------
// простая команда из одного пакета без ожидания ответа
void BusRS485::Command(uint8_t Id,       // Id получателя пакета
                       uint8_t Func,     // номер функции
                       uint8_t SizeDate, // размер дополнительных данных, не более 24 байт
                       uint8_t *Data){   // указатель на буфер дополнительных данных 
  
  Reply.OnReply = false;
  if (this->send(
         Id,            // ID получателя
         Func,          // номер функции
         1,             // номер кадра в команде
         1,             // всего кадров в команде
         false,         // флаг ошибки
         false,         // флаг ожидания
         false,         // флаг повтора
         false,         // флаг подтверждения
         SizeDate,      // размер дополнительных данных
         &(Data[0]))    // указатель на буфер дополнительных данных 
         == false) {    // попытка отправить слишком много данных, это критическая ошибка и отправка была заблокирована
     FStatus = FStatus | B10000000; // установим восьмой бит ошибки
  }
  
  if (this->Id_Unit > 0) {
       // попытка отправить простую команду со слейва - это ошибка, но не критическая, 
       // команда все равно будет отправлена, но она будет игнорироватся получателями 
       // отправка таких команды оставлена для резерва на будущее расширения возможностей
       FStatus = FStatus | B01000000; // установим седьмой бит ошибки
  }
}

//------------------------------------------------------------------
// начало команды из нескольких пакетов
void BusRS485::Command(uint8_t Id,              // Id получателя пакета
                       uint8_t Func,            // номер функции
                       uint8_t CountPack,       // всего кадров в команде
                       uint8_t SizeDate,        // размер дополнительных данных
                       uint8_t *Data,           // указатель на буфер дополнительных данных 
                       int TimeOut,             // время которое будем ожидать ответный пакет
                       unsigned long StartTime, // время начала ожидания ответного пакета               
                       void (*_userFunc)()){    // процедура вызываемая при получении ответа
  
  Reply.OnReply = false;  
  if (this->Id_Unit > 0) {
     // попытка отправить сложную команду со слейва - это критическая ошибка и отправка была заблокирована 
     FStatus = FStatus | B10000000; // установим восьмой бит ошибки
  }
  else if (this->send(
         Id,            // ID получателя
         Func,          // номер функции
         1,             // номер кадра в команде
         CountPack,     // всего кадров в команде
         false,         // флаг ошибки
         false,         // флаг ожидания
         false,         // флаг повтора
         false,         // флаг подтверждения
         SizeDate,      // размер дополнительных данных
         &(Data[0]))    // указатель на буфер дополнительных данных 
         == false) {    
     // попытка отправить слишком много данных - это критическая ошибка и отправка была заблокирована
     FStatus = FStatus | B10000000; // установим восьмой бит ошибки
  }
  else if (CountPack > 1) {  
    // отправка прошла, устанавливаем параметры ожидания ответа
    Reply.OnReply = true;
    Reply.TimeOut = TimeOut;
    Reply.StartTime = StartTime;
    Reply.Id_Destination = this->Id_Unit;
    Reply.Id_Source = Id;
    Reply.Control_1 = (CountPack << 4) | Func;
    Reply.Control_2 = 2;
    Reply.Reply_OnStep = _userFunc;;
  }
}

//------------------------------------------------------------------
// не первый пакет из сложной команды (вызывается из обработчиков ответа)
void BusRS485::Command(uint8_t Id,              // Id получателя пакета
                       uint8_t Func,            // номер функции
                       uint8_t Pack,            // номер кадра в команде
                       uint8_t CountPack,       // всего кадров в команде
                       boolean F1,              // флаг ошибки
                       boolean F2,              // флаг ожидания
                       boolean F3,              // флаг повтора
                       boolean F4,              // флаг подтверждения
                       uint8_t SizeDate,        // размер дополнительных данных
                       uint8_t *Data,           // указатель на буфер дополнительных данных 
                       int TimeOut,             // время которое будем ожидать ответный пакет
                       unsigned long StartTime, // время начала ожидания ответного пакета               
                       void (*_userFunc)()){    // процедура вызываемая при получении ответа
  
  Reply.OnReply = false;  
  if (Pack == 1) {
     // попытка отправить первый кадр команды - это критическая ошибка и отправка была заблокирована 
     FStatus = FStatus | B10000000; // установим восьмой бит ошибки
  }
  else if (this->send(
         Id,            // ID получателя
         Func,          // номер функции
         Pack,          // номер кадра в команде
         CountPack,     // всего кадров в команде
         F1,            // флаг ошибки
         F2,            // флаг ожидания
         F3,            // флаг повтора
         F4,            // флаг подтверждения
         SizeDate,      // размер дополнительных данных
         &(Data[0]))    // указатель на буфер дополнительных данных 
         == false) {    
     // попытка отправить слишком много данных - это критическая ошибка и отправка была заблокирована
     FStatus = FStatus | B10000000; // установим восьмой бит ошибки
  }
  else if (CountPack > Pack) {  
    // отправка прошла, устанавливаем параметры ожидания ответа
    Reply.OnReply = true;
    Reply.TimeOut = TimeOut;
    Reply.StartTime = StartTime;
    Reply.Id_Destination = this->Id_Unit;
    Reply.Id_Source = Id;
    Reply.Control_1 = (CountPack << 4) | Func;
    Reply.Control_2 = (Pack+1);
    Reply.Reply_OnStep = _userFunc;;
  }
}


//------------------------------------------------------------------
uint8_t BusRS485::Id (void)         { return Id_Unit; }
uint8_t BusRS485::Status (void)     { return FStatus; }
void BusRS485::SetEcho(uint8_t a)   { this->Echo = a; }

uint8_t BusRS485::Id_Destination () { return InPack.Id_Destination; }
uint8_t BusRS485::Id_Source ()      { return InPack.Id_Source; }
uint8_t BusRS485::SizeDate ()       { return InPack.SizeDate; }
uint8_t * BusRS485::Date ()         { return &(InPack.Data[0]); }

uint8_t BusRS485::NumFunc ()   { return (InPack.Control_1 & B00001111); }
uint8_t BusRS485::CountCadr () { return (InPack.Control_1 >> 4); }
uint8_t BusRS485::NumCadr ()   { return (InPack.Control_2 & B00001111); }
boolean BusRS485::FError ()    { return ((InPack.Control_2 >> 4) & B00000001); }
boolean BusRS485::FWait ()     { return ((InPack.Control_2 >> 5) & B00000001); }
boolean BusRS485::FRetry ()    { return ((InPack.Control_2 >> 6) & B00000001); }
boolean BusRS485::FValidate () { return (InPack.Control_2 >> 7); }

boolean BusRS485::OnReply (void)          { return Reply.OnReply; }
boolean BusRS485::OnReply (boolean value) { Reply.OnReply = value; return Reply.OnReply; }
uint8_t BusRS485::ReplyId (void)          { return Reply.Id_Source; }    
uint8_t BusRS485::ReplyNumFunc ()         { return (Reply.Control_1 & B00001111); }

int BusRS485::TimeOut (void)              { return Reply.TimeOut; }
unsigned long BusRS485::StartTime (void)  { return Reply.StartTime; }


void BusRS485::onRead() {
  port->flush();                        // ждем пока завершится отправка
  PORTD = PORTD & (B11111111 ^ MaskRW); // оба пина выключены
//  if ((CPinRx > 1)&&(CPinTx > 1)) { 
//    //    FStatus = FStatus ^ B11110111;
//    port->flush();
//    digitalWrite(CPinTx, LOW); // отправка выключена
//    digitalWrite(CPinRx, LOW); // получение включено (RE инверсный) 
//  }
} 

void BusRS485::onWrite() {
  port->flush();                        // ждем пока завершится предыдущая отправка, возможно было эхо
  PORTD = PORTD | MaskRW; // оба пина включены
//  if ((CPinRx > 1)&&(CPinTx > 1)) { 
//    //    FStatus = FStatus ^ B11110111;
//    port->flush();
//    digitalWrite(CPinRx, HIGH); // получение выключено (RE инверсный)
//    digitalWrite(CPinTx, HIGH); // отправка включена
//  }
} 

void BusRS485::off() {
//  if ((CPinRx > 1)&&(CPinTx > 1)) { 
//    //    FStatus = FStatus ^ B11110111;
//    digitalWrite(CPinRx, HIGH); // получение выключено (RE инверсный)
//    digitalWrite(CPinTx, LOW);  // отправка выключена
//    port->flush();
//  }
} 

uint8_t BusRS485::Read(){
  uint8_t a; 
  a = port->read();
  if (this->Echo == 1) { port->write(a); }
  return a; 
}

void BusRS485::poll() {
  uint8_t mCRC = 0;
  uint8_t i1 = 0;
  int ii;

  while (true) {
    // FInPack=0
    //    0-ждем заголовок 
    //    1-ждем дополнительные данные 
    //    2-пакет загружен валиден 
    //    3-пакет загружен, но не валиден
    
    if (FInPack > 3) {FInPack = 0;}  // не понятный флаг, значит будем ждать заголовок
    else if (FInPack == 2) {break;}  // пакет загружен и не обработан
    else if (FInPack == 3) {break;}  // пакет загружен и не валиден
    
    ii = port->available();
    if (ii == 0) { break; } // данных нет

    // вне зависимости от ожиданий пробуем выцепить заголовок
    if (port->peek() == MARK && ii >= 8){
      mCRC =  CRC(MARK, 0);
      mCRC =  CRC(port->peek(1), mCRC);
      mCRC =  CRC(port->peek(2), mCRC);
      mCRC =  CRC(port->peek(3), mCRC);
      mCRC =  CRC(port->peek(4), mCRC);
      mCRC =  CRC(port->peek(5), mCRC);
      mCRC =  CRC(port->peek(6), mCRC);
      if (mCRC == port->peek(7)) {  // да это заголовок пакета,
        InPack.Mark           = Read();
        InPack.Id_Destination = Read();
        InPack.Id_Source      = Read();
        InPack.Control_1      = Read();
        InPack.Control_2      = Read(); 
        InPack.SizeDate       = Read(); 
        InPack.CRC_Data       = Read(); 
        InPack.CRC_Head       = Read(); 
        
        if (InPack.SizeDate == 0) {              // пакет не содержит дополнительных данных, только номер и команду          
          FInPack = 2;
        }
        else if (InPack.SizeDate <= MAX_BUFFER){ // заголовок загружен, нужно пытатся загрузить данные          
          FInPack = 1; continue;
        }
        else {                                   // мы не можем обработать такой большой пакет          
          FInPack = 3;
        }
        break;
      }
      else if (FInPack == 0) {      // ждали заголовок а CRC не совпало
        Read();
        continue;        
      }
    }

    if (FInPack == 0) {   // ждем заголовка, а маркера нет
      if (port->peek() != MARK) {
        Read();
        continue; 
      } 
    }

//--------------------------------------------------------------------------
    if (FInPack == 1 && ii >= InPack.SizeDate) { 
      // Загрузим доп данные вне зависимости от CRC
      for (int i1=0; i1 < InPack.SizeDate; i1++){ InPack.Data[i1] = Read(); } 
      //теперь проверим валидность
      mCRC = 0;
      for (int i1=0; i1 < InPack.SizeDate; i1++){ mCRC = CRC(InPack.Data[i1], mCRC); } 
      if (mCRC == InPack.CRC_Data) { FInPack = 2; }   // это правильные дополнительные данные
      else                         { FInPack = 3; }   // контроль доп данных не сошелся весь пакет выкенем
    }
    break;
  } // ---- while ------
  
  if (FInPack == 2) { 
    if (Id_Unit == InPack.Id_Source) {
      // мы видим входящий пакет от устройства с нашим ID, это ошибка, в сети 2 устройства с одним ID
      FStatus = FStatus | B00000101;
      Id_Unit = 241;    
      Reply.OnReply = false;
    }
    else if (Id_Unit == 0) {
      // это мастер, на нем обрабатываем только пакеты которые мы ожидаем
      // неожиданно пришедшие пакеты пришедшие на мастер пропускаем

      if (   Reply.OnReply 
          && Reply.Id_Destination == InPack.Id_Destination
          && Reply.Id_Source == InPack.Id_Source
          && Reply.Control_1 == InPack.Control_1
          && Reply.Control_2 == (InPack.Control_2 & B00001111)
          ) {
            
       // запускаем подключеную обработку ответа   
       Reply.OnReply = false;
       Reply.Reply_OnStep();    
      }
    }  
    else {
      // это слейв, на нем обрабатываем 
      // 1. ожидаемые ответы
      // 2. широковещательные пакеты
      // 3. новые пакеты от мастера
      if (   Reply.OnReply 
          && Reply.Id_Destination == InPack.Id_Destination
          && Reply.Id_Source == InPack.Id_Source
          && Reply.Control_1 == InPack.Control_1
          && Reply.Control_2 == (InPack.Control_2 & B00001111)
          ) {
        // это ожидаемый пакет    
        // запускаем подключеную обработку           
       Reply.OnReply = false;
       Reply.Reply_OnStep();    
      } 
      // кроме ожидаемых ответов на слейве отрабатываем вариант прихода новой команы
      else if (InPack.Id_Destination == 255) {
        // это широковещательный пакет   
        Reply.OnReply = false;
        OnSlave();
      }
      else if (InPack.Id_Destination == Id_Unit
            && InPack.Id_Source == 0) {
        // это новый пакет от мастера      
        Reply.OnReply = false;
        OnSlave();
      }  
    }
    FInPack = 0;
  }  
  
  if (FInPack > 1) { FInPack = 0; } 
}


// ------------------PRIVATE FUNCTIONS------------------------------

boolean BusRS485::send(uint8_t Id,         // ID получателя
                       uint8_t Func,       // номер функции
                       uint8_t Pack,       // номер кадра в команде
                       uint8_t CountPack,  // всего кадров в команде
                       boolean F1,         // флаг ошибки
                       boolean F2,         // флаг ожидания
                       boolean F3,         // флаг повтора
                       boolean F4,         // флаг подтверждения
                       uint8_t SizeDate,   // размер дополнительных данных
                       uint8_t *Data) {    // указатель на буфер дополнительных данных 

  if (MAX_BUFFER >= SizeDate) {   // посылаем только если доп данные влезут в буфер
  
    uint8_t CRC_Data = 0;         // CRC дополнительных данных пакета
    uint8_t CRC_Head = 0;         // CRC заголовка, служит для определения корректности заголовка и выделения кадра из потока данных
    uint8_t a = (CountPack << 4) | Func;       
    uint8_t b = (F1 << 7) | (F2 << 6) | (F3 << 5) | (F4 << 4) | Pack;       
    
    for (int i=0; i < SizeDate; i++){ 
      CRC_Data = CRC(Data[i], CRC_Data);
    } 
  
    CRC_Head = CRC(CRC_Head, MARK);
    CRC_Head = CRC(CRC_Head, Id);
    CRC_Head = CRC(CRC_Head, Id_Unit);
    CRC_Head = CRC(CRC_Head, a);
    CRC_Head = CRC(CRC_Head, b);
    CRC_Head = CRC(CRC_Head, SizeDate);
    CRC_Head = CRC(CRC_Head, CRC_Data);

    onWrite();
    // перед отправкой выдержем паузу для того, что-бы остальные успелись переключится в режим приема
    delayMicroseconds(PauseWrite); 
    
    port->write(MARK);
    port->write(Id);
    port->write(Id_Unit);
    port->write(a);
    port->write(b);
    port->write(SizeDate);
    port->write(CRC_Data);
    port->write(CRC_Head);
    
    for (int i=0; i < SizeDate; i++){ 
      port->write(Data[i]);
    } 
    onRead(); 
    return true;
  } 
  else {
    return false;
  }
}

// ---------------------------------------------
// функция делает XOR и после циклический сдвиг
uint8_t BusRS485::CRC(uint8_t a, uint8_t b) {
  uint8_t c;
  c = a ^ b;
  return (c << 1) | (c >> 7);
}

и нужен небольшой патч IDE

"hardware\arduino\avr\cores\arduino\HardwareSerial.h"
"hardware\arduino\avr\cores\arduino\HardwareSerial.cpp"
 

/*
  HardwareSerial.cpp - Hardware serial library for Wiring
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  
  Modified 23 November 2006 by David A. Mellis
  Modified 28 September 2010 by Mark Sproul
  Modified 14 August 2012 by Alarus
  Modified 3 December 2013 by Matthijs Kooijman
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"

#include "HardwareSerial.h"
#include "HardwareSerial_private.h"

// this next line disables the entire HardwareSerial.cpp, 
// this is so I can support Attiny series and any other chip without a uart
#if defined(HAVE_HWSERIAL0) || defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3)

// SerialEvent functions are weak, so when the user doesn't define them,
// the linker just sets their address to 0 (which is checked below).
// The Serialx_available is just a wrapper around Serialx.available(),
// but we can refer to it weakly so we don't pull in the entire
// HardwareSerial instance if the user doesn't also refer to it.
#if defined(HAVE_HWSERIAL0)
  void serialEvent() __attribute__((weak));
  bool Serial0_available() __attribute__((weak));
#endif

#if defined(HAVE_HWSERIAL1)
  void serialEvent1() __attribute__((weak));
  bool Serial1_available() __attribute__((weak));
#endif

#if defined(HAVE_HWSERIAL2)
  void serialEvent2() __attribute__((weak));
  bool Serial2_available() __attribute__((weak));
#endif

#if defined(HAVE_HWSERIAL3)
  void serialEvent3() __attribute__((weak));
  bool Serial3_available() __attribute__((weak));
#endif

void serialEventRun(void)
{
#if defined(HAVE_HWSERIAL0)
  if (Serial0_available && serialEvent && Serial0_available()) serialEvent();
#endif
#if defined(HAVE_HWSERIAL1)
  if (Serial1_available && serialEvent1 && Serial1_available()) serialEvent1();
#endif
#if defined(HAVE_HWSERIAL2)
  if (Serial2_available && serialEvent2 && Serial2_available()) serialEvent2();
#endif
#if defined(HAVE_HWSERIAL3)
  if (Serial3_available && serialEvent3 && Serial3_available()) serialEvent3();
#endif
}


// Actual interrupt handlers //////////////////////////////////////////////////////////////

void HardwareSerial::_tx_udr_empty_irq(void)
{
  // If interrupts are enabled, there must be more data in the output
  // buffer. Send the next byte
  unsigned char c = _tx_buffer[_tx_buffer_tail];
  _tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_TX_BUFFER_SIZE;

  *_udr = c;

  // clear the TXC bit -- "can be cleared by writing a one to its bit
  // location". This makes sure flush() won't return until the bytes
  // actually got written
  sbi(*_ucsra, TXC0);

  if (_tx_buffer_head == _tx_buffer_tail) {
    // Buffer empty, so disable interrupts
    cbi(*_ucsrb, UDRIE0);
  }
}

// Public Methods //////////////////////////////////////////////////////////////

void HardwareSerial::begin(unsigned long baud, byte config)
{
  // Try u2x mode first
  uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2;
  *_ucsra = 1 << U2X0;

  // hardcoded exception for 57600 for compatibility with the bootloader
  // shipped with the Duemilanove and previous boards and the firmware
  // on the 8U2 on the Uno and Mega 2560. Also, The baud_setting cannot
  // be > 4095, so switch back to non-u2x mode if the baud rate is too
  // low.
  if (((F_CPU == 16000000UL) && (baud == 57600)) || (baud_setting >4095))
  {
    *_ucsra = 0;
    baud_setting = (F_CPU / 8 / baud - 1) / 2;
  }

  // assign the baud_setting, a.k.a. ubrr (USART Baud Rate Register)
  *_ubrrh = baud_setting >> 8;
  *_ubrrl = baud_setting;

  _written = false;

  //set the data bits, parity, and stop bits
#if defined(__AVR_ATmega8__)
  config |= 0x80; // select UCSRC register (shared with UBRRH)
#endif
  *_ucsrc = config;
  
  sbi(*_ucsrb, RXEN0);
  sbi(*_ucsrb, TXEN0);
  sbi(*_ucsrb, RXCIE0);
  cbi(*_ucsrb, UDRIE0);
}

void HardwareSerial::end()
{
  // wait for transmission of outgoing data
  flush();

  cbi(*_ucsrb, RXEN0);
  cbi(*_ucsrb, TXEN0);
  cbi(*_ucsrb, RXCIE0);
  cbi(*_ucsrb, UDRIE0);
  
  // clear any received data
  _rx_buffer_head = _rx_buffer_tail;
}

int HardwareSerial::available(void)
{
  return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
}

int HardwareSerial::peek(void)
{
  if (_rx_buffer_head == _rx_buffer_tail) {
    return -1;
  } else {
    return _rx_buffer[_rx_buffer_tail];
  }
}

// ------------------------------------------------------------
// расширение синтаксиса команды Serial.peek()
// 

int HardwareSerial::peek(uint8_t c) // надстройка для BusRS485
{
  int i = this->available();
  // проверяем, что индекс в рабочем диапазоне
  if (c < i) {
    return _rx_buffer[(SERIAL_RX_BUFFER_SIZE + c + _rx_buffer_tail) % SERIAL_RX_BUFFER_SIZE];
  } else {
    return -1;
  }
}

// 
// автор vde69@mail.ru (с)
// ------------------------------------------------------------


int HardwareSerial::read(void)
{
  // if the head isn't ahead of the tail, we don't have any characters
  if (_rx_buffer_head == _rx_buffer_tail) {
    return -1;
  } else {
    unsigned char c = _rx_buffer[_rx_buffer_tail];
    _rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
    return c;
  }
}

int HardwareSerial::availableForWrite(void)
{
#if (SERIAL_TX_BUFFER_SIZE>256)
  uint8_t oldSREG = SREG;
  cli();
#endif
  tx_buffer_index_t head = _tx_buffer_head;
  tx_buffer_index_t tail = _tx_buffer_tail;
#if (SERIAL_TX_BUFFER_SIZE>256)
  SREG = oldSREG;
#endif
  if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail;
  return tail - head - 1;
}

void HardwareSerial::flush()
{
  // If we have never written a byte, no need to flush. This special
  // case is needed since there is no way to force the TXC (transmit
  // complete) bit to 1 during initialization
  if (!_written)
    return;

  while (bit_is_set(*_ucsrb, UDRIE0) || bit_is_clear(*_ucsra, TXC0)) {
    if (bit_is_clear(SREG, SREG_I) && bit_is_set(*_ucsrb, UDRIE0))
 // Interrupts are globally disabled, but the DR empty
 // interrupt should be enabled, so poll the DR empty flag to
 // prevent deadlock
 if (bit_is_set(*_ucsra, UDRE0))
   _tx_udr_empty_irq();
  }
  // If we get here, nothing is queued anymore (DRIE is disabled) and
  // the hardware finished tranmission (TXC is set).
}

size_t HardwareSerial::write(uint8_t c)
{
  _written = true;
  // If the buffer and the data register is empty, just write the byte
  // to the data register and be done. This shortcut helps
  // significantly improve the effective datarate at high (>
  // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
  if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) {
    *_udr = c;
    sbi(*_ucsra, TXC0);
    return 1;
  }
  tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE;
 
  // If the output buffer is full, there's nothing for it other than to 
  // wait for the interrupt handler to empty it a bit
  while (i == _tx_buffer_tail) {
    if (bit_is_clear(SREG, SREG_I)) {
      // Interrupts are disabled, so we'll have to poll the data
      // register empty flag ourselves. If it is set, pretend an
      // interrupt has happened and call the handler to free up
      // space for us.
      if(bit_is_set(*_ucsra, UDRE0))
 _tx_udr_empty_irq();
    } else {
      // nop, the interrupt handler will free up space for us
    }
  }

  _tx_buffer[_tx_buffer_head] = c;
  _tx_buffer_head = i;
 
  sbi(*_ucsrb, UDRIE0);
  
  return 1;
}

#endif // whole file

и

/*
  HardwareSerial.h - Hardware serial library for Wiring
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  Modified 28 September 2010 by Mark Sproul
  Modified 14 August 2012 by Alarus
  Modified 3 December 2013 by Matthijs Kooijman
*/

#ifndef HardwareSerial_h
#define HardwareSerial_h

#include <inttypes.h>

#include "Stream.h"

// Define constants and variables for buffering incoming serial data.  We're
// using a ring buffer (I think), in which head is the index of the location
// to which to write the next incoming character and tail is the index of the
// location from which to read.
// NOTE: a "power of 2" buffer size is reccomended to dramatically
//       optimize all the modulo operations for ring buffers.
// WARNING: When buffer sizes are increased to > 256, the buffer index
// variables are automatically increased in size, but the extra
// atomicity guards needed for that are not implemented. This will
// often work, but occasionally a race condition can occur that makes
// Serial behave erratically. See https://github.com/arduino/Arduino/issues/2405
#if !defined(SERIAL_TX_BUFFER_SIZE)
#if ((RAMEND - RAMSTART) < 1023)
#define SERIAL_TX_BUFFER_SIZE 16
#else
#define SERIAL_TX_BUFFER_SIZE 64
#endif
#endif
#if !defined(SERIAL_RX_BUFFER_SIZE)
#if ((RAMEND - RAMSTART) < 1023)
#define SERIAL_RX_BUFFER_SIZE 16
#else
#define SERIAL_RX_BUFFER_SIZE 64
#endif
#endif
#if (SERIAL_TX_BUFFER_SIZE>256)
typedef uint16_t tx_buffer_index_t;
#else
typedef uint8_t tx_buffer_index_t;
#endif
#if  (SERIAL_RX_BUFFER_SIZE>256)
typedef uint16_t rx_buffer_index_t;
#else
typedef uint8_t rx_buffer_index_t;
#endif

// Define config for Serial.begin(baud, config);
#define SERIAL_5N1 0x00
#define SERIAL_6N1 0x02
#define SERIAL_7N1 0x04
#define SERIAL_8N1 0x06
#define SERIAL_5N2 0x08
#define SERIAL_6N2 0x0A
#define SERIAL_7N2 0x0C
#define SERIAL_8N2 0x0E
#define SERIAL_5E1 0x20
#define SERIAL_6E1 0x22
#define SERIAL_7E1 0x24
#define SERIAL_8E1 0x26
#define SERIAL_5E2 0x28
#define SERIAL_6E2 0x2A
#define SERIAL_7E2 0x2C
#define SERIAL_8E2 0x2E
#define SERIAL_5O1 0x30
#define SERIAL_6O1 0x32
#define SERIAL_7O1 0x34
#define SERIAL_8O1 0x36
#define SERIAL_5O2 0x38
#define SERIAL_6O2 0x3A
#define SERIAL_7O2 0x3C
#define SERIAL_8O2 0x3E

class HardwareSerial : public Stream
{
  protected:
    volatile uint8_t * const _ubrrh;
    volatile uint8_t * const _ubrrl;
    volatile uint8_t * const _ucsra;
    volatile uint8_t * const _ucsrb;
    volatile uint8_t * const _ucsrc;
    volatile uint8_t * const _udr;
    // Has any byte been written to the UART since begin()
    bool _written;

    volatile rx_buffer_index_t _rx_buffer_head;
    volatile rx_buffer_index_t _rx_buffer_tail;
    volatile tx_buffer_index_t _tx_buffer_head;
    volatile tx_buffer_index_t _tx_buffer_tail;

    // Don't put any members after these buffers, since only the first
    // 32 bytes of this struct can be accessed quickly using the ldd
    // instruction.
    unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE];
    unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE];

  public:
    inline HardwareSerial(
      volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
      volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
      volatile uint8_t *ucsrc, volatile uint8_t *udr);
    void begin(unsigned long baud) { begin(baud, SERIAL_8N1); }
    void begin(unsigned long, uint8_t);
    void end();
    virtual int available(void);
    virtual int peek(void);
    virtual int read(void);

    // ------------------------------------------------------------
    // расширение синтаксиса команды Serial.peek()
    // 

    virtual int peek(uint8_t);

    // 
    // автор vde69@mail.ru (с)
    // ------------------------------------------------------------

    int availableForWrite(void);
    virtual void flush(void);
    virtual size_t write(uint8_t);
    inline size_t write(unsigned long n) { return write((uint8_t)n); }
    inline size_t write(long n) { return write((uint8_t)n); }
    inline size_t write(unsigned int n) { return write((uint8_t)n); }
    inline size_t write(int n) { return write((uint8_t)n); }
    using Print::write; // pull in write(str) and write(buf, size) from Print
    operator bool() { return true; }

    // Interrupt handlers - Not intended to be called externally
    inline void _rx_complete_irq(void);
    void _tx_udr_empty_irq(void);

};

#if defined(UBRRH) || defined(UBRR0H)
  extern HardwareSerial Serial;
  #define HAVE_HWSERIAL0
#endif
#if defined(UBRR1H)
  extern HardwareSerial Serial1;
  #define HAVE_HWSERIAL1
#endif
#if defined(UBRR2H)
  extern HardwareSerial Serial2;
  #define HAVE_HWSERIAL2
#endif
#if defined(UBRR3H)
  extern HardwareSerial Serial3;
  #define HAVE_HWSERIAL3
#endif

extern void serialEventRun(void) __attribute__((weak));

#endif

 

vde69
Offline
Зарегистрирован: 10.01.2016

кстати вот тут думаю, чего лучше патч IDE или сделать свой класс наследник?

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

но и другой вариант то-же плох

M a x
Offline
Зарегистрирован: 20.06.2016

vde69 пишет:

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

Проблема в том, что РАБОТАЕТ на разных скоростях и НЕ РАБОТАЕТ на одинаковых

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

M a x пишет:

Проблема в том, что РАБОТАЕТ на разных скоростях и НЕ РАБОТАЕТ на одинаковых

Ну тогда либо кварцы разные и одна не на 16 мегагерц, а на 8, либо - что-то не так в консерватории. Чудес не бывает, надо смотреть весь код, как минимум. Это если принимать описанное вами поведение на веру.

M a x
Offline
Зарегистрирован: 20.06.2016

Это первое, что пришло в голову. Посмотрел - по маркировке обе 16 Мгц. Я это написал в первом посте. Код большой, куски, которые отправляют и принимают я написал. Больше ничего не отправляется, кроме таких и подобных кусков.

Нано вот такая - https://arduinobazar.ru/home/152-dccduino-nano-arduino-nano-r3-sovmestimaya-kupit-arduino-moskva-peterburg-dyoshevo.html

Про мини - вот такая - https://arduinobazar.ru/platy-arduino/2-arduino-pro-mini-16mhz-5v-atmega328-kupit-arduino-moskva-peterburg-dyoshevo.html

Есть пример скетча, как мегагерцы просто померять?

vde69
Offline
Зарегистрирован: 10.01.2016

терминал на компе пробовал подключать и туда и туда на одной скорости?

M a x
Offline
Зарегистрирован: 20.06.2016

vde69 пишет:

терминал на компе пробовал подключать и туда и туда на одной скорости?

да. Но само-собой подключал только к передающей - скорость совпадает. 

Неужели, подсунули 8 Мгц вместо 16-ти? Просто у продавца есть 8 Мгц версия, но она 3,3В, а эта 5В

vde69
Offline
Зарегистрирован: 10.01.2016

M a x пишет:

vde69 пишет:

терминал на компе пробовал подключать и туда и туда на одной скорости?

да. Но само-собой подключал только к передающей - скорость совпадает. 

Неужели, подсунули 8 Мгц вместо 16-ти? Просто у продавца есть 8 Мгц версия, но она 3,3В, а эта 5В

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

M a x
Offline
Зарегистрирован: 20.06.2016

это как? Типа в одну ЮСБ от одной и в другую - от другой?

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

M a x пишет:

Неужели, подсунули 8 Мгц вместо 16-ти? Просто у продавца есть 8 Мгц версия, но она 3,3В, а эта 5В

На кварце что написано?

Залей в обе ардуины какой-нибудь одинаковый простенький скетч на передачу данных по UART. Сначала подключи одну ардуину к компу, проверь скорость. Потом подключи другую и тоже поверь скорость.

M a x
Offline
Зарегистрирован: 20.06.2016
void setup() {
  Serial.begin (9600);
}
 
void loop() {
  Serial.println (millis ());
  delay (100);
}
 
на nano работает на 9600, на pro mini - 4800. Какие выводы можно сделать?
прошиваю то я ее как pro mini 16 Mhz, 5V
 
и в оригинальной программе, где у меня проблемы, ставлю 9600 на nano и 19200 
 
update.
Продолжил эксперименты. Вообще теперь ничего не понимаю. Прошил ее, как 3.3В 8 Мгц - стало работать на 9600....
Питание с программатора в обоих случаях было 5В и на выходе VCC у pro mini тоже 5В
 
Что написано на кварце разглядеть не могу :(
vde69
Offline
Зарегистрирован: 10.01.2016

M a x пишет:

это как? Типа в одну ЮСБ от одной и в другую - от другой?

берешь ДВА USB кабеля и каждую подключаешь к компу, у тебя будет 2 разных COM порта, терминалы подключаешь к этим ком портам и слушаешь чего они между собой шпарят

M a x
Offline
Зарегистрирован: 20.06.2016

все заработало, помогавшим - спасибо!

теперь другая проблема. передаю 5 байт на скорости 38400, принимаю 5 байт на той же скорости. иногда (не часто), что-то теряется. 

вопрос 1 - почему?, вопрос 2 - как добиться "железной 100%" передачи?

Код передачи

void sendToLED (byte s1, byte s2, byte s3, char s4, char s5) {
  Serial.write (s1);
  Serial.write (s2);
  Serial.write (s3);
  Serial.write (s4);
  Serial.write (s5);
 delay (150); // с 100  работало более-менее, c 150 стало лучше, но все-равно не доходят байты иногда
if (Serial.available() > 0) {
byte bytesSentToLED = Serial.read ();
lcd.print (bytesSentToLED);
}
else lcd.print ("-");
}

Код приема

  num1 = proSerial.available();
  if (num1 > 0)
  {
    delay (100);
    switch (num1) {
      case 1:
        num = proSerial.read ();
        spd = 0;
        spdD = 0;
        symb1 = 0;
        symb2 = 0;
        //       Serial.flush();
        break;
      case 2:
        num = proSerial.read ();
        spd = proSerial.read ();
        spdD = 0;
        symb1 = 0;
        symb2 = 0;
        //       Serial.flush();
        break;
      case 3:
        num = proSerial.read ();
        spd = proSerial.read ();
        spdD = proSerial.read ();
        symb1 = 0;
        symb2 = 0;
        //        Serial.flush();
        break;
      case 4:
        num = proSerial.read ();
        spd = proSerial.read ();
        spdD = proSerial.read ();
        symb1 = proSerial.read ();
        symb1 = 0;
        //        Serial.flush();
        break;
      case 5:
        num = proSerial.read ();
        spd = proSerial.read ();
        spdD = proSerial.read ();
        symb1 = proSerial.read ();
        symb2 = proSerial.read ();
        //        Serial.flush();
        break;
      default:
        //       Serial.flush();
        break;
    }

    proSerial.write (num1); // отправка обратно, сколько байт приняли
  }