HC-12 - время входа и выхода в-из sleep mode

b707
Offline
Зарегистрирован: 26.05.2017

Собрал выносной термосенсор (в пробке от большой бутылки :) состоящий из Attiny85, датчика DS18B20 и модема HC-12. Предполается мобильное питание, поэтому озадачился энерпотреблением.  Потратив несколько часов на чтение мануалов и форумов, удалось понизить общее потребление всей схемы в режиме сна примерно до 30мкА (22 мкА по даташиту берет НС-12, еще 5-6 должна брать тинька, оставшиеся 2-3мкА - видимо погрешность измерений). Результат меня полностью устраивает (честно говоря, ожидал порядка 100-200мкА).

Но это касается режима сна. В активном же режиме выяснилась неприятная особенность. Настроив по советам импортных форумов задержки для перехода HC-12 из активного режима в сон и обратно, я получил следующие процедуры (комментарии на английском - цитаты из форума по ссылке)

void HC-12_sleep() {
digitalWrite(SET_PIN, LOW);  //Down 'SET' pin low to enter SETUP mode
delay(50);                   //Wait at least 40m seconds
hc-12.println("AT+SLEEP");
delay(100);                  //Allow modem to response
digitalWrite(SET_PIN, HIGH); //Return the 'SET' line high again to exit SETUP mode
}

void HC-12_wakeup() {
digitalWrite(SET_PIN, LOW);  //Pulse 'Set' pin low, 50 mS should be enough
delay(50); 
digitalWrite(SET_PIN, HIGH); //Return the 'SET' line high
delay(250);                  //and WAIT at least 200mS for the module to reset itself
                             //HC-12 should now be OK to receive/send data
}

Видно, что переход HC-12 в сон занимает порядка 150мс, а выход из сна - 250-300мс. С учетом того, что все это время модем потребляет около 15мА, выходит, что на эти периоды приходится три четверти всего расхода батарейки. Довольно непроизводительно, ИМХО.

Собственно, вопрос - как уменьшить это время?

Путь экспериментально подобрать задержки, уменьшая их пока не найнет глючить - вариант мне не нравится. Один раз настроишь, а потом изменится напряжение батарейки или температура в комнате и все поедет. Хотелось бы каких-то обоснованных данных, какое минимальное время ставить в каждом пункте. К сожалению, на НС-12 я не нашел нормального даташита, все что выложено в инете - по сути "инструкции пользователя" с минимумом подробностей.

sadman41
Offline
Зарегистрирован: 19.10.2016
b707
Offline
Зарегистрирован: 26.05.2017

sadman41 пишет:

Поможет ли страница #20 https://datasheetspdf.com/pdf-down/S/i/4/Si4464-SiliconLaboratories.pdf ?

спасибо, посмотрел по диагонали. Ты прав, самая интересная - страница 20 :) согласно таблице 9. выход из полного shutdown в TX-mode занимает 15мс. Правда, написано, что цифры только для справки и не гарантируют готовность к работе. ОК, возьмем с двойным запасом. Сколько-то там еще выход в активный режим управляющего МК STM8. Ну пусть все вместе 50мс. Откуда же эти , на форуме,  взяли свои чудовищные 200?

Остальные цифры из их прописи остались непонятны. Почему переход в командный режим требует "at least 40mS" ? - откуда они это взяли, хотел бы я знать ...

sadman41
Offline
Зарегистрирован: 19.10.2016

Кто ж их знает. Может с осцилографом сидели и меряли разряд/заряд RC-цепочки. Или взяли с двойным запасом.

b707
Offline
Зарегистрирован: 26.05.2017

Да, без экспериментов никак :) попробую поставить вместо 200мс - 50. Согласно табличке, это и так с тройным запасом... Посмотрим, что получится.

sadman41
Offline
Зарегистрирован: 19.10.2016

Там еще какой-то пин Interrupt есть. Не дергается ли он, когда чип очухался? 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

А как часто отправка данных требуется? Может и бог с ним с потреблением в активном режиме из за 1 секунды работы в час например

b707
Offline
Зарегистрирован: 26.05.2017

andycat пишет:
А как часто отправка данных требуется? Может и бог с ним с потреблением в активном режиме из за 1 секунды работы в час например

Это выносной датчик для термостата, он должен давать данные раз минуту или в крайнем случае раз в 2 минуты.

В данном случае есть за что бороться - если снизить время "просыпания" НС-12 с 400 до 200мс - получим увеличение жизни батарейки в 1.5 раза.

sadman41
Offline
Зарегистрирован: 19.10.2016

У меня есть выносной датчик от метеостанции RST - год на батарее работает вместе с экраном и светодиодом. Шлет данные только в том случае, когда температура изменилась на градус.

