Arduino и модули RF433 нет передачи данных

mir0tv0rec
Offline
Зарегистрирован: 19.09.2018

Пытаюсь сделать метеостанцию с выносным датчиком, передача с него при помощи модулей RF433. Ну смысл не в "железе", а коде.

Написал скетч для термометра на 2х матрицах MAX7219, все работало как было задумано (Скроллировало температуру и влажность туда - сюда). Но не понравилась задержка прокрутки при передаче данных по радиочастоте. Переписал код на 2 дисплея TM1637 и тут возникла проблема - нет передачи данных.

Скетч следующий:

// Подключаем библиотеки:
#include <iarduino_RF433_Transmitter.h> // Подключаем библиотеку для работы с передатчиком FS1000A
#include <SPI.h>              // подключаем библиотеку для работы с шиной SPI
#include <Wire.h>             // подключаем библиотеку для работы с шиной I2C
#include <sav_button.h>       // подключаем библиотеку для работы с кнопками
#include <Adafruit_HTU21DF.h> // подключаем библиотеку для работы с HTU21DF
#include "TM1637Display.h"    // подключаем библиотеку для работы с TM1637 (для отладки)


#define CLK_PIN_T       6     // пин TM1637 - температура
#define DIO_PIN_T       7     // пин TM1637 - температура
#define CLK_PIN_H       8     // пин TM1637 - влажность
#define DIO_PIN_H       9     // пин TM1637 - - влажность

#define BT_PIN          2             // Пин подключения кнопки
#define RF_PIN          4             // Пин подключения передатчика
#define CHARGE_PIN      5             // Пин управления полевиком зарядки АКБ
#define RD_WAIT         5000          // Пауза в миллисекундах между опросами датчика
#define LOW_VOLT        174           // Значение низкого напряжения АКБ ~3V
#define HIGH_VOLT       242           // Значение высокого напряжения АКБ ~4.15V

Adafruit_HTU21DF HTU21 = Adafruit_HTU21DF();    // Создаём объект HTU21 для работы с библиотекой Adafruit_HTU21DF
iarduino_RF433_Transmitter radio(RF_PIN);       // Создаём объект radio для работы с библиотекой iarduino_RF433, указывая номер вывода к которому подключён передатчик

TM1637Display dispTemp(CLK_PIN_T,DIO_PIN_T);    // объявляем  переменную для работы с TM1637 (температура)
TM1637Display dispHum(CLK_PIN_H,DIO_PIN_H);    // объявляем  переменную для работы с TM1637 (влажность)

unsigned long ms, ms1;        // переменная таймера
float realTemp, realHum;      // переменные для хранения температуры и влажности
uint8_t backTime = 0;         // время отображения
uint8_t brLvl = 1 ;           // уровень яркости 0-7
uint8_t maxBr = 3 ;           // максимальный уровень яркости 0-7
int8_t lTmp, hTmp, hHum;      // переменные для разбивки данных по разрядам
uint8_t analog_ref = DEFAULT; // переменная для хранения состояния регистра ADMUX

bool  autoBr  = true;             // флаг включения дисплея
volatile bool brPin = false;      // флаг выбора входа АЦП
volatile bool trueValue = false;  // переменная для пропуска преобразования АЦП при переключении входов 
volatile bool lowVoltage = false; // флаг низкого напряжения
volatile bool charging = false;   // флаг включения зарядки АКБ 
volatile bool charge = false;     // флаг окончания зарядки АКБ

volatile uint8_t countBr = 0, countVolt = 0, countV = 0; // счетчики
volatile uint8_t voltVal = 0;         // значение с АЦП для ослеживания пропадания напряжения питания
volatile uint16_t voltValTmp = 0;     // значение для временного хранения и усреднения занчений с АЦП
volatile uint8_t brightVal = 0;       // значение с АЦП для автоматического изменения яркости
volatile uint16_t brightValTmp = 0;   // значение с АЦП для автоматического изменения яркости

const uint8_t SEG_Err[] = {
  SEG_A | SEG_D | SEG_E | SEG_F | SEG_G,  // E
  SEG_E | SEG_G,                          // r
  SEG_E | SEG_G};                         // r
   

