В статье расскажу, как конфигурировать сеть TinyOneWireNet с помощью стандартной Ардуино-библиотеки.
Предыдущая статья Навигация по рубрике Следующая статья
В предыдущей статье мы задавали конфигурацию сети с помощью готового устройства – монитора на базе платы ArduinoNano. Существуют еще другие устройства, позволяющие выполнить эту операцию. О них напишу позже.
Но кому-то может потребоваться выполнять функции конфигурации сети в своем устройстве, в своей программе. Для этого можно воспользоваться методами библиотеки TinyOneWireNet.h.
Общие для всех устройств функции библиотеки TinyOneWireNet.h.
Библиотека использует класс TinyOneWireNet. Вот методы, общие для всех устройств.
uint8_t onLine(uint8_t chargeTime); // включение линии связи
void offLine(); // выключение линии связи
void shortLine(); // замыкание линии связи
uint8_t getLineState(); // получить состояние линии
uint8_t dataTest(uint8_t adr, uint8_t bt); // тест данных сетевого устройства
uint8_t readDeviceType(uint8_t adr, uint8_t * dev, uint8_t * soft); // чтение типа устройства и версии ПО
uint8_t readUniqueIdent(uint8_t adr, uint32_t * ident); // чтение уникального идентификатора устройства
uint8_t addressLoadPermission(uint8_t adr, uint32_t ident); // разрешение загрузки адреса по уникальному идентификатору
void addressProg(uint8_t adr); // программирование адреса
uint8_t startFreqCalibrTimer(uint8_t adr); // запуск таймера калибровки частоты
uint8_t readFreqCalibrTimer(uint8_t adr, uint16_t * tm); // чтение таймера калибровки частоты
uint8_t loadOsctune(uint8_t adr, int8_t osctune); // загрузка OSCTUNE
uint8_t readOsctune(uint8_t adr, int8_t * osctune); // чтение OSCTUNE
Методы библиотеки возвращают следующие значения состояния операции:
- 0 – без ошибок;
- LINE_IS_OFF - линия выключена;
- LINE_SHORTING - короткое замыкание линии;
- RESPONSE_ERROR - ошибка ответа;
- CRC_ERROR - ошибка CRC;
- OPERATION_ERROR - ошибка операции;
- DATA_COMPARE_ERROR - ошибка сравнения данных.
Функции управления сетью.
Перед началом работы с сетью необходимо создать экземпляр класса с помощью конструктора.
TinyOneWireNet(uint8_t pin)
- pin – вывод микроконтроллера, на котором формируется сеть.
TinyOneWireNetline1(2); // формируем сеть TinyOneWireNet на выводе 2
Можно создавать несколько сетей.
TinyOneWireNetline1(3); // формируем сеть TinyOneWireNet на выводе 3
TinyOneWireNetline1(4); // формируем сеть TinyOneWireNet на выводе 4
Линия может быть в одном из состояний:
- включена;
- выключена (разомкнута);
- выключена (замкнута).
Для включения используется метод
uint8_t onLine(uint8_t chargeTime); // включение линии связи
chargeTime – время на включение в мс.
Если за это время линия не перешла в высокое логическое состояние, то линия считается замкнутой.
Функция возвращает
- 0 –линия включилась;
- LINE_SHORTING – короткое замыкание.
Для выключения линии есть функции:
void offLine(); // выключение линии связи
void shortLine(); // замыкание линии связи
Узнать текущее состояние линии можно функцией
uint8_t getLineState(); // получить состояние линии
Возвращает значения:
- 0 – линия включена;
- LINE_IS_OFF - линия выключена;
- LINE_SHORTING - короткое замыкание линии.
Дальше о сетевых методах я буду рассказывать на реальных задачах и примерах.
Я использую сеть из 3х устройств, которую я создал в предыдущей статье.
Сеть подключена к выводу 2.
Чтение типов устройств.
uint8_t readDeviceType(uint8_t adr, uint8_t * dev, uint8_t * soft); // чтение типа устройства и версии ПО
- adr – адрес устройства;
- dev – указатель на тип устройства;
- soft – указатель на версию ПО.
Вот скетч, который определяет типы устройств в сети и выводит информацию в монитор последовательного порта.
// определение типов устройств в сети
#include <TinyOneWireNet.h>
#define NET_PIN 2 // вывод данных сети
#define BETWEEN_COM_TIME 2 // пауза между командами (мс)
TinyOneWireNet sens(NET_PIN);
uint8_t dev, soft;
void setup() {
Serial.begin(9600);
sens.onLine(10);
}
void loop() {
for( int i=0; i < 64; i++ ) {
if( sens.readDeviceType(i, & dev, & soft) == 0 ) {
Serial.print("Address: ");
Serial.print(i);
Serial.print(" Type: ");
Serial.print(dev);
Serial.print(" Soft: ");
Serial.println(soft);
}
delay(BETWEEN_COM_TIME);
}
Serial.println("");
delay(1000);
}
Диагностика обмена данными с устройствами.
uint8_t dataTest(uint8_t adr, uint8_t bt); // тест данных сетевого устройства
- adr – адрес устройства;
- bt – тестовый байт.
Функция посылает на устройство с адресом adr байт bt. Устройство возвращает прямое и инверсное значения байта.
- В случае правильного ответа функция возвращает 0.
- При ошибочных данных – значение DATA_COMPARE_ERROR.
Вот, как выглядит скетч диагностики обмена для первого устройства с адресом 10.
// диагностика обмена устройства с адресом 10
#include <TinyOneWireNet.h>
#define NET_PIN 2 // вывод данных сети
#define BETWEEN_COM_TIME 2 // пауза между командами (мс)
TinyOneWireNet sens(NET_PIN);
uint32_t cycles=0, errors=0;
void setup() {
Serial.begin(9600);
sens.onLine(10);
}
void loop() {
if( sens.dataTest(10, rand()) != 0 ) errors++;
cycles++;
Serial.print("Cycles: ");
Serial.print(cycles);
Serial.print(" Errors: ");
Serial.println(errors);
delay(BETWEEN_COM_TIME);
}
Чтение уникального идентификатора устройства.
uint8_t readUniqueIdent(uint8_t adr, uint32_t * ident); // чтение уникального идентификатора устройства
- adr – адрес устройства;
- ident – указатель на идентификатор.
Давайте в первый скетч добавим вывод идентификаторов.
// определение типов устройств в сети
#include <TinyOneWireNet.h>
#define NET_PIN 2 // вывод данных сети
#define BETWEEN_COM_TIME 2 // пауза между командами (мс)
TinyOneWireNet sens(NET_PIN);
uint8_t dev, soft;
uint32_t ident;
void setup() {
Serial.begin(9600);
sens.onLine(10);
}
void loop() {
for( int i=0; i < 64; i++ ) {
if( sens.readDeviceType(i, & dev, & soft) == 0 ) {
delay(BETWEEN_COM_TIME);
sens.readUniqueIdent(i, & ident);
Serial.print("Address: ");
Serial.print(i);
Serial.print(" Type: ");
Serial.print(dev);
Serial.print(" Soft: ");
Serial.print(soft);
Serial.print(" Ident: ");
Serial.println(ident, HEX);
}
delay(BETWEEN_COM_TIME);
}
Serial.println("");
delay(1000);
}
Программирование адреса устройства.
Собственно загрузка нового адреса в устройство происходит функцией
void addressProg(uint8_t adr); // программирование адреса
adr – новый адрес, адрес, который надо загрузить в устройство.
В сети могут быть несколько устройств. Программирование адреса произойдет только в том устройстве, загрузка адреса в которое разрешена.
А эта операция производится следующей функцией.
uint8_t addressLoadPermission(uint8_t adr, uint32_t ident); // разрешение загрузки адреса по уникальному идентификатору
Общая последовательность программирования нового адреса устройства выглядит так.
- В исходном состоянии программирование адреса запрещено во всех устройствах сети.
- В нужное устройство посылается команда разрешения загрузки адреса по уникальному идентификатору. Идентификатор надо знать или его можно считать из устройства, зная его адрес. В крайнем случае, если в сети оказались устройства с одинаковыми адресами и неизвестными идентификаторами, можно оставить только одно, адрес которого надо изменить.
- Посылается команда программирования адреса, которая принимается только разрешенным устройством.
- После загрузки нового адреса разрешение программирования снимается автоматически.
Вот программа, в которой реализована описанная последовательность.
// программирование адреса
#include <TinyOneWireNet.h>
#define CURRENT_ADR 53 // текущий адрес
#define NEW_ADR 57 // новый адрес
#define NET_PIN 2 // вывод данных сети
#define BETWEEN_COM_TIME 2 // пауза между командами (мс)
TinyOneWireNet sens(NET_PIN);
uint32_t ident;
void setup() {
Serial.begin(9600);
sens.onLine(10);
sens.readUniqueIdent(CURRENT_ADR, & ident); // чтение уникального идентификатора
delay(BETWEEN_COM_TIME);
sens.addressLoadPermission(CURRENT_ADR, ident); // разрешение загрузки адреса по уникальному идентификатору
delay(BETWEEN_COM_TIME);
sens.addressProg(NEW_ADR); // программирование адреса
// проверка
if( sens.dataTest(NEW_ADR, 0x5a) == 0 ) {
// правильно
Serial.print("In the device with address ");
Serial.print(CURRENT_ADR);
Serial.print(" the address has been changed to ");
Serial.println(NEW_ADR);
}
else {
// ошибка
Serial.println("Address programming error");
}
}
void loop() {
}
Калибровка частоты тактового генератора.
В сетевых устройствах используется внутренний генератор тактовой частоты. Его стабильности (±3%) вполне достаточно для работы протокола интерфейса TinyOneWireNet. Но при желании, можно откалибровать генератор изменением внутреннего калибровочного коэффициента.
Для измерения текущей частоты генератора необходимо запустить таймер калибровки функцией
uint8_t startFreqCalibrTimer(uint8_t adr); // запуск таймера калибровки частоты
Через определенное время считать значение таймера функцией
uint8_t readFreqCalibrTimer(uint8_t adr, uint16_t * tm); // чтение таймера калибровки частоты
Для вычисления реального времени необходимо параметр tm * 32 мкс. Максимальное значение около 2 сек.
Остается вычислить пропорцию между временем измеренным устройством и временем измеренным ведущим устройством. Это и будет погрешность частоты генератора.
Считать значение калибровочного коэффициента и загрузить его в устройство можно функциями
uint8_t loadOsctune(uint8_t adr, int8_t osctune); // загрузка OSCTUNE
uint8_t readOsctune(uint8_t adr, int8_t * osctune); // чтение OSCTUNE
Калибровочный коэффициент должен быть в диапазоне -32 … 31.
Пример работы с калибровкой генератора я приводить не буду. Можно посмотреть в программе монитора на базе платы Arduino Nano.
Со следующей статьи начинаю рассказывать непосредственно о сетевых устройствах и работе с ними через библиотеку TinyOneWireNet.