Если getTemperatureb блокирующий, то луп короче его выполнения получить невозможно.
Извиняюсь, здесь не подумал, что всё так серьёзно))
В этом случае (ИМХО), нет возможности задать более-менее точный интервал. Остаётся надеяться на точность RC генератора в режиме SLEEP
Немного улучшить дело можно так:
(не проверял, т.к. не на чем)
Спойлер
#include "lgt_LowPower.h"
#include "FineOffset.h"
#include <Wire.h>
#include <AHTxx.h>
#define TX_PIN 2
#define DEVICE_ID 1235
//AHT20 aht20;
AHTxx aht20(AHTXX_ADDRESS_X38, AHT2x_SENSOR);
FineOffset tx(TX_PIN);
unsigned long timer1;
float temp;
void setup() {
timer1 = millis();
CLKPR = 1<<PMCE;
CLKPR = 0b00000100;// не уверен, что нужны эти строчки, но
//ни на чём не настаиваю, т.к. не могу проверить
// timer1 = millis(); //как вариант, эта строка здесь
Wire.begin();
aht20.begin();
temp = aht20.readTemperature();
}
void loop() {
if (millis() - timer1 > 1000) {
tx.send(DEVICE_ID, temp);
for (int i=0; i<2; i++) {
LowPower.powerDown(SLEEP_16S, ADC_OFF, BOD_OFF);
}
for (int i=0; i<1; i++) {
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
for (int i=0; i<1; i++) {
LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);
}
for (int i=0; i<1; i++) {
LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
}
for (int i=0; i<1; i++) {
LowPower.powerDown(SLEEP_128MS, ADC_OFF, BOD_OFF);
}
}
}
Я не понял на каком этапе у вас сейчас затруднения. Т.к. в приведенных вариантах кода нет комментариев, зачем это и почему.
Если надо просто иметь фиксированное время этапа то можно сделать вида
#define TIME_1 200 //
void loop() {
// Кусок кода который должен выполнятся фиксированное время TIME_1 200 мс
millis_1 = millis(); // Время начала
1 Получение температуры (длительность меняется например от 50 до 150)
2 Отправка результатов по Serial
Serial.flush(); // ждем окончание отправки по сериал.
//Общее время 1 + 2 (включая окончание отправки) должно быть меньше TIME_1
//для перестраховки проверим это.
if (millis() - millis_1 > TIME_1) { // если не уложились в TIME_1 то сообщаем
Serial.print("TIME_1 Error ");
Serial.println(millis() - millis_1);
Serial.flush(); // ждем окончание отправки по сериал.
}
while (millis() - millis_1 < TIME_1) {}; // Ждем окончание TIME1
// Конец куска кода который должен выполнятся фиксированное время
4 Команда спать.
}
Другой вариант, вам предлагали раньше (но с ним надо разбираться).
Если хочется еще уменьшить потребление, и допустимо отправлять результат предыдущего измерения, то как писали выше можно разбить получение температуры на два этапа - команда на чтение результата предыдущего измерения, команда на старт нового измерения, сон.
Не приходилось работать с этой библиотекой , поэтому поверил на слово.
Но теперь не уверен ,что это так, иначе не работали бы циклы
for (int i=0; i<2; i++) {
LowPower.powerDown(SLEEP_16S, ADC_OFF, BOD_OFF);
}
а сразу же, после первого прохода, проц уходил бы в ресет, и, начинал бы стартовать с “чистого листа”.
Посмотрел в библиотеку - так и есть.
Чтобы “отрубить чип полностью”, есть другая функция -
LowPower.deepSleep2(SLEEP_1S);
Можно легко проверить, запустив скетч, (подправить под lgt)
Спойлер
uint32_t timer1;
uint32_t timer2;
void setup() {
timer1 = millis();//начало отсчёта
wdt_enable(WDTO_1S);
Serial.begin(9600);
delay(1000);//время для усл. датчика
while (millis() - timer1 < 1500); //ждём, пока пройдёт 1.5 сек
timer2 = millis() - timer1;
Serial.println(timer2);//печатаем время с начала работы
delay(100);//задержка для печати
LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
Serial.println(millis() - timer2);
}
void loop(void) {
}
Если нижняя строчка в сетап отобразится - значит происходит выход из сна, и, продолжается выполнение программы
Это я собственно к тому, что мой скетч из #22, скорее всего нерабочий.
P.S.
Пока, лучше варианта не вижу, разве совсем всё переделывать
Спойлер
#include "lgt_LowPower.h"
#include "FineOffset.h"
#include <Wire.h>
#include <AHTxx.h>
#define TX_PIN 2
#define DEVICE_ID 1235
//AHT20 aht20;
AHTxx aht20(AHTXX_ADDRESS_X38, AHT2x_SENSOR);
FineOffset tx(TX_PIN);
float temp;
void setup() {
CLKPR = 1<<PMCE;
CLKPR = 0b00000100;
Wire.begin();
aht20.begin();
}
void loop() {
static uint32_t timer1 = 0;
static bool start = true;
if(start)
{
timer1 = millis();
start = false;
temp = aht20.readTemperature();// //датчик читаем здесь
}
if (millis() - timer1 > 1000 && !start) {
tx.send(DEVICE_ID, temp);//передаём показания датчика
for (int i=0; i<2; i++) {
LowPower.powerDown(SLEEP_16S, ADC_OFF, BOD_OFF);
}
for (int i=0; i<1; i++) {
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
for (int i=0; i<1; i++) {
LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);
}
for (int i=0; i<1; i++) {
LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
}
for (int i=0; i<1; i++) {
LowPower.powerDown(SLEEP_128MS, ADC_OFF, BOD_OFF);
}
start = true;
Serial.println(millis() - timer1);
}
}
Добрый вечер, уважаемые!
Спасибо за такое живое участие в “проблеме” и простите за нечастое посещение форума (дома жена, дети сопливые…).
Попробую по порядку:
Пост 22
Код работает и очень хорошо, повторяемость в пределах единиц миллисекунд, но сохраняется другая проблема, о ней позже.
Пост 23
С вашим куском еще не разбирался, обязательно позже посмотрю.
С потреблением проблем нет, в момент отправки (занимает в среднем 0,25 секунды) ~ 16мА, во время сна оставшиеся 47,75 сек - единицы мкА)
Пост 24
Да, на счет отрубания MCU вы правы, отрубается он только в deepSleep2, видимо до туда я не дочитал, хотя подозревал это, ведь циклы то работали в powerDown.
Проверить работу через сериал не получается, монитор в упор не видит ее на рекомендованных 57600, буду пробовать через putty, т.к. надо разбираться с “другой проблемой”.
Код отсюда обязательно попробую.
Ну и замеры с кодом из 22 поста:
21:47:03.900 -> ID: 1235, Temp: 31.4
21:47:51.889 -> ID: 1235, Temp: 31.4 //47.989
21:48:39.869 -> ID: 1235, Temp: 31.4
21:50:15.831 -> ID: 1235, Temp: 31.4
21:51:03.837 -> ID: 1235, Temp: 31.4 //48.006
21:52:39.856 -> ID: 1235, Temp: 31.4
21:53:27.845 -> ID: 1235, Temp: 31.4 //47.989
21:55:51.855 -> ID: 1235, Temp: 31.4
21:56:39.854 -> ID: 1235, Temp: 31.4 //47.999
21:57:27.877 -> ID: 1235, Temp: 31.4 //48.023
21:58:15.854 -> ID: 1235, Temp: 31.4 //47.977
21:59:51.867 -> ID: 1235, Temp: 31.4
22:01:27.922 -> ID: 1235, Temp: 31.4
22:03:03.920 -> ID: 1235, Temp: 31.4
22:03:51.934 -> ID: 1235, Temp: 31.4 //48.014
22:06:55.756 -> ID: 1235, Temp: 31.4
22:07:43.780 -> ID: 1235, Temp: 31.4 //48.024
22:08:31.783 -> ID: 1235, Temp: 31.4 //48.003
22:09:19.777 -> ID: 1235, Temp: 31.4 //47.994
Повторяемость очень хорошая, но на лицо две проблемы:
- Разбег между результатами 47* и 48* связан скорее всего с библиотекой FineOffset.h, в ней настраивается количество попыток отправки, по умолчанию - 3, поменял на 2, вероятно приходят данные от первой или второй попытки, отсюда и разница, но она думаю не критична, близка к оригинальным датчикам.
- Основная проблема - пропуски отправок, хорошо видно в логе, пока так и не удалось выяснить причин, как варианты - приемник, отсутствие данных от AHTxx, или одно из двух…
Еще раз всем спасибо, как разберусь с подключением по сериал, будет проще выяснить причину пропусков.
Ещё раз скажу: этот код рассчитан на сброс по WDT. Он будет работать только с функцией
Но с этой функцией не возможны никакие циклы.
В вашем случае, код не работает правильно, т.к передаёт одно и то же значение температуры.
#24 должен работать правильно.
Да, 22ой конечно не работает, в погоне за точностью не обратил что AHT в setup.
24ый работает сносно, в пределах 1,5 десятков разбег, но “пропуски” сохраняются, нужно еще поковыряться в библиотеке датчика, или попробовать другую.
Не библиотеки подбирать надо, а даташит открыть и увидеть, что готовность данных подтверждается статусным битом. И перед запуском конверсии нужно кое-что проверить и реинит устроить с ожиданием.
Так что тут только каждые 10 мс просыпаться, делать койчо с датчиком, посылать фигню в эфир и засыпать. Без библиотеки. Если с ней, то всегда будет разброд и шатание.
Про эти самые биты и думал, надо пробовать, опыта мало. Но вот сейчас подумалось, раз код из 22 поста отправлял константу а пропуски сохранялись, значит скорее всего проблема не с чтением датчика а с отправкой данных.
Вывод не соответствует логике.
Если проблема возникает в результате действий А и Б, но при этом сохраняется при несовершении действия А, то из этого не следует, что единственной причиной было действие Б.
Иными словами - если в пятницу закусить три литра водки тазиком несвежего салата и, впоследствии, лежать зелёным все выходные, то никак нельзя обвинять в отравлении исключительно салат.
Попробуйте пожертвовать временем сна. Уменьшите время сна на 1сек(к примеру), и, добавьте это время в условие с timer1 к 1000мс. Так, чтобы перекрыло пропуски.
P.S.
А если дело в отправке, то, можно ещё один таймер добавить, который “перекроет” нестабильное событие.
P.P.S.
Можно ссылку на эту библиотеку? Что-то не пойму , в чём её смысл
Как вариант, по-простому отправку выровнять
Спойлер
#include "lgt_LowPower.h"
#include "FineOffset.h"
#include <Wire.h>
#include <AHTxx.h>
#define TX_PIN 2
#define DEVICE_ID 1235
//AHT20 aht20;
AHTxx aht20(AHTXX_ADDRESS_X38, AHT2x_SENSOR);
FineOffset tx(TX_PIN);
float temp;
void setup() {
CLKPR = 1<<PMCE;
CLKPR = 0b00000100;
Wire.begin();
aht20.begin();
}
void loop() {
static uint32_t timer1 = 0;
static bool start = true;
if(start)
{
timer1 = millis();
start = false;
temp = aht20.readTemperature();// //датчик читаем здесь
}
if (millis() - timer1 > 1000 && !start) {
timer1 = millis();//запоминаем время начала отправки
tx.send(DEVICE_ID, temp);//передаём показания датчика
while(millis() - timer1 < 1000);//ждём, пока пройдёт 1сек
//от начала отправки
for (int i=0; i<2; i++) {//время сна придётся уменьшить
LowPower.powerDown(SLEEP_16S, ADC_OFF, BOD_OFF);
}
for (int i=0; i<1; i++) {
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
for (int i=0; i<1; i++) {
LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);
}
for (int i=0; i<1; i++) {
LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
}
for (int i=0; i<1; i++) {
LowPower.powerDown(SLEEP_128MS, ADC_OFF, BOD_OFF);
}
start = true;
Serial.println(millis() - timer1);//время от начала отправки
}
}
По моему уже было в другой теме : написанное выше бессмысленно, т.к. никакого цикла всё равно нет.
Можно просто записать
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
Я и сам скопировал, не глядя
Да, это проверю.
https://github.com/zagor/FineOffset
Конечно полностью А исключать не стоит)
Попробуйте наоборот, увеличить кол-во отправок.
Глянул, ничего там сложного. Одна отправка данных приёмнику занимает от 12 до 80мс .Но это крайние значения, в реальности длительность где-то между “плавать” будет. Повтор, если задан, через 10мс. Обратной связи нет, просто шлёт crc.
Так что выровнять отправку по времени не мешает.
Другое дело - неизвестно, как среагирует приёмник на несколько отправок подряд - примет за одну, или каждую посчитает. Если за одну - то можно смело добавлять число отправок, чтобы не было пропусков.