All streams
Search
Write a publication
Pull to refresh
25
0
Владимир Бойчук @Cadil_TM

Пользователь

Send message
В статье добавил ссылку на архив с набором тестовых скетчей для измерений времени выполнения и тока операций.
Результаты измерений, как и раньше, — в таблице статьи.
А почему бы и не Лора?

Поддерживаю. Да и мощности в пределах квартиры достаточно 4 дБ.
Ассемблер даст выигрыш в размере кода ну может процентов 10 по сравнению с Си. Это если проект не большой, сотня-две байт. Если проект больше, то выигрыш в размере кода стремится к нулю, а в больших проектах может и Си скомпилировать меньший код за счёт лучшей оптимизации. В общем не тот это случай чтобы париться с асмом. Не пользуйтесь printf(), float, string и что там ещё у вас многожрущее. И самый главный выигрыш — нафиг ардуину, пишите на обычном си.

Спасибо! Коротко, внятно и однозначно.
Ну, если Вы не понимаете как размер кода влияет на энергопотребление, тогда о чем говорить. Посмотрите, пожалуйста, техописание комнатного термостата стр 11 — это оттуда: Напряжение питания 2 x 1.5V алкальных батарейки (LR6 AA), Потребляемая мощность 1.3 mW, Срок действия батареек ~ 1 год.
Вряд ли прибор прошит в коде Ардуино или у Вас есть сомнения? )

Далее, для примера, один из тестовых скетчей и короткий фрагмент таблицы с результатами теста. Таких таблиц с записями на 1300-1500 строк и тестовых скетчей у меня десяток. В ближайшее время размещу их в каком-нибудь облаке, чтобы рассеять сомнения. Моя статья и так перегружена, поэтому не стал не размещать тестовые скетчи, таблицы, видео (гифки) с измерениями тока и т.п.

тестовый скетч
/*скетч для измерения операционного времени приемником LoRa и макc. операц. тока
операционное время 0,083сек (83 мсек)
операционный ток 11.5 mA (Vbat=3V, 8 MHz)
*/

#include <avr/io.h>
#include <util/delay.h>

#include <SPI.h>
#include <LoRa.h>
#include <LowPower.h>
#include "HTU21D.h"
#include <LCD5110_Graph.h>

String LoRaData;

void setup() {
Serial.begin(38400);
Serial.println("Power ON!");

int counter = 0;
while (!LoRa.begin(433E6) && counter < 10) {
Serial.println("Не удалось найти LoRa-передатчик!");
counter++;
_delay_ms(500);
}

// Диапазон для синхрослова – между "0-0xFF".
LoRa.setSyncWord(0xF3);
Serial.println("Прослушивание эфира. Ожидание пакета с в.датчика ...");

_delay_ms(2000);
}

void loop() {
int packetSize = LoRa.parsePacket();
Serial.println("Прослушивание эфира.");
if (packetSize) {
while (LoRa.available()) {
LoRaData = LoRa.readString();
}
int pos1 = LoRaData.indexOf('#');
if ((LoRaData).substring(pos1, pos1 + 1) == "#")
{
Serial.println("Принято, декодировано!");
}
}
}

int main() {
init();
setup();

for (;;) {
loop();
}
}


