Ошибка 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, мне нравится
  }
}

, 👍1


1 ответ


Лучший ответ:

3

У меня возникло множество проблем при использовании библиотеки 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.

,

Звучит здорово, я думал, что у 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