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

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

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

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

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

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

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

riv пишет:

01// Задаем перечисления и структуры для типов сообщений Y
02typedef enum Message_enum
03{
04    NULL_C,                //0
05    COMMAND_SEND,          //1
06    COMMAND_ANSVER,        //2
07    REQUEST_SEND,          //3
08    REQUEST_ANSVER,        //4
09    STATUS_REQUEST_SEND,   //5
10    STATUS_REQUEST_ANSVER  //6
11                    
12} Message_CAN_ENUM;              
13 
14typedef struct {
15    uint8_t          msg_num;
16    String           msg_name;
17}Message_CANvalueData;
18 
19const Message_CANvalueData Message_CANData[] =
20{
21        /*Key        KeyName */
22        { 0 ,    "NULL_C"},
23        { 1 ,    "COMMAND SEND"},
24        { 2 ,    "COMMAND_ANSVER"}, 
25        { 3 ,    "REQUEST_SEND"},
26        { 4 ,    "REQUEST_ANSVER"},
27        { 5 ,    "STATUS_REQUEST_SEND"},
28        { 6 ,    "STATUS_REQUEST_ANSVER"}
29 
30};

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

1#define NULL_C                0
2#define COMMAND_SEND          1
3#define COMMAND_ANSVER        2
4#define REQUEST_SEND          3
5#define REQUEST_ANSVER        4
6#define STATUS_REQUEST_SEND   5
7#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 это не переменные получаются, а как бы указания компилятору что вместо одного подставить другое.

Например 

1#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-типа) и пр.

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

1const uint8_t COMMAND_SEND = 1;

 

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

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

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

Будет так

01switch (direction) {
02    case 0: //выполняется, когда RX Reqv т.е у меня что то запрашивают
03       
04      break;
05    case 1: //выполняется когда RX Ansv т.е мне отвечают на мой запрос
06     
07      break;
08    default:
09     
10      // выполняется, если не выбрана ни одна альтернатива
11      // default необязателен
12  }
MaksVV
Offline
Зарегистрирован: 06.08.2015
01const uint8_t NULL_C                = 0;
02const uint8_t COMMAND_SEND          = 1;
03const uint8_t COMMAND_ANSVER        = 2;
04const uint8_t REQUEST_SEND          = 3;
05const uint8_t REQUEST_ANSVER        = 4;
06const uint8_t STATUS_REQUEST_SEND   = 5;
07const uint8_t STATUS_REQUEST_ANSVER = 6;
08 
09const uint8_t  center_node =   11;
10const uint8_t  kitchen_node =  22;
11const uint8_t  bathroom_node = 33;
12const uint8_t  officeroom_node = 44;
13const uint8_t  bedroom_node = 55;
14 
15 
16void RX()
17{
18  uint8_t direction, msg_type, dev_addr, rem_addr, dev_type;
19  
20  if(!digitalRead(CAN0_INT))                         //
21  {
22    CAN0.readMsgBuf(&rxId_can, &len_can, rxBuf_can);      // Read data: len = data length, buf = data byte(s)
23 
24    direction  = (rxId_can & 0x10000000)>>28; //  извлекаем 1-битный идентификатор запроса-ответа из ID
25    msg_type = (rxId_can &   0xF000000)>>24;  //  извлекаем 4-битный идентификатор сообщения из ID 
26    dev_addr  = (rxId_can &  0xFF0000)>>16;   //  извлекаем 8-битный адрес отправителя из ID
27    rem_addr = (rxId_can &   0xFF00)>>8;      //  извлекаем 8-битный адрес получателя из ID
28    dev_type = (rxId_can &   0xFF);           //  извлекаем 8-битный тип устройства у получателя из ID
29 
30Serial.print(F(" type_msg - "));
31     if (msg_type == COMMAND_SEND)   Serial.print(F("COMMAND_SEND")); //макрос F записывает строковую константу не в оперативу, а на флеш
32else if (msg_type == COMMAND_ANSVER) Serial.print(F("COMMAND_ANSVER"));
33else if (msg_type == REQUEST_SEND)   Serial.print(F("REQUEST_SEND"));
34else if (msg_type == REQUEST_ANSVER) Serial.print(F("REQUEST_ANSVER"));
35else if (msg_type == STATUS_REQUEST_SEND) Serial.print(F("STATUS_REQUEST_SEND"));
36else if (msg_type == STATUS_REQUEST_ANSVER) Serial.print(F("STATUS_REQUEST_ANSVER"));
37 
38Serial.print(F(" node_addr - "));
39 
40      if (dev_addr == center_node)     Serial.print(F("center_node"));
41 else if (dev_addr == kitchen_node)    Serial.print(F("kitchen_node"));
42 else if (dev_addr == bathroom_node)   Serial.print(F("bathroom_node"));
43 else if (dev_addr == officeroom_node) Serial.print(F("officeroom_node"));
44 else if (dev_addr == bedroom_node)    Serial.print(F("bedroom_node"));
45 
46 // и так далее в общем. Таким образом ты не кладёшь все String-и в оперативу,  и опять же экономишщ память и функций меньше
47    
48  }
49}
riv
Offline
Зарегистрирован: 20.07.2017

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

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