b707
Offline
Зарегистрирован: 26.05.2017

Поменял тайминги на 30 и 50мс в обоих процессах. Все отлично работает.

void HC-12_sleep() {
digitalWrite(SET_PIN, LOW);  //Down 'SET' pin low to enter SETUP mode
delay(50);                   //Wait at least 40 mS for switch mode
hc-12.println("AT+SLEEP");
delay(50);                  //Allow modem to response
digitalWrite(SET_PIN, HIGH); //Return the 'SET' line high again to exit SETUP mode
}

void HC-12_wakeup() {
digitalWrite(SET_PIN, LOW);  //Pulse 'Set' pin low, 50 mS should be enough
delay(50); 
digitalWrite(SET_PIN, HIGH); //Return the 'SET' line high
delay(50);                  //and WAIT at least 50mS for the module to reset itself
                             //HC-12 should now be OK to receive/send data
}

По результатам чтения даташита на Si446x эти цифры представляются мне более разумными, чем у ребят с того форума. В своем коде оставлю именно эти настройки.

sadman41 - спасибо за ссылку.

sadman41
Offline
Зарегистрирован: 19.10.2016

Я б камменты подправил еще на всякий случай, чтобы последователи голову не чесали

b707
Offline
Зарегистрирован: 26.05.2017

sadman41 пишет:

Я б камменты подправил еще на всякий случай, чтобы последователи голову не чесали

точно

b707
Offline
Зарегистрирован: 26.05.2017

не-а, не все так просто оказалось :) Насчет первой цифры - "как минимум 40 мс для входа в командный режим" - они, похоже, правы. Если поставить 30мс - переключается неустойчиво. Для первой задержки в обоих процедурах вернул значение 50. Поправил комменты выше.

a5021
Offline
Зарегистрирован: 07.07.2013

Черт его знает, как там китайцы рулят si4463 через STM8, но лично я бы в первую очередь озадачился попытками написать свою прошивку для тамошнего МК. Смысл такой, что si4463 имеет на борту собственные часики (RTC). Спящий чип с тикающими часиками потребляет 0.9мка. Часики умеют в нужное время пробуждать сам si4463, плюс пинать кого нужно снаружи. Общая логика работы модифицированного hc-12 может быть такой: после включения устройства, STM8 инициализирует что нужно, включая термосенсоры, после чего все устройство заваливается спать, оствив тикать только RTC. В заданное время все это хозяйство просыпается, STM8 производит все нужные измерения и передачи данных, после чего девайс опять засыпает. В таком режиме вполне можно добиться, чтобы усредненное потребление всего хозяйства с датчиками оказалось на уровне 10-20мка*ч, а ардуина вообще не нужен. Насчет энергопотребления, правда, стоит оговориться, что это без учета расходов на радиопередачу. Работа большой мощностью на низких скоростях может сильно подкорректировать приведенные цифры.

b707
Offline
Зарегистрирован: 26.05.2017

a5021 пишет:

Черт его знает, как там китайцы рулят si4463 через STM8, но лично я бы в первую очередь озадачился попытками написать свою прошивку для тамошнего МК.

это конечно да - если задействовать в качестве МК набортный STM8 - можно было бы делать очень компактные самодостаточные девайсы. В принципе, это возможно, у CTM8 на плате HC-12 выведен SWIM, а на Гитхабе даже лежит самописная прошивка для модуля. Но, судя по обсуждениям - это пока не более чем первый подход - прошивка поддерживает только самые общие функции Si4463. связь по дефолту, параметры не настраиваются.

Но как стартовая точка вполне... если хочется погрузится.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

b707 пишет:

Собрал выносной термосенсор (в пробке от большой бутылки :) состоящий из Attiny85, датчика DS18B20

А кодом самого получения температуры не поделитесь? и реализацию UART хотелось бы посмотреть.