uint8_t dataT[] = {0x00, 0x00, 0x00, 0x00}; // массив для вывода данных на дисплей температуры
uint8_t dataH[] = {0x00, 0x00, 0x00, 0x00}; // массив для вывода данных на дисплей влажности

char msg[20];


SButton BUT (BT_PIN,50,1500,0,0);

#include "text_to_disp.h"
#include "ADC.h"
#include "autobright.h"


void setup(){
  //Serial.begin(9600);

  pinMode(CHARGE_PIN, OUTPUT);  // пин включения зарядки на выход
  digitalWrite(CHARGE_PIN, LOW);  // низкий уровень на пине

  dispTemp.setBrightness(brLvl);  // устанавливаем яркость
  dispHum.setBrightness(brLvl);  // устанавливаем яркость

  radio.begin(1000);        // Инициируем работу передатчика FS1000A, 1000 bit/s
  radio.openWritingPipe(5); // Открываем 5 трубу для передачи данных

  if (!HTU21.begin()) {
    //Serial.println("Couldn't find sensor!");  // для отладки
    while(1){
      dispTemp.setSegments(SEG_Err);  // выводим "Err"
      delay(1000);
      dispTemp.clear();
      dispHum.setSegments(SEG_Err);   // выводим "Err"
      delay(1000);
      dispHum.clear();  
    }// end while
  }// end if

  BUT.begin();
  ADC_init();
  //realTemp = -35.45;  // отладка
  //realHum = 0;        // отладка
    
}// end setup()                                                        

void loop(){

  // включаем зарядку АКБ
  if (lowVoltage && !charging){
    digitalWrite(CHARGE_PIN, HIGH);  // высокий уровень на пине
    charging = true;  // флаг включения зарядки АКБ      
  }//end if

  // включаем зарядку АКБ
  if (charging && !charging){
    digitalWrite(CHARGE_PIN, HIGH);  // высокий уровень на пине
    charging = true;  // флаг включения зарядки АКБ      
  }//end if
  
  // выключаем зарядку АКБ
  if (charge){
    charge = false; // флаг окончания зарядки
    digitalWrite(CHARGE_PIN, LOW);  // низкий уровень на пине  
  }// end if

  // устанавливаем уровень яркости (при автоматической)
  if (millis() - ms > 250){
    ms = millis();
    if (autoBr) AutoBright();
  }// end if
  
  // считываем показания датчика раз в RD_WAIT mc
  // передаем данные по радиоканалу
  if ((millis() - ms1) > RD_WAIT){
    ms1 = millis();
    realTemp = HTU21.readTemperature();
    //realTemp += 0.1;  // отладка
    hTmp = realTemp * 100 / 100;  // выделяем целые градуса
    lTmp = abs(int(realTemp * 100) % 100);  // выделяем сотые градуса
    //округляем до десятых
    if (lTmp % 10 < 5) lTmp = lTmp / 10;  // в меньшую сторону
    else if (lTmp % 10 >= 5 && lTmp % 10 < 9 && lTmp / 10 < 9) lTmp = lTmp / 10 + 1; // если от 5 до 8 включительно, в большую
    else { // если 9, в большую
      lTmp = 0; // обнуляем
      hTmp++;   // увеличиваем десятки  
    }// end else if
    // вводим поправочный коэфф. при темп. от 0 до 80
    // влажность с учетом поправочного коэфф.
    if (realTemp > 0 && realTemp < 80)realHum = (HTU21.readHumidity() + (25 - realTemp) * -0.15);
    else realHum = HTU21.readHumidity();
    //realHum += 0.1; // отладка
    hHum = round(realHum); // округляем влажность, дробные нам не нужны...
    if (hHum > 99) hHum = 99; //
    String strMsg = "HTU21";  // сигнатура - данные
    strMsg += "=";  // разделитель
    strMsg += hTmp; // температуру в строку
    strMsg += ".";  // десятичная точка
    strMsg += lTmp; // температуру в строку
    strMsg += "=";  // разделитель
    strMsg += hHum; // присоединяем влажность
    strMsg.toCharArray(msg, strMsg.length() + 1); // переводим строку в массив символов + 1 конец строки
    radio.write(&msg, sizeof(msg)); // отправляем данные из массива msg указывая сколько байт массива мы хотим отправить
    //Serial.print("Температура:"); // для отладки
    //Serial.print(realTemp);       // для отладки
    //Serial.print(" - ");          // для отладки
    //Serial.print(hTmp);           // для отладки
    //Serial.print(".");            // для отладки
    //Serial.println(lTmp);         // для отладки
    //Serial.print("Влажность:");   // для отладки
    //Serial.print(realHum);        // для отладки
    //Serial.print(" - ");          // для отладки
    //Serial.println(hHum);         // для отладки
    //Serial.print("Яркость:");     // для отладки
    //Serial.println(brightVal);    // для отладки
    //Serial.print("Напряжение АКБ:");   // для отладки
    //Serial.println(voltVal);           // для отладки
    WriteToDisplay(); // выводим информацию на дисплеи
  }//end if
  
  //обработка кнопки
  switch(BUT.Loop()){
    case SB_NONE:
    break;
    
    case SB_CLICK:
      if (!autoBr){
        brLvl++;
        if (brLvl > 3) brLvl = 0;       // яркость ограничиваем 3
        dispTemp.setBrightness(brLvl);  // устанавливаем яркость температура 
        dispHum.setBrightness(brLvl);   // устанавливаем яркость влажность
        WriteToDisplay(); //  изменяем яркость (нужно вывести данные для изменения яркости)    
      }//end if
    break;
    
    case SB_LONG_CLICK:
      autoBr = !autoBr; // инвертируем флаг
    break;
    
    case SB_AUTO_CLICK:
      
    break;
  }//end switch(BUT.Loop())
}//end loop

