Радиомодуль HC-12 в режиме FU2 подвисает через несколько дней

Собрал очередной термометр удаленный на HC-12, все работает хорошо, но несколько дней, один раз отработало 4 дня, второй раз 11 дней, после чего модули ни на что не реагируют, на AT команды ответа тоже нет.
Почитал интернет, на буржуйских формах нашел похожую проблему, оказалось что модули могут тупо зависать даже если рядом мобильный телефон СМС ку будет отправлять или звонить.
Причем ничего не помогает, только передернуть ему питание.
Пробовал на МК переинициализировать UART и заново модулю давать команды DEFAULT - бесполезно, только отключение питания помогает.
Причем в прошлом году собрал аалогичный термометр, только отправка идет в режиме FU3 (по умолчанию который) с засыпанием в промежутках между отправкой - вот в Мае будет год как все отлично работает.

Отсюда вижу только такой вариант:
Транзисторный ключ, который раз например в три дня будет перезапускать модуль вместе с повторной инициализацией.

Вопрос:

  • кто нибудь встречался с таким поведением в энергосберегающем FU2 режиме?
  • может быть есть какая то волшебная AT команда или последовательность сигналов на пинах HC-12, перезагружащающая модуль?

Уж очень не хочется перепаивать уже готовые железки :frowning:

У меня будет несколько независимых, никак меж собой не связанных, реплик, ладно – не хочется делать несколько сообщений.

  1. Я бы вообще не “засыпал”, а выключал питание модуля, когда он не нужен (ключом на полевом транзисторе) . Мне кажется, так экономичнее для батареи. Или он слушать тоже должен?
  2. А модуль из той же партии, что тот, что уж скоро год как работает?
  3. Мне не нравятся версии о необъяснимом и неустранимом глюке в модулях даже на буржуйских (стал на колени и воздел руки к нему в молитвенном экстазе) форумах. Уж больно они (версии) похожи на оправдания кривого кода/рук китайскостью компонентов или (как в тебе намедни) санкциями. Если это avr – я бы посмотрел на код. Что-то мне сдаётся …
3 лайка
  1. Засыпание в режиме FU2 работает через раз, у меня во всяком случае. На старом форуме даже была тема похожая. Соотвественно и на передатчике и на приемнике я отказался от сна, повесил HC-12 на LowPower UART , приемник просыпается как приходит пакет по UART, передатчик просыпается по таймеру. Потребление всей схемы (на приемнике еще и ЖК дисплей постоянно включенный) порядка 100 мкА.
  2. модули из другой партии :frowning: хотел взять предыдущего продавца - уже нет их.
  3. конечно я допускаю что в коде проблема. Но он полная копия прошлогоднего, убран режим сна HC-12, добавлен другой дисплей + настройки STM32 для другого UART.
/**
 ******************************************************************************
 * @file           : main.c
 * @author         : Auto-generated by STM32CubeIDE
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2026 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */

/*
 * Очередной удаленный термометр на STM32g031f8p6 DS18b20 и ЖК экраном на приемнике
 */

#include <stdint.h>
#include "system_stm32g0xx.h"
#include "g0base.h"
#include "g0uart.h"
#include <stdio.h>
#include "stm32g0xx.h"
#include "g0st7567.h"
#include "g0ds18b20.h"
#include "g0oneware.h"
#include <string.h>
#include <stdlib.h>
#include "g0hc12.h"

#if !defined(__SOFT_FP__) && defined(__ARM_FP)
  #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif

extern "C" int __io_putchar(int ch) {
  g0uartWrite((const unsigned char) ch);
  return ch;
}

constexpr unsigned long periodSleepSec = 30UL*60UL; // период просыпания и отправки данных в секундах -> 30UL*60UL = 30 минут
constexpr unsigned long periodRebootSec = 15UL*24UL*60UL*60UL; // период принудительной перезагрузки 15 дней
// по результатам тестирования, через несколько дней беспрерывной работы перестает передаваться температура
// 27.03.2026 добавлен таймер переинициализации премопередатчика каждые почти три дня
constexpr unsigned long periodReinitSec = 3UL*23UL*60UL*60UL;

