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

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

Твой код из #379 не собирается. Сейчас поправлю выложу.

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

Ладно. Последний разряд весь для типов данных это много. Возьмем один ниббл для этого. Остается еще 4 бита. Самый младший из них это будет флаг - мультик (поменял местами). Получается крайние биты заголовка будут отвечать за флаг мультика и маркер окончания мультика. Самый правый бит (младший) это флаг. Самый левый бит (старший) - маркер окончания.

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

MaksVV пишет:
Ладно. Последний разряд весь для типов данных это много. Возьмем один ниббл для этого. Остается еще 4 бита. Самый младший из них это будет флаг - мультик (поменял местами). Получается крайние биты заголовка будут отвечать за флаг мультика и маркер окончания мультика. Самый правый бит (младший) это флаг. Самый левый бит (старший) - маркер окончания.

Мне 32 типа для устройств мало, мне нужно не менее 128.

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

Да и в TX() нет смысла node_addr передавать, он жестко забит в глобальной переменной, это наш адрес.

Убираем?

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

Да я тоже об этом думал, убираем

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

Это не типы устройств, а тип переменных.

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

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

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

Можно также через перечисления

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

MaksVV пишет:
Тебе придется создать, для каждого типа свою базу данных. У каждого типа будет 256 адресов

Не совсем понял мысль.

И кстати проверяй код перед выкладыванием. Не работает. Сижу твой ТХ допиливаю.