//------------------------------------------------------
// инициализируем АЦП
//
void ADC_init(){
  ACSR = 0x00;      // сбрасываем регистр компаратора
  ACSR |= 1 << ACD; // выключаем питание компаратора
  
  ADCSRA = 0;             // Сбрасываем регистр ADCSRA
  ADCSRB = 0;             // Сбрасываем регистр ADCSRB
  ADMUX |= (1 << REFS1) | (1 << REFS0);  // Задаем ИОН внутренний 1.1В (для АТМега328)

  ADMUX |= (1 << ADLAR);  // Меняем порядок записи бит, чтобы можно было читать только 8 бит регистра ADCH

  analog_ref = ADMUX;     // Запоминаем состояние регистра - из него мы будем формировать маску для смены входного пина вход A0
  ADMUX |= (1 << MUX2) | (1 << MUX1);   // Выбираем пин A6 для преобразования

  ADCSRA |= (1 << ADPS2) | (1 << ADPS0);      // Устанавливаем предделитель - 32 (биты 1 0 1)

  ADCSRA |= (1 << ADATE); // Включаем автоматическое преобразование
  ADCSRA |= (1 << ADIE);  // Разрешаем прерывания по завершении преобразования
  ADCSRA |= (1 << ADEN);  // Включаем АЦП
  ADCSRA |= (1 << ADSC);  // Запускаем преобразование
}// ADC_init()

