Ошибка RadioHead и DallasTemperature
Библиотека RadioHead работает только на очень старом ядре ATtiny85. Он отправляет данные, но я хотел бы отправить что-то полезное. Проблема в том, что я не могу прочитать данные датчиков, использующих это ядро. А на любом другом ядре библиотека RadioHead дает сбой.
Библиотека RadioHead
Ядро ATtiny
В старом сообщении на форуме Arduino, вероятно, та же проблема.
Я хотел бы знать, что в DallasTemperature конфликтует с RadioHead, из-за чего код зависает.
Проблема возникает, когда я добавляю в код Датчики температуры Dallas(&oneWire);
.
// RadioHead СПРОСИТЬ
#include <RH_ASK.h>
// DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS PB0
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// Спать
#include <avr/sleep.h>
#include <avr/wdt.h>
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
// Абсолютная ссылка PB для решения проблем между IDE
#define T_PIN PB1 // передача
#define L_PIN PB3 // дополнительный вывод светодиода
#define BAUD 2000
// Скорость передачи данных, приемник, передатчик
RH_ASK driver(BAUD, 9, T_PIN); // контакт 9 не существует
// структура Tickle, какое имя, тьфу
struct tickle {
uint16_t id;
uint16_t value1;
uint16_t value2;
};
// Сторожевая собака
volatile boolean f_wdt = 1;
ISR(WDT_vect) {
f_wdt=1;
}
// Спать
void system_sleep() {
cbi(ADCSRA,ADEN); // выключаем аналогово-цифровой преобразователь
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // здесь устанавливается спящий режим
sleep_enable();
sleep_mode(); // Здесь система спит
sleep_disable(); // Система продолжает выполнение здесь, когда истекло время сторожевого таймера
sbi(ADCSRA,ADEN); // включаем аналоговый преобразователь в цифровой
}
// Настройка сторожевого таймера
void setup_watchdog(int ii) {
byte bb;
int ww;
if (ii > 9 ) ii=9;
bb=ii & 7;
if (ii > 7) bb|= (1<<5);
bb|= (1<<WDCE);
ww=bb;
MCUSR &= ~(1<<WDRF);
// запускаем временную последовательность
WDTCR |= (1<<WDCE) | (1<<WDE);
// устанавливаем новое значение таймаута сторожевого таймера
WDTCR = bb;
WDTCR |= _BV(WDIE);
}
// При значении set_watchdog 8 (4 секунды) мы циклически от 0 до 14
// Этот таймер неточный
void minute_sleep(int ms) {
for (int c = 0; c < ms; c++) {
for (int i = 0; i < 15; i++) {
system_sleep();
}
}
}
void setup() {
// Отладка, если это занимает меньше секунды, проверяем фьюзы (ядро)
if (!driver.init()){
pinMode(L_PIN, OUTPUT);
digitalWrite(L_PIN, HIGH);
delay(500);
digitalWrite(L_PIN, LOW);
delay(500);
}
setup_watchdog(8);
sensors.begin();
}
void loop()
{
if (f_wdt==1) {
f_wdt=0;
struct tickle package; // создаем пакет Tickle
package.id = 38; // жестко заданный идентификатор устройства
package.value1 = analogRead(PB0); // любое положительное целое число до 2^16
package.value2 = analogRead(PB2); // любое положительное целое число до 2^16
// отправка данных
driver.send((uint8_t *)&package, sizeof(package));
driver.waitPacketSent(); // подожди ~Барни
minute_sleep(10); // проверено: 10 было 10:30, мне нравится
}
}
@Thijs, 👍1
1 ответ
Лучший ответ:
У меня возникло множество проблем при использовании библиотеки RadioHead на ATTiny85 вместе с Arduino IDE. Ваша проблема не в датчике температуры Dallas.
Проблема заключается в том, что RadioHead использует таймер 0 на ATTiny и изменяет прескалер таймера, чтобы он соответствовал скорости передачи данных, которую вы запросили для вашего трансивера. Изменение прескалера меняет способ работы функций Arduino IDE, таких как delay()
, поскольку они также используют таймер 0. Я считаю, что ваша библиотека Далласа зависит от delay()
для синхронизации сигналов на шине 1, поэтому возникает конфликт между двумя библиотеками.
Я решил эту проблему, переписав файлы RadioHead RHASK, чтобы вместо них можно было использовать таймер 1 ATTiny85. Вот мой код. Хотя я использую TinyHead вместо RadioHead, изменение будет таким же, поскольку TinyHead — это клон RadioHead.
Единственное изменение, которое я внес в RH_ASK.h, — это код, определяющий, использовать ли TIMER1 или нет.
// Флаг, указывающий, использовать ли таймер1 в attiny85.
#define RH_ASK_ATTINY_USE_TIMER1
Приведенные ниже изменения относятся к RH_ASK.cpp
Первое изменение. Обновите код прескалера и добавьте прескалеры, используемые таймером 1:
// Помещаем эти структуры прескалера в PROGMEM, а не в стек
#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) || (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8)
#if defined(RH_ASK_ARDUINO_USE_TIMER2)
// Таймер 2 имеет разные прескалеры
PROGMEM static const uint16_t prescalers[] = {0, 1, 8, 32, 64, 128, 256, 3333};
#else
#if defined(RH_ASK_ATTINY_USE_TIMER1)
PROGMEM static const uint16_t prescalers[] = {0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16834, 3333};
#else
PROGMEM static const uint16_t prescalers[] = {0, 1, 8, 64, 256, 1024, 3333};
#endif
#endif
Второе изменение. Этот код устанавливает таймер 1 и идет перед существующим кодом для таймера ATTINY 0 в функции RH_ASK::timerSetup(). обратите внимание на часть «... существующий код». Существующий код для настройки таймера 0 находится между #else и #endif
#if defined(RH_ASK_ATTINY_USE_TIMER1)
#warning RH_ASK_ATTINY_USE_TIMER1 set.
// определяем значение прескалера и значение совпадения счетчика
// REVISIT: неправильно обрабатывает тактовую частоту 1 МГц, работает только с тактовой частотой 8 МГц
// При тактовой частоте 1 МГц получаем 1/8 ожидаемой скорости передачи данных
prescaler = timerCalc(_speed, (uint8_t)-1, &nticks);
if (!prescaler)
return; // вина
TCCR1 = 0; // Остановить таймер
TCNT1 = 0; // Обнуляем таймер
GTCCR = _BV(PSR1); // Сброс прескалера
// Количество тактов, которые нужно посчитать перед срабатыванием прерывания
OCR1A = uint8_t(nticks);
TCCR1 = _BV(CTC1); // Включаем режим CTC/Выводы сравнения вывода отключены
// преобразуем индекс прескалера в биты прескалера TCCRnB CS00, CS01, CS02
TCCR1 |= prescaler; // устанавливаем CS00, CS01, CS02 (остальные биты не нужны)
// Установка маски для запуска прерывания, когда бит OCIE1A установлен в TMSK
#ifdef TIMSK0
// ATtiny84
TIMSK1 |= _BV(OCIE1A);
#else
// ATtiny85
TIMSK |= _BV(OCIE1A);
#endif
#else
#warning RH_ASK_ATTINY_USE_TIMER1 not set.
// используем таймер 0 (по умолчанию)
// определяем значение прескалера и значение совпадения счетчика
// REVISIT: неправильно обрабатывает тактовую частоту 1 МГц, работает только с тактовой частотой 8 МГц
// При тактовой частоте 1 МГц получаем 1/8 ожидаемой скорости передачи данных
prescaler = timerCalc(_speed, (uint8_t)-1, &nticks);
... existing code
// ATtiny85
TIMSK |= _BV(OCIE0A);
#endif
#endif
Третье изменение касается настройки векторов. Обратите внимание на добавленный #if, определенный для TIMER1 и соответствующего вектора. Также обратите внимание, что вектор для timer0 теперь называется TIM0_COMPA_vect в более поздних версиях RadioHead/TinyHead, но имена TIMx и TIMERx взаимозаменяемы.
#if (RH_PLATFORM == RH_PLATFORM_ARDUINO)
#if defined(RH_PLATFORM_ATTINY)
#if defined(RH_ASK_ATTINY_USE_TIMER1)
#define RH_ASK_TIMER_VECTOR TIMER1_COMPA_vect
#else
#define RH_ASK_TIMER_VECTOR TIMER0_COMPA_vect
#endif
#else // Предположим, что Arduino Uno (328p или аналогичный)
Имейте в виду, что у меня возникали и другие проблемы при использовании библиотеки DallasTempSensor. Я не уверен, связана ли проблема с кристаллом низкого качества в моем ATTiny или нет, но я получаю мусорные показания с моего датчика. Тот же код безупречно работает на моем Arduino Nano, поэтому в настоящее время я исследую, не слишком ли отстает мой ATTiny по времени для правильной работы с этой библиотекой. Я также собираюсь попробовать протокол OneWire, чтобы посмотреть, работает ли он лучше. Однако вышеуказанное изменение кода решило мои проблемы с Arduino IDE и RadioHead/TinyHead.
- Эмуляция 1-проводных устройств
- ATtiny85 и DHT11 - Датчик всегда возвращает 0
- При использовании Arduino Uno в качестве ISP: "Yikes! Invalid device signature" - плохое соединение, неверную конфигурацию или неверную версию avrdude?
- Как получить исходные файлы для библиотек Arduino?
- Ошибка: "недопустимое использование нестатической функции-члена" при вызове функции из моего собственного класса-метода
- Как подключить Wi-Fi Shield ESP-12E-ESP8266-UART-WIFI-Wireless-Shield к Arduino
- Связь ATtiny85 с компьютером через USB
- Получить доступ к EEPROM ATtiny с помощью кода Arduino?
Звучит здорово, я думал, что у ATtiny85 есть только один таймер... TinyHead — моя облегченная копия RadioHead, и я протестирую ваш код в новой версии этой библиотеки как можно скорее!, @Thijs
Привет, прошло много времени, но я сейчас изучаю этот вопрос. Я не могу найти подходящего места для вашего кода.
#else
предполагает, что за ним последует больше кода, поэтому он не принадлежитtimerSetup()
вRK_ASK.cpp
?, @Thijs@Thjis, я обновил изменения кода выше. Я надеюсь, что это помогает. Изменения вносятся в RH_ASK.cpp, а в RH_ASK.h остается только #define. Кстати , я вижу, что ссылка на ваш GitHub не работает, поэтому я обновил ссылку, чтобы она указывала на enisocha., @Octofinger
Спасибо! Я перешёл на GitLab: https://gitlab.com/thijsvanulden/TinyHead и подал заявку на включение в индекс библиотеки Platformio. Я проверю ваш код, спасибо за ваш вклад! Кроме того, мой датчик Далласа у меня работает нормально, я использую DallasTemperature из индекса библиотеки Platformio., @Thijs
Я внес изменения, и TinyHead отлично работает с Timer1, спасибо за это. Но библиотека Далласа каким-то образом прерывает радиопередачу. Как только я вызываю
sensors.requestTemperatures()
, я больше не могу отправлять радиопередачи., @ThijsЯ успешно использую библиотеку OneWire [https://github.com/PaulStoffregen/OneWire](https://github.com/PaulStoffregen/OneWire). Плюсом является то, что это работает для меня, но недостатком является то, что вам нужно знать, какие команды отправлять по 1-проводной сети и как интерпретировать байтовые ответы. Я отказался от библиотеки DallasTempSensor, поскольку получил ненадежные показания ATTiny., @Octofinger