01switch (msg_type){
02    case COMMAND_SEND: //выполняется, когда мне прислали команду от удаленного контроллера
03       
04      break;
05    case COMMAND_ANSVER: //выполняется когда удаленный контроллер отвечают на посланную команду
06     
07      break;
08    case REQUEST_SEND: //выполняется когда удаленный контроллер у меня запросил параметр датчика или еще чего то
09     
10      break;
11    case REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос параметра датчика
12     
13      break;
14    case STATUS_REQUEST_SEND: //выполняется когда удаленный контроллер у меня запрашивает состояние
15     
16      break;
17    case STATUS_REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос состояния
18     
19      break;
20    default:
21    //если параметр за пределами ENUM
22    }
а дальше в него вложить адреса
а потом типы датчиков
 
CASE это практически и есть IF ELSE
 
Только посмотри где наглядней код, вот тоже что и у меня только на IF
01if (msg_type=1)
02{
03}
04else if (msg_type=2)
05{
06}
07else if (msg_type=3)
08{
09}
10else if (msg_type=4)
11{
12}
13else if (msg_type=5)
14{
15}
16else if (msg_type=6)
17{
18}

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

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

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

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

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

 

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

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

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

01switch (direction) {
02    case 0: //выполняется, когда RX Reqv т.е у меня что то запрашивают
03      switch (msg_type){
04              case COMMAND_SEND: //выполняется, когда мне прислали команду от удаленного контроллера
05              // Функция обработки присланой команды от удаленного контроллера
06              break;
07              case REQUEST_SEND: //выполняется когда удаленный контроллер у меня запросил параметр датчика или еще чего то
08              // Функция обработки присланного запроса параметра с датчика
09              break;
10              case STATUS_REQUEST_SEND: //выполняется когда удаленный контроллер у меня запрашивает состояние
11              // Функция обработки запроса моего состояния
12              break;
13              default:
14              //если параметр за пределами ENUM
15              Serial.print(" Default msg - Recive Uncnown type message");
16             }   
17    break;
18    case 1: //выполняется когда RX Ansv т.е мне отвечают на мой запрос
19      switch (msg_type){
20              case COMMAND_ANSVER: //выполняется когда удаленный контроллер отвечает на посланную команду
21              // Функция обработки ответа на мою команду
22              break;
23              case REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос параметра датчика
24              // Функция обработки ответа на мой запрос параметра датчика  
25              break;
26              case STATUS_REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос состояния
27              // Функция обработки ответа на мой запрос состояния УК    
28              break
29              default:
30              //если параметр за пределами ENUM
31              Serial.print(" Default msg - Recive Uncnown type message");      
32              }
33    break;
34    default:
35    Serial.print(" Default direct ");
36    //если параметр за пределами ENUM
37    // default необязателен
38  }
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

Зачем

Делаю так 