таблица
10:53:29.744 -> Tin=21.90 Hin=41 BatIn=3.31 Tout=00.00 Hout=00 BatOut=BGood
10:53:30.144 -> Tin=21.90 Hin=41 BatIn=3.30 Tout=00.00 Hout=00 BatOut=BGood
10:53:30.544 -> Tin=21.90 Hin=41 BatIn=3.27 Tout=00.00 Hout=00 BatOut=BGood
10:53:30.944 -> Tin=21.90 Hin=41 BatIn=3.30 Tout=00.00 Hout=00 BatOut=BGood
10:53:31.304 -> Tin=21.90 Hin=41 BatIn=3.31 Tout=00.00 Hout=00 BatOut=BGood
10:53:31.704 -> Tin=21.90 Hin=41 BatIn=3.30 Tout=00.00 Hout=00 BatOut=BGood
10:53:32.104 -> Tin=21.80 Hin=41 BatIn=3.30 Tout=00.00 Hout=00 BatOut=BGood
10:53:32.504 -> Tin=21.90 Hin=41 BatIn=3.31 Tout=00.00 Hout=00 BatOut=BGood
10:53:32.904 -> Tin=21.90 Hin=41 BatIn=3.30 Tout=00.00 Hout=00 BatOut=BGood
10:53:33.304 -> Tin=21.90 Hin=41 BatIn=3.30 Tout=00.00 Hout=00 BatOut=BGood
10:53:33.704 -> Tin=21.90 Hin=41 BatIn=3.30 Tout=00.00 Hout=00 BatOut=BGood
10:53:34.064 -> Tin=21.90 Hin=41 BatIn=3.31 Tout=00.00 Hout=00 BatOut=BGood
10:53:34.464 -> Tin=21.80 Hin=41 BatIn=3.30 Tout=00.00 Hout=00 BatOut=BGood
10:53:34.866 -> Tin=21.90 Hin=41 BatIn=3.31 Tout=00.00 Hout=00 BatOut=BGood
10:53:35.266 -> Tin=21.90 Hin=41 BatIn=3.31 Tout=00.00 Hout=00 BatOut=BGood
10:53:35.666 -> Tin=21.90 Hin=41 BatIn=3.31 Tout=00.00 Hout=00 BatOut=BGood
10:53:36.066 -> Tin=21.90 Hin=41 BatIn=3.30 Tout=00.00 Hout=00 BatOut=BGood
10:53:36.466 -> Tin=21.90 Hin=41 BatIn=3.27 Tout=00.00 Hout=00 BatOut=BGood
10:53:36.866 -> Tin=21.90 Hin=41 BatIn=3.32 Tout=00.00 Hout=00 BatOut=BGood
10:53:37.226 -> Tin=21.80 Hin=41 BatIn=3.31 Tout=00.00 Hout=00 BatOut=BGood
10:53:37.626 -> Tin=21.90 Hin=41 BatIn=3.29 Tout=00.00 Hout=00 BatOut=BGood
10:53:38.026 -> Tin=21.90 Hin=41 BatIn=3.29 Tout=00.00 Hout=00 BatOut=BGood
10:53:38.426 -> Tin=21.90 Hin=41 BatIn=3.30 Tout=00.00 Hout=00 BatOut=BGood


Если уж сильно захочется посмотреть видео на тему потребления, тогда сюда. Тут подобных гифок хватает.

Я к тому, что отношусь к проблеме серьезно, а Вы делаете обобщающие выводы по одной неточности. Успехов!
Учту на будущее. Как-то не было проблем до сих пор. Спасибо!
А почему нет кода на ассемблер, откуда эти «оценочные» оценки? Очень интересно посмотреть, как Вы уместили в 200 байт шрифты для экранчика и преобразование данных с датчиков.

Работал с кодом термометра-гидрометра на ATtiny13. Получил объем занимаемой флеш-памяти 40 байт. Навскидку увеличил это число в 5 раз. Подредактирую эту цифру, если будут аргументы.
Вот код:
термометр-гидрометр на Ассемблере
// *********************************************
// *** Simple digital thermometer/hygrometer ***
// *********************************************
// *** (c) SD, 14.03.2016 ***
// *********************************************

// Based on ATtiny13, AM2303 and MAX7219

// **************
// *** Clocks ***
// **************

// MCU clock frequency is 9.6MHz (internal oscillator)
// Timer frequency is 75KHz = 9.6MHz/128
// (13.3 us between interrupts)

#define SKIPNEXT1W (PC + 2)
#define DS(var) Y + var - _dataStart

// ************
// *** Pins ***
// ************

// MAX7219 output pins
.equ MAX_DIN = 0
.equ MAX_CS = 1
.equ MAX_CLK = 4

// AM2302 input pin
.equ AM2302_PIN = 3

// MAX7219 registers
.equ MAX_DECODE = 0x09
.equ MAX_INTENSITY = 0x0A
.equ MAX_SCANLIMIT = 0x0B
.equ MAX_SHUTDOWN = 0x0C
.equ MAX_DISPTEST = 0x0F

// Temperature measurement state register
// Bits 0 - 2 define the byte number being received
// Bit 3 is set when there are valid data received
// Bits 4 - 7 define the current receiver state
.def R_TS = R0

// Temperature measurement tick
.def R_TT = R1

