[Программирование микроконтроллеров, Электроника для начинающих] На распутье — Ардуино, Cи или Ассемблер?

Автор Сообщение
news_bot ®

Стаж: 6 лет 2 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
22-Мар-2021 13:31

Сначала короткая предыстория появления этого поста. Относительно давно, помигав светодиодом, захотелось сделать что-то полезное. Так появился Беспроводной программируемый по Wi-Fi комнатный термостат с монитором качества воздуха и другими полезными функциями. Как назло, в это время перестал работать мой промышленный термостат. Меня выручила еще сырая поделка, наспех спрятанная в картонную коробочку. За время отопительного сезона напрягал лишь один недостаток прототипа – это необходимость таскать по квартире удлинитель 220В и кабель, который всегда путался под шваброй ногами. Поэтому решил сделать нечто похожее, но автономное, притом, с питанием от батареек, как в серийном образце. Тут я завис надолго.
Приступая к задаче, для меня было очевидно одно – вряд ли программы промышленных автономных устройств составлены на платформе Arduino IDE. Где все спрятано в громоздкие тяжеловесные библиотеки, а простые коды (скетчи) занимают в редакторе несколько десятков строк, делая работу в этой среде комфортной и не требующей особых усилий. Уточню сразу – дальше речь выборе языка программирования между Ардуино, Си или Ассемблером. Хотя, понятно, на потреблении устройства в целом сказывается слишком много факторов таких, как энергопотребление подключенных модулей, потребление самого контроллера, который управляет периферией, не последнюю роль тут играет оптимальное построение самого кода и алгоритм работы устройства.
«… направу ехати — женату быти; налеву ехати — богату быти»

В начале пути, перед выбором направления меня оптимистично настроила статья Почему многие не любят Arduino. Ниже, для наглядности, картинка оттуда с кодом «мигалки».

Пример слева написан на языке Ардуино, а справа — работа непосредственно с регистрами. Код на Ардуино выглядит несколько компактней, чем та же «мигалка», но с использованием регистров.
На изображении ниже — компиляция кода «мигалки» на Ассемблере. Как видно, былая компактность испарилась – количество строк в 3 раза больше, чем в Ардуино.

И так, с 2 картинок выше видно – размер памяти, занимаемой в контроллере кодом «мигалки» одним светодиодом, написанным на Ардуино, составляет 1030 байт, на Си – 176 байт, на Ассемблере – 42 байта.
Теперь взглянем на более сложный код. Поскольку в своих проектах использую модуль давления-температуры BMP280, составил код барометра-термометра на Си, чтобы заодно была какая-то польза.

барометр-термометр на Си