01#define debug
02 
03 
04#ifdef debug
05typedef struct {
06    uint8_t          msg_num;
07    String           msg_name;
08}Message_CANvalueData;
09 
10const Message_CANvalueData Message_CANData[] =
11{
12        /*Key        KeyName */
13        { 0 ,    "NULL_C"},
14        { 1 ,    "COMMAND SEND"},
15        { 2 ,    "COMMAND_ANSVER"}, 
16        { 3 ,    "REQUEST_SEND"},
17        { 4 ,    "REQUEST_ANSVER"},
18        { 5 ,    "STATUS_REQUEST_SEND"},
19        { 6 ,    "STATUS_REQUEST_ANSVER"}
20 
21};
22#endif
23 
24 #ifdef debug
25  DeCode_can_id_msg(direction,msg_type,dev_addr,rem_addr,dev_type,rxBuf_can); //Отладочная функция
26 #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 () убираем за ненадобностью

01#define EXTERNAL 1
02#define STANDART 0
03 
04void 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])
05{
06uint32_t txId_can;
07 
08if (can_msg_type==4) txId_can=0x40000000;
09else txId_can = (direction & 0xFFFFFFFF)<<28 | (msg_type & 0xFFFFFFFF)<<24 | (dev_addr & 0xFFFFFFFF)<<16 | (rem_addr & 0xFFFFFFFF)<<8 | dev_type;
10 
11if (can_msg_type==8 && can_type_id == STANDART)  txId_can+0x80000000;
12  
13byte sndStat = CAN0.sendMsgBuf(txId_can, can_type_id ,8, data);
14 
15#ifdef debug  
16if(sndStat == CAN_OK){Serial.print(F("Message Sent Successfully!   TX CAN ID ")); Serial.println(txId_can, HEX);}
17else Serial.println(F("Error Sending Message..."));
18#endif 
19}
20 
21 
22// вызов функции 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, это просто твоя библиотека уже переделывает к правильному виду. Получается так:

1прилетает 0x9ABCDEF0 а видим 0x1ABCDEF0, но это сообщение с данными
2прилетает 0x8ABCDEF0 а видим 0x0ABCDEF0, но это сообщение с данными
3прилетает 0xDABCDEF0 а видим 0x1ABCDEF0, но это сообщение запрос данных
4прилетает 0xCABCDEF0 а видим 0x0ABCDEF0, но это сообщение запрос данных
5 
6при всём при этом МОЖНО передавать байты в поле данных во всех этих типах сообщений

 

 

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

MaksVV пишет:

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

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

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

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