int main(void) {
	g0getIWDGreboot();
	g0initIWDG();
	g0resetIWDG();
	SystemInit();
	g0byHSI();
	SystemCoreClockUpdate();
	g0initPA4led();
	g0setPA4led(true);
	g0initPA7modeKEYS();
	g0onLSI();
	g0initLPTIM1wakeup();
	g0initUART1();
	printf("CLK = %d\r\n", (int)SystemCoreClock);
	g0initHC12();
	g0initDS18B20();
	if (g0readROMds18b20()) {
		g0saveTHTLCFG();
		printf("DS18B20 ready.\r\n");
		g0convertDS18B20();
		delay_ms(750);
		g0readRAMds18b20();
		t_ram_ds18b20 * ddd = getRAMds18B20();
		printf("local temp = %d\r\n", g0dsRAMtoTempInt(ddd));
		g0sendHC12tempDS18B20(ddd, true);
	}
	if (getDeviceRecieveMode()) { // reciever mode
		printf("reciever mode\r\n");
		initST7567bySPI1af0();
		st7567a_PrintString((const unsigned char *)"STM32G031F8P6", 0, 0);
		st7567a_PrintString((const unsigned char *)"ST7567A SPI1", 0, 1);
		st7567a_PrintString((const unsigned char *)"HC-12 LPUART1", 0, 2);
		st7567a_PrintString((const unsigned char *)"outdoor", 0, 3);
		st7567a_PrintString((const unsigned char *)"thermometer", 4, 4);
		if (g0lastIWDGreboot()) st7567a_PrintString((const unsigned char *)"IWDG start", 0, 5);
		else  st7567a_PrintString((const unsigned char *)"normal start", 0, 5);
		spiOFFST7567();
	}
	if (g0lastIWDGreboot()) printf("IWDG start\r\n");
	else  printf("normal start\r\n");
	while (g0uartLoopTX()) {};
	g0setPA4led(false);
	g0disableUART1();
    /* Loop forever */
	while (1) {
		if (getDeviceRecieveMode()) { // reciever mode
			// -- to sleep --
			PWR->CR1 &= ~PWR_CR1_LPMS; // 000: Stop 0 mode
			PWR->CR1 |= PWR_CR1_LPMS_0; // 001: Stop 1 mode
			SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;  // Set SLEEPDEEP bit
			LPUART1->CR1 |= USART_CR1_UESM; // 1: LPUART able to wake up the MCU from low-power mode. When this function is active, the clock source for the LPUART must be HSI or LSE (see RCC chapter)
			__WFI();
			// -- wakeup --
			LPUART1->CR1 &= ~USART_CR1_UESM; // 0: LPUART not able to wake up the MCU from low-power mode
		    PWR->SCR |= PWR_SCR_CWUF;   // Clear wake-up flags
			g0resetIWDG();
			//g0testIWDGsec40();
			static unsigned long currentTimerSleep = 0;
			static unsigned long lastTimeGetLocalTempSec = 0UL;
			static unsigned long periodLastGetTemp = 0UL;
			static int extTemp = 0;
			t_ram_ds18b20 extRAM;
			t_ram_ds18b20 * eee = &extRAM;
			delay_ms(50UL); // после просыпания ждем пока по uart прилетят все байты
		    if (((seconds() - currentTimerSleep) >= (periodSleepSec - 9UL*60UL)) || (g0getHC12data(eee))) { // приемник просыпается на 9 минут чаще передатчика
		    	currentTimerSleep = seconds();
		    	// internal / local sensor ds18b20
				g0initDS18B20();
				initST7567bySPI1af0();
				if (g0readROMds18b20()) {
					g0saveTHTLCFG();
					g0convertDS18B20();
					delay_ms(750);
					g0readRAMds18b20();
					st7567a_PrintString((const unsigned char *)"T local DS18B20", 0, 0);
					int localTemp = g0dsRAMtoTempInt(getRAMds18B20());
					unsigned char lT[16];
					lT[0] = '\0';
					DS18B20intToString((const int)localTemp, (const unsigned char *)&lT[0]);
					st7567a_PrintString((const unsigned char *)&lT[0], 5, 1);
					lastTimeGetLocalTempSec = seconds();
				} else {
					st7567a_PrintString((const unsigned char *)"no local DS18B20", 0, 0);
					if (lastTimeGetLocalTempSec) {
						unsigned char oS[16];
						oS[0] = '\0';
						strcpy((char *) &oS[0], (const char *) "last ");
						unsigned long wasPeriod = (seconds() -  lastTimeGetLocalTempSec) / 60UL;
						unsigned char lT[16];
						lT[0] = '\0';
						itoa((int)wasPeriod, (char *)&lT[0], 10);
						strcat((char *) &oS[0], (const char *)&lT[0]);
						strcat((char *) &oS[0], (const char *)"m.ago");
						st7567a_PrintString((const unsigned char *)&oS[0], 0, 1);
					} else {
						st7567a_PrintString((const unsigned char *)"data is missing", 0, 1);
					}
				}
				// show uptime
				unsigned char uS[17];
				uS[0] = '\0';
				unsigned long uPeriod = seconds() / 60UL; // minutes
				sprintf((char *)&uS[0], "%dd.%02dh.%02dm.", (int)(uPeriod/60UL/24UL), (int)((uPeriod%1440UL)/60UL), (int)(uPeriod%60UL));
				st7567a_PrintString((const unsigned char *)&uS[0], 0, 3);
				// outdoor / external sensor ds18b20
				if (g0getHC12last()) {
					periodLastGetTemp = seconds();
					extTemp = g0dsRAMtoTempInt(eee);
					unsigned char oS[16];
					oS[0] = '\0';
					DS18B20intToString((const int)extTemp, (const unsigned char *)&oS[0]);
					st7567a_PrintString((const unsigned char *)&oS[0], 1, 5, 1);
				} else if (periodLastGetTemp) { // приходили данные // отображаем температуру и время прошедшее с последнего прихода
						unsigned char oS[16];
						oS[0] = '\0';
						DS18B20intToString((const int)extTemp, (const unsigned char *)&oS[0]);
						st7567a_PrintString((const unsigned char *)&oS[0], 1, 5, 1);
						oS[0] = '\0';
						strcpy((char *) &oS[0], (const char *) "last ");
						unsigned long wasPeriod = (seconds() -  periodLastGetTemp) / 60UL;
						unsigned char lT[16];
						lT[0] = '\0';
						itoa((int)wasPeriod, (char *)&lT[0], 10);
						strcat((char *) &oS[0], (const char *)&lT[0]);
						strcat((char *) &oS[0], (const char *)"m.ago");
						st7567a_PrintString((const unsigned char *)&oS[0], 0, 7);
				}
				// end show display
				spiOFFST7567();
		    }
		} else { // transmitter mode
			// -- to sleep --
			PWR->CR1 &= ~PWR_CR1_LPMS; // 000: Stop 0 mode
			PWR->CR1 |= PWR_CR1_LPMS_0; // 001: Stop 1 mode
			SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;  // Set SLEEPDEEP bit
			__WFI();
			// -- wakeup --
		    PWR->SCR |= PWR_SCR_CWUF;   // Clear wake-up flags
			g0resetIWDG();
			static unsigned long transmitTimerSleep = 0UL;
		    if ((seconds() - transmitTimerSleep) >= periodSleepSec) {
		    	transmitTimerSleep = seconds();
				g0initDS18B20();
				if (g0readROMds18b20()) {
					g0saveTHTLCFG();
					g0convertDS18B20();
					delay_ms(750);
					g0readRAMds18b20();
					g0sendHC12tempDS18B20(getRAMds18B20());
				}
		    } else {
		    	g0setPA4led(true);
				delay_ms(80);
		    	g0setPA4led(false);
		    }
		}
		static unsigned long currentRebootTimer = 0UL;
		if ((seconds() - currentRebootTimer) >= periodRebootSec) {
			currentRebootTimer = seconds();
			NVIC_SystemReset();
		}
		static unsigned long currentReinitTimer = 0UL;
		if ((seconds() - currentReinitTimer) >= periodReinitSec) {
			currentReinitTimer = seconds();
			g0initHC12();
		}
	}
}


