Comments 28
Отключать модуль обрывая ему землюВидимо, этим и объясняется довольно большое потребление в паузах (из за паразитной запитки модуля по цепи Tx MCU):
Измерения показали, что в паузах вся схема потребляет не более 150 мкА
Использовать wdt вместо таймера— в AVR это типовое решение организации пауз с минимальным потреблением, ведь в этих контроллерах тактированием из программы особо не поуправляешь.
UPD: по поводу «паразитной запитки модуля по цепи Tx MCU» похоже написал не подумавши — ведь в паузе на Tx высокий уровень.
Отключать модуль обрывая ему землю.… Использовать wdt вместо таймера.… Так что либо avr либо stm8 тут лишние.
- В данном контексте — нормально, ИМХО. И с уровнем пауза на TxD микроконтроллера уже разобрались, так-что утечки вызваны чем-то другим. Вероятно — Z-состоянием порта B (ненастроенным после сброса).
- Тем не менее, WDT — тоже таймер.
- Это — да. И так было бы даже лучше. Но модули "чистых" трансиверов — вряд-ли продают (дурино-стайл рулит).
Автору хорошо-бы указать, к какому программатору относятся скриншоты Fuse-битов.
Очень помогло, и хорошо, что именно для ассемблера (только на нём и пишу :)))
Как по мне, лучше уж взять дешевый NTC, откалибровать и получить ту же точность в ±0.5…1℃, что и у DS18. Зато никакой мороки с ненормальным 1-wire (да и по цене раз в 50 дешевле выходит).
А насчет метрологии тоже не надо тут перегибать! Знаем, проходили неоднократно! Дома при желании можно устроить, но приятней на работе: беру пару литров жидкого азота, заливаю в тазик, ставлю в самодельный термостат рядом с дюралевой пластиной с термодатчиками или стаканом со спиртом, в котором они плавают, — вуаля! За трое-четверо суток выбираю статистику в диапазоне -50…+20℃. Для более высоких температур можно в термостат тазик с кипятком засунуть.
Если что, таким колхозно-кустарным методом была проведена калибровка с точностью в пять сотых градуса!!!1111 См. мой ЖЖ (на быдлохабре я уже давным-давно ничего не выкладываю, ибо метать бисер перед свиньями мне надоело).
И плюс к этому — ваша кусочно-линейная аппроксимация. Ознакомившись с типовой характеристикой термистора и немного посчитав, получите, что для приемлемого спрямления в пределах 0,5 градуса нужно обеспечить калибровку не менее, чем через 4 градуса (в середине диапазона, при высоких температурах можно пореже, для низких — почаще). Иначе это будет не калибровка, а теоретические гадания на кофейной гуще.
Понимаете, почему NTC никто всерьез не использует для ИЗМЕРЕНИЯ температуры? В качестве датчика для регулятора — очень часто (из-за высокой крутизны это удобно), а в качестве измерителя разве только для прикола. Даже банальный TMP36 и то намного удобнее. В пределах точности 1-2 градуса, конечно, не больше, но больше вы своей самодельщиной и не добъетесь. А 18b20 из коробки дает 0,5 градуса, без всяких тазиков.
Конечно, все это я не для вас пишу, на хамство обычно я не отвечаю, но кто-нибудь ведь может вам и поверить.
Интересная статья, но какую цель Вы всё-же преследовали делая это на ассемблере и attiny2313? Уменьшение затрат? Уменьшение энергопотребления?
10 лет назад коллега реализовал ethernet+ip+udp+snmp+icmp в atmega88 на чистом ассемблере, но тогда это было продиктовано уменьшением стоимости при производстве. В современных реалиях я бы так уже не делал.
а) изучать электронику, но не хочет вникать в нюансы построения языков высокого уровня, что само по себе требует вдумчивого изучения (и вообще это совсем другая дисциплина, чем электроника, требующая отдельной предрасположенности). И не всегда это просто — вообще говоря, для успешного обращения с МК язык надо знать изнутри не ниже уровнем, чем у грамотного бекенд разработчика «больших» систем. Но постойте, мы же изначально собирались просто цифровой термометр спроектировать, а не компиляторы изучать?
б) досконально владеть функционированием схемы, которую спроектировал и запустил. Которому хочется полностью, до команды в каждый момент времени, владеть спроектированным устройством, а не полагаться на дядю, изобретающего оптиимзирующие компиляторы.
Как-то так. Знаю, что не всегда и не всем такое надо, но я сам терпеть не могу ничего лишнего, не нужного для конкретной задачи. И вдруг кому-то тоже пригодится?
В связи с этим есть вопросы — вы пробовали увеличить скорость (битрейт)? тогда, вероятно, ток будет потребляться меньшее время. На какую дальность работают модули с заводскими настройками?
2. Я там упомянул, что на дальность не испытывал, негде пока. Дополню, когда смогу такое испытание провести
3. Вопрос про направление не понял. Это просто UART, он полнодуплексный (ну, почти). Наверно, голой микрухой надо управлять (не вникал, если честно), но вам ничего переключать не требуется, все делает модуль автоматически.
И для начала хотел бы заметить, что для взятия абсолютного значения отрицательного целого надо просто написать i=-i; а не заниматься черной магией с использованием «глубоких знаний» в представлении отрицательных чисел в дополнительном коде.
Ну и как вишенка на торте — автором предложен неправильный способ сделать то же самое в ассемблере, что лишний раз подтверждает — не следует применять его там, где чудесно справится С. Те, кто хотят знать, как это сделать, могут посмотреть генерированный компилятором код для приведенной операции.
ЗЫ: и кстати, тогда уж abs(i), не находите?
ЗЫЗЫ: по первому утверждению: смотря какой компилятор и какой разработчик, не кажется?
com valueH ;инвертируем старший байт
neg valueL ;младший -> доп. код
не соответствует приведенной Вами формуле. Для того, чтобы понять свою ошибку, посмотрите, как преобразуется число 0xFF00 (соответствующее десятичному -256), мне почему то кажется, что 0 — не совсем правильный ответ.А компилятор совершенно любой, я настоятельно рекомендую пользоваться gcc на сайте godbolt, вот ссылка на указанный код godbolt.org. В Ваших обозначениях должно быть:
neg valueH
neg valueL
sbc valueH,__zero_reg__
Между тем, простое
if (Temp<0) {Temp=-Temp; };
решало все проблемы.А компилятор языка С не «великий и могучий», а написан людьми, которые о системе команд того же AVR забыли больше, чем мы с Вами вместе знаем, так что он генерит совершенно правильный код.
PS. abs здесь не очень нужен, прямой код в данном случае нагляднее.
PPS. Любой современный компилятор и практически любой разработчик.
а) не понял, почему в результате моих команд 0xFF00 преобразуется в 0. Правильный ответ — 0x0100, он получается по любой из формул, и по моей, и по вашей последовательности тоже.
б) приведенная вами последовательность neg — neg — sbc делает ровно то же самое, что и просто com — neg, только зачем-то она сначала добавляет единицу к valueH, а затем ее обратно вычитает (флаг C командой NEG устанавливается всегда, кроме случая, когда результат = 0 — цитата из руководства). Вывод — если neg заменить в первой команде на com, то последняя команда оказывается лишней. Как раз пример неудачного и неоптимального кода, не понял, зачем и откуда вы это вытащили. У меня получилось лучше:
в) меня тоже разобрало любопытство, и я путем AVR Studio+GCC смоделировал функцию, возвращающую абсолютное значение 2-байтового числа:
int aaa(void) {
int i;
i=abs(i);
return i;
}
Вот фрагмент дизасемблированного кода, ей сооветствующего:
2: int aaa(void) {
+0000001A: E090 LDI R25,0x00 Load immediate
+0000001B: E080 LDI R24,0x00 Load immediate
+0000001C: 2F29 MOV R18,R25 Copy register
+0000001D: 2F38 MOV R19,R24 Copy register
+0000001E: FF37 SBRS R19,7 Skip if bit in register set
+0000001F: C003 RJMP PC+0x0004 Relative jump
+00000020: 9530 COM R19 One's complement
+00000021: 9521 NEG R18 Two's complement
+00000022: 4F3F SBCI R19,0xFF Subtract immediate with carry
6: }
+00000023: 01C9 MOVW R24,R18 Copy register pair
+00000024: 9508 RET Subroutine return
Как видите, и сама операция и даже определение знака полностью соотвествует моим командам (сам удивился, ни сейчас не мухлевал, ни раньше не интересовался). Вся остальная муть там относится к преобразованию регистров, с чем я бы тоже поспорил — до хрена всего лишнего. Хотя, может, в реальной программе и будет покомпактней, но этот фрагмент я бы сократил вдвое, как минимум (знаю, зачем они так делали, но это как раз пример, как руками лучше получается). Интересно было бы еще отключить оптимизацию, но уже лень возиться. Так что не знаю, откуда вы взяли свой код, но я все делал правильно и кратчайшим путем — зачем, собственно, и нужен ассемблер.
GarryC, я совершенно не собираюсь гнобить ни язык С, ни компилятор, но тем более его создателей. Они сделали замечательную штуку, только не надо ее идеализировать, возводить на пьедестал и объявлять божественной истиной в последней инстанции. В жизни за все надо платить — за удобство и универсальность мы платим неоптимальным кодом. Это закон природы такой — массовый продукт всегда лучше и дешевле именно в массовом порядке, но в каждом конкретном случае руками обязательно можно сделать лучше.
Godbolt AVR GCC, достаточно коротко(https://godbolt.org/z/oxzvTn):
__zero_reg__ = 1
aaa(int):
sbrs r25,7
rjmp .L2
neg r25
neg r24
sbc r25,__zero_reg__
.L2:
ret
Just for example.
А по поводу кода, порождаемого компилятором — Вы рассмотрели голую функцию abs, если посмотреть на код, порождаемый для конкретного случая, то многие лишние пересылки исчезают — компилятор научился убирать излишнюю универсальность в конкретных условиях.
Например, для кода на С
int main(int16_t i) {
i=abs(i);
i=(i*5)/8;
return i;
};
в режиме оптимизации -О2 получается
main:
mov r18,r24
mov r19,r25
sbrs r19,7
rjmp .L2
neg r19
neg r18
sbc r19,__zero_reg__
.L2:
mov r25,r19
mov r24,r18
lsl r24
rol r25
lsl r24
rol r25
add r24,r18
adc r25,r19
asr r25
ror r24
asr r25
ror r24
asr r25
ror r24
ret
Обратите внимание, что abs заинлайнилась, что ничуть не хуже написанного руками. Строго говоря, этот фрагмент исполняемого кода полностью совпадает с приведенным Вами, только на С он компактнее и понятнее. «А если разницы нет, зачем платить больше?».PS. Должен признать, что компилятор не всегда прав, когда я попробовал указать (i*10)/16? он честно добавил еще один сдвиг влево и сразу за ним сдвиг вправо, что меня несколько озадачило. То есть в данном конкретном случае сокращать дробь 10/16 до 5/8 приходится программисту.
Сначала я попробовал переписать ее в стиле i/2+i/8, которая потребовала 10 команд и 10 тактов, но это неверная формула.
А вот (i+i/4)/2 дает совершенно правильный результат и при этом требует все те же 10 команд и 10 тактов.
Если бы это решение нашел компилятор… но нет, его нашел человек, так что Вы отчасти правы, компилятору есть куда развиваться.
Как то совсем уж сложно и неэффективно. Я делал на attiny13 + простейший передатчик аналоговый за 50 рублей. Во сне — ничего не потребояется, компонентов — 0 (обвеса) только микруха, ds18b20 и мини передатчик 433mhz. Живет от 3в батарейки год, а то и больше. Приемник так же элементарен, делал его даже на esp8266 с трансляцией в сеть wifi данных)
Приемопередатчик HC-12 и датчик температуры DS18b20 на AVR-ассемблере