// Temperature data register
.def R_TD = R2

// Temperature measurement states
.equ TMS_NONE = 0x00 // TMS_NONE - do nothing an wait until
// somebody changes the state
.equ TMS_START = 0x10 // Start of the measurement cycle
.equ TMS_ST_LOW = 0x20 // Initial low signal is being sent
// (1 ms = 75 timer ticks)
.equ TMS_WRSP_LOW = 0x30 // Initial low signal has been sent,
// waiting for the response low signal
.equ TMS_WRSP_HIGH = 0x40 // Response low signal has been received,
// waiting for the response high signal
.equ TMS_W1ST_BIT_LOW = 0x50 // Waiting for the first bit low signal
.equ TMS_WBIT_HIGH = 0x60 // Waiting for the bit high signal
.equ TMS_WBIT_LOW = 0x70 // Waiting for the bit low signal
.equ TMS_WHIGH = 0x80 // Waiting for the final high signal

// Timer 100Hz tick counter
// (counts upwards from 0 to 255)
.def R_TICK100 = R3

// Timer 16bit 75KHz tick counter
// (counts downwords from 749 to 0)
.def R_TICKL = R4
.def R_TICKH = R5

// ************
// *** Data ***
// ************

.dseg
_dataStart: // Data start label

tempData: .byte 5 // Data, received from the AM2302 sensor
displayData: .byte 4 // Decimal printing result

.equ DATA_BUF_SIZE = 8 // AM2302 data buffer size in samples
// (each sample is 4 bytes)

dataBuffer: .byte DATA_BUF_SIZE*4

.cseg
.org 0

// *** Interrupts ***

// Reset Handler
rjmp start

// IRQ0 Handler
reti

// PCINT0 Handler
reti

// Timer0 Overflow Handler
rjmp timerOvfl

// EEPROM Ready Handler
reti

// Analog Comparator Handler
reti

// Timer0 CompareA Handler
rjmp timerCompA

// Timer0 CompareB Handler
reti

// Watchdog Interrupt Handler
reti

// ADC Conversion Handler
reti

// Table to convert decimal digit into 7-segment code
hexTable:
.db 0b01111110, 0b00110000, 0b01101101, 0b01111001
.db 0b00110011, 0b01011011, 0b01011111, 0b01110010
.db 0b01111111, 0b01111011

start:
cli
ldi R16, RAMEND
out (SPL), R16

// Init watchdog (4s interval)
wdr
ldi R16, (1 << WDCE) | (1 << WDE)
out (WDTCR), R16
ldi R16, (1 << WDE) | (1 << WDP3)
out (WDTCR), R16

// Init registers
ldi YL, low (_dataStart)
ldi YH, high (_dataStart)
clr R_TS
clr R_TT
clr R_TICKL
clr R_TICKH
clr R_TICK100

// Init ports
out (PORTB), R_TS
ldi R16, (1 << MAX_DIN) | (1 << MAX_CS) | (1 << MAX_CLK)
out (DDRB), R16

// Init LED driver
// Set all digits to "-"
ldi XL, 0b00000001
ldi XH, 1
init1:
rcall maxWriteWord
cpi XH, 9
brne init1

// Set control registers
ldi XL, 0 // Decode
rcall maxWriteWord
ldi XL, 4 // Intensity
rcall maxWriteWord
ldi XL, 7 // Scan limit
rcall maxWriteWord
ldi XL, 1 // Shutdown
rcall maxWriteWord
ldi XH, 0x0F
ldi XL, 0 // Display test
rcall maxWriteWord

// Init timer for 1 interrupt each 128 CPU cycles
ldi R16, 127
out (OCR0A), R16
ldi R16, 0b00000110
out (TIMSK0), R16
ldi R16, 0b00000001
out (TCCR0B), R16

// First part of the initialization is done.
// Enable interrupts
sei

// Wait 2 sec (while AM2302 initialize itself)
// with little animation
ldi XH, 1
ldi XL, 0
init2:
ldi R16, 25
rcall wait100Hz
rcall maxWriteWord
cpi XH, 9
brne init2

// R6 will contain the number of
// measurement values received
clr R6

// R7 will contain the number of
// continious errors
clr R7

loop:
// Reset watchdog timer
wdr

// Initiate measurement
ldi R16, TMS_START
mov R_TS, R16

