Очередной "Умный дом", на этот раз модульная система...

MaksVV
Offline
Зарегистрирован: 06.08.2015

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

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

MaksVV
Offline
Зарегистрирован: 06.08.2015

и чёто капец у тебя сложно как-то всё , запутаться можно  - из одной функции в другую функцию и т.д. Попроще можно всё и другим понятнее будет. 

Например это: 

riv пишет:

// Задаем перечисления и структуры для типов сообщений Y
typedef enum Message_enum
{
    NULL_C,                //0
    COMMAND_SEND,          //1
    COMMAND_ANSVER,        //2
    REQUEST_SEND,          //3 
    REQUEST_ANSVER,        //4
    STATUS_REQUEST_SEND,   //5
    STATUS_REQUEST_ANSVER  //6
                   
} Message_CAN_ENUM;               

typedef struct {
    uint8_t          msg_num;
    String           msg_name;
}Message_CANvalueData;

const Message_CANvalueData Message_CANData[] =
{
        /*Key        KeyName */
        { 0 ,    "NULL_C"},
        { 1 ,    "COMMAND SEND"},
        { 2 ,    "COMMAND_ANSVER"},  
        { 3 ,    "REQUEST_SEND"},
        { 4 ,    "REQUEST_ANSVER"},
        { 5 ,    "STATUS_REQUEST_SEND"},
        { 6 ,    "STATUS_REQUEST_ANSVER"}

};

Может так проще сделать? :

#define NULL_C                0
#define COMMAND_SEND          1
#define COMMAND_ANSVER        2
#define REQUEST_SEND          3 
#define REQUEST_ANSVER        4
#define STATUS_REQUEST_SEND   5
#define STATUS_REQUEST_ANSVER 6

 

 

riv
Offline
Зарегистрирован: 20.07.2017

А можно переменные объявленные  в #define использовать в case?

И второй вопрос у меня в коде объявлены 3 структуры тип команд, адрес и тип устройства. И 1 в разных структурах имеет разное значение.

Причем enum мне нужен для кодирования сообщения из переменных в байты, а struct для декодирования.

И к тому же я структуры и перечисления вынесу в общий код для всех контроллеров.

Насчет функций. Я из естественно опптимизирую, но без них никуда. Это типовые действия. Причем Decode я естественно в RX запихну (сейчас просто удобнее) , а вот Code и ТХ точно нужно разделять.

 

Я пока набрасываю структуру программы, общий алгоритм.

Это мы еще в классы и прерывания по таймеру и аппаратные не полезли ;) Все же протокол свой пишем.

MaksVV
Offline
Зарегистрирован: 06.08.2015

ну у меня совсем другой уровень программирования. Я в этих структурах , перечислениях и typedef ах не разбираюсь пока. А #define это не переменные получаются, а как бы указания компилятору что вместо одного подставить другое.

Например 

#define  COMMAND_SEND 1

в коде везде, где напишешь COMMAND_SEND компилятор подставит 1. Поэтому в case работать будет. 

Заметь, точка с запятой не ставится при этом. И ещё, директива #define не занимает оперативную память. 

MaksVV
Offline
Зарегистрирован: 06.08.2015

riv пишет:
Причем enum мне нужен для кодирования сообщения из переменных в байты, а struct для декодирования.

а  что байты это не переменные ? какого ещё кодирования и декодирования, я не пойму если чесно.

При получении мессаги из CAN прилетели байты, приравниваешь нужные тебе переменные соответствующим байтам. 

Наоборот, при отправке приравниваешь байты библиотеки CAN своим соответсвтующим переменным. 

 

 

riv
Offline
Зарегистрирован: 20.07.2017

Мой уровень программирования тоже не велик.  А что делать.

У меня 21 узел в сети, на структуре видно кол-во датчиков. Мне проще написать вместо адреса Hallway_net_center вместо его номера 6.

Это как DNS в интернете. 

Вот что умные люди пишут

define - текстовая замена препроцессором и для компилятора это уже просто циферки - 0,1,2 , а enum - это тип, соответственно получаем лучший контроль со стороны компилятора над ошибками, возможность вывода дополнительных предупреждений(например, если в switch указаны не все константы из enum-типа) и пр.

Вот сейчас изучаю http://robotosha.ru/arduino/multi-tasking-arduino.html

Нужно решить задачу с многозадачностью для этого отказываемя от delay используя вместо него millis (), так же нужны прерывания по таймеру 

https://habrahabr.ru/post/337430/ 

http://mypractic.ru/urok-10-preryvanie-po-tajmeru-v-arduino-biblioteka-mstimer2-parallelnye-processy.html

и по событиям  

http://arduino.ru/Reference/AttachInterrupt

http://robocraft.ru/blog/arduino/45.html

Без них сеть не построить. Мы же CAN ради почти реального времени используем.

MaksVV
Offline
Зарегистрирован: 06.08.2015

riv пишет:

Вот что умные люди пишут

define - текстовая замена препроцессором и для компилятора это уже просто циферки - 0,1,2 , а enum - это тип, соответственно получаем лучший контроль со стороны компилятора над ошибками, возможность вывода дополнительных предупреждений(например, если в switch указаны не все константы из enum-типа) и пр.

ну напиши тогда

const uint8_t COMMAND_SEND = 1;

 

riv
Offline
Зарегистрирован: 20.07.2017

Если я буду использовать define я могу забыть количество переменных и их не обработать в case. В общем объявление переменных можно делать поразному кому как удобнее.

