Всякий раз, когда приходится подбирать делитель частоты и количество тиков таймера, чтобы обеспечить нужную частоту ногодрыга (или нужную задержку до переполнения таймера), я пользуюсь калькулятором таймеров и вписываю в программу рассчитанные им значения. Когда вдруг приспичивает частоту изменить, опять запускаю калькулятор.
Давно хотелось иметь возможность вычислять конфигурационные биты делителя и количество тиков прямо в программе, чтобы я только частоту задавал, но всё как-то было «не до сук».
И вот, наконец, я таки собрался и написал некую «недобибилиотеку», которая это делает. Почему «недо-»? Ну, хотя бы потому, что в отличие от нормальной ардуиновской библиотеки, моя плевать хотела на всё, кроме ATmega328P. Думаю, в ближайшее время расширю на ATtiny85 и ATmega32U, но и всё, т.к. ничем другим я почти не пользуюсь.
Итак, задача:
по номеру таймера и требуемой частоте ногодрыга, подобрать такие делитель частоты таймера и количество тиков, чтобы получившаяся частота ногодрыга была наиболее точной из всех возможных на данном таймере. Делитель частоты выдать в виде готовых конфигурационных битов для записи в TCCRхB.
Речь идёт именно о наилучшем приближении, т.к. некоторые частоты невозможно получить точно (например, 3кГц). Там, где точное решение возможно, разумеется должно выдаваться именно оно.
Ну, вроде, написал и написал, а вам то зачем мозги пудрю?
А вот зачем. Недобиблиотеку я писал на самом что ни на есть богомерзком, гнусном С++ (даже с возможностями, появившимися только в 11-ом году), который, как всем известно: «неприменим на микроконтроллерах и на котором для микроконтроллеров пишут только дураки и преподы». И вот, решил я проверить сколько памяти отжирает моя библиотека. Какова, так сказать, цена вопроса?
Для проверки я написал такой в меру бессмысленный скетч. В нём производится «частичная» инициализация таймеров, причём если #define в строке №3 закомментировать, то работает моя библиотека, а если оставить на месте, то всё, связанное с библиотекой, выбрасывается нафиг, а в порты пишутся голимые числовые константы. Вот этот скетч, можете сами убедиться, что так оно и есть.
06 | #include <ConstTimers.h> |
10 | constexpr uint8_t timerBits2 = getPrescalerBits(2, 1000); |
11 | constexpr uint8_t timerTicks2 = getTimerTicks(2, 1000); |
15 | constexpr uint8_t timerBits1 = getPrescalerBits(1, 500); |
16 | constexpr uint16_t timerTicks1 = getTimerTicks(1, 500); |
Пробуем компилировать (IDE 1.8.9, опции «из коробки»). И что же видим?
С константами: 474 байт (1%) памяти устройства ... 9 байт (0%) динамической памяти
С библиотекой: 474 байт (1%) памяти устройства ... 9 байт (0%) динамической памяти
Найдите отличия!
А вот и сама недобиблиотека. Как видите, если убрать огромный комментарий в начале, то она состоит всего из 60 строк – десять функций, самая большая из которых – 5 строк.
004 | /////////////////////////////////////////////////////////////////////////////// |
085 | struct STimerParameters { |
086 | const uint32_t maxValue; |
087 | const int * prescalers; |
088 | const uint8_t totalPrescalers; |
091 | constexpr int prescalers01[] = {1, 8, 64, 256, 1024 }; |
092 | constexpr int prescalers2[] = {1, 8, 32, 64, 128, 256, 1024 }; |
094 | constexpr STimerParameters timerParameters[3] = { |
095 | {0x000000FFul, prescalers01, sizeof (prescalers01) / sizeof (prescalers01[0])}, |
096 | {0x0000FFFFul, prescalers01, sizeof (prescalers01) / sizeof (prescalers01[0])}, |
097 | {0x000000FFul, prescalers2, sizeof (prescalers2) / sizeof (prescalers2[0])}, |
099 | constexpr int8_t totalTimers = sizeof (timerParameters) / sizeof (timerParameters[0]); |
127 | /////////////////////////////////////////////////////////////////////////////// |
129 | constexpr uint32_t getPeriod( const uint32_t frequency) { |
130 | return (FCPU + frequency / 2) / frequency; |
133 | constexpr uint16_t prValue( const int8_t prescalerId, const int8_t nTimer) { |
134 | return timerParameters[nTimer].prescalers[prescalerId]; |
137 | constexpr uint32_t getDesiredTicks( const uint32_t frequency, const int8_t prescalerId, const int8_t nTimer) { |
138 | return (getPeriod(frequency) + prValue(prescalerId, nTimer) / 2) / prValue(prescalerId, nTimer); |
141 | constexpr uint32_t correctTicks(uint32_t dTicks, const uint32_t maxValue) { |
142 | return dTicks > maxValue ? maxValue : dTicks; |
145 | constexpr uint32_t getTicks( const uint32_t frequency, const int8_t prescalerId, const int8_t nTimer) { |
146 | return prescalerId >= timerParameters[nTimer].totalPrescalers ? 0x1FFFFFFF : |
147 | correctTicks(getDesiredTicks(frequency, prescalerId, nTimer), timerParameters[nTimer].maxValue); |
150 | constexpr uint32_t getBits( const int8_t prescalerId, const int8_t nTimer) { |
151 | return prescalerId >= timerParameters[nTimer].totalPrescalers ? timerParameters[nTimer].totalPrescalers : prescalerId + 1; |
155 | constexpr int32_t absError( const uint32_t frequency, const int8_t prescalerId, const int8_t nTimer) { |
156 | return abs(prescalerId >= timerParameters[nTimer].totalPrescalers ? 0x1FFFFFFF : |
157 | static_cast<int32_t>(getTicks(frequency, prescalerId, nTimer) * prValue(prescalerId, nTimer)) - |
158 | static_cast<int32_t>(getPeriod(frequency))); |
161 | constexpr uint8_t getPrescalerId( const uint32_t error, const uint32_t newError, const uint8_t prId, const uint8_t candidate, const uint32_t frequency, const int8_t nTimer) { |
163 | (prId >= timerParameters[nTimer].totalPrescalers) ? candidate |
164 | : getPrescalerId(newError, absError(frequency, prId+1, nTimer), prId+1, (error <= newError) ? candidate : prId, frequency, nTimer); |
167 | constexpr uint16_t getTimerTicks( const int8_t nTimer, const uint32_t freq) { |
168 | return getTicks(freq, getPrescalerId(0x1FFFFFul, absError(freq, 0, nTimer), 0, 0, freq, nTimer), nTimer); |
171 | constexpr uint8_t getPrescalerBits( const int8_t nTimer, const uint32_t freq) { |
172 | return getBits(getPrescalerId(0x1FFFFFul, absError(freq, 0, nTimer), 0, 0, freq, nTimer), nTimer); |
175 | #endif // CONSTTIMERS_H |
Модификация на другой микроконтроллер – всего лишь изменение одного трёхстрочного массива констант.
Ну, а теперь вопрос к апологетам идеи неприменимости С++ для микроконтроллеров: слабо повторить на чистом и кошерном?
Я не говорю сделать лучше (расход ресурсов – 0 и отрицательным он не станет), просто повторить также. Чтобы задача решалась, подбирались оптимальные (а не первые попавшиеся) величины, и чтобы это не ело память от слова совсем?
Кстати, чтобы не быть неправильно понятым, я вовсе не говорю, что это невозможно. Возможно, конечно (я - точно смогу), препроцессор – великая вещь. Но вот будет ли это также просто и элегантно? Или там гороху придётся скушать столько, что никакая диета не позволит? Попробуйте, чем голословно на С++ бочкотару катать. Задачка-то типично-микроконтроллерная - покажите неприменимость богомерзкого и ляпоту кошерного!
Ага, constexpr, изящно ;) Только инструмент не для начинающих, далеко не для. Спасибо, Евгений.
Так тут и нет заголовка "этюды для начинающих". Те же, к кому обращёны последние три абзаца, обычно считают себя гуру :)
Евгений, вы как человек науки всё ещё пытаетесь с верующими разговаривать на языке логики? "Богомерзкость" - это вполне достаточный для отрицания эффективности критерий.
Да, что Вы. Я не с ними разговариваю. Они - это так, к слову пришлись. Скорее, я разговариваю сам с собой.
Почему я стал писать это через constexpr? Как раз захотелось самому пощупать собственными пальцами, насколько это удобно/неудобно именно для такого типа задач. Вроде ничего, получилось, на препроцессоре было бы сложнее и менее удобно в изменениях. Честно говоря, давно не писал на функциональных языках - тяжеловато было мыслить в этой парадигме с непривычки.
А сюда выложил, когда "заметил", что памяти не ест вообще и на код никак не влияет. Знать-то я это (что не ест) и раньше, разумеется, знал (на то он и constexpr), но пока не написал как-то "неосознанно знал". А как увидел, так сразу - "Ух ты, блин! надо бы народу показать!" :) Вроде ж здесь на форуме про эту технику раньше не писали (или мимо меня прошло).
-------------
Кстати, в С++ есть ещё одна забавная и незаслуженно малораспространённая техника - "пользовательские литералы". Вот всё пытаюсь придумать под них "нативно-ардуиновскую" (не из пальца высосанную) задачу. Если придумаю - сделаю и выложу - покажу что это такое.
а я визард юзаю в cvavr для этого, собственно там и пишу. одно время помер, но щас возродился, добавили камней.
а я визард юзаю в cvavr для этого,
Для чего?
Для чего?
В СV есть vizard, в котором задаешь тики, предделители, время, тип прерывания , и он пишет заготовку кода. Типа Cube для STM32, но интегрирован в IDE CV. Кроме таймеров там можно все конфиги задать - прерывания, usart (с буфером), типы и ddr пинов, частоту, разгон (и он пишет фьюзы как надо), в общем весь конфиг фрагмент мк.
Генераторы кода есть и в других семействах. Правда их результат несколько каличный (не наглядный). Но, иногда бывает полезно сравнить со своим кодом, особенно когда свой не хочет как надо работать.)
Жалка, што я нихрена не понял.... :(
Захотели экспресии? Получайте )))
ЕвгенийП!
А для WAVGAT для третьего таймера, мне что, опять самому всё доделывать? )))
DetSemen!
Я тоже ничего не понял, но это же не мешает влезть своими кривыми ручками и поправить, всё же задокументировано! )
А для WAVGAT для третьего таймера, мне что, опять самому всё доделывать? )))
Я такого зверя и не видел никогда. Так что доделывайте, там делов-то - добавить элемент в массив timerParameters :)
Паша Хайдук - наш человек (соотечественник), создатель C компилятора CODEVISIONAVR с визардном для инициализации периферии. Одно время даже посещал наш известный российский форум.)
DetSimen, не прибедняйся :)
DetSimen, не прибедняйся :)
Ну, видима, я не до конца Страуса дочитал
Дед, думаю, ты меня троллишь, но так, на всякий случай, если вдруг, это мимо тебя прошло.
В 11-ом году появилось такое ключевое слово constexpr. Если не вдаваться в тонкости и детали, то ...
Применяется к переменным (на самом деле константам), функциям, статическим членам класса и конструкторам. В применении к переменным означает, что это на самом деле константа (в частности, обязана быть проинициализирована). В применении к функциям, конструкторам и т.д. - по большому счёту означает, что вызов такой функции может использоваться при инициализации constexpr-переменной.
Главная идея - constexpr-переменная должна быть вычислена на этапе компиляции и заменена в коде на своё значение (т.е. в коде она используется как готовый литерал). Отсюда и многочисленные ограничения не constexpr-функции (там много чего нельзя).
Собственно, всё. В моём примере четыре constexpr-переменные вычисляются на этапе компиляции и заменяются на вычисленные значения. Потому, результрующий код с использованием вычислений ничем (от слова "совсем") не отличается от кода с использованием готовых констант.
В принципе такое можно сделать и препроцессором, но там язык довольно специфический, нетривиальные вещи на нём тяжело писать. например, с циклом там столько гороху нажрёшься, а здесь пишешь на том же языке, что и всю программу.
К сожалению, наш компилятор поддерживает только С++11, а в нём constexpr-функция не имеет права содержать никаких исполняемых операторов, кроме return (глянь на мои функции). Уже в C++14 это органичение снято, но наш компилятор пока этого не поддерживает.
да неть, я constexpr то использовал, но только статически унутре класса, вместо чесного const, например, чтоб отдать ClassName (ну вот была такая задумка, щас от нее отказался). Но чтобы функции отдавали constexpr - до такова я не додумался бы, не гигант. Кстати, Страус тоже про это ничо не писал (памойму).
Слушай, а нет идей красивой задачи для "самогонного" литерала? О чём я в последнем абзаце #4 писал. Я бы примерчик сделал. Хочется, но задачу не могу придумать.
Слушай, а нет идей красивой задачи для "самогонного" литерала?
Хоть и название красивое, но я, к стыду своему, первый раз об этом слышу.
UPD. Нашол у себя constexpr. Вот так я это понимал
1
public
:
2
3
static
constexpr
const
char
*ClassName {
"TDS3231"
};
4
5
TDS3231() :TDS3231(DEV_DEFAULT_ADDRESS) {};
Это кусок из класса. А если б я разобрался, как это сразу во флэш встраивать...
UPD. UPD. Почитал за пользовательские литералы. Это не для моего скудоумия.
А для WAVGAT для третьего таймера, мне что, опять самому всё доделывать? )))
Я такого зверя и не видел никогда. Так что доделывайте, там делов-то - добавить элемент в массив timerParameters :)
Ан нет, у WAVGAT не все делители доступны для третьего таймера...
Посмотрел код, дополнить - это выше моих возможностей )))
UPD. UPD. Почитал за пользовательские литералы. Это не для моего скудоумия.
да, ладно. Все же пользуются литералами типа 100UL или там 100L. Здесь тоже самое, только свои хвосты определяем.
Вот пример для задания единиц времени в тиках контроллера. Т.е. я могу написать 1_sec - это будет 16000000 (при 16МГц) или там 2_us, в реальности это будет 32 (16*2). Т.е. перевод в тики спрятан за литералом.
01
#include <Printing.h>
02
03
//
04
// Определяем суффиксы времени.
05
// Результат - время в тиках контроллера
06
//
07
uint32_t
operator
""
_tick(
const
char
* s) {
return
strtoul(s, NULL, 10); }
08
uint32_t
operator
""
_us(
const
char
* s) {
return
operator
""
_tick(s) * (F_CPU/1000000ul); }
09
uint32_t
operator
""
_ms(
const
char
* s) {
return
operator
""
_us(s) * 1000ul; }
10
uint32_t
operator
""
_sec(
const
char
* s) {
return
operator
""
_ms(s) * 1000ul; }
11
12
void
setup
(
void
) {
13
Serial
.begin(57600);
14
Serial
<<
"1 tick = "
<< 1_tick <<
" ticks\r\n"
;
15
Serial
<<
"1 us = "
<< 1_us <<
" ticks\r\n"
;
16
Serial
<<
"1 ms = "
<< 1_ms <<
" ticks\r\n"
;
17
Serial
<<
"1 sec = "
<< 1_sec <<
" ticks\r\n"
;
18
19
Serial
<<
"2 us = "
<< 2_us <<
" ticks\r\n"
;
20
Serial
<<
"4 ms = "
<< 4_ms <<
" ticks\r\n"
;
21
Serial
<<
"5 sec = "
<< 5_sec <<
" ticks\r\n"
;
22
}
23
24
void
loop
(
void
) {}
Ан нет, у WAVGAT не все делители доступны для третьего таймера...
В смысле, есть пропущенные? Ну поставьте вместо них MAXINT, делов-то.Должно сработать
да я в общих чертах понял, канеш, про все эти ваши суффиксы, но сходу не могу придумать куда это можно применить, кто вот это вот всё придумал, и где сейчас эти люди.
Слушай, а нет идей красивой задачи для "самогонного" литерала? О чём я в последнем абзаце #4 писал. Я бы примерчик сделал. Хочется, но задачу не могу придумать.
Ну самый тупой из полезных примеров - это пересчет Вольт в целое, для использования с analogRead().
что-то типа: if (myAnalogValue > 2.35_V) ... Причем можно использовать рантайм вычисления и преобразовывать с учетом измерения питания... ну ты понял, что я имею ввиду? При обычном референсе Vcc, само значение референса уточнить через измерение своего питания. Оформить как библиотеку.
Больше, пока, ничего не приходит в голову....
Разве что: Если работаем с контроллером с достаточным к-вом памяти, то перекодировки символов.
Ан нет, у WAVGAT не все делители доступны для третьего таймера...
В смысле, есть пропущенные? Ну поставьте вместо них MAXINT, делов-то.Должно сработать
Не понимаю, у него вот так с делителями, значит брать как для таймера 1?
И вот тут не пойму, почему OCR1B а не OCR1A?
01
#ifdef CONSTANTS
02
TCCR2B = 4;
03
OCR2A = 250;
04
TCCR1B = 1;
05
OCR1B = 32000;
06
#else
07
TCCR2B = timerBits2;
08
OCR2A = timerTicks2;
09
TCCR1B = timerBits1;
10
OCR1B = timerTicks1;
11
#endif
01
#include "lgtx8p.h"
02
enum
Prescalers {
03
PRESCALER_STOP = 0,
04
PRESCALER_1 = 1,
05
PRESCALER_8 = 2,
06
// PRESCALER_32 = 3,
07
PRESCALER_64 = 3,
08
// PRESCALER_128 = 5,
09
PRESCALER_256 = 4,
10
PRESCALER_1024 = 5
11
};
Ну, тогда вообще никаких проблем! Также точно как в моём массиве prescalers01.
Ну, тогда вообще никаких проблем! Также точно как в моём массиве prescalers01.
Это ясно, а по OCR1A?
Это ясно, а по OCR1A?
А он тут причём? Он в библиотеке вообще никак не используется. Поставьте правильный массив делителей и всё должно работать.
К сожалению, наш компилятор поддерживает только С++11, а в нём constexpr-функция не имеет права содержать никаких исполняемых операторов, кроме return (глянь на мои функции). Уже в C++14 это органичение снято, но наш компилятор пока этого не поддерживает.
Женя!!! Дарагой! Зачем такой неправда говоришь?!! ;)))
Всё с нашим компилятором хорошо! В platform.txt поменять gnu++11 на gnu++14 и всё прекрасно собирается. Сам компилятор полностью поддерживет 14 стандарт.
Я поменял одну тернарку у тебя в коде на простой if и результат 474 байта кода и 9 байт переменных, как и было.
Оцени: я даже не поленился проверить, что для меня - уже-таки немного подвиг!
Женя!!! Дарагой! Зачем такой неправда говоришь?!! ;)))
Сам компилятор полностью поддерживет 14 стандарт.
Вау!!! Ахренеть! А я трахался с этими "только return" - по сути на лиспе писал :((((
Ща, пойду проверять! Мож он gnu++17 понимает? Тогда и "if constexpr" можно будет юзать! :)
Отчёт.
1. При опции gnu++14 - фишки 14-го понимает (не все проверял, но что проверил - работает)
2. При опции gnu++17 - фишки 17-го понимает, но не все. В частности "if constexpr" не компилируется.
Эххх...
Зато разделители разрядов (тоже фишка 17-го) отлично пашут!
1
void
setup
(
void
) {
2
Serial
.begin(57600);
3
long
frequency = 16
'000'
000;
4
Serial
.print(frequency);
5
}
6
7
void
loop
(
void
) {}
Это уже будет IDE 1.8.10 ;-)
мне тоже чота наданапица.
Птис классный, правда, дед?
классный. И на мня похож.
Отчёт.
1. При опции gnu++14 - фишки 14-го понимает (не все проверял, но что проверил - работает)
2. При опции gnu++17 - фишки 17-го понимает, но не все. В частности "if constexpr" не компилируется.
Я вот не проверял, как при gnu++14 все это потом в контроллере работает. Если ты все равно этим увлекся, то проверь что-нибудь собранное в стандарте 14 залить в контроллер. Я поеду на моте катаццо! Как раз новый шлем прикупил и наушники в него вклеил.
Так, Влад, заливал же ж! И в котроллер, и в протеус - то, что компилируется, то адекватно работает!
Стоит только выбрать плату WAVGAT и перестаёт компилироваться, а с платой LGT8F328P-LQFP32 всё компилируется:
001
Arduino: 1.8.8 (Windows XP), Плата:
"WAVGAT NANO 3.0"
002
003
Внимание: platform.txt из ядра
'Arduino AVR Boards'
содержит устаревшие recipe.ar.pattern=
"{compiler.path}{compiler.ar.cmd}"
{compiler.ar.flags} {compiler.ar.extra_flags}
"{build.path}/{archive_file}"
"{object_file}"
, автоматически преобразовано в recipe.ar.pattern=
"{compiler.path}{compiler.ar.cmd}"
{compiler.ar.flags} {compiler.ar.extra_flags}
"{archive_file_path}"
"{object_file}"
. Ожидайте обновления ядра.
004
In file included from D:\000\Timer-ALL_LIB-WAVGAT\Timer-ALL_LIB-WAVGAT.ino:7:0:
005
006
ConstTimers.h:91:1: error:
'constexpr'
does not name a type
007
008
constexpr
int
prescalers01[] = {1, 8, 64, 256, 1024 };
009
010
^
011
012
sketch\ConstTimers.h:91:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
013
014
ConstTimers.h:92:1: error:
'constexpr'
does not name a type
015
016
constexpr
int
prescalers2[] = {1, 8, 32, 64, 128, 256, 1024 };
017
018
^
019
020
sketch\ConstTimers.h:92:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
021
022
ConstTimers.h:94:1: error:
'constexpr'
does not name a type
023
024
constexpr STimerParameters timerParameters[3] = {
025
026
^
027
028
sketch\ConstTimers.h:94:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
029
030
ConstTimers.h:99:1: error:
'constexpr'
does not name a type
031
032
constexpr int8_t totalTimers =
sizeof
(timerParameters) /
sizeof
(timerParameters[0]);
033
034
^
035
036
sketch\ConstTimers.h:99:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
037
038
ConstTimers.h:129:1: error:
'constexpr'
does not name a type
039
040
constexpr uint32_t getPeriod(
const
uint32_t frequency) {
041
042
^
043
044
sketch\ConstTimers.h:129:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
045
046
ConstTimers.h:133:1: error:
'constexpr'
does not name a type
047
048
constexpr uint16_t prValue(
const
int8_t prescalerId,
const
int8_t nTimer) {
049
050
^
051
052
sketch\ConstTimers.h:133:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
053
054
ConstTimers.h:137:1: error:
'constexpr'
does not name a type
055
056
constexpr uint32_t getDesiredTicks(
const
uint32_t frequency,
const
int8_t prescalerId,
const
int8_t nTimer) {
057
058
^
059
060
sketch\ConstTimers.h:137:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
061
062
ConstTimers.h:141:1: error:
'constexpr'
does not name a type
063
064
constexpr uint32_t correctTicks(uint32_t dTicks,
const
uint32_t maxValue) {
065
066
^
067
068
sketch\ConstTimers.h:141:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
069
070
ConstTimers.h:145:1: error:
'constexpr'
does not name a type
071
072
constexpr uint32_t getTicks(
const
uint32_t frequency,
const
int8_t prescalerId,
const
int8_t nTimer) {
073
074
^
075
076
sketch\ConstTimers.h:145:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
077
078
ConstTimers.h:150:1: error:
'constexpr'
does not name a type
079
080
constexpr uint32_t getBits(
const
int8_t prescalerId,
const
int8_t nTimer) {
081
082
^
083
084
sketch\ConstTimers.h:150:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
085
086
ConstTimers.h:155:1: error:
'constexpr'
does not name a type
087
088
constexpr int32_t absError(
const
uint32_t frequency,
const
int8_t prescalerId,
const
int8_t nTimer) {
089
090
^
091
092
sketch\ConstTimers.h:155:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
093
094
ConstTimers.h:161:1: error:
'constexpr'
does not name a type
095
096
constexpr uint8_t getPrescalerId(
const
uint32_t error,
const
uint32_t newError,
const
uint8_t prId,
const
uint8_t candidate,
const
uint32_t frequency,
const
int8_t nTimer) {
097
098
^
099
100
sketch\ConstTimers.h:161:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
101
102
ConstTimers.h:167:1: error:
'constexpr'
does not name a type
103
104
constexpr uint16_t getTimerTicks(
const
int8_t nTimer,
const
uint32_t freq) {
105
106
^
107
108
sketch\ConstTimers.h:167:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
109
110
ConstTimers.h:171:1: error:
'constexpr'
does not name a type
111
112
constexpr uint8_t getPrescalerBits(
const
int8_t nTimer,
const
uint32_t freq) {
113
114
^
115
116
sketch\ConstTimers.h:171:1: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
117
118
Timer-ALL_LIB-WAVGAT:12:3: error:
'constexpr'
does not name a type
119
120
constexpr uint8_t timerBits2 = getPrescalerBits(2, 1000);
121
122
^
123
124
D:\000\Timer-ALL_LIB-WAVGAT\Timer-ALL_LIB-WAVGAT.ino:12:3: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
125
126
Timer-ALL_LIB-WAVGAT:13:3: error:
'constexpr'
does not name a type
127
128
constexpr uint8_t timerTicks2 = getTimerTicks(2, 1000);
129
130
^
131
132
D:\000\Timer-ALL_LIB-WAVGAT\Timer-ALL_LIB-WAVGAT.ino:13:3: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
133
134
Timer-ALL_LIB-WAVGAT:17:3: error:
'constexpr'
does not name a type
135
136
constexpr uint8_t timerBits1 = getPrescalerBits(1, 500);
137
138
^
139
140
D:\000\Timer-ALL_LIB-WAVGAT\Timer-ALL_LIB-WAVGAT.ino:17:3: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
141
142
Timer-ALL_LIB-WAVGAT:18:3: error:
'constexpr'
does not name a type
143
144
constexpr uint16_t timerTicks1 = getTimerTicks(1, 500);
145
146
^
147
148
D:\000\Timer-ALL_LIB-WAVGAT\Timer-ALL_LIB-WAVGAT.ino:18:3: note: C++11
'constexpr'
only available with -std=c++11 or -std=gnu++11
149
150
D:\000\Timer-ALL_LIB-WAVGAT\Timer-ALL_LIB-WAVGAT.ino: In function
'void setup()'
:
151
152
Timer-ALL_LIB-WAVGAT:30:14: error:
'timerBits1'
was not declared
in
this
scope
153
154
TCCR3B = timerBits1;
155
156
^
157
158
Timer-ALL_LIB-WAVGAT:31:13: error:
'timerTicks1'
was not declared
in
this
scope
159
160
OCR3A = timerTicks1;
161
162
^
163
164
Timer-ALL_LIB-WAVGAT:32:14: error:
'timerBits2'
was not declared
in
this
scope
165
166
TCCR2B = timerBits2;
167
168
^
169
170
Timer-ALL_LIB-WAVGAT:33:13: error:
'timerTicks2'
was not declared
in
this
scope
171
172
OCR2A = timerTicks2;
173
174
^
175
176
D:\000\Timer-ALL_LIB-WAVGAT\Timer-ALL_LIB-WAVGAT.ino: In function
'void loop()'
:
177
178
Timer-ALL_LIB-WAVGAT:39:20: error:
'timerBits1'
was not declared
in
this
scope
179
180
Serial
.println(timerBits1);
181
182
^
183
184
Timer-ALL_LIB-WAVGAT:41:23: error:
'timerTicks1'
was not declared
in
this
scope
185
186
Serial
.println(timerTicks1);
187
188
^
189
190
Timer-ALL_LIB-WAVGAT:44:20: error:
'timerBits2'
was not declared
in
this
scope
191
192
Serial
.println(timerBits2);
193
194
^
195
196
Timer-ALL_LIB-WAVGAT:46:24: error:
'timerTicks2'
was not declared
in
this
scope
197
198
Serial
.println(timerTicks2);
199
200
^
201
202
exit status 1
203
'constexpr'
does not name a type
204
205
Этот отчёт будет иметь больше информации с
206
включенной опцией Файл -> Настройки ->
207
"Показать подробный вывод во время компиляции"
Внимательно прочитайте 12-ую строчку, там всё написано, что Вам нужно знать, и выставьте нормальные опции.
Внимательно прочитайте 12-ую строчку, там всё написано, что Вам нужно знать, и выставьте нормальные опции.
я не знаю как это сделать, а то, что надо изменить опции компилятора усёк )))
Опции живут в файле platform.txt, нужная строчка начинается с "compiler.cpp.flags=" без кавычек
Опции живут в файле platform.txt, нужная строчка начинается с "compiler.cpp.flags=" без кавычек
Спасибо, поправил, работает )))
Только третий таймер у него конечно 16 битный но, представлен двумя восьмибитными регистрами, грузить которые надо раздельно, попробовал так, что-то не срослось:
01
// Если define ниже закомментировать, то работает библиотека
02
// Если же оставить, то простое присваивание числовых констант
03
//#define CONSTANTS
04
#include "lgtx8p.h"
05
06
#ifndef CONSTANTS
07
#include "ConstTimers.h"
08
09
// Параметры для работы таймера/счётчика №3 на частоте 73Гц
10
//
11
constexpr uint8_t timerBits3 = getPrescalerBits(1, 73);
12
constexpr uint16_t timerTicks3 = getTimerTicks(1, 73);
13
//
14
// Параметры для работы таймера/счётчика №2 на частоте 1кГц
15
//
16
constexpr uint8_t timerBits2 = getPrescalerBits(2, 1000);
17
constexpr uint8_t timerTicks2 = getTimerTicks(2, 1000);
18
//
19
// Параметры для работы таймера/счётчика №1 на частоте 500Гц
20
//
21
constexpr uint8_t timerBits1 = getPrescalerBits(1, 500);
22
constexpr uint16_t timerTicks1 = getTimerTicks(1, 500);
23
#endif
24
25
void
setup
(
void
) {
26
Serial
.begin(115200);
27
28
#ifdef CONSTANTS
29
TCCR3B = 4;
30
OCR3A = 250;
31
TCCR2B = 1;
32
OCR2A = 32000;
33
TCCR1B = 1;
34
OCR1A = 32000;
35
36
#else
37
TCCR3B = timerBits3;
38
if
(timerTicks3 > 256){
39
OCR3AH = timerTicks3 / 256;
40
OCR3AL = timerTicks3 % 256;
41
}
else
{
42
OCR3AH = 0x00;
43
OCR3AL = timerTicks3;
44
}
45
46
TCCR2B = timerBits2;
47
OCR2A = timerTicks2;
48
TCCR1B = timerBits1;
49
OCR1A = timerTicks1;
50
#endif
51
}
52
53
void
loop
(
void
) {
54
Serial
.print(
"TCCR3B = "
);
55
Serial
.println(timerBits3);
56
Serial
.print(
"OCR3A = "
);
57
Serial
.println(timerTicks3);
58
59
Serial
.print(
"TCCR2B = "
);
60
Serial
.println(timerBits2);
61
Serial
.print(
"OCR2A = "
);
62
Serial
.println(timerTicks2);
63
64
Serial
.print(
"TCCR1B = "
);
65
Serial
.println(timerBits1);
66
Serial
.print(
"OCR1A = "
);
67
Serial
.println(timerTicks1);
68
69
Serial
.print(
"Считанное из OCR3A = "
);
70
Serial
.println(OCR3A);
71
Serial
.println();
72
delay(5000);
73
}
Как харошо, что есть люди, которые во всем этом шарют. И есть, которые уже вхлам плюшевые. Как я. :-)
Как харошо, что есть люди, которые во всем этом шарют. И есть, которые уже вхлам плюшевые. Как я. :-)
В Москве еще без четверти 6, а я до 6 крепкое ни-ни! Так что пока вермутом разминаемся ;))) на льду.
Лыхаим! (то бишь: За жись!)
Лыхаим! Тяжолый был день, машину гавна растаскал по грядкам. Все болит. :-)
Только третий таймер у него конечно 16 битный но, представлен двумя восьмибитными регистрами, грузить которые надо раздельно, попробовал так, что-то не срослось:
И ещё, Вы обычные числа туда пихать умеете или нет? Мож там с какими сдвигами или масками? Так timerTicks1 - такое же обычное число.
Если хотите от меня какой-то разумной деятельности, то напишите словами что куда (в какой регистр) пихать надо, а ято я понятия не имею.
Только третий таймер у него конечно 16 битный но, представлен двумя восьмибитными регистрами, грузить которые надо раздельно, попробовал так, что-то не срослось:
И ещё, Вы обычные числа туда пихать умеете или нет? Мож там с какими сдвигами или масками? Так timerTicks1 - такое же обычное число.
Если хотите от меня какой-то разумной деятельности, то напишите словами что куда (в какой регистр) пихать надо, а ято я понятия не имею.
так пытаюсь, таймер 16 битный, но загружать его надо 8 битными значениями (регистры, их два (восьмибитных), OCR3AH и OCR3AL и загружать их надо сначала верхний, затем нижний
1
1
if
(timerTicks3 > 256){
2
OCR3AH = timerTicks3 / 256;
3
OCR3AL = timerTicks3 % 256;
4
}
else
{
5
OCR3AH = 0x00;
6
OCR3AL = timerTicks3;
7
}
На самом деле, ради фразы
опции «из коробки»
можно и потрахаться. Это правильная фраза.
1
if
(timerTicks3 > 256){
2
OCR3AH = timerTicks3 / 256;
3
OCR3AL = timerTicks3 % 256;
4
}
else
{
5
OCR3AH = 0x00;
6
OCR3AL = timerTicks3;
7
}
Условие в строке №1 не нужно. Достаточно написать ТОЛЬКО строки №№ 2 и 3.
А если уж хочется условие, то пишите правильно (255, а не 256).
Обычно у таких таймеров есть и общий 16-битный регистр. Например, в 329З есть и OCR1AH/OCR1AL, и общий OCR1A.
Так как Вы написали (с учётом ощшибки) должно работать. Если не работает, то виновата не библиотека. отладьте с голимыми числами и когда заработает, перейдёит на библиотеку. Разницы никакой.
можно и потрахаться.
Особенно, когда трахается кто-то другой :)
1
if
(timerTicks3 > 256){
2
OCR3AH = timerTicks3 / 256;
3
OCR3AL = timerTicks3 % 256;
4
}
else
{
5
OCR3AH = 0x00;
6
OCR3AL = timerTicks3;
7
}
Условие в строке №1 не нужно. Достаточно написать ТОЛЬКО строки №№ 2 и 3.
А если уж хочется условие, то пишите правильно (255, а не 256).
Обычно у таких таймеров есть и общий 16-битный регистр. Например, в 329З есть и OCR1AH/OCR1AL, и общий OCR1A.
Так как Вы написали (с учётом ощшибки) должно работать. Если не работает, то виновата не библиотека. отладьте с голимыми числами и когда заработает, перейдёит на библиотеку. Разницы никакой.
что значит его величество ОПЫТ, скосячил однако с 256 )))