loop1:
// Wait for the TMS_NONE state
// which indicates that the measurement
// is done
sleep

mov R16, R_TS
andi R16, 0xF0
brne loop1

// Do we have the valid data?
sbrs R_TS, 3
loop_error1:
rjmp loop_error

// Check control sum of the received data
ldd R16, DS (tempData)
ldd ZL, DS (tempData + 1)
add R16, ZL
ldd ZL, DS (tempData + 2)
add R16, ZL
ldd ZL, DS (tempData + 3)
add R16, ZL
ldd ZL, DS (tempData + 4)
cp R16, ZL
brne loop_error1

// We have valid new measurement data,
// reset error count
clr R7

// Move up data in the buffer
// and count the sum at the same time.
// R12:R13 will contain the humidity value and
// R14:R15 the temperature value
clr R12
clr R13
clr R14
clr R15
ldi ZL, low (dataBuffer + (DATA_BUF_SIZE - 2)*4)
ldi ZH, 0
buf1:
ldd R16, Z + 0
ldd R17, Z + 1
std Z + 4, R16
std Z + 5, R17
add R12, R16
adc R13, R17

ldd R16, Z + 2
ldd R17, Z + 3
std Z + 6, R16
std Z + 7, R17
add R14, R16
adc R15, R17

subi ZL, 4
cpi ZL, low (dataBuffer - 4)
brne buf1

// Add new humidity value to the buffer
// and to the sum
ldd R16, DS (tempData + 1)
ldd R17, DS (tempData)
std DS (dataBuffer + 0), R16
std DS (dataBuffer + 1), R17
add R12, R16
adc R13, R17

// Add new temperature value to the buffer
// and to the sum
ldd R16, DS (tempData + 3)
ldd R17, DS (tempData + 2)

// Check for a negative value
and R17, R17
brpl buf2

// Convert negative temperature to the 2's
// complement form
clr ZL
andi R17, 0x7F
neg R16
sbc ZL, R17
mov R17, ZL

buf2:
std DS (dataBuffer + 2), R16
std DS (dataBuffer + 3), R17
add R14, R16
adc R15, R17

// Divide the humidity and temperature
// sum values by 8 (by shifting them right
// three times)
ldi R16, 3
buf3:
asr R15
ror R14
asr R13
ror R12
dec R16
brne buf3

// Do we have 8 full measurements?
mov R16, R6
cpi R16, 7

// If so, use the average values from
// the buffer
breq buf4

// Otherwise use the latest measurement
ldd R12, DS (dataBuffer + 0)
ldd R13, DS (dataBuffer + 1)
ldd R14, DS (dataBuffer + 2)
ldd R15, DS (dataBuffer + 3)
inc R6

buf4:
// Print out values

// *** Humidity ***
movw X, R12
rcall printDecX

ldi XH, 1
ldd XL, DS (displayData + 3)
rcall maxWriteWord

ldd XL, DS (displayData + 2)
ori XL, 0x80
rcall maxWriteWord

ldd XL, DS (displayData + 1)
rcall maxWriteWord

ldd XL, DS (displayData)
rcall maxWriteWord

// *** Temperature ***
movw X, R14

// Check for a negative value
and XH, XH
brpl buf5

// Calculate the absolute value
clr ZL
neg XL
sbc ZL, XH
mov XH, ZL

buf5:
rcall printDecX

ldi XH, 5
ldd XL, DS (displayData + 3)
rcall maxWriteWord

ldd XL, DS (displayData + 2)
ori XL, 0x80
rcall maxWriteWord

ldd XL, DS (displayData + 1)
rcall maxWriteWord

// If temperature is negative
// write the minus sign to the first digit
// (temperatures of -100.0 and below
// are not supported anyway)
ldd XL, DS (displayData)
and R15, R15
brpl SKIPNEXT1W
ldi XL, 1
rcall maxWriteWord

loop2:
// Wait for 1 sec
ldi R16, 100
rcall wait100Hz

// And repeat
rjmp loop

loop_error:
// An error had occured.
// Increment error count
inc R7

// Do we have 3 or more errors in a row?
mov R16, R7
cpi R16, 3

// No? Just do nothing
brne loop2

// Prevent error count from growing
dec R7

