Обсуждаем контроллеры компании Atmel.
Ответить

Arduino. Вопросы по программированию.

Пт июл 07, 2017 04:31:19

Пробую уменьшить потребление Atmega328p с использованием спящего режима. Всё работает, но есть интересные вопросы. Сначала снизил тактовую частоту ядра, с 16 МГц до 2 МГц, включив фьюзом делитель частоты и залив модифицированный загрузчик с замечательного конструктора загрузчика (любая частота кварца или RC генератора выбирается):

http://homes-smart.ru/index.php/oborudo ... zagruzchik

Потребление микроконтроллера упало до 3 мА, отключив периферию, вставил код просто из бесплатного конструктора Codevision AVR, код Arduino IDE понимает вообще без проблем

Код:
// Analog Comparator initialization
// Analog Comparator: Off
// The Analog Comparator's positive input is
// connected to the AIN0 pin
// The Analog Comparator's negative input is
// connected to the AIN1 pin
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);
ADCSRB=(0<<ACME);
// Digital input buffer on AIN0: On
// Digital input buffer on AIN1: On
DIDR1=(0<<AIN0D) | (0<<AIN1D);

// ADC initialization
// ADC disabled
ADCSRA=(0<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);


Добавил код спящего режима, пример с одного из форумов
http://forum.amperka.ru/threads/%D0%A1% ... 0%BC.2032/
Код:
/*
5 режимов энергосбережения:
SLEEP_MODE_IDLE
SLEEP_MODE_ADC
SLEEP_MODE_PWR_SAVE
SLEEP_MODE_STANDBY
SLEEP_MODE_PWR_DOWN
*/
#include <avr/sleep.h>
extern volatile unsigned long timer0_millis;
void setup()
{
    pinMode(13, OUTPUT);
    interrupts(); // не обязательно по умолчанию и так включено
}
void loop()
{
    while(timer0_millis < 1000) {
        set_sleep_mode(SLEEP_MODE_IDLE); // выбор режима
        sleep_mode(); // уходим в спячку
    }
    timer0_millis = 0; // сброс счётчика
    bitSet(PINB, 5);  // переключение светодиода
}


Суть в том что паузу заменяем на спящий режим. Потребление микроконтроллера упало до 0.6 мА при напряжении питания 3.5В, в принципе хороший результат, но думаю можно еще снижать потребление. Интересно, что тут основной потребитель, кварц наверное на 16 МГц в самом "мощном" режиме оставленным по умолчанию? Имеет смысл ставить кварц 1-2 МГц и тактировать ядро напрямую, без делителя?

Далее, в примере видно что "спячка" не полная и самая энергозатратная из всех возможных. Какое-то прерывание будит микроконтроллер из режима IDLE (из остальных уже нет). Предполагаю что это один из таймеров, но возможно, сторожевой таймер WDT. Будит примерно каждые 8.2 миллисекунды. Что это за процесс? От системного таймера ожидал бы задержку в 1 мс. Если в это время идет передача через UART то просыпается чаще чем 8.2 мс, вероятно тоже прерывание от UART будит микроконтроллер. Если перед засыпанием ожидать очищение буфере передачи Serial.flush() тогда частота пробуждений возвращается к 8.2 мс.

В принципе большую часть времени микроконтроллер спит, но можно ли как-то варьировать время сна? И как войти в это самое странное прерывание, чтобы обрабатывать его по нормальному своей функцией. В Ардуино IDE документированы только прерывания от PIN 2, PIN 3 и всё. Хотя есть странные конструкции

http://arduino.ru/Tutorial/Arduino_Interrupts_part3
Код:
ISR(TIMER2_OVF_vect) {...}


Но они не расписаны в описании IDE (но расписаны в других статьях). Ну очень странно. Будет ли прерывание от ISR(TIMER1_OVF_vect) {...} отрабатываться? Вроде системный таймер, всегда включен.