/*
 * g0hc12.cpp
 *
 *  Created on: Apr 1, 2025
 *      Author: seleznev_a
 */

#include "g0hc12.h"
#include "stm32g0xx.h"
#include "g0base.h"
#include <stdio.h>
#include "g0uart.h"
#include <string.h>
#include <ctype.h>

unsigned char lpfoBufTXlog[max_buf_lpuart]; // буфер отправки
unsigned char lpfoBufRXlog[max_buf_lpuart]; // буфер приема
unsigned short lpfoPosTXlog; // текущая абсолютная позиция отправки
unsigned short lpfoPosRXlog; // аналогично для приема
unsigned short lpfoCountTXlog; // количество байт на отправку
unsigned short lpfoCountRXlog; // количество не прочитанных байт

bool lastOKextTemp = false;

bool g0getHC12last(void) {
	bool extLast = lastOKextTemp;
	lastOKextTemp = false;
	return extLast;
}

void g0hc12toSetMode(void) {
	GPIOA->BSRR |= GPIO_BSRR_BR5; // LOW
	delay_ms(50);
}

void g0hc12toWorkMode(void) {
	GPIOA->BSRR |= GPIO_BSRR_BS5; // HIGH
	delay_ms(50);
}

void g0initPinPA5(void) {
	RCC->IOPENR |= RCC_IOPENR_GPIOAEN; // GPIO A port ON
	GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD5; // No pull-up, pull-down
	GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEED5; // 00: Very low speed
	GPIOA->OTYPER |= GPIO_OTYPER_OT5; // 1: Output open-drain
	GPIOA->MODER |= GPIO_MODER_MODE5_0; // 01: Output mode
	GPIOA->MODER &= ~GPIO_MODER_MODE5_1; // 01: Output mode
}

