Ви не увійшли.
В якості proof of concept написав для викладеної вище "плати розробника" ось таку прошивку owio_mhtiny_i2c_ssd1306_128x32.hex В ній крутиться ось такий цикл:
int main() {
lcd_init();
owio_start();
for(;;) {
int c = getchar();
if (c != EOF)
lcd_putchar(c);
}
}
До mh-tiny підключаєм по i2c дисплей 128x32, саму mh-tiny її 1-wire інтерфейсом підключаєм до nano. На nano закачуєм прошивку:
avrdude -P /dev/ttyUSB0 -c arduino -p m328p -U flash:w:ArduinoOWISP.hex
Обираєм порт і адресу (в мене 1-wire на D2):
stty -F /dev/ttyUSB0 19200
echo -ne '#02[2043420F484E5927]' >/dev/ttyUSB0
Закачуєм прошивку на mh-tiny:
avrdude -P /dev/ttyUSB0 -b 19200 -c avrisp -p t88 -U flash:w:owio_mhtiny_i2c_ssd1306_128x32.hex
Активуєм з'єднання з owio на mh-tiny:
echo -ne '\r' >/dev/ttyUSB0
Тепер все, що ми відправляєм в ttyUSB0, буде друкуватись на екранчику. Крім звичайних символів я реалізував лише два спецсимволи: '\b' - очистка всього екрану, '\n' - друк з нового рядка. Коли символи не вміщаються в рядку, автоматично відбувається перехід на новий рядок, коли треба перейти на новий рядок з останнього, автоматично відбувається прокрутка на один рядок вгору.
Виконую таке:
echo -ne "\bQuick brown fox jumps over the lazy dog. На подушечці форми любої є й ґудзик щоб пір'я геть жовте сховати." |iconv -f koi8-u -t cp1251 >/dev/ttyUSB0
На екранчику відображається таке:
Ця "консоль" розуміє кодування Windows Codepage 1251, тому я у себе під лінуксом роблю конвертацію.
Як це можна корисно використати? Можна наприклад виводити з баш-скриптів якісь повідомлення чи логи. Ось так, наприклад, виглядає вивід команди:
tail -f /var/log/messages >/dev/ttyUSB0
Для тих, хто програмує на Сі, є аналог OWSerial, це ось така бібліотечка owio, яка дозволяє використовувати всі функції бібліотеки stdio.h для обміну по 1-wire. Приклад коду з використанням цієї бібліотеки:
#include <owio.h>
#include <util/delay.h>
int main() {
owio_start();
for (;;) {
printf("Hello, World!\n");
_delay_ms(1000);
}
}
Викладаю фото MH-Tiny, підключеної по SPI до розширювача портів, таку "плату розробника" можна запрграмувати як якийсь складний 1-wire датчик (на основі результатів від кількох датчиків щось обраховувати) або автономний виконавчий пристрій з якоюсь своєю логікою роботи, якою можна ще й керувати по 1-wire. Ну і звичайно ж оновлювати прошивку віддалено і будувати вкладені 1-wire мережі, як описано в попередніх постах.
Чому MH-Tiny а не Pro-mini як на схемі у прикладах? Ця платка виявилась зручною тим, що зі зворотнього боку не має деталей і її 6 виводів (ISP) з 7 необхідних розташовані на краю. Не менш цікавою була б ось така платка, але на аліекспресі її не побачив, буду вдячний, якщо хтось підкаже, по якому ключовому слову її там знайти.
Щоб ще більш спростити процес розробки ПЗ на віддаленій ардуіні, додав в ArduinoOWISP ще кілька команд:
[2041420f484e5949] - встановити поточну 1-wire адресу віддаленої ардуіни;
#07 - встановити номер піна ардуіни, до якого підключена шина 1-wire;
? - просканувати шину 1-wire і вивести знайдені адреси пристроїв, поточна адреса помічаєтьс в списку значком '<', якщо була знайдена, або значком '?', якщо не була знайдена при скануванні, поточний номер піна також виводиться;
Повернення каретки (CR, Enter або Ctrl+M в minicom, '\r' з командного радка лінукс) - встановлення двонаправленого каналу зв'язку з бібліотекою OWSerial на віддаленій ардуіні і перехід в режим ретранслятора в свій Serial (все що виводиться в OWSerial на віддаленій ардуіні, ми отримуєм в моніторі порта, все що натискаємо - передається на віддалену ардуіну). За замовчуванням вихід з цього режиму відбувається коли виконати будь-яку операцію з avrdude.
! - змінити алгоритм попередньої команди так, щоб вихід з режиму ретранслятора не відбувався. Для виходу з режиму буде потрібен ресет.
Команди можна передавати в моніторі порта (але зверніть увагу, CR (Enter) після команди не потрібен, це взагалі самостійна команда), а в лінуксі можна ще й з командного рядка, наприклад так:
echo -n '#02[2041420F484E5949]' >/dev/ttyUSB0
Таким чином відпадає потреба перекомпільовувати ArduinoOWISP заради зміни піна чи 1-wire адреси.
Продемонструю, як це виглядає, наприклад підключаюсь minicom-ом так:
minicom -D /dev/ttyUSB0 -b 19200
і в ньому натискаю клавішу '?', ось що виводиться:
#07
[5555555555555555]?
За замовчанням в прошивку вкомпільовані номер піна 7 і адреса 5555555555555555, яка, звичайно, не знайдена (значок '?'). Спочатку зміню номер піна, в мене шина 1-wire підключена до D2, ввожу три символи '#02' (вони не відображаються) і знову натискаю '?':
#07
[5555555555555555]?
#02
[2041420F484E5949]
[5555555555555555]?
Побачило мій пристрій, але активний зараз інший, роблю copy&paste [2041420F484E5949] і знов натискаю '?':
#07
[5555555555555555]?
#02
[2041420F484E5949]
[5555555555555555]?
#02
[2041420F484E5949]<
Тепер поточним став мій пристрій і він присутній на шині. Я навмисно залишав вивід попередніх команд, щоб було видно, що введені нами команди не відображаються.
Якщо натиснути Enter, то через пару секунд почнеться вивід "Hello World" від завантаженої раніше в віддалену ардуіну прошивки HelloWorld.hex. Можна вийти з мінікома і завантажити на віддалену адруіну нову прошивку:
avrdude -P /dev/ttyUSB0 -b 19200 -c avrisp -p m328p -U flash:w:Echo.hex
А що, як до віддаленої ардуіни, наприклад, до її піна D0 підключити іншу 1-wire шину, чи можна буде подібне витворяти з нею? Виявляється можна. Наша ArduinoOWISP "спілкується" з комп'ютером через USB-UART конвертер, використовуючи свій апаратний UART і стандартну бібліотеку Serial. Ми можемо обдурити ArduinoOWISP, підсунувши їй замість бібліотеки Serial свою OWSerial, для цього достатньо в код ArduinoOWISP.ino додати два рядки:
#include <OWSerial.h>
#define Serial OWSerial
Скомпільована прошивка ArduinoOWISP_OWSerial.hex призначена для віддаленої ардуіни, вона нічим не гірша за HelloWorld.hex, з нею також можна встановити канал звязку через OWSerial, але замість "Hello World" вона може виводити щось корисне і приймати команди. Перевіряємо:
avrdude -P /dev/ttyUSB0 -b 19200 -c avrisp -p m328p -U flash:w:ArduinoOWISP_OWSerial.hex
В minicomi натискаєм '?' (переконуємось, що настройки ті ж), потім Enter (встановлюєм звязок по OWSerial) і слідом за нею знову '?':
#02
[2041420F484E5949]<
#07
[5555555555555555]?
Останні два рядки - це вже вивід з віддаленої ардуіни (настройки за замовчанням), змінюєм пін на D0 (натискаєм '#00') і скануєм (натискаєм '?'):
#02
[2041420F484E5949]<
#07
[5555555555555555]?
#00
[2042420F484E5910]
[2043420F484E5927]
[5555555555555555]?
До піна D0 на віддаленій ардуіні я підключив одразу два 1-wire пристрої, 2043420F484E5927 - це модуль розширення портів, до якого я припаяв плату MH-Tiny (розкажу в наступному пості), давайте зробимо її активною і прочитаємо сигнатуру з допомогою avrdude. Я зроблю це з командного рядка:
echo -n '[2043420F484E5927]' >/dev/ttyUSB0
avrdude -P /dev/ttyUSB0 -b 19200 -c avrisp -p t88 -U sig:r:-:h
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.03s
avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: Expected signature for ATtiny88 is 1E 93 11
Double check chip, or use -F to override this check.
avrdude done. Thank you.
Чому m328p, якщо я знаю, що там підключена t88 ? А все тому, що avrdude розірвав наше OWSerial зєднання з віддаленою ардуіною. Ось тут нам допоможе команда '!', її треба подати до встановлення OWSerial зєднання, щоб зробити його нерозривним для avrdude. Зроблю це з командного рядка:
echo -ne '!\r#00[2043420F484E5927]' >/dev/ttyUSB0
avrdude -P /dev/ttyUSB0 -b 19200 -c avrisp -p t88 -U sig:r:-:h
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.06s
avrdude: Device signature = 0x1e9311 (probably t88)
avrdude: reading signature memory:
Reading | ################################################## | 100% 0.05s
avrdude: writing output file "<stdout>"
0x1e,0x93,0x11
avrdude done. Thank you.
От тепер все як і має бути, можна прошивати MH-Tiny.
Звичайно, рівень вкладеності не обмежується числом 2.
Що це все дає? Це дає можливість будувати багаторангову 1-wire мережу на AVR мікроконтролерах (тобто вже немає обмеження в 100..300м) і оновлювати прошивку на будь-якому вузлі цієї мережі дистанційно по самій мережі.
Оскільки на практиці виявилось не зручно заливати в nano по черзі то ArduinoOWISP.hex то OWSerialMaster.hex (до того ж і кількість перезаписів не безмежна), то вбудував функціонал OWSerialMaster в код ArduinoOWISP. Тепер достатньо залити в nano один раз ArduinoOWISP і можна про неї (nano) забути - для заливки прошивки в pro-mini і для монітора порта достатньо лише двох команд:
avrdude -P /dev/ttyUSB0 -b 19200 -c avrisp -p m328p -U flash:w:HelloWorld.hex
minicom -D /dev/ttyUSB0 -b 19200
Після запуску мінікома чекаєм пару секунд, натискаєм клавішу Enter (або Ctrl+M) і ще через пару секунд бачимо наш вивід з pro-mini.
UPD: змінив швидкість з 9600 на 19200, щоб в Arduino IDE не доводилось виправляти ніякі системні файли.
Інструкція для тих, хто користується Arduino IDE
1. В Arduino IDE створити новий скетч, додати в нього код ArduinoOWISP.ino, вибрати: Інструменти->Плата: "Arduino Nano" і натиснути "Вивантажити". Цей скетч нам більше не знадобиться, можна закрити.
2. Зібрати схему, як на малюнку в першому пості.
3. Створити новий скетч, написати свій код з використанням OWSerial (звичайно встановити бібліотеки OWSerial, DS2450, OneWire).
4. Вибрати: Інструменти->Плата: "Arduino Pro or Pro Mini", вибрати: Інструменти->Програматор: "Arduino as ISP" і натиснути Скетч->"Вивантажити за допомогою програматора". Скетч буде завантажуватися в pro-mini по 1-wire.
5. Вибрати: Інструменти->Монітор послідовного порту, у новомі вікні внизу вибрати "Повернення каретки (CR)", "19200 бод" і натиснути "Надіслати", через пару секунд почнеться вивід.
Тепер щоразу після редагування скетчу просто натискаєм Скетч->"Вивантажити за допомогою програматора", після закінчення вивантаження у вікні монітора порта натискаєм "Надіслати" і через пару секунд знову бачимо вивід.
UPD: для тих, хто використовує майстер шини на DS2480B, у пункті 1 перед вивантаженням треба знайти в скетчі ArduinoOWISP.ino стрічку "#define HAVE_DS2480B 0" і замінити 0 на 1. Необхідні бібліотеки завантажити звідси.
Якщо при вивантаженні свого скетчу отримуєм помилку:
avrdude: Yikes! Invalid device signature.
То, скоріш за все, забули в ArduinoOWISP.ino замінити адресу модуля розширення портів на свою, шукаєм таку стрічку і міняєм:
byte addr[] = {0x20,0x41,0x42,0x0F,0x48,0x4E,0x59,0x49};
Просканувати шину 1-wire і дізнатися адреси всіх пристроїв на ній можна за допомогою простого скетчу (завантажувати його потрібно в nano):
#include <OneWire.h>
OneWire ow(10);
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
byte i, addr[8];
if (!ow.search(addr)) {
Serial.println("No more addresses.");
ow.reset_search();
delay(5000);
return;
}
Serial.print("ROM =");
for (i = 0; i < 8; i++) {
Serial.write(' ');
Serial.print(addr[i], HEX);
}
Serial.println();
}
Описана вище технологія віддаленої прошивки і монітора порта дозволяє мати на одній шині 1-wire багато плат розширювача портів + pro-mini і працювати з кожною індивідуально.
Лайк за спробу відняти шматок хліба у розробників UPDI. Взяли б контроллер з нової лінійки Attiny 0-,1-,2- series і не мучались.
Це вийшло випадково))) Перша версія розширювача портів просто повторювала DS2450 (АЦП і gpio) плюс зовсім прості додаткові фішки, але залишалось ще трохи місця в памяті програм, тому придумував, що ще цікавого додати. Памяті вистачило лише на SPI, щоб можна було підключити датчик з SPI інтерфейсом (в планах є окремий пристій 1wire_slave -> I2C_master, типу DS28E17). Те, що можна дистанційно прошивати AVR, я вже збагнув трохи пізніше. А в OWSerial потреба виникла в процесі вирішення іншої задачі.
Якщо порівнювати це рішення з UPDI:
* дозволяє створити канал комунікації з програмою на м/к і писати на ньому свої датчики і пристрої (UPDI лише для прошивки)
* дозволяє використовувати одну шину для багатьох таких пристроїв ще й одночасно з іншими датчиками (UPDI - лише точка-точка)
* що у UPDI з відстанню роботи? 1-wire працює на 100-300м
Ще раз. Я ні на що не претендую, те що вийшло - вийшло випадково і на мою думку цікаво. Якщо підходить/подобається - користуйтесь.
Лайк за спробу відняти шматок хліба у розробників UPDI. Взяли б контроллер з нової лінійки Attiny 0-,1-,2- series і не мучались.
До заголовку можна ще додати ... та віддалений монітор порта.
Оскільки знадобилося якось бачити те, що виводить Serial.print() на віддаленій pro-mini, то написав бібліотеку OWSerial, яка дозволяє по 1-wire емулювати послідовний порт для програми.
В скетчі знадобиться замінити всі Serial. на OWSerial. додати #include <OWSerial.h> та замінити Serial.begin(9600); на OWSerial.begin();
Наприклад, скетч HCS301.ino, який я постив у сусідній темі, віглядатиме так:
#include <OWSerial.h>
#define HCS301_TE 400
#define HCS301_BITS 66
typedef struct {
uint32_t SerialNum;
uint32_t Encrypted;
uint8_t Btn1 :1;
uint8_t Btn2 :1;
uint8_t Btn3 :1;
uint8_t Btn4 :1;
uint8_t BatLow :1;
uint8_t Repeat :1;
} hcs301_t;
void hcs301_msg(hcs301_t *msg, uint8_t *a) {
msg->SerialNum = ((uint32_t)(a[7] & 0xf) << 24) | ((uint32_t)a[6] << 16) |
((uint32_t)a[4] << 8) | a[5];
msg->Encrypted = ((uint32_t)a[0] << 24) | ((uint32_t)a[1] << 16) |
((uint32_t)a[2] << 8) | a[3];
msg->Btn1 = (a[7] >> 5) & 1;
msg->Btn2 = (a[7] >> 6) & 1;
msg->Btn3 = (a[7] >> 7) & 1;
msg->Btn4 = (a[7] >> 4) & 1;
msg->BatLow = (a[8] >> 6) & 1;
msg->Repeat = (a[8] >> 7) & 1;
}
#define RF_RECV_PIN 2
#define is_roughly(d,t) ((d) > (t)-(t)/4 && (d) < (t)+(t)/4)
#define RF_TE HCS301_TE
#define RF_BITS HCS301_BITS
uint32_t RF_last_change = 0;
uint8_t RF_byte, RF_array[(RF_BITS+7)>>3];
uint8_t RF_mode = 0;
volatile boolean RF_catched = false;
void RF_interrupt() {
if (RF_catched)
return;
uint32_t duration = micros() - RF_last_change;
uint8_t pin = digitalRead(RF_RECV_PIN);
RF_last_change += duration;
if (!(RF_mode & 0x80)) {
if (RF_mode > 20 && pin == HIGH && is_roughly(duration, 10*RF_TE))
RF_mode = 0x80;
else if (!is_roughly(duration, RF_TE))
RF_mode = 0;
else if (!(RF_mode & 0x40))
RF_mode++;
} else {
uint8_t bit = 0;
if (is_roughly(duration, RF_TE))
bit = 0x80;
else if (!is_roughly(duration, 2*RF_TE))
RF_mode = 0;
if (RF_mode) {
if (pin == HIGH) {
if ((bit ^= RF_byte) & 0x80)
RF_mode++;
else
RF_mode = 0;
RF_byte >>= 1;
} else {
RF_byte |= bit;
RF_array[(RF_mode >> 3) & 0xf] = RF_byte;
if (RF_mode >= 0x80 + RF_BITS - 1) {
RF_catched = true;
RF_mode = 0;
}
}
}
}
}
void setup() {
OWSerial.begin();
attachInterrupt(digitalPinToInterrupt(RF_RECV_PIN), RF_interrupt, CHANGE);
OWSerial.println("Listening RF");
}
void loop() {
if (RF_catched) {
hcs301_t msg;
hcs301_msg(&msg, RF_array);
RF_catched = false;
OWSerial.print("#");
OWSerial.print(msg.SerialNum, HEX);
OWSerial.print(" ");
OWSerial.print(msg.Encrypted, HEX);
OWSerial.print(" ");
if (msg.Btn1) OWSerial.print("1");
if (msg.Btn2) OWSerial.print("2");
if (msg.Btn3) OWSerial.print("3");
if (msg.Btn4) OWSerial.print("4");
if (msg.BatLow) OWSerial.print(" BatLow");
if (msg.Repeat) OWSerial.print(" R");
OWSerial.println();
}
}
Щоб залити цей скетч на віддалену pro-mini, спочатку перетворюєм локальну nano (див. схему в першому повідомленні) в програматор ArduinoOWISP (перед компіляцією цього скетчу замінюєм в ньому адресу модуля розширення портів на свою в цій стрічці: byte addr[] = {0x20,0x41,0x42,0x0F,0x48,0x4E,0x59,0x49};).
Заливаєм ArduinoOWISP.hex в nano:
avrdude -P /dev/ttyUSB0 -c arduino -p m328p -U flash:w:ArduinoOWISP.hex
Тепер nano стала повноцінним програматором по 1-wire для pro-mini - можна не лише заливати і читати прошивку і EEPROM, а й змінювати ф'юзи. При цьому на pro-mini не потрібен ніякий бутлоадер, і можемо не боятися, що прошивка на віддаленій pro-mini зависне і ми втратим до неї доступ.
Заливаєм HCS301.hex в pro-mini:
avrdude -P /dev/ttyUSB0 -b 9600 -c avrisp -p m328p -U flash:w:HCS301.hex
Програма на pro-mini починає працювати, щось виводить в OWSerial і нам тепер треба побачити, що там виводиться. Для цього в nano заливаєм скетч-ретранслятор (перед компіляцією цього скетчу замінюєм в ньому адресу модуля розширення портів на свою в цій стрічці: byte addr[] = {0x20,0x41,0x42,0x0F,0x48,0x4E,0x59,0x49};).
Заливаєм OWSerialMaster.hex в nano:
avrdude -P /dev/ttyUSB0 -c arduino -p m328p -U flash:w:OWSerialMaster.hex
Цей скетч через модуль розширення портів забирає з буферу OWSerial дані і виводить в свій Serial (в зворотньому напрямку дані також будуть передаватися).
Дивимось, що в нас виводиться в Serial на nano:
minicom -D /dev/ttyUSB0 -b 9600
Listening RF
#12345 1B6A46A2 1
#12345 1B6A46A2 1 R
#12345 9F204069 2
#12345 9F204069 2 R
#12345 D6A5816C 1234 BatLow
#12345 D6A5816C 1234 BatLow R
На брелоку я послідовно натискав кнопки 1, 2 і 1+2. Приймач 433МГц підключений до піна 2 на pro-mini.
Ділюся досвідом, може кому знадобиться така ідея програмування для його задачі.
Виникла потреба віддалено керувати (додавати/видаляти) списком радіо-брелоків, які можуть відчиняти ворота. Керуванням воріт займається одна плата, а для подачі їй сигналу на відкривання використовувався китайський приймач 433МГц, який замикав своїм реле два контакти з цієї плати. Все це розташовано поряд з воротами в ящику. Додатково під землею/асфальтом вже давно був проведений кабель до пульту охорони, щоб кнопкою можна було також вручну відкрити ворота. Проблема в тому, що китайський приймач дозволяє лише додавати в свою память коди брелоків, для чого потрібно натиснути кнопку безпосередьо на його платі (а для цього потрібно до неї добратись).
Перш за все я перевірив, чи працюватиме 1-wire по двом проводам, які призначені для кнопки відкривання воріт на пульті охорони. 1-wire працює чудово за винятком періодів часу, коли працює мотор, який відкриває/закриває ворота (мабуть він в цей час створює завади через кабель живлення, який десь там під землею проходить поряд).
Спочатку була ідея віддалено модифікувати память китайського приймача (память в ньому 24LC16B з I2C інтерфейсом, формат збереження даних стає зрозумілим з першого разу після додавання нового брелоку і зчитування памяті). Модифікувати память можна було б по 1-wire за допомогою pro-mini, включеної за такою схемою:
До того ж за цією схемою можна віддалено оновлювати прошивку pro-mini, не відкриваючи ящик, в якому вона знаходиться.
Коли я почав придумувати протокол для додавання/видалення кодів брелоків по 1-wire, прийшла друга ідея.
По-перше відмовитися від китайського приймача, а написати його реалізацію на pro-mini.
По-друге не витрачати зусилля і час на придумування протоколу додавання/видалення кодів.
Ідея полягає в тому, щоб коди всіх брелоків помістити в програму (в PGM/EEPROM) і віддалено прошивати в pro-mini щоразу, коли потрібно якийсь брелок додати/видалити. Тобто редагуємо програму (додаємо/видаляємо код брелока в масиві), компілюємо і прошиваємо по 1-wire в pro-mini.
Отже, якщо стоїть задача розробки протоколу для віддаленого керування якоюсь базою даних на ардуіно і немає вимог до доступності до цієї ардуіни 100% часу, то можна не витрачати зусилля на розробку такого протоколу. Для цього можна щоразу зчитувати з віддаленої ардуіни її память, модифікувати і записувати назад.