// Display error
ldi ZL, low (errText*2)
ldi ZH, high (errText*2)
rcall maxWrite8Bytes
rjmp loop2

errText:
// "Sn Error"
.db 0b00000101, 0b00011101, 0b00000101, 0b00000101
.db 0b01001111, 0b00000000, 0b00010101, 0b01011011

// **********
// Waits given number (R16) of 100Hz ticks
// Uses: Z
wait100Hz:
// Enable sleep
ldi ZL, 0b00100000
out (MCUCR), ZL

mov ZL, R_TICK100
w100:
sleep
mov ZH, R_TICK100
sub ZH, ZL
cp ZH, R16
brcs w100
ret

// Timer interrupt

timerOvfl:
timerCompA:
push R16
in R16, (SREG)
push R16
push ZL
push ZH

// Receive AM2303 data
rcall am2302proc

// Decrement current 75KHz tick
ldi R16, 1
sub R_TICKL, R16
brcc timerRet
sub R_TICKH, R16
brcc timerRet

// Initialize 75KHz tick value
ldi ZL, low (750 - 1)
ldi ZH, high (750 - 1)
movw R_TICKL, Z

// Increment current 100Hz tick
inc R_TICK100

timerRet:
pop ZH
pop ZL
pop R16
out (SREG), R16
pop R16
reti

// **************
// *** AM2302 ***
// **************

amStart:
// Send the start low signal.
// Switch corresponding PORTB pin to output
// (there is already 0 in the PORTB register)
sbi (DDRB), AM2302_PIN
ldi R16, TMS_ST_LOW
rjmp amSetState

amStartLow:
// Initial start low signal is being sent.
// Wait for 75 ticks
cpi R16, 75
brne amNone

// Switch PORTB pin back to input
cbi (DDRB), AM2302_PIN
ldi R16, TMS_WRSP_LOW

// Do not check AM2303 input pin at this tick
// since it's possible that it has not recovered
// from the low state yet.
rjmp amSetState

amWRespLow:
// Waiting for the response low signal
sbrc ZH, AM2302_PIN
ret

ldi R16, TMS_WRSP_HIGH
rjmp amSetState

amWRespHigh:
// Waiting for the response high signal
sbrs ZH, AM2302_PIN
ret

ldi R16, TMS_W1ST_BIT_LOW
rjmp amSetState

amW1StBitLow:
// Waiting for the first bit low signal
sbrc ZH, AM2302_PIN
ret

// Get ready to receive the first bit
ldi R16, 1
mov R_TD, R16

// Set new state and reset the byte counter
ldi ZL, TMS_WBIT_HIGH
rjmp amSetState2

amBitHigh:
sbrs ZH, AM2302_PIN
ret

// If the bit low signal was there too long
// (longer than 5 ticks (5*13.3 = 66.5us)
// something went wrong)
cpi R16, 6
brcc amResetState

ldi R16, TMS_WBIT_LOW
rjmp amSetState

am2302proc:
// First, check for the TMS_NONE state.
// In this case just do nothing to
// not waste MCU cycles.
mov ZL, R_TS
andi ZL, 0xF0

cpi ZL, TMS_NONE
breq amNone

// Increment receiver tick
inc R_TT

// If we are waiting for too long,
// something went wrong, reset the state
breq amResetState

// Save the current tick into a more
// convenient register
mov R16, R_TT

// Get input signal
in ZH, (PINB)

// Branch depending on the current state.
// Check for TMS_WBIT_LOW first since it
// has the longest service routine
cpi ZL, TMS_WBIT_LOW
breq amBitLow

cpi ZL, TMS_START
breq amStart

cpi ZL, TMS_ST_LOW
breq amStartLow

cpi ZL, TMS_WRSP_LOW
breq amWRespLow

cpi ZL, TMS_WRSP_HIGH
breq amWRespHigh

cpi ZL, TMS_W1ST_BIT_LOW
breq amW1StBitLow

cpi ZL, TMS_WBIT_HIGH
breq amBitHigh

cpi ZL, TMS_WHIGH
breq amWHigh

amResetState:
// In case of an error, reset state to
// the default TMS_NONE
ldi R16, TMS_NONE

amSetState:
// Preserve the current byte number
mov ZL, R_TS
andi ZL, 0x07
or ZL, R16