extern "C" void USART3_USART4_LPUART1_IRQHandler(void) {
	if (LPUART1->ISR & USART_ISR_RXNE_RXFNE) { //Следим за состоянием данного флага 1 - данные пришли, 0- пусто
		while (g0uartLoopTX()) {};
                lpfoBufRXlog[lpfoPosRXlog] = (unsigned char)LPUART1->RDR; // вносим его в массив  // считываем байт из регистра МК
                ++lpfoCountRXlog; // увеличиваем счетчики
                ++lpfoPosRXlog; // увеличиваем счетчики
                if (lpfoPosRXlog >= max_buf_lpuart) lpfoPosRXlog = 0; // если позиция превысила размер - обнуляем
	}
}

void g0initLPUART1(void) {
    lpfoPosTXlog = 0; lpfoPosRXlog = 0; lpfoCountTXlog = 0; lpfoCountRXlog = 0; // сбрасываем все переменные
	RCC->IOPENR |= RCC_IOPENR_GPIOAEN; // GPIO A port ON
    // PA2 Настраиваем порт Tx
    GPIOA->MODER |= GPIO_MODER_MODE2_1; // 10 — режим альтернативной функции.
    GPIOA->MODER &= ~GPIO_MODER_MODE2_0; // 10 — режим альтернативной функции.
	GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEED2; // 00: Very low speed
    GPIOA->OTYPER &= ~GPIO_OTYPER_OT2; // 0 - двухтактный выход или push-pull сокращено PP (после сброса)
    GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD2_1; // 01 — подтяжка к плюсу питания или pull-up сокращено PU
    GPIOA->PUPDR |= GPIO_PUPDR_PUPD2_0; // 01 — подтяжка к плюсу питания или pull-up сокращено PU
    GPIOA->AFR[0] &= ~GPIO_AFRL_AFSEL2; // 0000: AF0 >> port2
    GPIOA->AFR[0] |= GPIO_AFRL_AFSEL2_2; // 0110: AF6 >> port2
    GPIOA->AFR[0] |= GPIO_AFRL_AFSEL2_1; // 0110: AF6 >> port2
    // PA3 Настаиваем Rx
    GPIOA->MODER |= GPIO_MODER_MODE3_1; // 10 — режим альтернативной функции.
    GPIOA->MODER &= ~GPIO_MODER_MODE3_0; // 10 — режим альтернативной функции.
	GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEED3; // 00: Very low speed
    GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD3_1; // 01 — подтяжка к плюсу питания или pull-up сокращено PU
    GPIOA->PUPDR |= GPIO_PUPDR_PUPD3_0; // 01 — подтяжка к плюсу питания или pull-up сокращено PU
    GPIOA->AFR[0] &= ~GPIO_AFRL_AFSEL3; // 0000: AF0 >> port3
    GPIOA->AFR[0] |= GPIO_AFRL_AFSEL3_2; // 0110: AF6 >> port3
    GPIOA->AFR[0] |= GPIO_AFRL_AFSEL3_1; // 0110: AF6 >> port3
    // Настраиваем LPUART1 by HSI16
	RCC->APBENR1 &= ~RCC_APBENR1_LPUART1EN; // LPUART1 clock OFF
	RCC->CCIPR &= ~RCC_CCIPR_LPUART1SEL; // 00: LPUART1 clock by PCLK
	RCC->CCIPR |= RCC_CCIPR_LPUART1SEL_1; // 10: HSI16
	RCC->APBENR1 |= RCC_APBENR1_LPUART1EN; // LPUART1 clock ON
	LPUART1->PRESC = 2; // 0010: input clock divided by 4
	LPUART1->BRR = 0x1A0AB; // 16000000 * 256 / 4 / 9600 = 106666 -> 0x1A0AA
	// start LPUART1
    LPUART1->ISR = 0;
    LPUART1->CR1 |= USART_CR1_RXNEIE_RXFNEIE; // 1: USART interrupt generated whenever ORE = 1 or RXNE = 1 in the USART_ISR register
    NVIC_EnableIRQ(LPUART1_IRQn);
    LPUART1->CR1 |= USART_CR1_UE|USART_CR1_TE|USART_CR1_RE;
}

