Сделал обновление программы в МК через радиосвязь на nRF24l01+, Битлэш

toc
Offline
Зарегистрирован: 09.02.2013

arduino wireless program upload RF24 nrf24l01+

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

молодец. где код? :)

toc
Offline
Зарегистрирован: 09.02.2013

...это не совсем то, на что вы, вероятно, рассчитываете...

Введение
Если у вас есть проект на ардуино, и плата застряла в чреве машины, или прикреплена к дереву за окном или недоступна по другим причинам, беспроводная связь для программирования / отладки сэкономит вам кучу времени, вероятно. (portions by ladyada)

Моя цель: сделать работающий прототип, позволяющий загрузить программу в МК  посредством радиосвязи.

Возможные варианты:
1. Uploading Arduino sketches wirelessly using a Bluetooth breakout board.
Минус: у меня нет такого оборудования.
2. Xbee radios, wireless Arduino programming, serial link.
Минус: модули xbee дорогие и у меня их нет.
3. Радиоудлинитель для последовательного порта на nrf24 и МК, обновление программы на основном МК через бутлоадер.  
Минус: дополнительный МК для удлинителя.
Но, мы пойдём другим путём.

Предварительная подготовка читателя этой статьи:
1. Обязательно: уверенная работа в Arduino IDE и успешное освоение примера Blink;
2. Обязательно: успешное выполнение примера pingpair из библиотеки RF24 (от maniacbug) на двух устройствах;
3. Желательно: ознакомиться с Bitlash (от billroy).
О значении неизвестных слов смело спрашивайте гугл, пожалуйста.

Оборудование, которое я использовал:
1. дуина Nano atmega168 плюс модуль nRF24l01+
Всегда подключёно к компьютеру по usb,  далее буду называть этот блок «клиент».
2. дуина Nano atmega328 плюс модуль nRF24l01+
Иногда подключёно к компьютеру по usb, на нём буду обновлять программу, далее буду называть этот блок «сервер».
3. Блок питания 220 Вольт AC – 5 Вольт DC с USB разъёмом.
 
Как это работает:
1. Между клиентом и сервером построен виртуальный радиоудлинитель компорта
2. Весь текст вводимый в мониторе порта клиента, отправляется на сервер через радиосвязь и передаётся посимвольно в битлэш.
3. Текст появляющийся в мониторе порта сервера передаётся клиенту и также выводится в мониторе клиента.
4. Всё остальное — заслуга битлэша.

За дело!
1. Разместим на столе клиент слева, а сервер справа.
2. Запустим arduino.exe два раза. Одно окно разместим слева (для клиента), другое справа (для сервера).
3. Выберем в каждом окне правильный ком порт и правильную плату.
4. Заливаем скетч myRf24BitlashClient_0 на клиент (через usb)


/*
 myRf24BitlashClient
 Copyright (C) 2013 <toc arduino.ru> 

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 version 2 as published by the Free Software Foundation.
 */

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(9,10);

// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF1F0F0F0E1LL, 0xF1F0F0F0D2LL };

void setup(void)
{
  Serial.begin(57600);
  radio.begin();
  radio.setRetries(10,15);
  radio.setPayloadSize(1);
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1,pipes[1]);
  radio.startListening();
}

#define serialPrintByte(b) Serial.write(b)

byte buf;

void loop(void)
{
  if(radio.available())
  {
    radio.read(&buf , 1);
    serialPrintByte(buf);	
  }
  
  if(Serial.available())
  {
    buf = Serial.read();
    serialPrintByte(buf);
    radio.stopListening();
    radio.write(&buf,1);
    radio.startListening();
  }
}

Binary sketch size: 5 492 bytes (of a 14 336 byte maximum)

5. Заливаем скетч myRf24BitlashServer_0 на сервер (через usb)
 


/*
 myRf24BitlashServer_0
 Copyright (C) 2013 <toc arduino.ru> 
 
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 version 2 as published by the Free Software Foundation.
 */