amSetState2:
mov R_TS, ZL

// Clear receiver tick counter
clr R_TT

amNone:
ret

amBitLow:
sbrc ZH, AM2302_PIN
ret

// The high bit signal was too long?
cpi R16, 8
brcc amResetState

// Store input bit (inverted, since cpi produces
// inverted result in the carry flag)
cpi R16, 4
rol R_TD

// Initally we set R_TD to 1, so when all 8
// bits are received, the carry flag will be set
// indicating that a full byte has been received.
// Otherwise, receive the next bit
ldi R16, TMS_WBIT_HIGH
brcc amSetState

// We have the full byte. Invert it
com R_TD

// Save it
mov ZL, R_TS
andi ZL, 0x07
subi ZL, low (-tempData)
ldi ZH, high (tempData)
st Z+, R_TD

// Did we receive all 5 bytes?
cpi ZL, low (tempData + 5)
ldi R16, TMS_WHIGH
breq amSetState

// OK, receive the next byte.
// Increment the byte counter
inc R_TS

// Initialize R_TD
ldi R16, 1
mov R_TD, R16

ldi R16, TMS_WBIT_HIGH
rjmp amSetState

amWHigh:
sbrs ZH, AM2302_PIN
ret

cpi R16, 6
brcc amResetState

// We received everything. Set
// the state to TMS_NONE and set
// the data validity bit
ldi R16, 0x08
mov R_TS, R16
ret

// *********

/*
// Write data from Z
// Uses R16 - R19, X, Z
maxWriteData:
lpm XH, Z+
tst XH
brne SKIPNEXT1W
ret
lpm XL, Z+
rcall maxWriteWord
rjmp maxWriteData

maxInit:
.db MAX_DECODE, 0
.db MAX_INTENSITY, 4
.db MAX_SCANLIMIT, 7
.db MAX_SHUTDOWN, 1
.db MAX_DISPTEST, 0
.db 0, 0

maxTest:
.db 0, 0b00011101, 0b00010101, 0b00010000, 0b00011100, 0b00111101, 0b00000101, 0b01110111
*/

// Writes 8 bytes from (Z) (program memory)
// to MAX7219
// Uses R16 - R19, X, Z
maxWrite8Bytes:
ldi XH, 0x01

mw8b1:
lpm XL, Z+
rcall maxWriteWord
cpi XH, 9
brne mw8b1
ret

// Write word X (XL = data, XH = address) to MAX2719
// Uses R16 - R19, X
maxWriteWord:
// Set all pins to zero
in R17, (PORTB)
andi R17, ~((1 << MAX_DIN) | (1 << MAX_CS) | (1 << MAX_CLK))
out (PORTB), R17

ldi R19, (1 << MAX_CLK)

mov R16, XH
rcall mww1

mov R16, XL
rcall mww1

// Set LOAD(CS) to high thus writing all 16 bits into
// MAX register
sbi (PORTB), MAX_CS

// Increment MAX register number
inc XH
ret

mww1:
ldi R18, 8

mww2:
bst R16, 7
bld R17, MAX_DIN
out (PORTB), R17

lsl R16
dec R18

// Create clock impulse by toggling clock output twice
out (PINB), R19
out (PINB), R19

brne mww2
ret

// *********

printDecX:
ldi ZH, low (1000)
ldi R16, high (1000)
rcall pdx

// Change zero digit to empty space
cpi ZL, 0b01111110
brne SKIPNEXT1W
ldi ZL, 0
std DS (displayData), ZL

ldi ZH, 100
ldi R16, 0
rcall pdx

// If this digit is zero and the first
// digit is empty (i.e. it was zero too)
// change this digit to empty space
ldi R16, 0b01111110
eor R16, ZL
ldd ZH, DS (displayData)
or R16, ZH
brne SKIPNEXT1W
ldi ZL, 0
std DS (displayData + 1), ZL

ldi ZH, 10
ldi R16, 0
rcall pdx
std DS (displayData + 2), ZL

mov ZL, XL
rcall pdx3
std DS (displayData + 3), ZL

// Clear carry flag to indicate that
// no error occurred
clc
ret

pdx:
ldi ZL, 0
pdx1:
sub XL, ZH
sbc XH, R16
brcs pdx2