void g0setLPUARTto4800(void) {
    LPUART1->CR1 &= ~(USART_CR1_UE|USART_CR1_TE|USART_CR1_RE);
	LPUART1->BRR = 0x34155; // 16000000 * 256 / 4 / 4800 = 213333 -> 0x34155
    LPUART1->CR1 |= USART_CR1_UE|USART_CR1_TE|USART_CR1_RE;
}

void g0lprtWrite(const unsigned char inByte) { // кладет байт в отправляемый кольцевой буфер
    if (lpfoCountTXlog < max_buf_lpuart) { // если в кольцевом буфере есть место
        lpfoBufTXlog[lpfoPosTXlog] = inByte; // кладем байт в буфер
        ++lpfoCountTXlog; //увеличиваем счетчик
        ++lpfoPosTXlog; //увеличиваем счетчик
        if (lpfoPosTXlog >= max_buf_lpuart) lpfoPosTXlog = 0; // если позиция перепрыгрула за границу - обнуляем
    }
}

bool g0lprtLoopTX(void) {
	if (lpfoCountTXlog) { // если есть что отправлять
		if (LPUART1->ISR & USART_ISR_TXE_TXFNF) { // в сдвиговом регистре пусто
		    if (lpfoCountTXlog <= lpfoPosTXlog) { // если позиция отправки больше количества отправляемых байт
		    	LPUART1->TDR = (unsigned char)lpfoBufTXlog[lpfoPosTXlog-lpfoCountTXlog]; // берем первый вошедший байт // кладем байт в регистр МК для непосредственно отправки
		    } else { // если хвост кольцевого буфера выходит за границы размеров
		    	LPUART1->TDR = (unsigned char)lpfoBufTXlog[max_buf_lpuart-(lpfoCountTXlog-lpfoPosTXlog)]; // берем байт по другой логике // кладем байт в регистр МК для непосредственно отправки
		    }
	        --lpfoCountTXlog; // уменьшаем счетчик не отправленных байт
		}
		return true;
	}
	return false;
}

unsigned short g0lprtAvailable(void) { // возвращает количество байт в приемном буфере лога
    return lpfoCountRXlog;
}

unsigned char g0lprtRead(void) { // читаем входящий байт из кольцевого буфера
    unsigned char currOut; // Переменная куда читать
    if (lpfoCountRXlog <= lpfoPosRXlog) { // если позиция чтения больше остатка
        currOut = lpfoBufRXlog[lpfoPosRXlog-lpfoCountRXlog]; // читаем
    } else { // если хвост чтения за границей буфера
        currOut = lpfoBufRXlog[max_buf_lpuart-(lpfoCountRXlog-lpfoPosRXlog)]; // читаем по другой формуле
    }
    --lpfoCountRXlog; // уменьшаем счетчик количества
    return currOut; // возвращаем прочитанный байт
}

void g0lprtPrint(const unsigned char * inString) {
	unsigned short i = 0;
	while (*(inString+i)) {
		g0lprtWrite(*(inString+i));
		++i;
	}
}

bool g0waitHC12responseOKRN(bool showResp) {
	unsigned char responseStr[] = "OK\r\n";
	constexpr unsigned char lenResponse = 4;
	bool outResult = false;
	delay_ms(200); // wait for get response from HC-12
	unsigned char findPos = 0;
	while (g0lprtAvailable()) {
		unsigned char inB = g0lprtRead();
		if (inB) {
			if (showResp) {
				g0uartWrite(inB);
				while (g0uartLoopTX()) {};
			}
			if (inB == responseStr[findPos]) {
				if ((++findPos) >= lenResponse) {
					findPos = 0;
					outResult = true;
					break;
				}
			} else {
				findPos = 0;
				break;
			}
		}
	}
	return outResult;
}

void g0justWaitHC12response(bool showResp) {
	delay_ms(200); // wait for get response from HC-12
	while (g0lprtAvailable()) {
		unsigned char inB = g0lprtRead();
		if ((inB) && (showResp)) {
			g0uartWrite(inB);
			while (g0uartLoopTX()) {};
		}
	}
}