#include <bitlash.h>
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"

RF24 radio(9,10);

const uint64_t pipes[2] = { 0xF1F0F0F0E1LL, 0xF1F0F0F0D2LL };

void setup(void)
{
  initBitlash(57600);
  radio.begin();
  radio.setRetries(10,15);
  radio.setPayloadSize(1);
  setOutputHandler(&serialHandler);
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
  radio.startListening();
}

#define serialPrintByte(b) Serial.write(b)
byte buf;

void serialHandler(byte b) 
{
  buf=b;
  serialPrintByte(buf);
  radio.stopListening();
  radio.write(&buf,1);
  radio.startListening();
}

void loop(void)
{
  if(radio.available())
  {
    radio.read(&buf , 1);
    doCharacter(buf);
  }
  else
  {
    runBitlash();
  }
}


Binary sketch size: 20 498 bytes (of a 32 256 byte maximum)

6. Открываем два монитора порта, слева (для клиента), справа (для сервера). Далее пишем и читаем только в левом мониторе. Правый на всякий случай, для контроля.
7. Вводим в левом мониторе «print 2+3» нажимаем ввод.
8. В обоих мониторах появилось:
print 2+3    
3
>

В принципе, на этом моя цель уже достигнута. Программа “print 2+3” передана по радио на  соседний МК, выполнена, результат получен. Продолжайте читать, дальше чуть интереснее.

Бонус. Исследуем возможности Bitlash
Термины
Скетч — Программа на языке Ардуино, компилируемая и загружаемая во флеш память МК;
Bitlash – библиотека, интерпретатор одноимённого «языка». Скетч myRf24BitlashServer_0 загруженный на сервер содержит битлэш.
Функция Bitlash — Программа на языке Bitlash, интерпретируемая интерактивно при получении из ком порта или загружаемая в eeprom память МК. Осторожно! Битлэш использует EEPROM! Если в вашей еепром памяти есть что-то важное, сохраните в надёжном месте. В моём случае ничего не пропало, просто первая функция получила слишком длинное имя с иероглифами. Похоже, битлэш считает последовательности 0xFF пустым местом, а 0x00 разделителем функций.

1. Вводим в левом мониторе «function printmil{print "mil=",millis();}» нажимаем ввод.
Битлэш отвечает saved – значит функция сохранена в еепром памяти.
2. Вводим в левом мониторе «function startup{run printmil,5000;}» нажимаем ввод.
Битлэш отвечает saved.
3. Команда ls позволяет получить полный список сохранённых функций
4. Нажимаем пальцем резет на правой дуине (сервере).
5. Наблюдаем результат: в мониторах каждые пять секунд появляется новая строка
mil=5035
mil=1080
mil=15122
6. Понимаете, что мы сделали? Мы сохранили в постоянную память сервера программу (набор функций битлэш), которая автоматически выполняется после старта дуины.
По радиоканалу.

Запустить классический Блинк на пятом порту (13-й занят для радио) можно так:

function toggle5{d5=!d5;}
run toggle5,1000;

Добавим сенсор
и создадим «пользовательскую функцию».
“Сенсор” будет измерять напряжение питания сервера.

1. Добавим в скетч сервера перед setup это

numvar readVcc() {
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    ADMUX = _BV(MUX5) | _BV(MUX0);
  #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
    ADMUX = _BV(MUX3) | _BV(MUX2);
  #else
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #endif  
 
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring
 
  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
  uint8_t high = ADCH; // unlocks both
 
  long result = (high<<8) | low;
 
  result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  return result; // Vcc in millivolts
}

2. Добавим в скетч сервера, внутрь setup, в начало:

addBitlashFunction("readvcc", (bitlash_function) readVcc);

3. Зальём скетч в сервер по usb кнопкой upload
4. Вводим в левом мониторе

function printmil{print "mil=",millis();print "vcc=",readvcc();}

