Ладно. Последний разряд весь для типов данных это много. Возьмем один ниббл для этого. Остается еще 4 бита. Самый младший из них это будет флаг - мультик (поменял местами). Получается крайние биты заголовка будут отвечать за флаг мультика и маркер окончания мультика. Самый правый бит (младший) это флаг. Самый левый бит (старший) - маркер окончания.
Ладно. Последний разряд весь для типов данных это много. Возьмем один ниббл для этого. Остается еще 4 бита. Самый младший из них это будет флаг - мультик (поменял местами). Получается крайние биты заголовка будут отвечать за флаг мультика и маркер окончания мультика. Самый правый бит (младший) это флаг. Самый левый бит (старший) - маркер окончания.
Мне 32 типа для устройств мало, мне нужно не менее 128.
Тебе придется создать, для каждого типа свою базу данных. У каждого типа будет 256 адресов
Не совсем понял мысль.
И кстати проверяй код перед выкладыванием. Не работает. Сижу твой ТХ допиливаю.
Ты использовал функцию с определением 11 или 29 бит и FR через 0x80000000 и 0x40000000 но забыл их прибавить в ID, вот и не работает, шлет 11 битный ID (((. Я то в теме а народ скопирует и работать не будет. (
возми эту строку в фигурные скобки, после этой строки в эти же скобки добавь
txId_can = txId_can тут знак ИЛИ (одна палка вертик.) 0x80000000
Пс . Пишу с телефона.
возми эту строку в фигурные скобки, после этой строки в эти же скобки добавь txId_can = txId_can тут знак ИЛИ (одна палка вертик.) 0x80000000 Пс . Пишу с телефона.
короче не взял я с собой CAN модуль с работы, есть только дуня. Проверил ID перед отправкой - он становиться в правильном виде. Должно работать по идее
я вчера как раз всё это на канхакере и проверял. Всё идеально работало. Вручную правда (сам задавал ID) Потом уже скетч TX писал. Попробуй пример из библиотеки поотправлять.
я вчера как раз всё это на канхакере и проверял. Всё идеально работало. Вручную правда (сам задавал ID) Потом уже скетч TX писал. Попробуй пример из библиотеки поотправлять.
Короче пробуй последний скетч #367 Отпишись как в отладчике ID и дата пишется, отправляются ли RTR.
Сразу скажу, что RTR с CANhackera нормально не отправляется (только если DLC не ноль поставить, но тогда байты хаотично гуляют в поле данных). А на CANHacker RTR норм приходит от дуни
должен сказать, что CAN данные, которые будут стекаться на CAN-Мастер, выходит будут иметь уже не только свой адрес, но и адрес МК, от которого они пришли. Получается какбы двойной адрес,вернее адрес, представленный двумя с половиной байтами. Т.е. старший байт - адрес МК предоставившего данные, средний ниббл - тип данных и младший байт - адрес самих данных в этом типе.
Тебе придётся на мастере создавать большой список глобальных переменных, которым соответствуют все адреса. Перечисления это будут адреса, и им будут соответствовать эти глобальные переменные. Наподобие как ты большой список Стрингов адресовал.
будут иметь уже не только свой адрес, но и адрес МК, от которого они пришли. Получается какбы двойной адрес,вернее адрес, представленный двумя с половиной байтами. Т.е. старший байт - адрес МК предоставившего данные, средний ниббл - тип данных и младший байт - адрес самих данных в этом типе.
typedef enum Node_addr_enum содержит адреса всех контроллеров. В протоколе мы задали адрес получателя и отправителя. В чем вопрос. Либо я не совсем тебя понял.
Но идею ты подал хорошую
Смотри у нас 3 группы (пока) запрос-ответов
1. Опрос-ответ Контроллера (опрос состяний, версии прошивки , готовности и пр.)
2. Опрос-ответ датчика
3. Отправка -квитанция команды.
Соответственно в зависимости от того какой тип используем 1,2 или 3 используем разные ENUM в типе устройств
Вот смотрю о чем я толкую. Как сделано У меня на данный момент - данные по кан передаются в жестких местах в поле данных. Т.е. тип сообщения ДАТА имеет несколько страниц. Для каждого МК страницы свои и на них жестко указано в каких байтах что должно быть. Такой подход требует большую карту данных.
Мы же с тобой вроде как решили ввести адресацию данных. Т.е. у каждого параметра есть свой адрес. разрядность адреса - 1байт. При передаче данных в поле данных кадра сначала передается байт адреса, затем байт данных. Адреса в принципе ты уже задал в енум.
Дак вот сейчас нужно енумы отдельно для булевых задать, отдельно для одно и двубайтовых данных.
Смотри я в loop запускаю функцию по алгоритму ниже.
Ну и как мне ее обработать? Перестать на 3-5 секунд принимать другие данные?
Посмотри как у меня в скетче сделано, в начале нашей беседы. Там все на миллис. Отправили запрос -, флаг обращение к слейву - труе, таймер вкл, Счетчик +1. пока таймер тикает, не запрашиваем. Как только кончился опять запрос. Как наберется 10 - перестаем. Таймер и флаг наличия обращения к слейву и счетчик сбрасывает положительный ответ слейва
Вот смотрю о чем я толкую. Как сделано У меня на данный момент - данные по кан передаются в жестких местах в поле данных. Т.е. тип сообщения ДАТА имеет несколько страниц. Для каждого МК страницы свои и на них жестко указано в каких байтах что должно быть. Такой подход требует большую карту данных. Мы же с тобой вроде как решили ввести адресацию данных. Т.е. у каждого параметра есть свой адрес. разрядность адреса - 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 байт
Смотри я в loop запускаю функцию по алгоритму ниже.
Ну и как мне ее обработать? Перестать на 3-5 секунд принимать другие данные?
Посмотри как у меня в скетче сделано, в начале нашей беседы. Там все на миллис. Отправили запрос -, флаг обращение к слейву - труе, таймер вкл, Счетчик +1. пока таймер тикает, не запрашиваем. Как только кончился опять запрос. Как наберется 10 - перестаем. Таймер и флаг наличия обращения к слейву и счетчик сбрасывает положительный ответ слейва
Кинь плиз № сообщения. Уже вариантов кода столько, что запутаешься. Видимо ты говоришь о сообщени что реализовал, прокинул кабель на 2 этаж и все заработало, это сообщение?
1. RX() которая обрабатывает все что нам ответят на то что ниже у устанавливает флаг ответ получен на запрос ниже
2. Функция передачи запроса в которой
2.1 Посмотрел флаги запросов если есть не отвеченый установил счетчик запроса +1
2.2 Если счетчик запросов более 3 выдал аварию завершил функцию
2.3 Если счетчик 1 то запустил таймер, установил глобальнцю переменную с временем отправки запроса, считал номер последнего сообщения из глобальной переменной, добавил 1, записал глобальную переменную, отправил 1 й запрос с номером сообщения
2.4 Если счетчик 2 или 3 то сравнил время с гобальной переменной времени запроса
2.5 Если с времени запроса прошло больше чем в заданом таймауте и флаг отвтета не установлен то, читал номер последнего сообщения из глобальной переменной, добавил 1, записал глобальную переменную, делаем перезапрос
Короче это ппц. Эту функцию ставлю в loop. Без делеев. Она 3 раза отправляет запрос к МК и если не получает ответ то отправляет другому МК отчет авария. Если ответ будет получен то в RX нужно будет поставить flag_mk_ansver. Дальше я должен его какой то другой функцией периодически ставить в false чтобы опросить МК.
Serial.print("С отправки прошло - ");Serial.println(currentMillis - previousMillis);
18
if(!flag_mk_ansver){flag_mk_reepet=flag_mk_reepet+1;} //2.1 Посмотрел флаги запросов если есть не отвеченый установил счетчик запроса +1
19
if(flag_mk_reepet>quantity__repeat_req_mk) //2.2 Если счетчик запросов более quantity__repeat_req_mk выдал аварию, установил счетчик запросов в 0 завершил функцию
Я не пойму зачем все время слать запрос статуса , это лишнее сообщение в шине. Пусть узлы сами его периодически шлют.
1. Центральный МК ничем кроме контроля и управления не занят, датчиков и ИУ не имеет и мощнее, это его задача.
2. как минимум у него должна быть процедура запросчик статуса инициативная по команде от сервера УД.
3. Никто не заставляет запрашивать постоянно, смотри алгоритм. Сверху именно процедура диагностики а это только запросчик.
Сейчас меня более беспокоит как избавиться от такаго кол-ва переменных. Только для опроса 1 контроллера используется 6 глобальных переменных. Если их 20 то будет 120, ну убавлю до 3 переменных - только флаги, будет 60. Как то много.
Думаю про двумерный массив. И не знаю что более критично по ресурсу массив заполнять или флаги менять.
Что то вроде
int array_reqvest_status[20][6]; (20 это контроллеры, а 6 это как раз те самые флаги и переменные)
Твой код из #379 не собирается. Сейчас поправлю выложу.
Ладно. Последний разряд весь для типов данных это много. Возьмем один ниббл для этого. Остается еще 4 бита. Самый младший из них это будет флаг - мультик (поменял местами). Получается крайние биты заголовка будут отвечать за флаг мультика и маркер окончания мультика. Самый правый бит (младший) это флаг. Самый левый бит (старший) - маркер окончания.
Мне 32 типа для устройств мало, мне нужно не менее 128.
Да и в TX() нет смысла node_addr передавать, он жестко забит в глобальной переменной, это наш адрес.
Убираем?
Да я тоже об этом думал, убираем
Это не типы устройств, а тип переменных.
Тебе придется создать, для каждого типа свою базу данных. У каждого типа будет 256 адресов
Можно также через перечисления
Не совсем понял мысль.
И кстати проверяй код перед выкладыванием. Не работает. Сижу твой ТХ допиливаю.
Ты использовал функцию с определением 11 или 29 бит и FR через 0x80000000 и 0x40000000 но забыл их прибавить в ID, вот и не работает, шлет 11 битный ID (((. Я то в теме а народ скопирует и работать не будет. (
1
if
(!can_ID_type) {}
// тут как-то формируем 11 битный ID если нужно
2
3
else
txId_can = (direction & 0xFFFFFFFF)<<28 | (msg_type & 0xFFFFFFFF)<<24 | (dev_addr & 0xFFFFFFFF)<<16 | (rem_addr & 0xFFFFFFFF)<<8 | dev_type;
4
5
//ниже если это REMOTE FRAME подравняем ID, а DLC в ноль
6
if
(can_frame_type) {txId_can = txId_can | 0xC0000000; DLC = 0;}
7
8
byte
sndStat = CAN0.sendMsgBuf(txId_can, DLC, data);
//отсылаем кадр в CAN
Это НЕ рабочий код.
Покажи как функцию вызываешь
Выведи перед 8 строкой в порт переменную с ID, посмотреть нужно в каком она виде перед отправкой
Писал код на коленке, не на чем проверить.
Прибавлять там ничего не надо вроде
1
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
1
txId_can = (direction & 0xFFFFFFFF)<<28 | (msg_type & 0xFFFFFFFF)<<24 | (dev_addr & 0xFFFFFFFF)<<16 | (rem_addr & 0xFFFFFFFF)<<8 | dev_type;
А вот твой вызов
1
byte
sndStat = CAN0.sendMsgBuf(txId_can,DLC, data);
//отсылаем кадр в CAN
возми эту строку в фигурные скобки, после этой строки в эти же скобки добавь
txId_can = txId_can тут знак ИЛИ (одна палка вертик.) 0x80000000
Пс . Пишу с телефона.
Не работает.
CAN hacker видит либо 11 бит либо вообще ничего.
Щас мин через40 напишу, у меня же блин, все работало
короче не взял я с собой CAN модуль с работы, есть только дуня. Проверил ID перед отправкой - он становиться в правильном виде. Должно работать по идее
01
#define EXTENDED 1
02
#define STANDART 0
03
#define DATA_FRAME 0
04
#define REMOTE_FRAME 1
05
06
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])
07
{
08
uint32_t txId_can;
09
10
if
(!can_ID_type) {}
// тут как-то формируем 11 битный ID если нужно
11
12
else
txId_can = (direction & 0xFFFFFFFF)<<28 | (msg_type & 0xFFFFFFFF)<<24 | (dev_addr & 0xFFFFFFFF)<<16 | (rem_addr & 0xFFFFFFFF)<<8 | dev_type;
13
14
15
16
//ниже если это REMOTE FRAME подровняем ID, а DLC в ноль
17
if
(can_frame_type) {txId_can = txId_can | 0xC0000000; DLC = 0;}
18
else
txId_can = txId_can | 0x80000000;
// иначе формируем 29 битный ID DATA_FRAME
19
20
byte
sndStat = CAN0.sendMsgBuf(txId_can, DLC, data);
//отсылаем кадр в CAN
21
22
#ifdef debug
23
if
(sndStat == CAN_OK){
Serial
.print(F(
"Message Sent Successfully! - "
));
Serial
.print(txId_can, HEX);
24
Serial
.print (
" "
);
if
(DLC!=0) {
for
(
int
i=0; i<DLC; i++) {
25
if
(data<=0x0F)
Serial
.print (
"0"
);
26
Serial
.print (data[i]);
Serial
.print (
" "
); }}
27
Serial
.println();
28
}
29
else
Serial
.println(F(
"Error Sending Message..."
));
30
#endif
31
}
32
33
// вызов TX (direction, тип сообщения, адрес отправителя, адрес получателя, тип устройства, тип ID, тип FRAME, длина поля данных кадра, data)
34
// тип ID 0 - 11 bit; 1 - 29 bit
35
// тип FRAME 0 - DATA; 1 - REMOTE FRAME
36
37
// вызов TX (1, STATUS_REQUEST_ANSVER, node_address, rem_addr, null_s, EXTENDED, DATA_FRAME, 8, data)
Меня терзают смутные сомнения, ты где то писал что CanHacker как то плохо 29 бит ловит, может дело в нем? Ты 8 на D менял?
я вчера как раз всё это на канхакере и проверял. Всё идеально работало. Вручную правда (сам задавал ID) Потом уже скетч TX писал. Попробуй пример из библиотеки поотправлять.
01
// CAN Send Example
02
//
03
04
#include <mcp_can.h>
05
#include <SPI.h>
06
07
MCP_CAN CAN0(10);
// Set CS to pin 10
08
09
void
setup
()
10
{
11
Serial
.begin(115200);
12
13
// Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
14
if
(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK)
Serial
.println(
"MCP2515 Initialized Successfully!"
);
15
else
Serial
.println(
"Error Initializing MCP2515..."
);
16
17
CAN0.setMode(MCP_NORMAL);
// Change to normal mode to allow messages to be transmitted
18
}
19
20
byte
data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
21
22
void
loop
()
23
{
24
25
byte
sndStat = CAN0.sendMsgBuf(0x8FAB04C6, 8, data);
26
if
(sndStat == CAN_OK){
27
Serial
.println(
"Message Sent Successfully!"
);
28
}
else
{
29
Serial
.println(
"Error Sending Message..."
);
30
}
31
delay(100);
// send data per 100ms
32
}
33
34
/*********************************************************************************************************
35
END FILE
36
*********************************************************************************************************/
У меня при отправке CAN0.sendMsgBuf(0x8FAB04C6, 8, data); выдавалось 0x0FAB04C6
при отправке CAN0.sendMsgBuf(0xCFAB04C6, 8, data); выдавалось 0x0FAB04C6 но RTR
при отправке CAN0.sendMsgBuf(0x4BC, 8, data); выдавалось 0x4BC
В общем CanHacker так видит причем только 4С6
1
byte
sndStat = CAN0.sendMsgBuf(0x8FAB04C6,0, 8, data);
а так не видит ничего (((((((((((((((
1
byte
sndStat = CAN0.sendMsgBuf(0x8FAB04C6,1, 8, data);
По колесу пинал, дверью хлопал ) в смысле Win перегружал, ардуину тоже, скетч переливал.
попробуй свою либу временно удали, вот эту поставь, может я на ней пробовал.
Или ещё эту
а вот так ?
1
byte
sndStat = CAN0.sendMsgBuf(0x1FAB04C6,1, 8, data);
и не забывай везде скорость шины одну ставить и про 8 MHZ кварца
а вот так ?
1
byte
sndStat = CAN0.sendMsgBuf(0x1FAB04C6,1, 8, data);
Так видит.
1
byte
sndStat = CAN0.sendMsgBuf(0x1FAB04C6, 8, data);
Так видит как 4С6
1
byte
sndStat = CAN0.sendMsgBuf(0x8FAB04C6, 8, data);
Так пошло
попробуй также, залей на другой модуль (вместо анализатора) пример Read этой <mcp2515.h> и смотри приходят ли 29 бит.
01
#include <SPI.h>
02
#include <mcp2515.h>
03
04
struct
can_frame canMsg;
05
MCP2515 mcp2515(10);
06
07
08
void
setup
() {
09
Serial
.begin(115200);
10
SPI.begin();
11
12
mcp2515.reset();
13
mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ);
14
mcp2515.setNormalMode();
15
16
Serial
.println(
"------- CAN Read ----------"
);
17
Serial
.println(
"ID DLC DATA"
);
18
}
19
20
void
loop
() {
21
22
if
(mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
23
24
Serial
.print(canMsg.can_id, HEX);
// print ID
25
Serial
.print(
" "
);
26
Serial
.print(canMsg.can_dlc, HEX);
// print DLC
27
Serial
.print(
" "
);
28
29
for
(
int
i = 0; i<canMsg.can_dlc; i++) {
// print the data
30
31
Serial
.print(canMsg.data[i],HEX);
32
Serial
.print(
" "
);
33
34
}
35
36
Serial
.println();
37
}
38
39
}
1
byte
sndStat = CAN0.sendMsgBuf(0x8FAB04C6, 8, data);
Так пошло
вот я же предлагал такой пример.
я вчера как раз всё это на канхакере и проверял. Всё идеально работало. Вручную правда (сам задавал ID) Потом уже скетч TX писал. Попробуй пример из библиотеки поотправлять.
01
// CAN Send Example
02
//
03
04
#include <mcp_can.h>
05
#include <SPI.h>
06
07
MCP_CAN CAN0(10);
// Set CS to pin 10
08
09
void
setup
()
10
{
11
Serial
.begin(115200);
12
13
// Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
14
if
(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK)
Serial
.println(
"MCP2515 Initialized Successfully!"
);
15
else
Serial
.println(
"Error Initializing MCP2515..."
);
16
17
CAN0.setMode(MCP_NORMAL);
// Change to normal mode to allow messages to be transmitted
18
}
19
20
byte
data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
21
22
void
loop
()
23
{
24
25
byte
sndStat = CAN0.sendMsgBuf(0x8FAB04C6, 8, data);
26
if
(sndStat == CAN_OK){
27
Serial
.println(
"Message Sent Successfully!"
);
28
}
else
{
29
Serial
.println(
"Error Sending Message..."
);
30
}
31
delay(100);
// send data per 100ms
32
}
33
34
/*********************************************************************************************************
35
END FILE
36
*********************************************************************************************************/
У меня при отправке CAN0.sendMsgBuf(0x8FAB04C6, 8, data); выдавалось 0x0FAB04C6
при отправке CAN0.sendMsgBuf(0xCFAB04C6, 8, data); выдавалось 0x0FAB04C6 но RTR
при отправке CAN0.sendMsgBuf(0x4BC, 8, data); выдавалось 0x4BC
Честно говоря сработало что то из вышеперечисленного, я всзял по CanHacker новый контроллер с MCP, перезалил его, ребутнул систему и скетч пошел.
P.S
У меня ноут на док станции, а USB к докстанции подключены. Снимаю с док станции USB отключается. CanHacker падает.
сначала отключай от кан. (Кнопка с красным крестиком), не будет виснуть.
Короче пробуй последний скетч #367 Отпишись как в отладчике ID и дата пишется, отправляются ли RTR.
Сразу скажу, что RTR с CANhackera нормально не отправляется (только если DLC не ноль поставить, но тогда байты хаотично гуляют в поле данных). А на CANHacker RTR норм приходит от дуни
и попробуй отправить 0x200001AB, по идее должен 11-битный 1AB RTR отправиться
Так , для прикола. Просто я не пробовал REMOTE_FRAME для 11-бит
Я разбил проект на n файлов, смотри https://yadi.sk/d/zkejlJ3K3Td48S
На меге собирается, CanHacker видит.
Дальше займусь обработчиками протокола сверху вниз.
1. Опрос-обмен контроллеров Master,Slave, Base
2. Опрос-обмен датчиков
3.Отправка -квитанция команды
Глобальные переменные в struct.h
Поцедуры и функции в отдельные файлы xxx.ino по типам
Потом после отладки выкинем протокол в либу и пиши логику работы дома.
PS
У тебя как то ловче получается с битами байтами так что я туда пока не полезу. Я имею ввиду мультифрейм, RF установка RTR и пр.
ок время будет, буду править прогу
и попробуй отправить 0x200001AB, по идее должен 11-битный 1AB RTR отправиться
Так , для прикола. Просто я не пробовал REMOTE_FRAME для 11-бит
проверил, работает. только нужно не 2 в начале , а 6. Вот так отпраляется FR 11 бит
0x600007CC
должен сказать, что CAN данные, которые будут стекаться на CAN-Мастер, выходит будут иметь уже не только свой адрес, но и адрес МК, от которого они пришли. Получается какбы двойной адрес,вернее адрес, представленный двумя с половиной байтами. Т.е. старший байт - адрес МК предоставившего данные, средний ниббл - тип данных и младший байт - адрес самих данных в этом типе.
Тебе придётся на мастере создавать большой список глобальных переменных, которым соответствуют все адреса. Перечисления это будут адреса, и им будут соответствовать эти глобальные переменные. Наподобие как ты большой список Стрингов адресовал.
по идее тут нужно двумерные массивы использовать.
будут иметь уже не только свой адрес, но и адрес МК, от которого они пришли. Получается какбы двойной адрес,вернее адрес, представленный двумя с половиной байтами. Т.е. старший байт - адрес МК предоставившего данные, средний ниббл - тип данных и младший байт - адрес самих данных в этом типе.
typedef enum Node_addr_enum содержит адреса всех контроллеров. В протоколе мы задали адрес получателя и отправителя. В чем вопрос. Либо я не совсем тебя понял.
Но идею ты подал хорошую
Смотри у нас 3 группы (пока) запрос-ответов
1. Опрос-ответ Контроллера (опрос состяний, версии прошивки , готовности и пр.)
2. Опрос-ответ датчика
3. Отправка -квитанция команды.
Соответственно в зависимости от того какой тип используем 1,2 или 3 используем разные ENUM в типе устройств
И соответвенно можно ввести
Тип
4. Мултифрейм
ит еще что нибудь придумать
Ага, вот я и уткнулся в то что RX() в чистом виде не имеет смысла.
Смотри я в loop запускаю функцию по алгоритму ниже.
Ну и как мне ее обработать? Перестать на 3-5 секунд принимать другие данные?
Файл с алгоритмом и структурой сети смотри в https://yadi.sk/d/zkejlJ3K3Td48S
Вот смотрю о чем я толкую. Как сделано У меня на данный момент - данные по кан передаются в жестких местах в поле данных. Т.е. тип сообщения ДАТА имеет несколько страниц. Для каждого МК страницы свои и на них жестко указано в каких байтах что должно быть. Такой подход требует большую карту данных.
Мы же с тобой вроде как решили ввести адресацию данных. Т.е. у каждого параметра есть свой адрес. разрядность адреса - 1байт. При передаче данных в поле данных кадра сначала передается байт адреса, затем байт данных. Адреса в принципе ты уже задал в енум.
Дак вот сейчас нужно енумы отдельно для булевых задать, отдельно для одно и двубайтовых данных.
Смотри я в loop запускаю функцию по алгоритму ниже.
Ну и как мне ее обработать? Перестать на 3-5 секунд принимать другие данные?
Посмотри как у меня в скетче сделано, в начале нашей беседы. Там все на миллис. Отправили запрос -, флаг обращение к слейву - труе, таймер вкл, Счетчик +1. пока таймер тикает, не запрашиваем. Как только кончился опять запрос. Как наберется 10 - перестаем. Таймер и флаг наличия обращения к слейву и счетчик сбрасывает положительный ответ слейва
Давай немного подробнее.
1. Со структурой CAn ID определились, ее не трогаем? (Единстуенное посмотри что я предлагал немного выше
Смотри я в loop запускаю функцию по алгоритму ниже.
Ну и как мне ее обработать? Перестать на 3-5 секунд принимать другие данные?
Кинь плиз № сообщения. Уже вариантов кода столько, что запутаешься. Видимо ты говоришь о сообщени что реализовал, прокинул кабель на 2 этаж и все заработало, это сообщение?
Пока на ум приходит такое извращение
в loop
1. RX() которая обрабатывает все что нам ответят на то что ниже у устанавливает флаг ответ получен на запрос ниже
2. Функция передачи запроса в которой
2.1 Посмотрел флаги запросов если есть не отвеченый установил счетчик запроса +1
2.2 Если счетчик запросов более 3 выдал аварию завершил функцию
2.3 Если счетчик 1 то запустил таймер, установил глобальнцю переменную с временем отправки запроса, считал номер последнего сообщения из глобальной переменной, добавил 1, записал глобальную переменную, отправил 1 й запрос с номером сообщения
2.4 Если счетчик 2 или 3 то сравнил время с гобальной переменной времени запроса
2.5 Если с времени запроса прошло больше чем в заданом таймауте и флаг отвтета не установлен то, читал номер последнего сообщения из глобальной переменной, добавил 1, записал глобальную переменную, делаем перезапрос
Короче это ппц. Эту функцию ставлю в loop. Без делеев. Она 3 раза отправляет запрос к МК и если не получает ответ то отправляет другому МК отчет авария. Если ответ будет получен то в RX нужно будет поставить flag_mk_ansver. Дальше я должен его какой то другой функцией периодически ставить в false чтобы опросить МК.
01
long
interval_repeat_req_mk = 2000;
02
int
quantity__repeat_req_mk=3;
03
long
previousMillis = 0;
// время, когда отправлен запрос
04
byte
message_number = 0;
05
bool
flag_mk_ansver =
false
;
06
int
flag_mk_reepet = 0;
07
unsigned
long
currentMillis = millis();
08
09
//отправка опроса удаленному МК на предмет жив не жив
10
void
send_status_reqvest(uint8_t rem_addr)
11
{
12
bool
exit_function =
false
;
13
// Serial.print("currentMillis - ");Serial.println(currentMillis);
14
// Serial.print("previousMillis - ");Serial.println(previousMillis);
15
if
(currentMillis - previousMillis > interval_repeat_req_mk)
16
{
17
Serial
.print(
"С отправки прошло - "
);
Serial
.println(currentMillis - previousMillis);
18
if
(!flag_mk_ansver){flag_mk_reepet=flag_mk_reepet+1;}
//2.1 Посмотрел флаги запросов если есть не отвеченый установил счетчик запроса +1
19
if
(flag_mk_reepet>quantity__repeat_req_mk)
//2.2 Если счетчик запросов более quantity__repeat_req_mk выдал аварию, установил счетчик запросов в 0 завершил функцию
20
{
21
Serial
.println(
"!!!!!!!!!Авария"
);
22
flag_mk_reepet=0;
23
previousMillis=0;
24
exit_function =
true
;
25
message_number = message_number +1;
26
if
(message_number == 255) {message_number=1;}
27
data[6]= 10;
28
data[7]= message_number;
29
TX(1, ACCIDENT_SEND, Net_center_PC,null_s,BIT_29,DATA_FRAME,8,data);
30
}
31
if
(!exit_function)
32
{
33
message_number = message_number +1;
34
if
(message_number == 255) {message_number=1;}
35
data[7]= message_number;
36
data[6]= 0;
37
TX(1, STATUS_REQUEST_SEND, rem_addr,null_s,BIT_29,DATA_FRAME,8,data);
38
Serial
.print(
"Отправка в - "
);
Serial
.println(currentMillis);
39
// сохраняем последний момент отправки
40
previousMillis = currentMillis;
41
}
42
}
Я не пойму зачем все время слать запрос статуса , это лишнее сообщение в шине. Пусть узлы сами его периодически шлют.
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вот приемник статусов (мастер). При условии, что узлы периодически сами шлют статус . Скетч не проверен!!! И сделай вкладку debug тоже файлом debug.h
001
#include <mcp_can.h>
002
#include <SPI.h>
003
#include "can_struct.h"
004
005
#define debug //отладка в сериал_монитор. Закоментировать строку после отладки
006
007
#include "debug.h"
008
009
010
011
012
013
014
unsigned
long
prevtimeStatus = 0;
//для таймера статус
015
unsigned
long
curMillis = 0;
//снимок машинного времени
016
const
byte
intervalStatus = 2;
//интервал таймера прибавления счетчика неответов
017
018
#define NODS_NUMBER 32 //количество узлов в сети
019
#define MAX_NoTAnsverCOUNT 5 //число счетчика неответов, превысив которое, делаем статус узла "Мёртв"
020
021
022
bool
StatusNode_OK[NODS_NUMBER] = {0};
// массив состояние живы или нет узлы
023
byte
countNoTAnsverNode[NODS_NUMBER] = {0};
// массив счетчиков неответов от узлов
024
// номер элемента массива это АДРЕС УЗЛА В СЕТИ!!!
025
// ниже для мониторинга статуса
026
#ifdef debug
027
bool
flagPrintStatus_down = 0;
028
bool
flagPrintStatus_up = 0;
029
# define NODE_MONITOR_STATUS Boxroom_main // тут выберем узел, статус которого будем мониторить
030
#endif
031
032
void
setup
() {
033
#ifdef debug
034
Serial
.begin(115200);
035
#endif
036
037
if
(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK)
038
039
#ifdef debug
040
Serial
.println(F(
"MCP2515 Initialized Successfully!"
));
041
else
042
Serial
.println(F(
"Error Initializing MCP2515..."
));
043
#endif
044
045
CAN0.setMode(MCP_NORMAL);
046
047
pinMode(CAN0_INT, INPUT);
048
049
050
}
051
052
void
loop
() {
053
curMillis = millis();
054
055
RX();
056
057
StatusControl();
058
}
059
060
061
062
void
StatusControl () {
063
064
//создаем тикающий таймер раз в интервал
065
//по окончании которого, будут прибавляться счетчики неответов от узлов
066
//PS эти счетники будут сбрасываться в "0", если в фунции RX() принят ответ от узла
067
068
if
(curMillis -prevtimeStatus > intervalStatus) {
069
070
// ниже прибавляем счетчики неответов от узлов, если они ещё живы конечно
071
for
(
int
i = 0; i<NODS_NUMBER; i++)
if
(countNoTAnsverNode[i] > 5)
if
(StatusNode_OK[i]) countNoTAnsverNode[i]++;
072
073
prevtimeStatus = curMillis;
074
}
075
//ниже если счетчик превысил 5
076
for
(
int
i = 0; i<NODS_NUMBER; i++)
if
(countNoTAnsverNode[i] > 5) StatusNode_OK[i] =
false
;
077
078
079
// ниже отладка. Жалуемся в порт при отсутствии связи с узлом
080
#ifdef debug
081
if
(!StatusNode_OK[NODE_MONITOR_STATUS] && !flagPrintStatus_down) {
082
Serial
.print (F(
"Vnimanie! Net svyazi s "
)) ;
083
Serial
.println (Node_addr_CANData[NODE_MONITOR_STATUS].node_name) ;
084
085
flagPrintStatus_down = 1; flagPrintStatus_up = 0;
086
}
087
#endif
088
}
089
090
091
092
093
094
void
RX()
095
{
096
uint32_t rxId_can;
097
byte
len_can = 0;
098
byte
rxBuf_can[8];
099
if
(!digitalRead(CAN0_INT))
// If CAN0_INT pin is low, read receive buffer
100
{
101
CAN0.readMsgBuf(&rxId_can, &len_can, rxBuf_can);
// Read data: len = data length, buf = data byte(s)
102
103
uint8_t msg_type, dev_addr, rem_addr, dev_type;
104
bool
direction, can_frame_type, can_ID_type;
105
uint8_t data_b0,data_b1,data_b2,data_b3,data_b4,data_b5,data_b6,data_b7;
106
107
can_ID_type = (rxId_can & 0x80000000)>>31;
//извлекаем тип ID (0 - 11bit, 1 - 29 bit)
108
can_frame_type = (rxId_can & 0x40000000)>>30;
//извлекаем тип СAN FRAME (0 - Data, 1 - Remote)
109
110
direction = (rxId_can & 0x10000000)>>28;
// извлекаем 1-битный идентификатор запроса-ответа из ID
111
msg_type = (rxId_can & 0xF000000)>>24;
// извлекаем 4-битный идентификатор сообщения из ID
112
dev_addr = (rxId_can & 0xFF0000)>>16;
// извлекаем 8-битный адрес отправителя из ID
113
rem_addr = (rxId_can & 0xFF00)>>8;
// извлекаем 8-битный адрес получателя из ID
114
dev_type = rxId_can;
// извлекаем 8-битный тип устройства у получателя из ID
115
116
117
118
//Начинаем разбор принятого
119
switch
(msg_type){
120
121
case
COMMAND_SEND:
//выполняется, когда мне прислали команду от удаленного контроллера
122
// Функция обработки присланой команды от удаленного контроллера
123
// Что за команда запрошена
124
break
;
125
case
REQUEST_SEND:
//выполняется когда удаленный контроллер у меня запросил параметр датчика или еще чего то
126
// Функция обработки присланного запроса параметра с датчика
127
// Что за датчик запрошен
128
break
;
129
case
STATUS_REQUEST_SEND:
//выполняется когда удаленный контроллер у меня запрашивает состояние
130
// Функция обработки запроса моего состояния
131
// Вернуть состояние
132
break
;
133
// выполняется когда мне отвечают на мой запрос
134
case
COMMAND_ANSVER:
//выполняется когда удаленный контроллер отвечает на посланную команду
135
// Функция обработки ответа на мою команду
136
break
;
137
case
REQUEST_ANSVER:
//выполняется когда удаленный контроллер мне отвечают на мой запрос параметра датчика
138
// Функция обработки ответа на мой запрос параметра датчика
139
break
;
140
141
//////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
142
143
case
STATUS_REQUEST_ANSVER: {
//выполняется когда удаленный контроллер мне отвечают на мой запрос состояния
144
145
countNoTAnsverNode[dev_addr] = 0;
//если получили ответ от узла, сбрасываем счетчик неответов в ноль
146
StatusNode_OK[dev_addr] =
true
;
//и возвращаем статус "ЖИВ"
147
}
148
// ниже отладка. Жалуемся в порт при появлении связи с узлом
149
150
#ifdef debug
151
if
(StatusNode_OK[NODE_MONITOR_STATUS] && !flagPrintStatus_up) {
152
Serial
.print (F(
"Status "
)) ;
153
Serial
.print (Node_addr_CANData[NODE_MONITOR_STATUS].node_name) ;
154
Serial
.println (F(
"OK ! "
)) ;
155
flagPrintStatus_down = 0; flagPrintStatus_up = 1;
156
}
157
#endif
158
159
160
//////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
161
162
break
;
163
default
:
164
{
165
#ifdef debug
166
Serial
.print(F(
"Default msg - Recive Uncnown type message"
));
167
#endif
168
}
169
}
170
}
171
}
Только смотри, я предлагал 3 типа узлов
1. мастер - управление починенными контроллерами
2.слейв - те же функции что и мастера но если мастер не жив
3. подчиненный - датчики, ИУ
Соответственно нам нужно
1. Делать пин-понг между мастером и слейвом в обе стороны
(если мастер погиб, то его функции подхватил слейв, если слейв погиб то мастер выдал авария на вышестоящее у-во)
2. Опрашивать и/или собирать информацию от подчиненных о их статусе и выдавать выше.
Соответсвенно это у тебя функция 2 а я делаю пока функцию 1 и она должна быть пин-понг обязателььно, это резервирование.
- мастер будет также периодически слать слейву жив он или нет
- слейв будет также периодически слать мастеру жив он или нет
оба могут Опрашивать и/или собирать информацию от подчиненных о их статусе и выдавать выше.
- мастер будет также периодически слать слейву жив он или нет
- слейв будет также периодически слать мастеру жив он или нет
оба могут Опрашивать и/или собирать информацию от подчиненных о их статусе и выдавать выше.
Да но не одновремено, т.е если слейв видит что мастер жив то он не опрашивает подчиненные.
Подчиненные все отсылают на мастер если слейв не прислал им сообщение что слать ему.
можно так. Ты в енумах добавь последним элементом размер. Чтобы знать количество элементов в енуме. типа так
01
typedef
enum
Message_enum
02
{
03
NULL_C,
//0
04
COMMAND_SEND,
//1
05
COMMAND_ANSVER,
//2
06
REQUEST_SEND,
//3
07
REQUEST_ANSVER,
//4
08
STATUS_REQUEST_SEND,
//5
09
STATUS_REQUEST_ANSVER,
//6
10
MESSAGE_ENUM_SIZE
//7
11
} Message_CAN_ENUM;
12
13
const
byte
size_Message_CAN_ENUM = MESSAGE_ENUM_SIZE;
14
15
16
17
18
void
setup
() {
19
Serial
.begin (115200);
20
Serial
.print (size_Message_CAN_ENUM);
21
}
22
23
void
loop
() {}
можно так. Ты в енумах добавь последним элементом размер. Чтобы знать количество элементов в енуме. типа так
Не уловил. Зачем добавлять, где это использовать?