Так же пробовал будить микроконтроллер по сторожевому таймеру WDT. Не получилось. Так же ставил код из Codevision AVR, чтобы работало только прерывание от WDT, но кристалл сбрасывается, а не просыпается. Предполагаю что прерывание от WDT срабатывает, но в прошивке Ардуины нет кода на это прерывание и кристалл перезагружается. Или там корректная заглушка, а причина в другом? пример из этой статьи:
http://robotosha.ru/arduino/arduino-interrupts.html

Хотелось настроить более глубокий режим сна STANDBY, но не получилось. Сам микроконтроллер из этого режима не просыпается, только перезагрузкой по WDT.
Еще подумал, можно сделать RC цепочку и перед уходом в STANDBY заряжать конденсатор. Через некоторое время RC цепочка разряжается и МК пробуждается по прерыванию от пина. Но вырастет потребление, даже 1 мегаом резистор это 2 мка тока утечки.
Последний раз редактировалось SIM31 Пт июл 07, 2017 14:15:46, всего редактировалось 2 раз(а).

Re: Arduino вопросы по программированию

Пт июл 07, 2017 06:30:43

проблема может быть в фьюзах — конкретнее в WDTON он, если запроган, не даст выключить собаку и, вроде, режим перезагрузки тоже не дает выключить.
если обработчик прерывания не отработал — следующая сработка собаки перезагрузит кристалл (не зависимо от настроек).
если точность не важна — можно на внутренний RC генератор перейти (это тоже фьюзы крутить надо), ещё экономия будет.

Re: Arduino вопросы по программированию

Пт июл 07, 2017 14:12:53

если обработчик прерывания не отработал — следующая сработка собаки перезагрузит кристалл (не зависимо от настроек).

Интересно, это в каком режиме работы так? Прерывание или reset? Там вроде 2 режима работы.

Re: Arduino вопросы по программированию

Сб июл 08, 2017 02:11:44

В качестве эксперимента сделал RC цепочку, которая будет микроконтроллер из режима глубокого сна.

Изображение

С конденсатора подключаемся на вход с прерыванием. Резистор подключен к выходу. В прерывании проверяем, если уровень на входе высокий, на выход пишем низкий уровень и наоборот. Работает стабильно. Резистор 1 мегаом, конденсатор керамический 1 микрофарад, частота переключения около 10 Гц при напряжении 5В и 2 Гц при 3.5В.

Время сна можно увеличить, заряжая конденсатор сильнее, достаточно вход переключить в режим выхода и всего на 1 микросекунду и более, подать тот уровень, какой считали на входе перед этим. Было 3 вольта, станет 4 вольта, а через 50 микросекунд и все 5 вольт, разряжаться конденсатор будет уже дольше в несколько раз. Нога микроконтроллера возможно будет перегружена, но очень кратковременно.

Теоретически может произойти сбой генерации, в момент переключения на входе вдруг окажется обратный сигнал, так как там достаточно помехи выше уровня гистерезиса, может в 0.5 вольта. Генерация прекратится навсегда и микроконтроллер ни кто не разбудит. Тут можно программно уточнить, чтобы выход всегда инвертировался. А можно использовать watch dog timer, если что перезагрузит.
Дополнительное потребление от RC цепочки что-то вроде 2 мка.

Re: Arduino вопросы по программированию

Вс дек 09, 2018 15:31:55

Подскажите такую простую вещь, о которой почему-то все молчат.

Когда я принимаю с uart данные, вот таким образом в бесконечном цикле void loop():

while (Serial.available()) {
input += Serial.read();
}

То как часто можно (нужно) вызывать данный код? Одно дело когда только он крутится быстро-быстро, и совсем другое дело когда МК занят еще кучей задач и чтение происходит там раз в несколько секунд. А если данные отправляются быстрее чем читаются, то прочтены не будут? Или есть некий буфер который в любом случае собирает и потом выплюнет?

Или даже не так, а вот со счетчиком:
Код:
    while (Serial.available() > 0) // Don't read unless
                                   // there you know there is data
    {
        if(index < 19) // One less than the size of the array
        {
            inChar = Serial.read(); // Read a character
            inData[index] = inChar; // Store it
            index++; // Increment where to write next
            inData[index] = '\0'; // Null terminate the string
        }
    }