SPL
/*
    На распутье - Ардуино, Cи или Ассемблер?
    https://habr.com/ru/post/547752/
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "bmp180/bmp180.c"
#include "uart.c"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nokia/nokia5110.h"
int main(void) {
    serial_init();
    DDRD |= (1 << 7);  //pin 13, atmega328p
    PORTD &= ~(1 << 7);
    nokia_lcd_init();
    while (1) {
        init_sensor(bmp180_mode_0);
        calculate();
        PORTD |= (1 << 7);
        _delay_ms(100);
        printf("Temperature: %.2f C, Pressure: %.2f Pa, \n", (float) bmp_180.temperature / 10, (float)bmp_180.pressure);
        nokia_lcd_clear();
        nokia_lcd_write_string("789",1);
        nokia_lcd_set_cursor(0, 10);
        nokia_lcd_write_string("22.2", 3);
        nokia_lcd_render();
        _delay_ms(2000);
        PORTD &= ~(1 << 7);
        _delay_ms(100);
        int a=54325;
        char buffer[20];
        itoa(a,buffer,2);   // here 2 means binary
        printf("Binary value = %s\n", buffer);
        itoa(a,buffer,10);   // here 10 means decimal
        printf("Decimal value = %s\n", buffer);
        itoa(a,buffer,16);   // here 16 means Hexadecimal
        printf("Hexadecimal value = %s\n", buffer);
    }
    return 0;
}

В проект входят следующие компоненты: контроллер ATMEGA328P, модуль давления-температуры BMP180 и дисплей Nokia 3110. ATMEGA328P принимает инфу с датчика BMP180 и после преобразований отображает ее на дисплее Nokia 3110, затем спит. Сон задается сторожевым таймером Watchdog. Проект собирается в Atmel Studio 7 и эмулируется в Proteus 8 Pro. Этот проект Atmel Studio был создан для отладки кода в Proteus'e. В библиотеке Proteus 8 Pro модуля BMP280 нет, поэтому пришлось составить код с включением BMP180. Светодиод в коде — для наглядности, чтобы придать динамику статичной картинке.

Ниже — электрическая схема устройства. При монтаже схемы обращайте внимание на функциональное назначение выводов контроллера и модулей. Подключение кварца — XTAL1, XTAL2 (ATMEGA328P). Уточню, схему барометра-термометра на BMP180 я "в железе" не собирал, поэтому тут могут проявиться проблемы, которые не видны при эмуляции в Proteus'e.

Для скачивания zip-файла проекта в Atmel Studio 7 перейдите по ссылке – тут все виртуальные проекты и коды программ из этой публикации.
Файл прошивки bmp180-nokia3110-watchdog-1.hex для Proteus'а находится в папке Debug. В файле main.c есть закомментированный код барометра-термометра на BMP280. Его электрическая схема такая же, как и у барометра-термометра на BMP180. Он успешно собирается в Atmel Studio 7 и работает "в железе". Для работы "в железе" пришлось внести изменения в строке #define BMP280_ADDR 0x77 файла библиотеки bmp280.c, а именно: заменить начальный адрес 0x77 на 0x76. Не забудьте сделать эту корректировку, если будете использовать в своих проектах код барометра-термометра на BMP280 из main.c, с уже подключенной библиотекой bmp280.c.
Ниже — код этого же барометра-термометра в платформе Arduino IDE. Естественно, с другими библиотеками.

барометр-термометр на Ардуино

SPL
/*
    На распутье - Ардуино, Cи или Ассемблер?
    https://habr.com/ru/post/547752/
*/
#include <SPI.h>
#include <LowPower.h>
#include <SimpleTimer.h>
#include <Adafruit_BMP280.h>
#include <Adafruit_GFX.h> //https:esp8266.ru/forum/threads/esp8266-5110-nokia-lcd.1143/#post-16942
#include <Adafruit_PCD8544.h> //https:esp8266.ru/forum/threads/esp8266-5110-nokia-lcd.1143/#post-16942
Adafruit_BMP280 bmp280;
float Press, Tin; //давление, температура
Adafruit_PCD8544 display = Adafruit_PCD8544(5, 7, 6);
void setup() {
  Serial.begin(9600);
  display.begin();
  // display.clearDisplay();
  display.setContrast(60); // установка контраста
  while (!bmp280.begin(BMP280_ADDRESS - 1)) {
    Serial.println(F("Could not find a valid BMP280 sensor, check wiring!"));
    delay(100);
  }
}
void loop() {
  // измерение температуры, давления
  Tin = bmp280.readTemperature();
  Press = bmp280.readPressure() / 133.3;
  Serial.println("Temperature: " + String(Tin) + "*C");
  Serial.println("Pressure: " + String(Press) + "mm Hq");
  display.clearDisplay();
  //давление, мм рт.ст.
  {
    display.setTextSize(1);
    display.setCursor(20, 5);
    display.println (Press, 0); // нет знаков после запятой
    display.setCursor(41, 5);
    display.println("mmHq");
  }
  //температура, *C
  {
    display.setTextSize(2);
    display.setCursor(15, 20);
    display.println (Tin, 1); // один знак после запятой
    display.setCursor(66, 20);
    display.println("C");
  }
  display.display();
  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}

Ресурсы, потребляемые программой барометра-термометра на Си и в Arduino IDE наглядно показаны на картинке:

Как видно, эти примеры потребляют 5954 байт (С) и 12956 байт (Arduino IDE) в Flash. Соотношение изменилось с 6-ти раз для «мигалки» до 2-х с небольшим. К сожалению, линейной зависимости нет – чем объемней код, тем меньше соотношение размеров памяти Ардуино к Си. В идеале на этой картинке должен присутствовать 3 столбец с кодом на Ассемблере, но такого кода в Интернете я не нашел, а составить код самому мне не под силу.
Попутно замечу, что использование компилируемых в Arduino IDE библиотек и функций на С/С++ особо имеет смысл в тех случаях, когда размер занимаемой памяти превышает или близок к размеру памяти контроллера. Мне, например, часто удается уходить от предупреждения: Недостаточно памяти, программа может работать нестабильно.

Теперь посмотрим еще один вариант – это цифровой термометр-гигрометр на AM2302 (DHT22), ATtiny13 и MAX7219, код которого составлен на Ассемблере.
Автор статьи задался целью разработать простой термометр-гигрометр выполненном на одном из самых «маленьких» микроконтроллеров — ATtiny13 с весьма скромными характеристиками – 1Кб программной памяти, 64 байтами ОЗУ и 5 интерфейсными выводами. Он решил эту непростую задачку, выбрав Ассемблер, заодно вспомнив те далекие времена, когда код можно было составлять на низкоуровневых языках, используя машины типа ZX-Spectrum.
Ниже скриншот со сборкой данного кода в Atmel Studio 7.