а то мне не нравиться, то что я применяю - иногда 0 возвращает :(


void OneWireReset()
{
  PORTB &= ~_BV(DS_BIT);
  DDRB |= _BV(DS_BIT);
  _delay_us(500);
  DDRB &= ~_BV(DS_BIT);
  _delay_us(500);
}

void OneWireOutByte(uint8_t d)
{
  uint8_t n;
  for (n = 8; n != 0; n--)
  {
    if ((d & 0x01) == 1)
    {
      PORTB &= ~_BV(DS_BIT);
      DDRB |= _BV(DS_BIT);
      _delay_us(5);
      DDRB &= ~_BV(DS_BIT);
      _delay_us(60);
    }
    else
    {
      PORTB &= ~_BV(DS_BIT);
      DDRB |= _BV(DS_BIT);
      _delay_us(60);
      DDRB &= ~_BV(DS_BIT);
    }
    d = d >> 1;
  }
}


uint8_t OneWireInByte()
{
  uint8_t d, n, b;
  for (n = 0; n < 8; n++)
  {
    PORTB &= ~_BV(DS_BIT);
    DDRB |= _BV(DS_BIT);
    _delay_us(5);
    DDRB &= ~_BV(DS_BIT);
    _delay_us(5);
    b = ((PINB & _BV(DS_BIT)) != 0);
    _delay_us(50);
    d = (d >> 1) | (b << 7);
  }
  return (d);
}


word GetTemp() {
  uint8_t DSdata[2];
  OneWireReset();
  OneWireOutByte(0xcc);
  OneWireOutByte(0x44);
  PORTB |= _BV(DS_BIT);
  DDRB |= _BV(DS_BIT);
  unsigned long delp = millis(); while ((millis() - delp) <= 1000);
  //_delay_ms(1000); // если хотим ждать когда датчик посчитает температуру.
  DDRB &= ~_BV(DS_BIT);
  PORTB &= ~_BV(DS_BIT);
  OneWireReset();
  OneWireOutByte(0xcc);
  OneWireOutByte(0xbe);
  DSdata[0] = OneWireInByte();
  DSdata[1] = OneWireInByte();
  word TReading = (word)(DSdata[1] << 8) + DSdata[0];
  if ((word)(TReading & 0x8000) == (word)(0x8000)) {
    TReading = (~TReading) + (word)1;
    TReading = (((word)6 * TReading) + TReading / (word)4) / (word)10;
  } else {
    TReading = (((word)6 * TReading) + TReading / (word)4) / (word)10 + (word)2000;
  }
  return TReading;
}

 

b707
Offline
Зарегистрирован: 26.05.2017

andycat пишет:

А кодом самого получения температуры не поделитесь? и реализацию UART хотелось бы посмотреть.

боюсь вы будете разочарованы. У меня все на Ардуино-коде, без регистров... это же тинька85, там памяти дофига.

Код чтения температуры - стандартный, только в задержку я вставил включение передатчика:

int getTemp(){
  int t=1111;  // default value - return in case of error
  byte i;
  byte data[9];
    
    ds.reset(); 
    ds.write(0xCC);
    ds.write(0x44);
    delay(800);
    hc_12_wakeup();
    ds.reset();
    ds.write(0xCC);
    ds.write(0xBE);
    for ( i = 0; i < 9; i++) {                // we need 9 bytes
      data[i] = ds.read(); }
    if (OneWire::crc8(data, 8) != data[8]) {  //CRC check
      DEBUG_PRINTLN(("CRC is not valid!"));
      return t;
     }
     t = (data[1] << 8) | data[0];
     return  (t*10)>>4;   // integer celcius * 10  (214=>21,4*C)
  
}

реализация UART - через #include <SoftwareSerial.h> :)

sadman41
Offline
Зарегистрирован: 19.10.2016

ds.reset возвратит 1, если шина готова. Можно немного поэкономить батарею. А небольшая математическая операция - "дождать" N msec после завершения hc_12_wakeup(), это еще поэкономит.

b707
Offline
Зарегистрирован: 26.05.2017

sadman41 пишет:

А небольшая математическая операция - "дождать" N msec после завершения hc_12_wakeup(), это еще поэкономит.

Насчет ds.reset() понятно, согласен. А вот что там "дождать" после wake_up -  честно говоря, не вкурил идею.

sadman41
Offline
Зарегистрирован: 19.10.2016

delay(800) + дилеи в функции пробуждения - это больше, чем нужно для конверсии. можно же delay(800-50-50) cделать, например. Или запустить конверсию, засечь время, запустить пробуждение, посчитать сколько миллисов оно заняло и вычесть из планируемого времени конверсии. И дождать остаток.

b707
Offline
Зарегистрирован: 26.05.2017

sadman41 пишет:

delay(800) + дилеи в функции пробуждения - это больше, чем нужно для конверсии. можно же delay(800-50-50) cделать, например.

А, ну это так и сделано :) - изначально в этом коде стояло delay(1000), я добавил в конец задержки пробуждение модуля и уменьшил делей до 800. Можно и 700 поставить

sadman41 пишет:
Или запустить конверсию, засечь время, запустить пробуждение, посчитать сколько миллисов оно заняло и вычесть из планируемого времени конверсии. И дождать остаток.

это будет невыгодно. В активном режиме модуль HC-12 потребляет в 12 раз больше энергии, чем вся остальная схема, поэтому его нужно включать в самый последний момент.