Но все-равно вопрос тот же. Как часто можно (нужно) вызывать данный код? Чаще чем передаются данные, или реже? Ведь никакой синхронизации нет?


Добавлено after 5 minutes 9 seconds:
Генерация прекратится навсегда и микроконтроллер ни кто не разбудит.
Внешний аппаратный таймер-собака разбудет. Правда он тоже будет потреблять что-то... :(

Добавлено after 2 minutes 24 seconds:
Резистор 1 мегаом, конденсатор керамический 1 микрофарад
Керамика плывет от изменения температуры. Для стабильности времени имхо лучше пленку.

Re: Arduino вопросы по программированию

Вс дек 09, 2018 15:48:03

У "стандартного" serial буфер в 128 байт, у софтсериал в 64.
Ежли "стандартный" основан на аппаратном блоке и работает автономно от программы (использует прерывания), то программный несколько похуже - надо смотреть за вероятным "перекрытием" при одновременной передаче и приеме - возможны потери данных.
И второе замечание - у простых адурин на Rx/Tx висит еще и микросхема USB-COM драйвера - возможен конфликт выходных уровней у Tx. Второй момент - там и бутлоадер при начальном запуске активен - надо выдержать интервал в 2-3 секунды после подачи питания перед началом работы с приемопередатчиком.
:roll:

Re: Arduino вопросы по программированию

Вс дек 09, 2018 15:58:54

И второе замечание - у простых адурин на Rx/Tx висит еще и микросхема USB-COM драйвера - возможен конфликт выходных уровней у Tx.
Блин. :?
А в каком случае будет конфликт? Я имею ввиду конечно если USB не подключен (и не проблема отключить Rx/Tx разъем перед прошивкой через usb).
Так то вообще в принципе можно аппаратный порт юзать для своих целей, для связи с другими устройствами? С висящим параллельно USB-COM адаптером? :oops: :)))

У "стандартного" serial буфер в 128 байт, у софтсериал в 64.
Т.е. нужно успеть прочитать пока не переполнится буфер?
Последний раз редактировалось Upgrader Вс дек 09, 2018 16:04:51, всего редактировалось 1 раз.

Re: Arduino вопросы по программированию

Вс дек 09, 2018 16:03:58

Надо схемотехнику USB-COM примененного в адуринке высматривать.
Или адуринью с несколькими CОМ портами искать.
Мне с СН340 разбираться влом было...
Как вариант - софтовый СОМ, но там могут бысть свои особенности (см.личку с примером).
:roll:
Или ардуино-про-мини - там для прошивки внешний USB-COM используется - так что все лапы в полном распоряжении.
:hunger:

Re: Arduino вопросы по программированию

Вс авг 25, 2019 19:06:15

Подскажите, почему проект отлично компилируется под ATMega328, но никак не хочет компилироваться под ATMega168? Лезут ошибки при любой попытке обращения к функциям в библиотеке CyberLib.h (она необходима).
Библиотека не поддерживает ATMega168? Можно ли это исправить?

Добавлено after 3 minutes 24 seconds:
Она вот https://github.com/AlexGyver/AC_Dimmer/ ... Lib-master

Добавлено after 9 minutes 41 second:
Судя по коду, вроде должно работать. Тем более там даже предусмотрена ошибка "#error Ваш контроллер библиотекой CyBerLib не поддерживается"
Но ей нету.

Re: Arduino вопросы по программированию

Вс авг 25, 2019 19:15:31

Судя по строке
Код:
#if defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega88__)

в CyberLib.h, она не видит разницы между перечисленными в ней МК.
Все должно работать.
Лезут ошибки при любой попытке обращения к функциям в библиотеке CyberLib.h

Какие именно ошибки?

Re: Arduino вопросы по программированию

Вс авг 25, 2019 19:19:16

Если на вскидку, то
в файле CyberLib.cpp есть строка
Код:
#if defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
замените на
Код:
#if defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__)