void g0sendHC12(const unsigned char * inCMD, bool showLog, bool needWaitResp = false) {
	g0lprtPrint(inCMD);
	while (g0lprtLoopTX()) {};
	if (showLog) {
		g0uartPrint(inCMD);
		g0uartWrite('\n');
		while (g0uartLoopTX()) {};
	}
	if (needWaitResp) g0justWaitHC12response(showLog);
}

void g0testSpeedHC12(void) {
	unsigned long cntRepiter = 4UL;
	unsigned char strOK[] = "OK\r\n";
	unsigned long lenStr = strlen((const char *)strOK);
	constexpr unsigned long getStr = 8UL;
	unsigned char inStr[getStr];
	while (cntRepiter--) {
		unsigned long posIn = 0UL;
		g0sendHC12((const unsigned char *)"AT\r", true, false);
		delay_ms(200);
		while (g0lprtAvailable() && (posIn < getStr)) {
			unsigned char inB = g0lprtRead();
			if (inB) {
				g0uartWrite(inB);
				while (g0uartLoopTX()) {};
				inStr[posIn++] = inB;
				if (posIn == lenStr) {
					if (!memcmp((const void *)&strOK[0], (const void *)&inStr[0], lenStr)) return;
				}
			}
		}
		if (cntRepiter == 2UL) g0setLPUARTto4800();
	}
}

void g0initHC12(void) {
	g0initLPUART1();
	g0initPinPA5();
	g0hc12toSetMode();
	g0testSpeedHC12();
	g0sendHC12((const unsigned char *)"AT+DEFAULT\r", true, true);
	g0sendHC12((const unsigned char *)"AT+C056\r", true, true); // channel 001...127
	g0sendHC12((const unsigned char *)"AT+FU2\r", true, true); // 4800 baudrate
	g0sendHC12((const unsigned char *)"AT+RX\r", true, true);
	g0hc12toWorkMode();
	g0setLPUARTto4800();
}

unsigned char * addByteToStringAs2char(const unsigned char * inS, const unsigned char inByte) {
	unsigned char * pStr = (unsigned char *)inS;
	char sN[3] = {'\0', '\0', '\0'};
	sprintf((char*)&sN[0], "%02X", inByte);
	strcat((char *)pStr, (const char *)&sN[0]);
	return pStr + 2;
}

void g0sendHC12tempDS18B20(t_ram_ds18b20 * outData, bool needShowLog) {
	unsigned char * pData = (unsigned char *)outData;
	constexpr unsigned char lenData = sizeof(t_ram_ds18b20);
	unsigned char outStr[lenData*2+1];
	unsigned char * pStr = (unsigned char *) &outStr[0];
	memset(pStr, '\0', lenData*2+1);
	for (unsigned char i = 0; i < lenData; ++i) {
		pStr = addByteToStringAs2char(pStr, *(pData+i));
	}
	g0sendHC12((const unsigned char *)&outStr[0], needShowLog, true);
}

unsigned char getByteByChar(const unsigned char * inPos) { // преобразования двух текстовых байт в число
    unsigned char outByte = 0;
    unsigned char c1 = *inPos;
    if (isdigit(c1)) outByte = c1 - '0'; else outByte = c1 - 55;
    outByte *= 16;
    c1 = *(inPos + 1);
    if (isdigit(c1)) outByte += c1 - '0'; else outByte += c1 - 55;
    return outByte;
}

bool g0getHC12data(t_ram_ds18b20 * pData) {
	constexpr unsigned char lenData = sizeof(t_ram_ds18b20);
	constexpr unsigned char lenStr = lenData*2;
	if (g0lprtAvailable() != lenStr) {
		while (g0lprtAvailable()) __attribute__((unused)) unsigned char y = g0lprtRead();
		return false;
	}
	unsigned char inStr[lenStr+1];
	inStr[lenStr] = '\0';
	unsigned char posStr = 0;
	while (g0lprtAvailable()) {
		unsigned char iB = g0lprtRead();
		if (iB) {
			if ((((iB>='A') && (iB<='F')) || ((iB>='0') && (iB<='9'))) && (posStr < lenStr)) {
				inStr[posStr++] = iB;
			} else {
				posStr = 0;
			}
		}
	}
	if (posStr == lenStr) {
		unsigned char * ta = (unsigned char *)pData;
		unsigned char * as = (unsigned char *)&inStr[0];
		for(unsigned char i = 0; i <= lenData; ++i) {
			*(ta++) = getByteByChar(as);
			as += 2;
		}
		lastOKextTemp = true;
		return true;
	} else {
		return false;
	}
}