cpi ZL, 9
breq pdxOverflow
inc ZL
rjmp pdx1

pdx2:
add XL, ZH
adc XH, R16

pdx3:
subi ZL, -low (hexTable << 1)
ldi ZH, high (hexTable << 1)
lpm ZL, Z
ret

pdxOverflow:
// Set carry flag to indicate error
sec

// Pop return address out of the stack
// so we can return to the caller of printDecX
pop R16
pop R16
ret

Снизить энергопотребление в режиме сна можно, если питание внешних модулей коммутировать p-канальным полевиком или даже просто запитать их от одного или нескольких пинов GPIO микроконтроллера. Максимальный ток 20мА на пин.

Питание периферии с коммутацией транзистором или от пинов контроллера у меня практически во всех проектах.
В nRF24L01+ требуется повторная инициализация контроллера радиомодуля. Инициализация несовместима с командами библиотеки LowPower.h, которые задают у меня время сна.
Короче, чтобы восстановить настройки радиомодуля после сна надо сделать Reset контроллера, который ним управляет. У меня — это atmega328p. При ресетах с интервалом минута ресурса флеш-памяти хватит на несколько суток.
Возможно я заблуждаюсь, еще поиграюсь с nRF24L01+ уж очень низкое у него энергопотребление.
Также переписывание с С на ассемблер не имеет почти никакого смысла. Зато имеет смысл порой избавиться от стандартной функции printf() и написать свою, если вы выводите, например, только целые числа

Перед отправкой данных с десятыми-сотыми умножаю на 100, а дальше — дело техники.
Экран E-ink 2.13 + Контроллер NRF52 < 2мкА потребления в режиме сна
Либо взять E-ink + Zigbee как на Xiaomi термометрах

Дисплей 2.13 будет маловат для комнатного термостата и метеостанции в одном. В списке желаний на Али уже несколько месяцев e-paper дисплей 3,7 дюйма.
NRF52832 уже в пути.
Коль уж с Arduino уходим на C/asm, возникает резонный вопрос: может уже «гулять на все» и с самой atmega уйти на что-нибудь специально созданное для низкого потребления? STM8L или STM32L например.

Спасибо, но Вы переоцениваете мои возможности.
Для меня программисты, работающие на низкоуровневых языках типа Ассемблера — небожители и, как оказалось, на Ардуино тоже можно решать не тривиальные задачи.
Это все меняет. Я готов внести изменения. Если не трудно — представьте, пожалуйста, свой вариант setup'a для приемника.
Ваши аргументы не вызывают у меня сомнений. Но перед тем как внести изменения в скетч хотелось проверить их на «железе». Сейчас у меня такой возможности нет. Как только проверю — отредактирую код. Заранее благодарю за понимание.
Спасибо!
NRF52832 уже в пути несколько дней, библиотеку скачал сегодня. Буду работать в этом направлении.
Давно существует комбинированный крепёж — полугвоздь/полувинт, этакий плоский скрученный спиралью гвоздь, но с нормальной резьбой на последнем сантиметре и шлицами. Забивается сначала молотком, потом докручивается шуруповёртом, держит на ура доски или ОСБ плиту, прибитую к балкам хоть 100 мм.

Уточню, тут спор между государствами с исками в международных судах и суммами на десятки миллионов зеленых за повреждение имущества. Беленко — в стороне. Поэтому японская сторона затягивала переговоры о передаче самолета, чтобы качественно и добротно упаковать разобранный самолет и в будущем обвинить советскую сторону в нарушений условий договора, а именно в нарушении сроков приемки.
Рассуждения о отвертках, шлицах, саморезах, шуруповертах явно не для этой темы. Тем более, что конструкция контейнеров прояснилась после того, как их раскурочили с помощью зубил, кувалд и ломов.
И еще. Посмотрите картинку. aliexpress.ru/item/32712841432.html?spm=a2g0s.9042311.0.0.3c0f33ed7mbG9Q&_ga=2.182776358.1876782405.1614251579-443101207.1611486899&_gac=1.19296330.1611486899.Cj0KCQiA0rSABhDlARIsAJtjfCfwGdizyrjlBIjO_aQcCM5GrlQkyE3LRx-4dqPCc1exMpMvSHGUSH4aApqBEALw_wcB
Мне пришлось заказывать набор таких бит, чтобы разобрать свою кофеварку Kenwood — два ремонта кофеварки в сервисе стоили бы мне новой. Фирмы и в настоящем и, наверное, в прошлом усложняют доступ вовнутрь — они на этом зарабатывают.
Не все так просто, особенно, если интерес на миллионы долларов…
Вот и вскрылась причина проигрыша в холодной войне — отсутствие крестовых отвёрток и правильного крепежа. Точнее, отвёртки были, но косо штампованные из некачественного металла, а вместо цилиндрических саморезов — конические шурупы, тоже штампованные, нередко с облоем, которые даже в мягкое дерево было тяжело закручивать — с каждым оборотом усилие увеличивалось, а отвёртка и шуруп слизывались. И никаких заумных профилей PZn/PHn — только Толстая хреновая и Тонкая, так что уж лучше её величество Шлицевая, на каждом полобороте соскальзывающая и снова вставляемая в шлиц в темноте под углом наощупь окоченевшими руками.