//----------------------------------------------------------
// обработчик прерывания
// по завершению преобразования АЦП
ISR(ADC_vect) {
  if (trueValue) {
    uint8_t result = ADCH;    // ADLAR=1, Получаем 8-битный результат, 2 младшими битами пренебрегаем (ADCL)
    // Если актуальный входной пин A7, то присваиваем значение соответствующей переменной
    if (brPin) {
      if (countBr < 10){
        brightValTmp += result;
        countBr++;
      }// end if 
      else{
        brightVal = brightValTmp / countBr;
        brightValTmp = 0;  
        countBr = 0;
        brPin = false; // выбираем пин
        ADMUX = analog_ref;  // сбрасываем вход (A0)
        ADMUX |= (1 << MUX2) | (1 << MUX1);   // Выбираем пин A6 для преобразования
      }// end else
    }// end if
    else {
      if (countVolt < 10){  //10 отсчетов для более стабильного результата
        voltValTmp += result;
        countVolt++;
      }// end if 
      else {
        voltVal = voltValTmp / countVolt;  // находим среднее значание из  количества отсчетов
        voltValTmp = 0; // обнуляем временную переменную
        countVolt = 0; // обнуляем счетчик
        if (voltVal < LOW_VOLT) { // если напряжения меньше LOW_VOLT
          countV++; // инкрементируем счетчик
          if (countV > 4) {  // считываем несколько раз, исключая ошибку 
            countV = 0; // обнуляем счетчик
            lowVoltage = true;  // устанавливаем флаг низкого напряжения
          }// end if (countV > 4)
        }// end if (voltVal < LOW_VOLT)
        else if (voltVal >= HIGH_VOLT && charging){
          countV++; // инкрементируем счетчик
          if (countV > 4) {  // 
            countV = 0; // обнуляем счетчик
            charging = false; // флаг зарядки
            lowVoltage = false; // флаг низкого напряжения
            charge = true;  // флаг окончания зарядки    
          }// end if (countV > 4)  
        }// end else if
        brPin = true;  // выбираем пин
        ADMUX = analog_ref;  // сбрасываем вход
        ADMUX |= (1 << MUX2) | (1 << MUX1) | (1 << MUX0);   // Выбираем пин A7 для преобразования
      }// end else  
    }// end else
    trueValue = false;  // Устанавливаем флаг смены входного пина - следующее прерывание пропускаем
  }// end if (trueValue)
  else {
    trueValue = true;   // Первый раз пропускаем считывание и устанавливаем флаг на чтение в следующий раз
  }// end else
}// ISR(ADC_vect)

//----------------------------------------------
// авторегулировка яркости
void AutoBright(){
  uint8_t brLvlAuto = 0;
  if (brightVal <= 215){
    brLvlAuto = 0;    
  }// end if
  else if (brightVal > 215 && brightVal <= 225){
    brLvlAuto = 1;
  }//end else if
  else if (brightVal > 225 && brightVal <= 235){
    brLvlAuto = 2;
  }//end else if
  else if (brightVal > 235){
    brLvlAuto = 3;
  }//end else if
  dispTemp.setBrightness(brLvlAuto);  // устанавливаем яркость
  dispHum.setBrightness(brLvlAuto);   // устанавливаем яркость 
}// end AutoBright()

//==== Выводим данные на дисплеи ====
void WriteToDisplay(){
  if (hTmp < 0) dataT[0] = SEG_G; // 1 символ
  else dataT[0] = 0;
  dataT[1] = dispTemp.encodeDigit(abs(hTmp) / 10); // 2 символ
  dataT[2] = dispTemp.encodeDigit(abs(hTmp) % 10) | SEG_H; // 3 символ
  dataT[3] = dispTemp.encodeDigit(lTmp); // 4 символ
  dispTemp.setSegments(dataT);  // выводим на 1 дисплей
  
  dataH[0] = dispTemp.encodeDigit(hHum / 10); // 1 символ
  dataH[1] = dispTemp.encodeDigit(hHum % 10); // 2 символ
  dataH[2] = SEG_A |SEG_B | SEG_F |SEG_G;     // 3 символ (0 - вверху)
  dataH[3] = SEG_C | SEG_D | SEG_E | SEG_G;   // 4 символ (0 - внизу)
  dispHum.setSegments(dataH);  // выводим на 2 дисплей
  
}// end WriteToDisplay()

А вот из примера этой библиотеки код работает, не могу понять, что у меня не так? Причем даже заливаю его в 2 ардуины, меняю местами передатчики, ставлю оба на одну ардуину...

// ПРИМЕР ДЛЯ ПРОВЕРКИ РАБОТЫ ПРИЁМНИКА (MX-RM-5V) И ПЕРЕДАТЧИКА (FS1000A) НА ОДНОЙ ПЛАТЕ ARDUINO
//
// Приёмник   подключён к выводу D3
// Передатчик подключён к выводу D4
//
// Алгоритм: Значение массива i отправляется передатчиком, принимается приёмником в массив j и выводится на монитор
// Если приёмник и передатчик работают, то на монитере будут появляться строки Hello World с указанием номера трубы, по которой они получены
//
// Подключаем библиотеку:
#include <iarduino_RF433_Transmitter.h>                   // Подключаем библиотеку для работы с передатчиком FS1000A
#include <iarduino_RF433_Receiver.h>                      // Подключаем библиотеку для работы с приёмником MX-RM-5V