нажимаем ввод.
Битлэш отвечает saved – значит функция сохранена (перезаписана) в еепром памяти.
5. Наблюдаем результат: в мониторах каждые пять секунд появляются новые строки
mil=158234
vcc=5121

Добавим lcd экран
1. Добавим в скетч сервера перед setup это

#define useLcd

#if defined(useLcd)
#include <PCD8544.h>
PCD8544 nokia = PCD8544(4, 5, 6, 0, 8);

numvar lcdClear(void) {
  nokia.clear();
  nokia.display();
}

numvar lcdPrint(void) {
  for (int i=1; i <= getarg(0); i++) {
    if (isstringarg(i)) nokia.print((const char *) getstringarg(i));
    else nokia.print(getarg(i));
  }
  nokia.display();
}
#endif

2. Добавим в скетч сервера, внутрь setup, в начало:

#if defined(useLcd)
  nokia.init(25);
  nokia.print("myRf24 BitlashServer");
  nokia.display();
  addBitlashFunction("lcdclear", (bitlash_function) lcdClear);
  addBitlashFunction("lcdprint", (bitlash_function) lcdPrint);
#endif

3. Зальём скетч в сервер по usb кнопкой upload
4. Вводим в левом мониторе lcdprint("Hello, world"); смотрим на экран
5. Вводим в левом мониторе

function toLcd{ lcdclear;lcdprint("sec=",millis()/1000);lcdprint("\nvcc=",readVcc());}
function startup {run printmil,5000; run toLcd,1000};

нажимаем ввод.
Битлэш отвечает saved – значит функции сохранены (перезаписана) в еепром памяти.
6. Наблюдаем результат: в мониторах по прежнему каждые пять секунд появляются новые строки
mil=158234
vcc=5121

И на экране появляется то что надо.

Замеченные недостатки:
1. Битлэш занимает 17 килобайт флеш памяти

Замеченные недостатки этого прототипа:
1. Обмен информацией по радиоканалу производится по одному байту, сравнительно медленно
2. Иногда отдельные символы пропадают
3. Дальность радиосвязи на том же оборудовании меньше чем в другом моём проекте. Только что подумал: может плохой канал?
4. Похоже битлэш не может обрабатывать новые команды поступающие по радио в его «последовательный порт» если дуина не подключена к компьютеру. Но, сервер питающийся от розетки успешно выполняет сохранённые в нём битлэш-функции.
5. Похоже, что с библиотекой для экрана осталось мало оперативки. Функция битлэша free() говорит, что около 350 байт. Он начинает подглючивать из-за дифицита памяти.

Todo
1. Исправить недостатки
2. Битлэш умеет запускать функции с sd карты. Надо попробовать.

Timespent:
1. Изучение битлэша и программирование концепта — часа два.
2. Осознание желания поделиться и написание этого текста — неделя.

Возможны ошибки, опечатки, неточности.

toc
Offline
Зарегистрирован: 09.02.2013

std
Offline
Зарегистрирован: 05.01.2012

Круто, с SD было бы любопытно, и может меньше проблем с оперативой будет. Или сделать на Atmega1284, у неё мозгов 16K.

А в идеале конечно подружить с ArduinoISP и писать прямо по ISP, в обход загрузчика. Но это уже наверно с двумя контроллерами в сервере, один прошивающий, другой рабочий.

vlkam
Offline
Зарегистрирован: 17.02.2013

Спасибо!

Подписался на тему

a5021
Offline
Зарегистрирован: 07.07.2013

Материал любопытный и подан доходчиво. Лично мне теперь осталось придумать, где это можно использовать с пользой.

ujuf66
Offline
Зарегистрирован: 18.08.2014

Круто, в идеале передать бы на серевер скетч в HEX формате.

art100
Offline
Зарегистрирован: 09.03.2014

Спасибо.  Чего не прикрутят bitlash.h лишь бы провод не тянуть. А про батареку актуаленько у меня. Попробую прикрутить.