И структура с декодированием не нужна только для отладки, чтобы видеть что получаю в виде текста. Потом останутся только ENUM, структуры и декодирование уберу.

Будет так

switch (direction) {
    case 0: //выполняется, когда RX Reqv т.е у меня что то запрашивают
      
      break;
    case 1: //выполняется когда RX Ansv т.е мне отвечают на мой запрос
    
      break;
    default:
    
      // выполняется, если не выбрана ни одна альтернатива
      // default необязателен
  }
MaksVV
Offline
Зарегистрирован: 06.08.2015

const uint8_t NULL_C                = 0;
const uint8_t COMMAND_SEND          = 1;
const uint8_t COMMAND_ANSVER        = 2;
const uint8_t REQUEST_SEND          = 3;
const uint8_t REQUEST_ANSVER        = 4;
const uint8_t STATUS_REQUEST_SEND   = 5;
const uint8_t STATUS_REQUEST_ANSVER = 6;

const uint8_t  center_node =   11;
const uint8_t  kitchen_node =  22;
const uint8_t  bathroom_node = 33;
const uint8_t  officeroom_node = 44;
const uint8_t  bedroom_node = 55;


void RX()
{
  uint8_t direction, msg_type, dev_addr, rem_addr, dev_type;
 
  if(!digitalRead(CAN0_INT))                         // 
  {
    CAN0.readMsgBuf(&rxId_can, &len_can, rxBuf_can);      // Read data: len = data length, buf = data byte(s)

    direction  = (rxId_can & 0x10000000)>>28; //  извлекаем 1-битный идентификатор запроса-ответа из ID
    msg_type = (rxId_can &   0xF000000)>>24;  //  извлекаем 4-битный идентификатор сообщения из ID  
    dev_addr  = (rxId_can &  0xFF0000)>>16;   //  извлекаем 8-битный адрес отправителя из ID
    rem_addr = (rxId_can &   0xFF00)>>8;      //  извлекаем 8-битный адрес получателя из ID
    dev_type = (rxId_can &   0xFF);           //  извлекаем 8-битный тип устройства у получателя из ID

Serial.print(F(" type_msg - "));
     if (msg_type == COMMAND_SEND)   Serial.print(F("COMMAND_SEND")); //макрос F записывает строковую константу не в оперативу, а на флеш
else if (msg_type == COMMAND_ANSVER) Serial.print(F("COMMAND_ANSVER"));
else if (msg_type == REQUEST_SEND)   Serial.print(F("REQUEST_SEND"));
else if (msg_type == REQUEST_ANSVER) Serial.print(F("REQUEST_ANSVER"));
else if (msg_type == STATUS_REQUEST_SEND) Serial.print(F("STATUS_REQUEST_SEND"));
else if (msg_type == STATUS_REQUEST_ANSVER) Serial.print(F("STATUS_REQUEST_ANSVER"));

Serial.print(F(" node_addr - "));

      if (dev_addr == center_node)     Serial.print(F("center_node"));
 else if (dev_addr == kitchen_node)    Serial.print(F("kitchen_node"));
 else if (dev_addr == bathroom_node)   Serial.print(F("bathroom_node"));
 else if (dev_addr == officeroom_node) Serial.print(F("officeroom_node"));
 else if (dev_addr == bedroom_node)    Serial.print(F("bedroom_node"));

 // и так далее в общем. Таким образом ты не кладёшь все String-и в оперативу,  и опять же экономишщ память и функций меньше
   
  }
} 

riv
Offline
Зарегистрирован: 20.07.2017

При увеличении кол-ва обрабатываемых параметров у нас получится увеличение строк кода в геометрической прогрессии

Вот это я должен вложить во внутрь первого


switch (msg_type){
    case COMMAND_SEND: //выполняется, когда мне прислали команду от удаленного контроллера
      
      break;
    case COMMAND_ANSVER: //выполняется когда удаленный контроллер отвечают на посланную команду
    
      break;
    case REQUEST_SEND: //выполняется когда удаленный контроллер у меня запросил параметр датчика или еще чего то
    
      break;
    case REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос параметра датчика
    
      break;
    case STATUS_REQUEST_SEND: //выполняется когда удаленный контроллер у меня запрашивает состояние
    
      break;
    case STATUS_REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос состояния 
    
      break;
    default:
    //если параметр за пределами ENUM
    }
а дальше в него вложить адреса
а потом типы датчиков
 
CASE это практически и есть IF ELSE
 
Только посмотри где наглядней код, вот тоже что и у меня только на IF
if (msg_type=1)
{
}
else if (msg_type=2)
{
}
else if (msg_type=3)
{
}
else if (msg_type=4)
{
}
else if (msg_type=5)
{
}
else if (msg_type=6)
{
}

+ из Case выходишь сразу а IF полный перебор.

 
MaksVV
Offline
Зарегистрирован: 06.08.2015

riv пишет:
При увеличении кол-ва обрабатываемых параметров у нас получится увеличение строк кода в геометрической прогрессии

дак эти параметры всё равно где-то придётся писать -  не в Rx() дак в труктурах твоих. А вместо IF пожалуйства применяй swith какие проблемы. Просто IF лично мне удобнее и вот так вообщето 