Код устройства на Ассемблере занимает 738 байт памяти в контроллере. Безусловно, программа барометра-термометра, о котором шла речь выше, будь ее код составлен на Ассемблере, заняла бы больше места. По нескольким причинам — в схеме реализовано управление дисплеем Nokia3110 по интерфейсу SPI (это 5 линий связи, тут – 3), связь с датчиком BMP280 осуществляется по протоколу I2C (2 линии, тут – 1) и дополнительные символы, которые позволяют не гадать – температура это или другой параметр.
Из того, что я нашел в Интернете, можно утверждать, Ассемблер даст выигрыш в размере кода для относительно больших проектов процентов 10-20 по сравнению с Си. Но надо учитывать, что в больших проектах Си может уменьшить размер кода за счёт лучшей оптимизации.
Код Ассемблера выполняется практически на машинном уровне: один цикл – одна команда. В качестве аргумента приведу пример из справочника по командам ассемблера AVR. Установка бита в регистре ввода/вывода — SBI A, b. Эта команда устанавливает заданный бит в регистре ввода-вывода. На выполнение этой операции контроллерами megaAVR потребуется 2 цикла и на tinyAVR, XMEGA — 1 цикл. Для схемы с контроллером ATtiny13 и резонатором 9,6 МГц выполнение команды займет один цикл, то есть 1/9600000 Гц = 0,104 мксек.
Выполнение похожей операции на языке Си, например, задать состояние порта — PORTB = 32; займет в этой же схеме не меньше времени. А о Ардуино и говорить нечего – там придется выполнить объемную функцию void digitalWrite(uint8_t pin, uint8_t val);. Подробно о размерах кода в Си и Ардуино читайте тут.
Поэтому разработчики серийных продуктов, как правило, пишут коды на низкоуровневых языках. С тем, чтобы разместить программу в контроллере с меньшей памятью. Тут работают законы экономики — контроллер с меньшими ресурсами стоит дешевле, следовательно себестоимость изделия становится ниже.
Теперь о энергосбережении немножко издали. Вспомним, что код Ассемблера выполняется на машинном уровне: один цикл – одна или несколько команд. в зависимости от типа контроллера. Это — десятые доли микросекунды. То есть, на выполнение программы с размером несколько десятков байт уйдут единицы-десятки микросекунд. Дальше контроллер бесконечно будет крутить этот набор «0» и «1», затрачивая энергию на перезаряд емкости затворов сотен полевых транзисторов, на которых построен кристалл контроллера, а также чтение и записи данных в его память. Длительность периода повтора будет зависеть только от размера кода в памяти контроллера, неважно на каком языке он составлен. Просто на Ассемблере он будет наименьшим, а на Ардуино – наибольшим. Соответственно, период цикла для кода на Ассемблере – наименьший, на Ардуино – наибольший.
Уменьшить эти затраты можно остановив процессор или программно уменьшив частоту его работы. В Ассемблере переход в "спящий" режим сна выполняет функция управления контроллером SLEEP. В других можно использовать функцию WDT (WatchDog Timer), а в Ардуино еще и функцию LowPower.powerDown (SLEEP_1S, ADC_OFF, BOD_OFF), заодно отключив все лишнее, что не используется в конкретной задаче. В эффективности этой функции сможет убедиться каждый, заменив в скетче «мигалки» (скетч — на картинке вначале статьи) функцию отсчета времени delay(1000); этой функцией и включив в разрыв питания контроллера амперметр. Да, не забудьте подключить библиотеку LowPower.h. На Си это сделал автор этой статьи. Ток в цепи питания attiny13a с паузой — 1,5мА, со сном — 240мкА. Потребление в 6(!) раз меньше.
Допустим, вы намерены собрать барометр-термометр и задумываетесь о энергосбережении. Понятно, что давление/температура в заданной разрядности не изменятся за несколько минут, которые для контроллера целая вечность. Ему можно выделить это время для сна. После сна он снова выполнит свою работу: примет информацию с датчика, преобразует в понятные для человека циферки и выведет все это на дисплей. И в таком режиме «работа-сон» он будет крутиться, пока не сядут батарейки. Объем «работы» контроллера, вернее время, которое контроллер будет занят выполнением работы, зависит от того, на каком языке составлена программа барометра-термометра. Если есть возможность загрузить в контроллер код на выбор – ArduinoIDE, C, Assembler, с одинаковым временем «сна», то в каком из трех предложенных вариантов батарейки сядут раньше (позже)? Мой ответ – ArduinoIDE (Assembler).
Кстати, настоятельно рекомендую хотя бы вскользь посмотреть Реальная правда о Программистах ненавидящих Arduino. Поучительный материал. Автор подробно описывает свою историю от первых радостей мигания светодиодом и чуда по тем временам — вывода температуры на дисплей от мобилки до Ардуино с дельными советами.
Так куда же идти? На мой взгляд, для любителей, как я, – это платформа Arduino IDE с низкоуровневыми вставками. Тем же, кому тесно в Ардуино, — в С. Assembler не освоить за несколько месяцев. Да и осваивать не имеет особого смыла — коды на С можно оптимизировать иногда до размеров не намного больше, чем в Ассемблере.
Спасибо за внимание. Всего наилучшего!
Ссылки по теме

===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_programmirovanie_mikrokontrollerov (Программирование микроконтроллеров), #_elektronika_dlja_nachinajuschih (Электроника для начинающих), #_arduino_ide, #_c/c++, #_assembler, #_atmel_studio_7, #_proteus, #_programmirovanie_mikrokontrollerov (программирование микроконтроллеров), #_programmirovanie_mikrokontrollerov (
Программирование микроконтроллеров
)
, #_elektronika_dlja_nachinajuschih (
Электроника для начинающих
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 02-Май 19:20
Часовой пояс: UTC + 5