По задержке конверсии резерв для экономии - уменьшить разрядность данных с датчика, тогда и задержка будет меньше.

sadman41
Offline
Зарегистрирован: 19.10.2016

По спецификации - 750ms на 12бит. 1000 - это как-то уж слишком.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Спасибо, моя ошибка в том что, что crc не проверял.

Дмитро5
Offline
Зарегистрирован: 16.12.2019

Тоже пытаюсь перевести в режим сна.

Arduino Pro Mini, HC12, датчик DS18B20. скорость 1200bps, режим FU4 (до 100мА при передаче).

Несмотря на вішеуказанные команды (delay ставил и по 50мс и по 250мс (чтобы команда прошла на этой скорости гарантированно), все равно потребление НС12 = 14мА. DS18B20 с подтяшивающим резистором потребляет меньше 1мА.

То ли не воспринимает команду, непонятно почему, то ли скорость команд исключительно 9600bps.

Что можно сделать? Заранее спасибо.

b707
Offline
Зарегистрирован: 26.05.2017

Дмитро5 пишет:

То ли не воспринимает команду, непонятно почему, то ли скорость команд исключительно 9600bps.

Что можно сделать? Заранее спасибо.

ответ на команду получаете? После команды "AT+SLEEP, модуль должен ответить "OK+SLEEP".

 

Дмитро5
Offline
Зарегистрирован: 16.12.2019

Экспериментальным путем (десяток заливок) определил что на 1200bps работают только огромные тайминги(

void HC12_sleep() {
  Serial.println(); 
  Serial.flush(); // Перевод строки после payload информации и ожидании сброса буфера
  delay(750);
  digitalWrite(HC12_SET_PIN, LOW);  //Down 'SET' pin low to enter SETUP mode
  delay(450);                   //Wait at least 40 mS for switch mode
  Serial.println("AT+SLEEP");
  Serial.flush();
  delay(500);    

...

И только тогда получаю желанный OK+SLEEP ! Нужно 1,6 с, чтобы вйоти в режим сна! (((

b707
Offline
Зарегистрирован: 26.05.2017

не забывайте еще SET пин вернуть обратно, а то модем в сон так и не уйдет

kms
Offline
Зарегистрирован: 16.11.2020

У меня другая проблема. hc-12 засыпает но уже не просыпается. Кто нибудь сталкивался с таким?

С таймингами разумеется игрался, вплоть до 1 сек.

#define RF_SET PB2

void rf_sleep()
{
  PORTB &= ~(1 << RF_SET); // Пин Set устанавливаем в 0
  _delay_ms(50);
  uart_write((uint8_t *)&at_sleep, 10, false); // Отправляем по uart
  _delay_ms(100);
  PORTB |= (1 << RF_SET); // Пин Set устанавливаем в 1
  _delay_ms(100);
  slp = true;
}

void rf_wakeup()
{
  if (!slp)
    return;
  PORTB &= ~(1 << RF_SET);
  _delay_ms(50);
  PORTB |= (1 << RF_SET);
  _delay_ms(100);
  slp = false;
}

int main()
{
  DDRB |= (1 << RF_SET);
  PORTB |= (1 << RF_SET);
  slp = false;
  uart_init();                // Инициализация UART
  setResolution(TEMP_11_BIT); // Устанавливаем разрешение дачика 11 бит
  requestTemp();              // Запрос датчику для чтения температуры

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  i = 0;

  while (1)
  {
    if (i == 1)
    {
      rf_wakeup();
      tx_data.temp = readTemp();                // Получаем температуру t / 10
      uart_write((uint8_t *)&tx_data, 4, true); // Отправляем по uart
      wait_for_send();                          // Ждем пока все отправитиься
      rf_sleep();
    }
    else if (i >= SEND_PERIOD) // i >= 20
    {
      requestTemp();
      i = 0;
    }

    sleep_enable();
    sleep_cpu();
  }
}

 

kms
Offline
Зарегистрирован: 16.11.2020

Вобщем почитал я интернет, спящий режим в hc-12 какая то не надежная штука, да и долго засыпает и просыпается. Решил просто отключать питание на модуль.

Как например тут https://habr.com/ru/post/545758/

Так наверное и оставлю.

kms
Offline
Зарегистрирован: 16.11.2020

А кто нибудь замерял потребление на разных мощностях?

У меня мультиметр погорел, как раз на миллиамперах, временно пользуюсь мультиметром встроенный в осциллограф, но там он какой то тормознутый и я ему не доверяю. Если конкретно то интересует на 11-14dbm.

PS: Сделал отключение HC-12 как писал выше, норм. Вместе с паузами и отправкой данных занимает 116мс.

Наверное можно и меньше сделать, но хватает и так.