if (msg_type == COMMAND_SEND)             {выполняется, когда мне прислали команду от удаленного контроллера
}
else if (msg_type == COMMAND_ANSVER) {выполняется когда удаленный контроллер отвечают на посланную команду}
else if (msg_type == REQUEST_SEND)        {выполняется когда удаленный контроллер у меня запросил параметр датчика или еще чего то}
else if (msg_type == REQUEST_ANSVER)   {выполняется когда удаленный контроллер мне отвечают на мой запрос параметра датчика}
else if (msg_type == STATUS_REQUEST_SEND) {выполняется когда удаленный контроллер у меня запрашивает состояние}
else if (msg_type == STATUS_REQUEST_ANSVER) {выполняется когда удаленный контроллер мне отвечают на мой запрос состояния}
else {выполняется когда параметр за пределами}

 

riv
Offline
Зарегистрирован: 20.07.2017

Так и получается что вместо define я использую enum, вместо if использую case. И еще функции и процедуры.

Вот смотри что получилось. Глубже только функции иначе код перестанет читаться вообще.


switch (direction) {
    case 0: //выполняется, когда RX Reqv т.е у меня что то запрашивают
      switch (msg_type){
              case COMMAND_SEND: //выполняется, когда мне прислали команду от удаленного контроллера
              // Функция обработки присланой команды от удаленного контроллера
              break;
              case REQUEST_SEND: //выполняется когда удаленный контроллер у меня запросил параметр датчика или еще чего то
              // Функция обработки присланного запроса параметра с датчика
              break;
              case STATUS_REQUEST_SEND: //выполняется когда удаленный контроллер у меня запрашивает состояние
              // Функция обработки запроса моего состояния
              break;
              default:
              //если параметр за пределами ENUM
              Serial.print(" Default msg - Recive Uncnown type message");
             }    
    break;
    case 1: //выполняется когда RX Ansv т.е мне отвечают на мой запрос
      switch (msg_type){
              case COMMAND_ANSVER: //выполняется когда удаленный контроллер отвечает на посланную команду
              // Функция обработки ответа на мою команду
              break;
              case REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос параметра датчика
              // Функция обработки ответа на мой запрос параметра датчика   
              break;
              case STATUS_REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос состояния 
              // Функция обработки ответа на мой запрос состояния УК     
              break;  
              default:
              //если параметр за пределами ENUM
              Serial.print(" Default msg - Recive Uncnown type message");       
              }
    break;
    default:
    Serial.print(" Default direct ");
    //если параметр за пределами ENUM
    // default необязателен
  }
MaksVV
Offline
Зарегистрирован: 06.08.2015

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

MaksVV
Offline
Зарегистрирован: 06.08.2015

твой малюсенький вродебы скетч node1 даже на Uno не влазит. 150% оперативы О_О это всё стринги)

riv
Offline
Зарегистрирован: 20.07.2017

Я отладочные структуры уберу потом. Остануться только перечисления. Они в памяти едят столько же сколько define. Я как раз введу параметры компилятору что если флаг отладка использовать структуру если рабочая программа то структуры убираю.

Ну и естественно только меги а в центре вообще Due + Orange Pi + Linux сервер 

riv
Offline
Зарегистрирован: 20.07.2017

MaksVV пишет:

твой малюсенький вродебы скетч node1 даже на Uno не влазит. 150% оперативы О_О это всё стринги)

Так убери структуры. Протсто закоментируй 

typedef struct {
    uint8_t          dev_num;
    String           dev_name;
}sens_dev_CANvalueData;
 
И убери ее в декодере.
Мне удобнее отлаживаться видя не биты с байтами а название параметра.
Ты же так же будешь убирать serial.print(""); везде?
MaksVV
Offline
Зарегистрирован: 06.08.2015

тогда уж проще было один дебагер собрать, который декодирует. А все узлы, если надо (ставим флаг например), шлют в кан это служебное сообщение (получается тоже которое получили, но, например, message_type делаем особенный =0) и ты отладчиком уже видишь - кто что видит в кане, и преобразует в удобный тебе вид в сериал.

типа эхо чтоли, получается, только в ID message_type другой.

И не надо на всех контроллерах эту шляпу со стрингами. плюсом тебе не надо со всех сериал монитор - всё по кану. 

 

riv
Offline
Зарегистрирован: 20.07.2017

Зачем

Делаю так 

#define debug


#ifdef debug
typedef struct {
    uint8_t          msg_num;
    String           msg_name;
}Message_CANvalueData;

const Message_CANvalueData Message_CANData[] =
{
        /*Key        KeyName */
        { 0 ,    "NULL_C"},
        { 1 ,    "COMMAND SEND"},
        { 2 ,    "COMMAND_ANSVER"},  
        { 3 ,    "REQUEST_SEND"},
        { 4 ,    "REQUEST_ANSVER"},
        { 5 ,    "STATUS_REQUEST_SEND"},
        { 6 ,    "STATUS_REQUEST_ANSVER"}

};
#endif

 #ifdef debug
  DeCode_can_id_msg(direction,msg_type,dev_addr,rem_addr,dev_type,rxBuf_can); //Отладочная функция 
 #endif 

если закоментировать #define debug то структуры и функция декодер в программе не участвует

смотри последнюю версию

https://yadi.sk/d/7pyVRdHJ3TNYXr

MaksVV
Offline
Зарегистрирован: 06.08.2015

а если программа будет побольше занимать, то не сможет работать твой декодер или глюки будут. короче ладно. Идёшь правильной дорогой, просто реально многовато конечно, твой отладчик занимает. 

riv
Offline
Зарегистрирован: 20.07.2017

Я просто хочу сделать единую прошику для всех контроллеров