Ты использовал функцию с определением 11 или 29 бит и FR через 0x80000000 и 0x40000000 но забыл их прибавить в ID, вот и не работает, шлет 11 битный ID (((. Я то  в теме а народ скопирует и работать не будет. (

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

Это НЕ рабочий код.

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

Покажи как функцию вызываешь
Выведи перед 8 строкой в порт переменную с ID, посмотреть нужно в каком она виде перед отправкой

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

Писал код на коленке, не на чем проверить.

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

Прибавлять там ничего не надо вроде

riv
Offline
Зарегистрирован: 20.07.2017
TX(1, STATUS_REQUEST_SEND, node_address, rem_addr,null_s,BIT_29,DATA_FRAME,8,data); 

А вот что разраб. пишет про ф-ю

The sendMsgBuf(ID, DLC, DATA) function can send extended or standard IDs.

To mark an ID as extended, OR the ID with 0x80000000.

To send a remote request, OR the ID with 0x40000000.

А вот как ты формируешь ID

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

А вот твой вызов

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

 

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

возми эту строку в фигурные скобки, после этой строки в эти же скобки добавь
txId_can = txId_can тут знак ИЛИ (одна палка вертик.) 0x80000000
Пс . Пишу с телефона.

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

MaksVV пишет:
возми эту строку в фигурные скобки, после этой строки в эти же скобки добавь txId_can = txId_can тут знак ИЛИ (одна палка вертик.) 0x80000000 Пс . Пишу с телефона.

Не работает.

CAN hacker видит либо 11 бит либо вообще ничего.

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

Щас мин через40 напишу, у меня же блин, все работало

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

короче не взял я с собой CAN модуль с работы, есть только дуня. Проверил ID перед отправкой  - он становиться в правильном виде. Должно работать по идее

#define EXTENDED 1
#define STANDART 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;}
else txId_can = txId_can | 0x80000000;          // иначе формируем 29 битный ID DATA_FRAME

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, EXTENDED, DATA_FRAME, 8, data)

 

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

Меня терзают смутные сомнения, ты где то писал что CanHacker как то плохо 29 бит ловит, может дело в нем? Ты 8 на D менял?

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

я вчера как раз всё это на канхакере и проверял. Всё идеально работало. Вручную правда (сам задавал ID) Потом уже скетч TX  писал. Попробуй пример из библиотеки поотправлять. 

// 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_500KBPS, 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()
{
  
  byte sndStat = CAN0.sendMsgBuf(0x8FAB04C6, 8, data);
  if(sndStat == CAN_OK){
    Serial.println("Message Sent Successfully!");
  } else {
    Serial.println("Error Sending Message...");
  }
  delay(100);   // send data per 100ms
}

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

У меня при отправке CAN0.sendMsgBuf(0x8FAB04C6, 8, data);  выдавалось 0x0FAB04C6

при отправке CAN0.sendMsgBuf(0xCFAB04C6, 8, data);  выдавалось 0x0FAB04C6 но RTR

при отправке CAN0.sendMsgBuf(0x4BC, 8, data);  выдавалось 0x4BC

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

В общем CanHacker так видит причем только 4С6

byte sndStat = CAN0.sendMsgBuf(0x8FAB04C6,0, 8, data);

а так не видит ничего ((((((((((((((( 

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

По колесу пинал, дверью хлопал ) в смысле Win перегружал, ардуину тоже, скетч переливал.

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

попробуй свою либу временно удали, вот эту поставь, может я на ней пробовал. 

Или ещё эту

 

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

а вот так ?

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

 

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

и не забывай везде скорость шины одну ставить и про 8 MHZ кварца 

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

MaksVV пишет:

а вот так ?

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

 

Так видит.

byte sndStat = CAN0.sendMsgBuf(0x1FAB04C6, 8, data);

Так видит как 4С6

byte sndStat = CAN0.sendMsgBuf(0x8FAB04C6, 8, data);

Так пошло

 

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

попробуй также, залей на другой модуль (вместо анализатора) пример Read этой <mcp2515.h> и смотри приходят ли 29 бит. 

#include <SPI.h>
#include <mcp2515.h>

struct can_frame canMsg;
MCP2515 mcp2515(10);


void setup() {
  Serial.begin(115200);
  SPI.begin();
  
  mcp2515.reset();
  mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ);
  mcp2515.setNormalMode();
  
  Serial.println("------- CAN Read ----------");
  Serial.println("ID  DLC   DATA");
}

void loop() {
  
  if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
      
    Serial.print(canMsg.can_id, HEX); // print ID
    Serial.print(" "); 
    Serial.print(canMsg.can_dlc, HEX); // print DLC
    Serial.print(" ");
    
    for (int i = 0; i<canMsg.can_dlc; i++)  {  // print the data
        
      Serial.print(canMsg.data[i],HEX);
      Serial.print(" ");

    }

    Serial.println();      
  }

}

 

 

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

riv пишет:

byte sndStat = CAN0.sendMsgBuf(0x8FAB04C6, 8, data);

Так пошло

вот я же предлагал такой пример. 

MaksVV пишет:

я вчера как раз всё это на канхакере и проверял. Всё идеально работало. Вручную правда (сам задавал ID) Потом уже скетч TX  писал. Попробуй пример из библиотеки поотправлять. 

// 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_500KBPS, 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()
{
  
  byte sndStat = CAN0.sendMsgBuf(0x8FAB04C6, 8, data);
  if(sndStat == CAN_OK){
    Serial.println("Message Sent Successfully!");
  } else {
    Serial.println("Error Sending Message...");
  }
  delay(100);   // send data per 100ms
}

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

У меня при отправке CAN0.sendMsgBuf(0x8FAB04C6, 8, data);  выдавалось 0x0FAB04C6

при отправке CAN0.sendMsgBuf(0xCFAB04C6, 8, data);  выдавалось 0x0FAB04C6 но RTR

при отправке CAN0.sendMsgBuf(0x4BC, 8, data);  выдавалось 0x4BC

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

Честно говоря сработало что то из вышеперечисленного, я всзял по CanHacker новый контроллер с MCP, перезалил его, ребутнул систему и скетч пошел.

P.S

У меня ноут на док станции, а USB к докстанции подключены. Снимаю с док станции USB отключается. CanHacker падает.

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

сначала отключай от кан. (Кнопка с красным крестиком), не будет виснуть.

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

Короче пробуй последний  скетч #367 Отпишись как в отладчике ID и дата пишется, отправляются ли RTR. 

Сразу скажу, что RTR с CANhackera нормально не отправляется (только если DLC не ноль поставить, но тогда байты хаотично гуляют в поле данных). А на CANHacker RTR норм приходит от дуни

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

и попробуй отправить 0x200001AB, по идее должен 11-битный  1AB   RTR отправиться

Так , для прикола. Просто я не пробовал REMOTE_FRAME для 11-бит

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

Я разбил проект на n файлов, смотри https://yadi.sk/d/zkejlJ3K3Td48S

На меге собирается, CanHacker видит.

Дальше займусь обработчиками протокола сверху вниз.

1. Опрос-обмен контроллеров Master,Slave, Base

2. Опрос-обмен датчиков

3.Отправка -квитанция команды

Глобальные переменные в struct.h

Поцедуры и функции в отдельные файлы xxx.ino по типам

Потом после отладки выкинем протокол в либу и пиши логику работы дома.

PS

У тебя как то ловче получается с битами байтами так что я туда пока не полезу. Я имею ввиду мультифрейм, RF установка RTR и пр.

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

ок время будет, буду править прогу

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

MaksVV пишет:

и попробуй отправить 0x200001AB, по идее должен 11-битный  1AB   RTR отправиться

Так , для прикола. Просто я не пробовал REMOTE_FRAME для 11-бит

проверил, работает. только нужно не 2 в начале , а  6. Вот так отпраляется FR 11 бит

0x600007CC

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

должен сказать, что CAN данные, которые будут стекаться на CAN-Мастер, выходит будут иметь уже не только свой адрес, но и адрес МК, от которого они пришли. Получается какбы двойной адрес,вернее адрес, представленный двумя с половиной байтами. Т.е. старший байт - адрес МК предоставившего данные, средний ниббл - тип данных и младший байт - адрес самих данных в этом типе. 

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

по идее тут нужно двумерные массивы использовать.  

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

MaksVV пишет:

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

typedef enum Node_addr_enum содержит адреса всех контроллеров. В протоколе мы задали адрес получателя и отправителя. В чем вопрос. Либо я не совсем тебя понял.

Но идею ты подал хорошую

Смотри у нас 3 группы (пока) запрос-ответов

1. Опрос-ответ Контроллера (опрос состяний, версии прошивки , готовности и пр.)

2. Опрос-ответ датчика

3. Отправка -квитанция команды.

Соответственно в зависимости от того какой тип используем 1,2 или 3 используем разные ENUM в типе устройств

И соответвенно можно ввести

Тип 

4. Мултифрейм

ит еще что нибудь придумать

 

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

Ага, вот я и уткнулся в то что RX() в чистом виде не имеет смысла.

Смотри я в loop запускаю функцию по алгоритму ниже.

Ну и как мне ее обработать? Перестать на 3-5 секунд принимать другие данные? 

 

Файл с алгоритмом и структурой сети смотри в https://yadi.sk/d/zkejlJ3K3Td48S

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

Вот смотрю о чем я толкую. Как сделано У меня на данный момент - данные по кан передаются в жестких местах в поле данных. Т.е. тип сообщения ДАТА имеет несколько страниц. Для каждого МК страницы свои и на них жестко указано в каких байтах что должно быть. Такой подход требует большую карту данных.
Мы же с тобой вроде как решили ввести адресацию данных. Т.е. у каждого параметра есть свой адрес. разрядность адреса - 1байт. При передаче данных в поле данных кадра сначала передается байт адреса, затем байт данных. Адреса в принципе ты уже задал в енум.
Дак вот сейчас нужно енумы отдельно для булевых задать, отдельно для одно и двубайтовых данных.

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

riv пишет:

Смотри я в loop запускаю функцию по алгоритму ниже.

Ну и как мне ее обработать? Перестать на 3-5 секунд принимать другие данные?


Посмотри как у меня в скетче сделано, в начале нашей беседы. Там все на миллис. Отправили запрос -, флаг обращение к слейву - труе, таймер вкл, Счетчик +1. пока таймер тикает, не запрашиваем. Как только кончился опять запрос. Как наберется 10 - перестаем. Таймер и флаг наличия обращения к слейву и счетчик сбрасывает положительный ответ слейва

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

MaksVV пишет:
Вот смотрю о чем я толкую. Как сделано У меня на данный момент - данные по кан передаются в жестких местах в поле данных. Т.е. тип сообщения ДАТА имеет несколько страниц. Для каждого МК страницы свои и на них жестко указано в каких байтах что должно быть. Такой подход требует большую карту данных. Мы же с тобой вроде как решили ввести адресацию данных. Т.е. у каждого параметра есть свой адрес. разрядность адреса - 1байт. При передаче данных в поле данных кадра сначала передается байт адреса, затем байт данных. Адреса в принципе ты уже задал в енум. Дак вот сейчас нужно енумы отдельно для булевых задать, отдельно для одно и двубайтовых данных.

Давай немного подробнее. 

1. Со структурой CAn ID определились, ее не трогаем? (Единстуенное посмотри что я предлагал немного выше

если msg_type
    COMMAND_SEND,          //1
    COMMAND_ANSVER,        //2
то в последней байте ID передаем dev_type из ENUM1
если msg_type
    REQUEST_SEND,          //3 
    REQUEST_ANSVER,        //4
то в последней байте ID передаем dev_type из ENUM2 
если msg_type
    STATUS_REQUEST_SEND,   //5
    STATUS_REQUEST_ANSVER  //6
то в последней байте ID передаем dev_type из ENUM3
если msg_type
   MULTIFRAME_SEND
   MULTIFRAME_ANSVER
то в последней байте ID передаем dev_type из ENUM4
2. У тебя n  контроллеров имеет разные наборы датчиков, исп. устройств и либо подпрограмм конечных автоматов (чтобы тебя от работы с датчиками по сети абстрагировать и ты шлеш померить температуру в комнате, МК снимает показания с 3х датчиков, их усредняет и выдает тебе 1 цифру) корорые ты предлагаешь загнать в шаблоны.Т.е 20 контроллеров, 20 шаблонов с адресами устройств?
 
3. Ты предлагаешь в поле данных передавать из 8 байт
1. Байт адреса
2. Байт данных
3. Байт данных
4. Байт данных
5. Байт данных
6. Байт данных
7. Резерв
8. № сообщения
Так?
Если нет распиши подробнее не понял идею.
riv
Offline
Зарегистрирован: 20.07.2017

MaksVV пишет:
riv пишет:

Смотри я в loop запускаю функцию по алгоритму ниже.

Ну и как мне ее обработать? Перестать на 3-5 секунд принимать другие данные?

Посмотри как у меня в скетче сделано, в начале нашей беседы. Там все на миллис. Отправили запрос -, флаг обращение к слейву - труе, таймер вкл, Счетчик +1. пока таймер тикает, не запрашиваем. Как только кончился опять запрос. Как наберется 10 - перестаем. Таймер и флаг наличия обращения к слейву и счетчик сбрасывает положительный ответ слейва

Кинь плиз № сообщения. Уже вариантов кода столько, что запутаешься. Видимо ты говоришь о сообщени что реализовал, прокинул кабель на 2 этаж и все заработало, это сообщение?

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

Пока на ум приходит такое извращение

в loop

1. RX() которая обрабатывает все что нам ответят на то что ниже у устанавливает флаг ответ получен на запрос ниже

2. Функция передачи запроса в которой

2.1 Посмотрел флаги запросов если есть не отвеченый установил счетчик запроса +1

2.2 Если счетчик запросов более 3 выдал аварию завершил функцию

2.3 Если счетчик 1 то запустил таймер, установил глобальнцю переменную с временем отправки запроса,  считал номер последнего сообщения из глобальной переменной, добавил 1, записал глобальную переменную, отправил 1 й запрос с номером сообщения

2.4 Если счетчик 2 или 3 то сравнил время с гобальной переменной времени запроса

2.5 Если с времени запроса прошло больше чем в заданом таймауте и флаг отвтета не установлен то,  читал номер последнего сообщения из глобальной переменной, добавил 1, записал глобальную переменную, делаем перезапрос

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

Короче это ппц. Эту функцию ставлю в loop. Без делеев. Она 3 раза отправляет запрос к МК и если не получает ответ то отправляет другому МК отчет авария. Если ответ будет получен то в RX нужно будет поставить flag_mk_ansver. Дальше я должен его какой то другой функцией периодически ставить в false чтобы опросить МК.

long interval_repeat_req_mk = 2000;
int quantity__repeat_req_mk=3;
long previousMillis = 0; // время, когда отправлен запрос
byte message_number = 0;
bool flag_mk_ansver = false;
int flag_mk_reepet = 0;
unsigned long currentMillis = millis();

//отправка опроса удаленному МК на предмет жив не жив
void send_status_reqvest(uint8_t rem_addr) 
  {
    bool exit_function = false;
   // Serial.print("currentMillis - ");Serial.println(currentMillis);
   // Serial.print("previousMillis - ");Serial.println(previousMillis);
   if(currentMillis - previousMillis > interval_repeat_req_mk) 
   {
    Serial.print("С отправки прошло  - ");Serial.println(currentMillis - previousMillis);
    if (!flag_mk_ansver){flag_mk_reepet=flag_mk_reepet+1;} //2.1 Посмотрел флаги запросов если есть не отвеченый установил счетчик запроса +1
    if (flag_mk_reepet>quantity__repeat_req_mk) //2.2 Если счетчик запросов более quantity__repeat_req_mk выдал аварию, установил счетчик запросов в 0 завершил функцию
      {
        Serial.println("!!!!!!!!!Авария");
        flag_mk_reepet=0;
        previousMillis=0;
        exit_function = true;
      message_number = message_number +1;
      if (message_number == 255) {message_number=1;}
      data[6]= 10;
      data[7]= message_number;        
        TX(1, ACCIDENT_SEND, Net_center_PC,null_s,BIT_29,DATA_FRAME,8,data); 
      } 
    if (!exit_function)
    { 
      message_number = message_number +1;
      if (message_number == 255) {message_number=1;}
      data[7]= message_number;
      data[6]= 0;
      TX(1, STATUS_REQUEST_SEND, rem_addr,null_s,BIT_29,DATA_FRAME,8,data); 
      Serial.print("Отправка в  - ");Serial.println(currentMillis);
      // сохраняем последний момент отправки
      previousMillis = currentMillis;
    }
 }

 

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

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

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

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

1. Центральный МК ничем кроме контроля и управления не занят, датчиков и ИУ не имеет и мощнее, это его задача.

2. как минимум у него должна быть процедура запросчик статуса инициативная по команде от сервера УД.

3. Никто не заставляет запрашивать постоянно, смотри алгоритм. Сверху именно процедура диагностики а это только запросчик.

Сейчас меня более беспокоит как избавиться от такаго кол-ва переменных. Только для опроса 1 контроллера используется 6 глобальных переменных. Если их 20 то будет 120, ну убавлю до 3 переменных  - только флаги, будет 60. Как то много.

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

Что то вроде

int array_reqvest_status[20][6]; (20 это контроллеры, а 6 это как раз те самые флаги и переменные)

Ну и писать и чтатать при опросе в/из массива. 

 

int array_reqvest_status[20][6] = 
//настройки опроса
{1,2,3,4,5,6,7,8,9,10,11,12,14,14,15,16,17,18,19,20}, //адрес контроллера
                            {1000,1000,2000,1000,1000,2000,1000,1000,2000,1000,1000,2000,1000,1000,2000,1000,1000,2000,1000,1000},  //interval_repeat_req_m
{3,4,4,3,5,3,4,4,3,5,3,4,4,3,5,3,4,4,3,5}, //quantity__repeat_req_mk
//переменные для работы
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, //previousMillis
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, //message_number
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, //flag_mk_ansver
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, //flag_mk_reepe
MaksVV
Offline
Зарегистрирован: 06.08.2015

вот приемник статусов (мастер). При условии, что узлы периодически сами шлют статус . Скетч не проверен!!! И сделай вкладку debug тоже файлом debug.h

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

#define debug                     //отладка в сериал_монитор. Закоментировать строку после отладки

#include "debug.h"






unsigned long prevtimeStatus = 0; //для таймера статус
unsigned long curMillis = 0;      //снимок машинного времени
const byte intervalStatus = 2;    //интервал таймера прибавления счетчика неответов

#define NODS_NUMBER 32             //количество узлов в сети
#define MAX_NoTAnsverCOUNT 5       //число счетчика неответов, превысив которое, делаем статус узла "Мёртв"


bool StatusNode_OK[NODS_NUMBER] = {0};      // массив состояние живы или нет узлы
byte countNoTAnsverNode[NODS_NUMBER] = {0}; // массив счетчиков неответов от узлов
                                            // номер элемента массива это АДРЕС УЗЛА В СЕТИ!!!
// ниже для мониторинга статуса
#ifdef debug
bool flagPrintStatus_down = 0;            
bool flagPrintStatus_up = 0;            
# define NODE_MONITOR_STATUS Boxroom_main   // тут выберем узел, статус которого будем мониторить
#endif

void setup() {
#ifdef debug
    Serial.begin(115200);
#endif 
 
  if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK)
   
#ifdef debug
    Serial.println(F("MCP2515 Initialized Successfully!"));
    else
    Serial.println(F("Error Initializing MCP2515..."));
#endif 
  
  CAN0.setMode(MCP_NORMAL);                     

  pinMode(CAN0_INT, INPUT);                            


}

void loop() {
curMillis = millis();

RX();

StatusControl();
}



void StatusControl () {

//создаем тикающий таймер раз в интервал
//по окончании которого, будут прибавляться счетчики неответов от узлов
//PS эти счетники будут сбрасываться в "0", если в фунции RX() принят ответ от узла
 
 if  (curMillis -prevtimeStatus > intervalStatus) {

 // ниже прибавляем счетчики неответов от узлов, если они ещё живы конечно
 for (int i = 0; i<NODS_NUMBER; i++) if (countNoTAnsverNode[i] > 5) if (StatusNode_OK[i])   countNoTAnsverNode[i]++; 
 
    prevtimeStatus = curMillis;
                                                  }
//ниже если счетчик превысил 5 
for (int i = 0; i<NODS_NUMBER; i++) if (countNoTAnsverNode[i] > 5) StatusNode_OK[i] = false;


// ниже отладка. Жалуемся в порт при отсутствии связи с узлом
#ifdef debug
if (!StatusNode_OK[NODE_MONITOR_STATUS] && !flagPrintStatus_down) {
 Serial.print   (F("Vnimanie! Net svyazi s ")) ;
 Serial.println (Node_addr_CANData[NODE_MONITOR_STATUS].node_name) ;

 flagPrintStatus_down = 1; flagPrintStatus_up = 0;
}
#endif   
  }




  
void RX()
{
  uint32_t rxId_can;
  byte len_can = 0;
  byte rxBuf_can[8];
  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    = (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


   
      //Начинаем разбор принятого
      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: { //выполняется когда удаленный контроллер мне отвечают на мой запрос состояния 
              
            countNoTAnsverNode[dev_addr] = 0; //если получили ответ от узла, сбрасываем счетчик неответов в ноль  
            StatusNode_OK[dev_addr] = true;   //и возвращаем статус "ЖИВ"
                                          }
      // ниже отладка. Жалуемся в порт при появлении связи с узлом

#ifdef debug
if (StatusNode_OK[NODE_MONITOR_STATUS] && !flagPrintStatus_up) {
 Serial.print (F("Status ")) ;
 Serial.print (Node_addr_CANData[NODE_MONITOR_STATUS].node_name) ;
 Serial.println   (F("OK ! ")) ;
 flagPrintStatus_down = 0; flagPrintStatus_up = 1;
}
#endif   
       
      
      //////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                 
              break;  
              default:
              {
                #ifdef debug
                Serial.print(F("Default msg - Recive Uncnown type message"));
                #endif
              }
      }
  }   
}

 

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

Только смотри, я предлагал 3 типа узлов

1. мастер - управление починенными контроллерами

2.слейв - те же функции что и мастера но если мастер не жив

3. подчиненный - датчики, ИУ

Соответственно нам нужно

1. Делать пин-понг между мастером и слейвом в обе стороны

(если мастер погиб, то его функции подхватил слейв, если слейв погиб то мастер выдал авария на вышестоящее у-во)

2. Опрашивать и/или собирать информацию от подчиненных о их статусе и выдавать выше.

Соответсвенно это у тебя функция 2 а я делаю пока функцию 1 и она должна быть пин-понг обязателььно, это резервирование.

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

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

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

оба могут Опрашивать и/или собирать информацию от подчиненных о их статусе и выдавать выше.

 

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

MaksVV пишет:

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

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

оба могут Опрашивать и/или собирать информацию от подчиненных о их статусе и выдавать выше.

Да но не одновремено, т.е если слейв видит что мастер жив то он не опрашивает подчиненные. 

Подчиненные все отсылают на мастер если слейв не прислал им сообщение что слать ему.

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

можно так. Ты в енумах добавь последним элементом размер. Чтобы знать количество элементов в енуме. типа так 

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_ENUM_SIZE      //7
} Message_CAN_ENUM;      

const byte size_Message_CAN_ENUM = MESSAGE_ENUM_SIZE;




void setup() {
  Serial.begin (115200);
  Serial.print (size_Message_CAN_ENUM); 
}

void loop() {}

 

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

MaksVV пишет:

можно так. Ты в енумах добавь последним элементом размер. Чтобы знать количество элементов в енуме. типа так 

Не уловил. Зачем добавлять, где это использовать?