Да, слово «саморез» тут не совсем к месту. Скорее всего болт с резьбой, как у самореза, — не могу найти подходящее слово. Любая отвертка при монтаже 60-и мм досок — это нонсенс.
В свое время мне довелось присутствовать на встрече с членом правительственной делегации, которая работала в Японии над вопросами передачи угнанного самолета.
Что запомнилось:
  • Вначале шла длительная дискуссия о сроках приемки советской стороной. Японцы настаивали на записи «два рабочих дня», советская сторона — «двое суток». В конце-концов записали «двое суток».
  • Как выяснилось позже, после загрузки контейнеров на советский корабль в порту Японии, японцы сделали ставку на то, что за столь короткое время не удастся распаковать ящики. Каждый ящик состоял из трех слоев. Верхний — фанера с металлической окантовкой, затем — обрезные, качественно подогнанные одна к одной доски и третий слой — необрезные доски еще потолще, чем во втором слое. Монтаж досок был выполнен саморезами с потайными головками.
  • Срочно на помощь было вызвана бригада такелажников с медиками, кажется, с Владивостока. Работали без сна двое суток, медики обеспечивали работоспособнось. Контейнеры распаковали в оговоренное время.
  • Со многих узлов было взято по несколько проб, например с лобового стекла. О проверке комплектности тогда еще речи не было. Самолет восстановлению не подлежал.
  • Японцы выставили ответный иск на несколько акров земли, испорченных Беленко при посадке — у него не было опыта работы на взлетно-посадочных полосах, которые сливаются с горизонтом моря.
А подскажите, поможет ли решить данную проблему подключения модуля nRF через кренку?

Решить проблему в целом — сомневаюсь. Не забывайте о ВЧ-помехах по цепи питания nRF и качестве этого питания, которое определяется мощностью источника.
Неплохо-бы добавить на линии питания конденсатор микрофарад на 100 для облегчения работы батареек.

Для батареек с током короткого замыкания больше 2А (точнее не позволяет измерить шкала моего амперметра) вряд ли нужна помощь при работе с нагрузкой около 10-ти мА.
Контроль питания. С такими сопротивлениями делителя — надо зашунтировать «нижний» конденсатором (10..100 нФ), чтобы данные соответствовали действительности.

Я думал над этим и проверял — ставил конденсатор 470 нФ, но изменений в десятых вольта не заметил. Конденсатор, по-моему, важен при подключении к блоку питания — для сглаживания пульсаций напряжения. Для страховки — поставлю.
А лучше — измерять напряжение питания полностью встроенными средствами МК. Сконфигурировать опорное напряжение АЦП как напряжение питания и измерять относительно него внутреннее опорное напряжение 1,1 В.

Обязательно реализую этот подход.
Большинство ПС как раз сделано на батарейках, тк у них низкий саморазряд.

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

Учту на будущее.
Уточнил в статье: Метеостанция состоит из двух узлов, назовем их для простоты гигрометром и термометром. Связь между узлами — беспроводная, по радиоэфиру.
А почему не использовали прерывание — wake on radio, встроенное в чип? Как только SX1278 словил сигнал, он выставляет высокий уровень на DIO4. Atmega328 просыпается делает дела и засыпает до следующего прерывания.

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

Information

Rating
Does not participate
Registered
Activity