Менять только Node_address и некоторые обработчики

Ну и понятно что головные будут отличаться

MaksVV
Offline
Зарегистрирован: 06.08.2015

это понятно, ТС так и писал в начале

riv
Offline
Зарегистрирован: 20.07.2017

Думаю нужно в конце концов библиотеку сделать и на гитхаб положить.

MaksVV
Offline
Зарегистрирован: 06.08.2015

riv пишет:

Я просто хочу сделать единую прошику для всех контроллеров

Менять только Node_address и некоторые обработчики

Ну и понятно что головные будут отличаться

#135 в вот тут #142 посмотри скетчи, как сделал ТС, может полезно будет. 

riv
Offline
Зарегистрирован: 20.07.2017

Да именно так через #ifdef определить тип прошивки, вытащить общие структуры в отдельные файлы и лучше сделать либу на наш протокол.

MaksVV
Offline
Зарегистрирован: 06.08.2015

и то верно, чтобы простыней поменьше

MaksVV
Offline
Зарегистрирован: 06.08.2015

MaksVV пишет:
и чёто капец у тебя сложно как-то всё , запутаться можно  - из одной функции в другую функцию и т.д. Попроще можно всё и другим понятнее будет.

вот так например, можно упростить функцию TX(). При этом функцию  Code_can_id_msg () убираем за ненадобностью

#define EXTERNAL 1
#define STANDART 0

void TX(uint8_t direction, uint8_t msg_type, uint8_t dev_addr, uint8_t rem_addr, int8_t dev_type, uint8_t can_msg_type, uint8_t can_type_id, byte data[8])
{
uint32_t txId_can;

if (can_msg_type==4) txId_can=0x40000000;
else txId_can = (direction & 0xFFFFFFFF)<<28 | (msg_type & 0xFFFFFFFF)<<24 | (dev_addr & 0xFFFFFFFF)<<16 | (rem_addr & 0xFFFFFFFF)<<8 | dev_type;

if (can_msg_type==8 && can_type_id == STANDART)  txId_can+0x80000000;
 
byte sndStat = CAN0.sendMsgBuf(txId_can, can_type_id ,8, data); 

#ifdef debug   
if(sndStat == CAN_OK){Serial.print(F("Message Sent Successfully!   TX CAN ID ")); Serial.println(txId_can, HEX);}
else Serial.println(F("Error Sending Message..."));
#endif  
} 


// вызов функции TX (1, STATUS_REQUEST_ANSVER, node_address, rem_addr, null_s, 0, EXTERNAL, data)

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

riv пишет:
Кстати начал тут глубже копать CAN так вот эти 3 бита забирает т.н. удаленный кадр, в котором нет поля данных но он является запросчиком. (Вернее даже не удаленный кадр а типизация видов сообщений)

"Удаленные кадры можно использовать для реализации управления трафиком шины типа «запрос–ответ». На практике, однако, удаленный кадр используется мало. Это не так важно, поскольку стандарт CAN не предписывает действовать именно так, как здесь обозначено. Большинство контроллеров CAN можно запрограммировать так, что они будут автоматически отвечать на удаленный кадр, или же вместо этого извещать локальный процессор."

На самом деле всё не совсем так. Я вроде бы разобрался с этим. В стандартных 11 битных ID , служебный бит (недостающий до 12)  - один, это бит RTR.  Он и определяет сообщение с данными это ли запрос данных. НО! даже, если это запрос параметров, то мы можем передавать байты в поле данных, хотя в стандарте CAN не должно быть поля данных и ответ должен быть с таким же ID. 

В кадрах данных RTR бит должен быть передан нулевым уровнем. Внутри кадра удаленного запроса данных RTR бит должен быть единичным.

В расширенных ID служебных бита уже три:

1. При передаче просто раширенного ID бит RTR также определяет сообщение с данными это или запрос данных.

2. В расширенном варианте могут также передаваться и обычные стандартные 11 битные ID. Дак вот в таком случае определение сообщение с данными это или запрос данных делает уже не бит RTR, а бит SRR (это только в случае, когда при схеме с раширенными ID передаётся стандартный ID). 

3. Ну и посдний бит, собственно, и определяет расширенный данный ID или стандариный - бит IDE

Я научился управлять этим служебным битом RTR, поэтому мы имеем в распоряжении ещё один бит в ID, можно назначение его и оставить таким же как в стандарте CAN -  определять либо это данные, либо запрос данных. 

поэтому в моей библе так и было :

MaksVV пишет:
Единственное, для того, чтобы значение первого разряда в моей библиотеке (<mcp2515.h>) было равно 1, нужно отправлять 9

и соответственно чтобы было равно 0 - нужно отправлять 8 . Такова особенность библиотеки видимо. 

Пример. Для отправки ID 0х0aabbccd нам нужно отправить 0х8aabbccd

             Для отправки ID 0х1aabbccd нам нужно отправить 0х9aabbccd

 

т.е. если прилетает ID 0x1ABCDEF0, то в реале, на самом деле, прилетает 0x9ABCDEF0, это просто твоя библиотека уже переделывает к правильному виду. Получается так:

прилетает 0x9ABCDEF0 а видим 0x1ABCDEF0, но это сообщение с данными
прилетает 0x8ABCDEF0 а видим 0x0ABCDEF0, но это сообщение с данными
прилетает 0xDABCDEF0 а видим 0x1ABCDEF0, но это сообщение запрос данных
прилетает 0xCABCDEF0 а видим 0x0ABCDEF0, но это сообщение запрос данных