01void 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])
02{
03uint32_t txId_can;
04 
05if (can_msg_type==4)
06  txId_can=0x40000000;
07else if (can_msg_type==0)
08  txId_can = (direction & 0xFFFFFFFF)<<28 | (msg_type & 0xFFFFFFFF)<<24 | (dev_addr & 0xFFFFFFFF)<<16 | (rem_addr & 0xFFFFFFFF)<<8 | dev_type;
09else
10{
11#ifdef debug  
12Serial.println(("Error can_msg_type"));
13#endif 
14  break;
15
16 
17byte sndStat = CAN0.sendMsgBuf(txId_can, 1 ,8, data);
18 
19#ifdef debug  
20if(sndStat == CAN_OK){Serial.print(("Message Sent Successfully! - "; Serial.println(txId_can, HEX);}
21else Serial.println(("Error Sending Message..."));
22#endif 
23}
24 
25 
26// вызов функции 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

 

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() 

 

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

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

01void RX()
02{
03  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
04  {
05    CAN0.readMsgBuf(&rxId_can, &len_can, rxBuf_can);      // Read data: len = data length, buf = data byte(s)
06        
07uint8_t direction, msg_type, dev_addr, rem_addr, dev_type, can_msg_type;
08uint8_t data_b0,data_b1,data_b2,data_b3,data_b4,data_b5,data_b6,data_b7;
09 
10    can_msg_type = (rxId_can & 0xF0000000)>>28;  //извлекаем тип ID
11if (can_msg_type == 0) {тут что нибудт делаем}                            // получили ID 11 бит
12if (can_msg_type == 8 || can_msg_type == 9) {тут что нибудт делаем}       // получили ID 29 бит, сообщение -  DataFrame
13if (can_msg_type == 0x0C || can_msg_type == 0x0D) {тут что нибудт делаем} // получили ID 29 бит, сообщение -  RemoteFrame
14     
15    direction  = (rxId_can & 0x10000000)>>28; //  извлекаем 1-битный идентификатор запроса-ответа из ID
16    msg_type = (rxId_can &   0xF000000)>>24;  //  извлекаем 4-битный идентификатор сообщения из ID 
17    dev_addr  = (rxId_can &  0xFF0000)>>16;   //  извлекаем 8-битный адрес отправителя из ID
18    rem_addr = (rxId_can &   0xFF00)>>8;      //  извлекаем 8-битный адрес получателя из ID
19    dev_type = rxId_can;                      //  извлекаем 8-битный тип устройства у получателя из ID
20 
21     
22    #ifdef debug
23    DeCode_can_id_msg(direction,msg_type,dev_addr,rem_addr,dev_type,rxBuf_can); //Отладочная функция
24    #endif
25    //Начинаем разбор принятого
26    switch (direction) {
27    case 0: //выполняется, когда RX Reqv т.е у меня что то запрашивают
28      switch (msg_type){
29              case COMMAND_SEND: //выполняется, когда мне прислали команду от удаленного контроллера
30              // Функция обработки присланой команды от удаленного контроллера
31              // Что за команда запрошена
32              break;
33              case REQUEST_SEND: //выполняется когда удаленный контроллер у меня запросил параметр датчика или еще чего то
34              // Функция обработки присланного запроса параметра с датчика
35              // Что за датчик запрошен
36              break;
37              case STATUS_REQUEST_SEND: //выполняется когда удаленный контроллер у меня запрашивает состояние
38              // Функция обработки запроса моего состояния
39              // Вернуть состояние
40              break;
41              default:
42               {
43              //если параметр за пределами ENUM
44              #ifdef debug
45              Serial.println("Default msg - Recive Uncnown type message");
46              #endif
47               }
48             }   
49    break;
50    case 1: //выполняется когда RX Ansv т.е мне отвечают на мой запрос
51      switch (msg_type){
52              case COMMAND_ANSVER: //выполняется когда удаленный контроллер отвечает на посланную команду
53              // Функция обработки ответа на мою команду
54              break;
55              case REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос параметра датчика
56              // Функция обработки ответа на мой запрос параметра датчика  
57              break;
58              case STATUS_REQUEST_ANSVER: //выполняется когда удаленный контроллер мне отвечают на мой запрос состояния
59              // Функция обработки ответа на мой запрос состояния УК    
60              break
61              default:
62               {
63              //если параметр за пределами ENUM
64              #ifdef debug
65              Serial.println("Default msg - Recive Uncnown type message");    
66              #endif
67                }
68              }
69    break;
70    default:
71     {
72    #ifdef debug
73    Serial.print(" Default direct ");
74    #endif
75    //если параметр за пределами ENUM
76    // default необязателен
77     }
78  }
79     
80  }
81}

 

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

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

 

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

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

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

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

01uint8_t  msg_type, dev_addr, rem_addr, dev_type;
02bool direction, can_frame_type; can_ID_type;
03uint8_t data_b0,data_b1,data_b2,data_b3,data_b4,data_b5,data_b6,data_b7;
04 
05can_ID_type    = (rxId_can & 0x80000000)>>31;  //извлекаем тип ID        (0 - 11bit, 1 - 29 bit)
06can_frame_type = (rxId_can & 0x40000000)>>30;  //извлекаем тип СAN FRAME (0 - Data,  1 - Remote)
07  
08direction  = (rxId_can & 0x10000000)>>28; //  извлекаем 1-битный идентификатор запроса-ответа из ID
09msg_type   = (rxId_can & 0xF000000)>>24;  //  извлекаем 4-битный идентификатор сообщения из ID 
10dev_addr   = (rxId_can & 0xFF0000)>>16;   //  извлекаем 8-битный адрес отправителя из ID
11rem_addr   = (rxId_can & 0xFF00)>>8;      //  извлекаем 8-битный адрес получателя из ID
12dev_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, (смотри на кварц на модулях)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 

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

MaksVV пишет:

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

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

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

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

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

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