Re: Arduino вопросы по программированию

Вс авг 25, 2019 19:24:42

ЭлектроKOT писал(а):Какие именно ошибки?

Вот такие:
Код:
Arduino: 1.8.8, Плата:"Arduino Nano, ATmega168"

C:\Users\usera\AppData\Local\Temp\ccwxl2w5.ltrans0.ltrans.o: In function `detect_down()':

D:\Project1\AC_Dimmer-master\Sketches\dimmer_timer/dimmer_timer.ino:56: undefined reference to `StopTimer1()'

C:\Users\usera\AppData\Local\Temp\ccwxl2w5.ltrans0.ltrans.o: In function `detect_up()':

D:\Project1\AC_Dimmer-master\Sketches\dimmer_timer/dimmer_timer.ino:50: undefined reference to `ResumeTimer1()'

C:\Users\usera\AppData\Local\Temp\ccwxl2w5.ltrans0.ltrans.o: In function `setup':

D:\Project1\AC_Dimmer-master\Sketches\dimmer_timer/dimmer_timer.ino:23: undefined reference to `StartTimer1(void (*)(), unsigned long)'

D:\Project1\AC_Dimmer-master\Sketches\dimmer_timer/dimmer_timer.ino:24: undefined reference to `StopTimer1()'

collect2.exe: error: ld returned 1 exit status

Используем библиотеку CyberLib-master в папке: C:\Program Files (x86)\Arduino\libraries\CyberLib-master (legacy)
exit status 1
Ошибка компиляции для платы Arduino Nano.


Dimon456 писал(а):замените на
Код:
#if defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__)
Попробовал.
После замены появились совсем другие ошибки:
Код:
Arduino: 1.8.8, Плата:"Arduino Nano, ATmega168"

C:\Program Files (x86)\Arduino\libraries\CyberLib-master\CyberLib.cpp:22:24: error: attempt to use poisoned "SIG_USART_TRANS"

 #define SIG_UART_TRANS SIG_USART_TRANS

                        ^
C:\Program Files (x86)\Arduino\libraries\CyberLib-master\CyberLib.cpp:23:24: error: attempt to use poisoned "SIG_USART_RECV"

 #define SIG_UART_RECV  SIG_USART_RECV

                        ^
C:\Program Files (x86)\Arduino\libraries\CyberLib-master\CyberLib.cpp:24:24: error: attempt to use poisoned "SIG_USART_DATA"

 #define SIG_UART_DATA  SIG_USART_DATA

                        ^
exit status 1
Ошибка компиляции для платы Arduino Nano.

Re: Arduino вопросы по программированию

Вс авг 25, 2019 19:33:57

Есть такая мыслЯ, что библиотека у вас все-таки не подключена.
Покажите код, которым ее подключаете.

Re: Arduino вопросы по программированию

Вс авг 25, 2019 19:48:51

Нет, скетч рабочий. На ATmega328 работает всё же.
Покажите код, которым ее подключаете.
#include "CyberLib.h" :)))

Re: Arduino вопросы по программированию

Вс авг 25, 2019 19:53:24

А простейший тест пройдет?
Код:
зажечь светодиод + StartTimer1 (пауза) + погасить светодиод + StopTimer1

Или будет 2 ошибки
D:\Project1\AC_Dimmer-master\Sketches\dimmer_timer/dimmer_timer.ino:23: undefined reference to `StartTimer1(void (*)(), unsigned long)'
D:\Project1\AC_Dimmer-master\Sketches\dimmer_timer/dimmer_timer.ino:56: undefined reference to `StopTimer1()'

Вдогонку:
фрагменту
#if defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__)
//**********Small UART****************************
#define UART_DOUBLESPEED
#define UART_TXREADY UDRE0
#define UART_RXREADY RXC0
...
...
#define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 4UL)) / ((uint32_t)(baudRate) * 8UL) - 1)

из CyberLib.cpp, который любезно подправил Dimon456,
вроде бы самое место в CyberLib.h
Последний раз редактировалось ЭлектроKOT Вс авг 25, 2019 20:01:15, всего редактировалось 1 раз.

Re: Arduino вопросы по программированию

Вс авг 25, 2019 20:00:59

Закомментируйте три строки
Код:
//#define SIG_UART_TRANS SIG_USART_TRANS
//#define SIG_UART_RECV  SIG_USART_RECV
//#define SIG_UART_DATA  SIG_USART_DATA

Re: Arduino вопросы по программированию

Вс авг 25, 2019 20:09:32

Ух ты, спасибо! Скомпилировалось! :tea: :beer:
Интересно, на работу это не повлияет? :)) Завтра соберу схему и проверю. :solder: :music:

P.S. ATmega168 зло! Пожалел что связался с ней... ресурсов КОТ наплакал :cry: Проверил один старый проект - чтение цифровых датчиков температуры, вывод информации на дисплей 16х2, чтение-запись аппаратного порта, да и ничего более. И это заняло 90% памяти. Хотя на более жирной ATmega328 было всего-лишь 40% занято!!! Имхо покупка ATmega168 нецелесообразна для домашнего использования.
Последний раз редактировалось Upgrader Вс авг 25, 2019 22:18:09, всего редактировалось 6 раз(а).

Re: Arduino вопросы по программированию

Вс авг 25, 2019 20:22:34

Скомпилировалось! :tea: :beer:

:beer:
Да, в CyberLib.h не хватало того самого фрагмента, поэтому сыпались ошибки.

Добавлено after 8 minutes 35 seconds:
Закомментируйте три строки
Код:
//#define SIG_UART_TRANS SIG_USART_TRANS
//#define SIG_UART_RECV  SIG_USART_RECV
//#define SIG_UART_DATA  SIG_USART_DATA

В дальнейшем это может привести к проблемам при работе с USART, нет?

Re: Arduino вопросы по программированию

Ср авг 28, 2019 12:44:34

Такой вопросик. Ни у кого случайно нету примера как преобразовать значение с линейного переменного резистора, в логарифмическое? Т.е. чтобы использовать более распространенный линейный резистор, а получить характеристику логарифмического? :tea: :))

Нашел пока только один пример чего-то наподобие https://playground.arduino.cc/Main/Fscale/ Надо разбираться...

Re: Arduino вопросы по программированию

Ср авг 28, 2019 13:56:29

Upgrader, если с математической точки зрения, то, например, для логарифимической шкалы по основанию e надо это основание возвести в степень, полученного напряжения с ADC от этого линейного потенциометра и нормированного. Так как логарифм нуля есть минус бесконечность, то, обычно, логарифмическую шкалу рассматривают для аргументов от нуля (логарифм нуля - единица), а потом просто вычитают из результата эту единицу. То бишь, пусть считано значение x, диапазон допустимых значений в нашем случае l..m, где 0<l<m. Результат логарифмической шкалы должен находиться в диапазоне L..M, где 0<L<M. Тогда нам нужно решить систему уравнений [k+a=L,e^(m-l)*k+a=M] по k (множитель) и a (слагаемое). Ответ: [k=-(e^l*L-e^l*M)/(e^m-e^l),a=(e^m*L-e^l*M)/(e^m-e^l)].
Конкретный пример. Пусть у нас напряжение на входе ADC изменяется от 0 до 3 вольт. Преобразовываем целое, считанное с ADC в плавающее в вольтах (U). Интервал нашей логарифмической шкалы выберем 0..1. Тогда результат Y=e^U*k+a, где k=0.053 и a=-0.053
Проверяем:
U=0.0 -> 2.71^0.5*0.053-0.053=0.00
U=0.5 -> 2.71^0.5*0.053-0.053=0.03
U=1.0 -> 2.71^1.0*0.053-0.053=0.09
U=1.5 -> 2.71^1.5*0.053-0.053=0.18
U=2.0 -> 2.71^2.0*0.053-0.053=0.34
U=2.5 -> 2.71^2.5*0.053-0.053=0.59
U=3.0 -> 2.71^3.0*0.053-0.053=1.00
Ответить