при всём при этом МОЖНО передавать байты в поле данных во всех этих типах сообщений

 

 

riv
Offline
Зарегистрирован: 20.07.2017

MaksVV пишет:

MaksVV пишет:
и чёто капец у тебя сложно как-то всё , запутаться можно  - из одной функции в другую функцию и т.д. Попроще можно всё и другим понятнее будет.

вот так например, можно упростить функцию TX(). При этом функцию  Code_can_id_msg () убираем за ненадобностью

Упрощения само собой, это пока наброски кода. И я делал оба варианта 11-29 просто попробовать как либа себе ведет. На выходе только 29 бит с использованием FR.

Вот почти боевой код

void TX(uint8_t direction, uint8_t msg_type, uint8_t dev_addr, uint8_t rem_addr, int8_t dev_type, uint8_t can_msg_type,  byte data[8])
{
uint32_t txId_can;

if (can_msg_type==4) 
  txId_can=0x40000000;
else if (can_msg_type==0)
  txId_can = (direction & 0xFFFFFFFF)<<28 | (msg_type & 0xFFFFFFFF)<<24 | (dev_addr & 0xFFFFFFFF)<<16 | (rem_addr & 0xFFFFFFFF)<<8 | dev_type;
else
{
#ifdef debug   
Serial.println(("Error can_msg_type"));
#endif  
  break;
}  

byte sndStat = CAN0.sendMsgBuf(txId_can, 1 ,8, data); 

#ifdef debug   
if(sndStat == CAN_OK){Serial.print(("Message Sent Successfully! - "; Serial.println(txId_can, HEX);}
else Serial.println(("Error Sending Message..."));
#endif  
} 


// вызов функции TX (1, STATUS_REQUEST_ANSVER, node_address, rem_addr, null_s, 0, data) предпоследний параметр 0 или 4 если FR.

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

попробовал, чето твоя либа не хочет Request Frame отправлять, на моей получилось. Сужу по анализатору шины. Он так и пишет: RTR. 

MaksVV
Offline
Зарегистрирован: 06.08.2015

я думаю нафиг эта поддержка стандартых ID и  кадров Remote не нужна короче. 

И зря убираешь макрос  F из печати Serial.print

riv
Offline
Зарегистрирован: 20.07.2017

Тут все хитрее, смотри поисание либы

есть ф-я 

sendMsgBuf(txId_can, 8, data); тут 3 параметра

здесь можно передать RF если txId_can=0x4000000

а есть

sendMsgBuf(txId_can, 0, 8, data); тут 4 праметра

здесь нельза передать RF и даже если txId_can=0x4000000 либа просто отфильтрует и в сеть уйдет txId_can=0x0000000

 

riv
Offline
Зарегистрирован: 20.07.2017

MaksVV пишет:

я думаю нафиг эта поддержка стандартых ID и  кадров Remote не нужна короче. 

И зря убираешь макрос  F из печати Serial.print

Ху из F?

MaksVV
Offline
Зарегистрирован: 06.08.2015

этот маркос всю писанину (строковые константы в кавычках при сериалпринте) кладет не ОЗУ а на флеш

MaksVV
Offline
Зарегистрирован: 06.08.2015

riv пишет:
sendMsgBuf(txId_can, 8, data); тут 3 параметра

здесь можно передать RF если txId_can=0x4000000

интересно,  а нафига тогда цифра 8 и дата, если поля данных нет

MaksVV
Offline
Зарегистрирован: 06.08.2015

короче всё равно не отправляет FR ы, всяко попробовал

нет, не всяко попробовал. Нужно было как всегда внимательнее читать. И нужно брать не 0x40000000 , а 0xC0000000

Делаем ИЛИ с нужным нам ID и Обязательно DLC в ноль. Я когда пробовал видимо по очереди и то и то , а вместе  - нет, поэтому не работало. Рабочий код отправки FR

// CAN Send Example
//

#include <mcp_can.h>
#include <SPI.h>

MCP_CAN CAN0(10);     // Set CS to pin 10

void setup()
{
  Serial.begin(115200);

  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if(CAN0.begin(MCP_ANY, CAN_250KBPS, MCP_8MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!");
  else Serial.println("Error Initializing MCP2515...");

  CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted
}

byte data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};

void loop()
{
  // send data:  ID = 0x10000000, Standard CAN Frame, Data length = 8 bytes, 'data' = array of data bytes to send
uint32_t txId_can = 0x1ABCDEF6;
 
  byte sndStat = CAN0.sendMsgBuf((txId_can|0xС0000000), 0, data); // SEND REMOTE REQUEST FRAME
  if(sndStat == CAN_OK){
    Serial.println("Message Sent Successfully!");
  } else {
    Serial.println("Error Sending Message...");
  }
  delay(1000);   // send data per 100ms
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

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

riv
Offline
Зарегистрирован: 20.07.2017

MaksVV пишет:

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

Обязательно Nano или я могу залить в любой свой контроллер?

И второй вопрос. У меня W7 64, основное окно запустилось при попытке настроит виснет наглухо. (Пришлось подсовывать mscomm32.ocx и регистрировать). Есть подводные камни?

MaksVV
Offline
Зарегистрирован: 06.08.2015

Чето не помню уже, вроде норм всё должно быть. Мегу можно конечно. Когда нажимаешь настроить вроде порт должен быть вставлен. Покажи куда тычешь когда виснет

MaksVV
Offline
Зарегистрирован: 06.08.2015

т.к. мы разобрались с этими ID и Remote ами предлагаю исправить функцию RX() 

void RX()
{
  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
  {
    CAN0.readMsgBuf(&rxId_can, &len_can, rxBuf_can);      // Read data: len = data length, buf = data byte(s)
       
uint8_t direction, msg_type, dev_addr, rem_addr, dev_type, can_msg_type;
uint8_t data_b0,data_b1,data_b2,data_b3,data_b4,data_b5,data_b6,data_b7;

    can_msg_type = (rxId_can & 0xF0000000)>>28;  //извлекаем тип ID 
if (can_msg_type == 0) {тут что нибудт делаем}                            // получили ID 11 бит
if (can_msg_type == 8 || can_msg_type == 9) {тут что нибудт делаем}       // получили ID 29 бит, сообщение -  DataFrame
if (can_msg_type == 0x0C || can_msg_type == 0x0D) {тут что нибудт делаем} // получили ID 29 бит, сообщение -  RemoteFrame
    
    direction  = (rxId_can & 0x10000000)>>28; //  извлекаем 1-битный идентификатор запроса-ответа из ID
    msg_type = (rxId_can &   0xF000000)>>24;  //  извлекаем 4-битный идентификатор сообщения из ID  
    dev_addr  = (rxId_can &  0xFF0000)>>16;   //  извлекаем 8-битный адрес отправителя из ID
    rem_addr = (rxId_can &   0xFF00)>>8;      //  извлекаем 8-битный адрес получателя из ID
    dev_type = rxId_can;                      //  извлекаем 8-битный тип устройства у получателя из ID

    
    #ifdef debug
    DeCode_can_id_msg(direction,msg_type,dev_addr,rem_addr,dev_type,rxBuf_can); //Отладочная функция 
    #endif 
    //Начинаем разбор принятого
    switch (direction) {
    case 0: //выполняется, когда RX Reqv т.е у меня что то запрашивают
      switch (msg_type){
              case COMMAND_SEND: //выполняется, когда мне прислали команду от удаленного контроллера
              // Функция обработки присланой команды от удаленного контроллера
              // Что за команда запрошена
              break;
              case REQUEST_SEND: //выполняется когда удаленный контроллер у меня запросил параметр датчика или еще чего то
              // Функция обработки присланного запроса параметра с датчика
              // Что за датчик запрошен
              break;
              case STATUS_REQUEST_SEND: //выполняется когда удаленный контроллер у меня запрашивает состояние
              // Функция обработки запроса моего состояния
              // Вернуть состояние
              break;
              default:
              //если параметр за пределами ENUM
              #ifdef debug
              Serial.println("Default msg - Recive Uncnown type message");
              #endif
             }    
    break;
    case 1: //выполняется когда RX Ansv т.е мне отвечают на мой запрос
      switch (msg_type){
              case COMMAND_ANSVER: //выполняется когда удаленный контроллер отвечает на посланную команду
              // Функция обработки ответа на мою команду
              break;
              case REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос параметра датчика
              // Функция обработки ответа на мой запрос параметра датчика   
              break;
              case STATUS_REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос состояния 
              // Функция обработки ответа на мой запрос состояния УК     
              break;  
              default:
              //если параметр за пределами ENUM
              #ifdef debug
              Serial.println("Default msg - Recive Uncnown type message");     
              #endif 
              }
    break;
    default:
    #ifdef debug
    Serial.print(" Default direct ");
    #endif
    //если параметр за пределами ENUM
    // default необязателен
  }
    
  }
} 

 

riv
Offline
Зарегистрирован: 20.07.2017

Немного поменять, сам проверь, если закоментировать debug то за default: нет ничего, компилятор ругнется. Поэтому так:

void RX()
{
  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
  {
    CAN0.readMsgBuf(&rxId_can, &len_can, rxBuf_can);      // Read data: len = data length, buf = data byte(s)
       
uint8_t direction, msg_type, dev_addr, rem_addr, dev_type, can_msg_type;
uint8_t data_b0,data_b1,data_b2,data_b3,data_b4,data_b5,data_b6,data_b7;

    can_msg_type = (rxId_can & 0xF0000000)>>28;  //извлекаем тип ID 
if (can_msg_type == 0) {тут что нибудт делаем}                            // получили ID 11 бит
if (can_msg_type == 8 || can_msg_type == 9) {тут что нибудт делаем}       // получили ID 29 бит, сообщение -  DataFrame
if (can_msg_type == 0x0C || can_msg_type == 0x0D) {тут что нибудт делаем} // получили ID 29 бит, сообщение -  RemoteFrame
    
    direction  = (rxId_can & 0x10000000)>>28; //  извлекаем 1-битный идентификатор запроса-ответа из ID
    msg_type = (rxId_can &   0xF000000)>>24;  //  извлекаем 4-битный идентификатор сообщения из ID  
    dev_addr  = (rxId_can &  0xFF0000)>>16;   //  извлекаем 8-битный адрес отправителя из ID
    rem_addr = (rxId_can &   0xFF00)>>8;      //  извлекаем 8-битный адрес получателя из ID
    dev_type = rxId_can;                      //  извлекаем 8-битный тип устройства у получателя из ID

    
    #ifdef debug
    DeCode_can_id_msg(direction,msg_type,dev_addr,rem_addr,dev_type,rxBuf_can); //Отладочная функция 
    #endif 
    //Начинаем разбор принятого
    switch (direction) {
    case 0: //выполняется, когда RX Reqv т.е у меня что то запрашивают
      switch (msg_type){
              case COMMAND_SEND: //выполняется, когда мне прислали команду от удаленного контроллера
              // Функция обработки присланой команды от удаленного контроллера
              // Что за команда запрошена
              break;
              case REQUEST_SEND: //выполняется когда удаленный контроллер у меня запросил параметр датчика или еще чего то
              // Функция обработки присланного запроса параметра с датчика
              // Что за датчик запрошен
              break;
              case STATUS_REQUEST_SEND: //выполняется когда удаленный контроллер у меня запрашивает состояние
              // Функция обработки запроса моего состояния
              // Вернуть состояние
              break;
              default:
               {
              //если параметр за пределами ENUM
              #ifdef debug
              Serial.println("Default msg - Recive Uncnown type message");
              #endif
               }
             }    
    break;
    case 1: //выполняется когда RX Ansv т.е мне отвечают на мой запрос
      switch (msg_type){
              case COMMAND_ANSVER: //выполняется когда удаленный контроллер отвечает на посланную команду
              // Функция обработки ответа на мою команду
              break;
              case REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос параметра датчика
              // Функция обработки ответа на мой запрос параметра датчика   
              break;
              case STATUS_REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос состояния 
              // Функция обработки ответа на мой запрос состояния УК     
              break;  
              default:
               {
              //если параметр за пределами ENUM
              #ifdef debug
              Serial.println("Default msg - Recive Uncnown type message");     
              #endif
                }
              }
    break;
    default:
     {
    #ifdef debug
    Serial.print(" Default direct ");
    #endif
    //если параметр за пределами ENUM
    // default необязателен
     }
  }
    
  }
} 

 

riv
Offline
Зарегистрирован: 20.07.2017

Кстати вот мои Mega в компактном формфакторе (пока резинкой с 2515 соединил. Потом что то буду думать.

 

riv
Offline
Зарегистрирован: 20.07.2017

И кстати 1 голова хорошо, а две во много крат лучше. Так что к лету думаю протокол доведем ;-)

MaksVV
Offline
Зарегистрирован: 06.08.2015

Это точно. Я ещё лучше придумал выуживание типа ID.  Нужно бит определённый выделять а не байт) щас покажу

uint8_t  msg_type, dev_addr, rem_addr, dev_type;
bool direction, can_frame_type; can_ID_type;
uint8_t data_b0,data_b1,data_b2,data_b3,data_b4,data_b5,data_b6,data_b7;

can_ID_type    = (rxId_can & 0x80000000)>>31;  //извлекаем тип ID        (0 - 11bit, 1 - 29 bit)
can_frame_type = (rxId_can & 0x40000000)>>30;  //извлекаем тип СAN FRAME (0 - Data,  1 - Remote)
 
direction  = (rxId_can & 0x10000000)>>28; //  извлекаем 1-битный идентификатор запроса-ответа из ID
msg_type   = (rxId_can & 0xF000000)>>24;  //  извлекаем 4-битный идентификатор сообщения из ID  
dev_addr   = (rxId_can & 0xFF0000)>>16;   //  извлекаем 8-битный адрес отправителя из ID
rem_addr   = (rxId_can & 0xFF00)>>8;      //  извлекаем 8-битный адрес получателя из ID
dev_type   = rxId_can;                    //  извлекаем 8-битный тип устройства у получателя из ID

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

а че CANHAcker то заработал? Если чё, уно же есть у тебя, там точно должно. 

riv
Offline
Зарегистрирован: 20.07.2017

Програ раступилась. Просто долго думала при первом запуске, видимо порты искала.

Но данные в нее не идут.

Я залил твой скетч, изменил пин с 10 на 53 (Мега), подключил МК с CanHacker к сети, запустил Win прогу, выбрал в ней порт меги с  CanHacker, нажал коннект и .... ничего (

MaksVV
Offline
Зарегистрирован: 06.08.2015

потому что у тебя нужно во всех скетчах сделать 8MHZ а не 16, (смотри на кварц на модулях)

if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK)

И ЕЩЁ!!! смотри на каком пине у МЕГИ прерывание INT0, на 23 вроде, попробуй это тоже поменять. У Наны на 2 пине.

скорость шины и компорт выбирается во вкладке Settings

PS в канхакере ( в библиотеке которая по ссылке) я там уже исправил. 

MaksVV
Offline
Зарегистрирован: 06.08.2015

вот у тебя типы сообщений 

COMMAND_SEND:          //выполняется, когда мне прислали команду от удаленного контроллера
REQUEST_SEND:          //выполняется когда удаленный контроллер у меня запросил параметр датчика или еще чего то
STATUS_REQUEST_SEND:   //выполняется когда удаленный контроллер у меня запрашивает состояние
COMMAND_ANSVER:        //выполняется когда удаленный контроллер отвечает на посланную команду
REQUEST_ANSVER:        //выполняется когда удаленный контроллер мне отвечают на мой запрос параметра датчика
STATUS_REQUEST_ANSVER: //выполняется когда удаленный контроль

Только я не могу понять, зачем нужен direction?

Понятно, что раз приставка SEND то выполняется, когда у меня что то запрашивают

и если приставка ANSVER то выполняется когда  мне отвечают на мой запрос

Может так проще? 

void RX()
{
  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
  {
    CAN0.readMsgBuf(&rxId_can, &len_can, rxBuf_can);      // Read data: len = data length, buf = data byte(s)
       
uint8_t  msg_type, dev_addr, rem_addr, dev_type;
bool direction, can_frame_type; can_ID_type;
uint8_t data_b0,data_b1,data_b2,data_b3,data_b4,data_b5,data_b6,data_b7;

 can_ID_type    = (canMsg.can_id & 0x80000000)>>31;  //извлекаем тип ID        (0 - 11bit, 0 - 29 bit)
 can_frame_type = (canMsg.can_id & 0x40000000)>>30;  //извлекаем тип СAN FRAME (0 - Data,  1 - Remote)
 
       
direction  = (rxId_can & 0x10000000)>>28; //  извлекаем 1-битный идентификатор запроса-ответа из ID
msg_type = (rxId_can &   0xF000000)>>24;  //  извлекаем 4-битный идентификатор сообщения из ID  
dev_addr  = (rxId_can &  0xFF0000)>>16;   //  извлекаем 8-битный адрес отправителя из ID
rem_addr = (rxId_can &   0xFF00)>>8;      //  извлекаем 8-битный адрес получателя из ID
dev_type = rxId_can;                      //  извлекаем 8-битный тип устройства у получателя из ID

    
    #ifdef debug
    DeCode_can_id_msg(direction,msg_type,dev_addr,rem_addr,dev_type,rxBuf_can); //Отладочная функция 
    #endif 
   
  //Начинаем разбор принятого
    
    
      switch (msg_type){
              
    // ниже выполняется, когда  у меня что-то запрашивают
    
              case COMMAND_SEND: //выполняется, когда мне прислали команду от удаленного контроллера
              // Функция обработки присланой команды от удаленного контроллера
              // Что за команда запрошена
              break;
              case REQUEST_SEND: //выполняется когда удаленный контроллер у меня запросил параметр датчика или еще чего то
              // Функция обработки присланного запроса параметра с датчика
              // Что за датчик запрошен
              break;
              case STATUS_REQUEST_SEND: //выполняется когда удаленный контроллер у меня запрашивает состояние
              // Функция обработки запроса моего состояния
              // Вернуть состояние
              break;
                  
     // выполняется когда мне отвечают на мой запрос
     
              case COMMAND_ANSVER: //выполняется когда удаленный контроллер отвечает на посланную команду
              // Функция обработки ответа на мою команду
              break;
              case REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос параметра датчика
              // Функция обработки ответа на мой запрос параметра датчика   
              break;
              case STATUS_REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос состояния 
              // Функция обработки ответа на мой запрос состояния УК     
              break;  
              
      }
    default:
    {
    #ifdef debug
    Serial.print(F("Default msg - Recive Uncnown type message"));
    #endif
    }
    
  
  }   
}
 
MaksVV
Offline
Зарегистрирован: 06.08.2015

и нужно добавить ещё один тип сообщений - СOMMAND_ANSVER_OK - команда выполнена

отпличие от СOMMAND_ANSVER  - команда принята к исполнению

MaksVV
Offline
Зарегистрирован: 06.08.2015

и вот подравнял TX(). Теперь FRы должны отправляться

#define 29_BIT 1
#define 11_BIT 0
#define DATA_FRAME   0
#define REMOTE_FRAME 1

void TX(bool direction, uint8_t msg_type, uint8_t dev_addr, uint8_t rem_addr, int8_t dev_type, bool can_ID_type, bool can_frame_type, int8_t DLC,  byte data[8])
{
uint32_t txId_can;

if (!can_ID_type) {}// тут как-то формируем 11 битный ID если нужно

else  txId_can = (direction & 0xFFFFFFFF)<<28 | (msg_type & 0xFFFFFFFF)<<24 | (dev_addr & 0xFFFFFFFF)<<16 | (rem_addr & 0xFFFFFFFF)<<8 | dev_type;

//ниже если это REMOTE FRAME подравняем ID, а DLC  в ноль
if (can_frame_type) {txId_can = txId_can | 0xC0000000;  DLC = 0;}

byte sndStat = CAN0.sendMsgBuf(txId_can, DLC, data);   //отсылаем кадр в CAN

#ifdef debug   
if(sndStat == CAN_OK){Serial.print(F("Message Sent Successfully! - ")); Serial.print(txId_can, HEX);
Serial.print ("    "); if (DLC!=0) {for (int i=0; i<DLC; i++) {
if (data<=0x0F) Serial.print ("0");
Serial.print (data[i]); Serial.print (" "); }}
Serial.println();
}
else Serial.println(F("Error Sending Message..."));
#endif  
} 

// вызов TX (direction, тип сообщения, адрес отправителя, адрес получателя, тип устройства, тип ID, тип FRAME, длина поля данных кадра, data)
// тип ID     0 - 11 bit;   1 - 29 bit
// тип FRAME  0 - DATA;     1 - REMOTE FRAME

// вызов TX (1, STATUS_REQUEST_ANSVER, node_address, rem_addr, null_s, 29_BIT, DATA_FRAME, 8, data)

 

riv
Offline
Зарегистрирован: 20.07.2017

MaksVV пишет:

Только я не могу понять, зачем нужен direction?

Понятно, что раз приставка SEND то выполняется, когда у меня что то запрашивают

и если приставка ANSVER то выполняется когда  мне отвечают на мой запрос

Может так проще? 

Тут скоре плюшкиничество работает, твой not use покоя не дает.  Давай думать куда его приспособить ;-)

Ты там выше про биты писал. Просто пока идей не приходит.