// Объявляем объекты, переменные и массивы:
iarduino_RF433_Transmitter radioTX(4);                    // Создаём объект radioTX для работы с библиотекой iarduino_RF433, указывая номер вывода к которому подключён передатчик
iarduino_RF433_Receiver    radioRX(3);                    // Создаём объект radioRX для работы с библиотекой iarduino_RF433, указывая номер вывода к которому подключён приёмник (можно подключать только к выводам использующим внешние прерывания)
char                     i[]="Hello World!!!";               // Создаём массив для передачи данных
char                     j[20];                           // Создаём массив для приёма   данных
uint8_t                  k;                               // Создаём переменную, в которую получим номер трубы, по которой приняты данные

void setup(){
//  ===============================
    Serial.begin(9600);                                   // Инициируем передачу данных по последовательному порту на скорости 9600 бит/сек
//  =============================== ПЕРЕДАТЧИК
    radioTX.begin(1000);                                  // Инициируем работу передатчика FS1000A на скорости 1 кбит/сек
//  radioTX.setDataRate(i433_1KBPS);                      // Скорость передачи данных можно изменить вызвав данную функцию в любом месте кода. Параметры (i433_5KBPS, i433_4KBPS, i433_3KBPS, i433_2KBPS, i433_1KBPS, i433_500BPS, i433_100BPS), i433_1KBPS - 1кбит/сек
    radioTX.openWritingPipe(5);                           // Открываем 5 трубу для передачи данных (передатчик может передавать данные только по одной из труб: 0...7). Если повторно вызвать функцию openWritingPipe указав другой номер трубы, то передатчик начнёт передавать данные по вновь указанной трубе
//  =============================== ПРИЁМНИК
    radioRX.begin(1000);                                  // Инициируем работу приёмника MX-RM-5V (в качестве параметра можно указать скорость ЧИСЛО бит/сек, тогда можно не вызывать функцию setDataRate)
//  radioRX.setDataRate(i433_1KBPS);                      // Скорость приёма данных можно изменить вызвав данную функцию в любом месте кода. Параметры (i433_5KBPS, i433_4KBPS, i433_3KBPS, i433_2KBPS, i433_1KBPS, i433_500BPS, i433_100BPS), i433_1KBPS - 1кбит/сек
    radioRX.openReadingPipe (5);                          // Открываем 5 трубу для приема данных (если вызвать функцию без параметра, то будут открыты все трубы сразу, от 0 до 7)
//  radioRX.openReadingPipe (2);                          // Открываем 2 трубу для приёма данных (таким образом можно прослушивать сразу несколько труб)
//  radioRX.closeReadingPipe(2);                          // Закрываем 2 трубу от  приёма данных (если вызвать функцию без параметра, то будут закрыты все трубы сразу, от 0 до 7)
    radioRX.startListening  ();                           // Включаем приемник, начинаем прослушивать открытую трубу
//  radioRX.stopListening   ();                           // Выключаем приёмник, если потребуется
}

void loop(){
//  =============================== ПРИЁМНИК
    if(radioRX.available(&k)){                            // Если в буфере имеются данные принятые приёмником, то получаем номер трубы в переменную k и ...
       radioRX.read(&j, sizeof(j));                       // Читаем данные в массив j и указываем сколько байт читать
       Serial.print(j);                                   // Выводим полученные данные на монитор
       Serial.println((String)" (Pipe="+k+")");           // Выводим номер трубы, по которой эти данные получены. Так можно определить, от кокого передатчика они получены
    }
//  =============================== ПЕРЕДАТЧИК
    radioTX.write(&i, sizeof(i));                         // Отправляем данные из массива i указывая сколько байт массива мы хотим отправить
    delay(200);                                           // Ждем 200мс
}

 

mir0tv0rec
Offline
Зарегистрирован: 19.09.2018

Отвечаю себе сам - отключил прерывания в момент передачи, все стало нормально.