Arduino и модули RF433 нет передачи данных
- Войдите на сайт для отправки комментариев
Вс, 07/02/2021 - 00:15
Пытаюсь сделать метеостанцию с выносным датчиком, передача с него при помощи модулей 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мс }
Отвечаю себе сам - отключил прерывания в момент передачи, все стало нормально.