Как и обещал, поковырялся вчера. Действительно, тяжко с одними return'ами, надо переходить на С++14 или 17.
В общем, сделал следующее:
1. К работе с частотами добавлена работа с периодами/интервалами;
2. Добавлено задание максимальной допустимой погрешности количества тактов;
3. Появилась возможность выдавать ошибку компиляции в случае выхода за допустимую погрешность;
4. Добавлены суффиксы для работы с временными интервалами (на основе другого кода от ЕвгенийП);
5. Добавлена поддержка Мега, Леонардо и ATmega32A
6. Все «внутренние» функции спрятаны в своё пространство имён.
Вот библиотека:
#ifndef CONSTTIMERS_H
#define CONSTTIMERS_H
///////////////////////////////////////////////////////////////////////////////
//
// Модификация недобиблиотеки от ЕвгенийП.
// Выполнена: Ворота, 11.07.2019.
//
// Основные изменения:
// 1. К работе с частотами добавлена работа с периодами/интервалами;
// 2. Добавлено задание максимальной допустимой погрешности количества тактов;
// 3. Появилась возможность выдавать ошибку компиляции в случае выхода за допустимую погрешность;
// 4. Добавлены суффиксы для работы с временными интервалами (на основе другого кода от ЕвгенийП);
// 5. Добавлена поддержка Мега, Леонардо и ATmega32A
// 6. Все «внутренние» функции спрятаны в своё пространство имён.
//
// ---------------
//
// Определяются биты конфигурации делителя частоты таймера и количество тактов с данным делителем для
// получения нужного интервала срабатывания таймера. Интервал задаётся либо частотой, либо периодом
// (длительностью, если речь идёт об одиночном сигнале, например, по переполнению).
// Соответственно, имеются четыре функции:
//
// uint8_t prescalerBitsByPeriod(int8_t nTimer, uint32_t period);
// uint16_t timerTicksByPeriod(int8_t nTimer, uint32_t period, int8_t error = 0);
//
// uint8_t prescalerBitsByFrequency(int8_t nTimer, uint32_t frequency);
// uint16_t timerTicksByFrequency(int8_t nTimer, uint32_t frequency, int8_t error = 0);
//
// Первый параметр у всех функций – номер таймера. Параметры period и frequency – соответственно
// требуемые период в тактах микроконтроллера (см. ниже о суффиксах) и частота (в герцах).
// Параметр error задаёт допустимое отклонение от запрошенных характеристик в процентах.
// Если не удаётся получить решение в пределах допустимого отклонения, то timerTicksByХХХ вернут 0.
//
// Также имеется функция, возвращающая значение делителя частоты заданного таймера по битам конфигурации,
// полученным от функций prescalerBitsByХХХ.
//
// int16_t prescalerValue(uint8_t nTimer, uint8_t bits);
//
// Для удобства работы с временными интервалами добавлены суффиксы _clk, _us, _ms и _sec. Таким образом,
// второй параметр функций prescalerBitsByPeriod и timerTicksByPeriod (время в тактах микроконтроллера)
// можно задавать при помощи суффиксов, например:
//
// 100 или 100_clk – сто тактов микроконтроллера;
// 100_us – сто микросекунд;
// 100_ms – сто миллисекунд;
// 2_sec – две секунды.
//
// Допускаются также арифметические операции, например, запись
//
// 2_ms + 50_us
//
// вполне допустима и означает 2050 микросекунд.
//
// ИСПОЛЬЗОВАНИЕ
//
// Для использования необходимо включить файл «ConstTimers.h» и определить константы с
// модификатором constexpr для нужных конфигурационных битов и количества тиков, которым
// присвоить значения, возвращаемые функциям prescalerBitsByХХХ и timerTicksByХХХ соответственно.
//
// Если использовать именно так, то код библиотеки целиком исполняется во время компиляции
// и не оказывает никакого влияния ни на размер занимаемой памяти, ни на код программы.
// В коде программы будут вставлены готовые (вычисленные на этапе компиляции) константы.
//
// Это позволяет организовать проверку полученного на этапе компиляции значения (функции
// timerTicksByХХХ возвращают 0 в случае невозможности соблюсти необходимую точность)
// и прервать компиляцию с соответствующим сообщением об ошибке при помощи static_assert.
//
// Пример рекомендуемого использования:
//
// /////////////////////////////////////////////////
// //
// // Получаем меандр с частотой 50Гц на 9-ом пине
// // для этого заводим его на СТС и инвертированием
// // на частоте 100Гц (как раз 100/2 = 50)
// //
// #include <ConstTimers.h>
//
// #define TIMER 1
// #define FREQUENCY 100
//
// static constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY);
// static constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY);
//
// // проверка установилась ли частота (например, при частоте 101 будет ошибка компиляции)
// static_assert(timerTicks, "The required frequency with a desired accuracy is unattainable for timer/counter");
//
// void setup() {
// pinMode(9, OUTPUT);
// TCCR1A = bit(COM1A0); // Инвертирование пина 9 по сравнению
// TCCR1B = bit(WGM12) | prescalerBits; // Установить СТС режим и делитель частоты
// OCR1A = timerTicks; // установить TOP равным timerTicks
// }
//
// void loop() {}
//
//Результат работы будет точно такой же, как если написать константы, вместо вычислений:
//
// void setup() {
// pinMode(9, OUTPUT);
// TCCR1A = bit(COM1A0);
// TCCR1B = bit(WGM12) | 2;
// OCR1A = 20000;
// }
// void loop() {}
//
// Ни на один байт код не изменится.
//
// КОНФИГУРАЦИЯ:
//
// 1. расчёт производится для текущей тактовой частоты микроконтроллера. Если нужно
// считать для какой-то другой частоты, измените константу FCPU.
//
// 2. STimerParameters - массив конфигурации таймеров. Количество элементов массива
// соответствует количеству таймеров. Нулевой элемент описывает нулевой таймер,
// первый элемент – первый таймер и т.д. Если требуется расширить недобиблиотеку для других
// микроконтроллеров, нужно изменить именно этот массив и больше изменять ничего не надо.
//
// В массиве для каждого таймера указано:
// 1) разрядность таймера в виде максимально возможного значения количества тиков
// (для 8-разрядных таймеров – 0xFF, для 16-разрядных – 0xFFFF.
// 2) указатель на массив делителей частоты. Делители начинаются с 1 (делитель 0 писать не нужно)
// 3) количество делителей частоты у данного таймера.
//
// ЛИЦЕНЗИЯ
//
// Данный код поставляется по лицензии ПНХ.
//
// 1. Вы можете свободно использовать или не использовать его в коммерческих,
// некоммерческих, и любых иных, не запрещённых законом, целях.
//
// 2. Автор не несёт решительно никакой ответственности за любые положительные
// или отрицательные результаты использования или неиспользования данного кода.
//
// 3. Если Вам таки хочется сделать автору предъяву, то Вы знаете, куда
// Вам следует обратиться. А если не знаете, то см. название лицензии.
//
// 4. Если данный код вдруг Вам пригодился (как учебник или ещё как что) и Вам
// почему-либо (ну, приболели, может) захотелось отблагодарить автора рублём,
// то это всегда пожалуйста – WebMoney, кошелёк № R626206676373
//
// 5. Возникновение или невозникновение у Вас желаний, обозначенных в п.4
// настоящей лицензии никак не связано с п.1, который действует безусловно
// и независимо от п.4.
//
// 6. Если данный код нужен Вам с какой-либо другой лицензией, например, с
// сопровождением или Вы нуждаетесь во внесении изменений, свяжитесь с автором
// на предмет заключения договора гражданско-правового характера.
//
///////////////////////////////////////////////////////////////////////////////
#define ATtiny85Detected (defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__))
#define ATmega328Detected (defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || defined(__AVR_ATmega88A__) \
|| defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) \
|| defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__))
#define ATmega2561Detected (defined(__AVR_ATmega640__) || defined(__AVR_ATmega640V__) || defined(__AVR_ATmega1280__) \
|| defined(__AVR_ATmega1280V__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1281V__) \
|| defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2560V__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega2561V__))
#define ATmega32U4Detected (defined(__AVR_ATmega32U4__))
#define ATmega32ADetected (defined(__AVR_ATmega32A__))
#define FCPU F_CPU
namespace constTimersNS {
struct STimerParameters {
const uint32_t maxValue;
const int16_t * prescalers;
const uint8_t totalPrescalers;
};
static constexpr uint32_t bits8 = 0x000000FFul;
static constexpr uint32_t bits10 = 0x000003FFul;
static constexpr uint32_t bits16 = 0x0000FFFFul;
#if ATmega328Detected || ATmega32ADetected
static constexpr int16_t prescalers01[] = { 1, 8, 64, 256, 1024 };
static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 };
static constexpr STimerParameters timerParameters[] = {
{ bits8, prescalers01, sizeof(prescalers01) / sizeof(prescalers01[0]) },
{ bits16, prescalers01, sizeof(prescalers01) / sizeof(prescalers01[0]) },
{ bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) }
};
#elif ATmega32U4Detected
static constexpr int16_t prescalers013[] = { 1, 8, 64, 256, 1024 };
static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 };
static constexpr int16_t prescalers4[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 };
static constexpr STimerParameters timerParameters[] = {
{ bits8, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) },
{ bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) },
{ bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) },
{ bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) },
{ bits10, prescalers4, sizeof(prescalers4) / sizeof(prescalers4[0]) }
};
#elif ATmega2561Detected
static constexpr int16_t prescalers01345[] = { 1, 8, 64, 256, 1024 };
static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 };
static constexpr STimerParameters timerParameters[] = {
{ bits8, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) },
{ bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) },
{ bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) },
{ bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) },
{ bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) },
{ bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) }
};
#elif ATtiny85Detected
static constexpr int16_t prescalers0[] = { 1, 8, 64, 256, 1024 };
static constexpr int16_t prescalers1[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 };
static constexpr STimerParameters timerParameters[] = {
{ bits8, prescalers0, sizeof(prescalers0) / sizeof(prescalers0[0]) },
{ bits8, prescalers1, sizeof(prescalers1) / sizeof(prescalers1[0]) }
};
#else
#error The library does not seem to support your MCU
#endif
constexpr int8_t totalTimers = sizeof(timerParameters) / sizeof(timerParameters[0]);
static constexpr uint32_t getPeriod(const uint32_t frequency) {
return (FCPU + frequency / 2) / frequency;
}
static constexpr uint16_t prValue(const int8_t prescalerId, const int8_t nTimer) {
return timerParameters[nTimer].prescalers[prescalerId];
}
static constexpr uint32_t getDesiredTicks(const uint32_t period, const int8_t prescalerId, const int8_t nTimer) {
return (period + prValue(prescalerId, nTimer) / 2) / prValue(prescalerId, nTimer);
}
static constexpr uint32_t correctTicks(uint32_t dTicks, const uint32_t maxValue) {
//if (dTicks > maxValue) return maxValue; else return dTicks; // начиная с C++14
return dTicks > maxValue ? maxValue : dTicks;
}
static constexpr uint32_t getTicks(const uint32_t period, const int8_t prescalerId, const int8_t nTimer) {
return prescalerId >= timerParameters[nTimer].totalPrescalers ? 0x1FFFFFFF :
correctTicks(getDesiredTicks(period, prescalerId, nTimer), timerParameters[nTimer].maxValue);
}
static constexpr uint32_t getBits(const int8_t prescalerId, const int8_t nTimer) {
return prescalerId >= timerParameters[nTimer].totalPrescalers ? timerParameters[nTimer].totalPrescalers : prescalerId + 1;
}
static constexpr int32_t absErrorTicks(const uint32_t period, const uint32_t ticks) {
return period > ticks ? period - ticks : ticks - period;
}
static constexpr int32_t absError(const uint32_t period, const int8_t prescalerId, const int8_t nTimer) {
return prescalerId >= timerParameters[nTimer].totalPrescalers ? 0x1FFFFFFF :
absErrorTicks(period, getTicks(period, prescalerId, nTimer) * prValue(prescalerId, nTimer));
}
static constexpr uint8_t getPrescalerId(const uint32_t error, const uint32_t newError, const uint8_t prId, const uint8_t candidate, const uint32_t period, const int8_t nTimer) {
return
(prId >= timerParameters[nTimer].totalPrescalers) ? candidate
: getPrescalerId(newError, absError(period, prId + 1, nTimer), prId + 1, (error <= newError) ? candidate : prId, period, nTimer);
}
static constexpr double calcErrorPercentage(const double fcpu, const double perc) {
return (fcpu < perc ? 1.0 - fcpu / perc : fcpu / perc - 1.0) * 100.0;
}
static constexpr uint16_t returnTicksOrZero(const uint32_t left, const uint32_t right, const int8_t allowableError, const uint32_t ticks) {
return left == right || calcErrorPercentage(left, right) <= allowableError ? ticks : 0;
}
static constexpr uint16_t getTimerTicksIntFTicks(const uint32_t ticks, const int8_t nTimer, const uint32_t freq, uint8_t prescalerId, const int8_t allowableError) {
return returnTicksOrZero(FCPU, freq * ticks * timerParameters[nTimer].prescalers[prescalerId], allowableError, ticks);
}
static constexpr uint16_t getTimerTicksIntF(const int8_t nTimer, const uint32_t freq, uint8_t prescalerId, const int8_t allowableError) {
return getTimerTicksIntFTicks(getTicks(getPeriod(freq), prescalerId, nTimer), nTimer, freq, prescalerId, allowableError);
}
static constexpr uint16_t getTimerTicksIntTTicks(const uint32_t ticks, const int8_t nTimer, const uint32_t period, uint8_t prescalerId, const int8_t allowableError) {
return returnTicksOrZero(period, ticks * timerParameters[nTimer].prescalers[prescalerId], allowableError, ticks);
}
static constexpr uint16_t getTimerTicksIntT(const int8_t nTimer, const uint32_t period, uint8_t prescalerId, const int8_t allowableError) {
return getTimerTicksIntTTicks(getTicks(period, prescalerId, nTimer), nTimer, period, prescalerId, allowableError);
}
//////////////////////////////////////////////////////////////////
//
// Суффиксы литералов для задания времени
// 100 или 100_clk - время в тактах контроллера (100 тактов)
// 100_us - время в микросекундах (100 микросекунд)
// 100_ms - время в милисекундах (100 милисекунд)
// 5_sec - время в секундах (5 секунд)
//
static constexpr int8_t __sLen(const char * str, const int8_t candidate = 0) { return (!*str) ? candidate : __sLen(str + 1, candidate + 1); }
static constexpr bool __isFin(const char * str, const int8_t lInd) { return lInd < 0 || !isdigit(str[lInd]); }
static constexpr uint32_t __toDig(const char * str, const uint32_t lg, const int8_t lInd) { return (str[lInd] - '0') * lg; }
static constexpr uint32_t ___s2ul(const char * str, const uint32_t, const int8_t);
static constexpr uint32_t __nextL(const char * str, const uint32_t lg, const int8_t lInd) { return __toDig(str, lg, lInd) + ___s2ul(str, lg * 10, lInd - 1); }
static constexpr uint32_t ___s2ul(const char * str, const uint32_t lg, const int8_t lInd) { return __isFin(str, lInd) ? 0 : __nextL(str, lg, lInd); }
static constexpr uint32_t __s2ul(const char * str) { return ___s2ul(str, 1, __sLen(str) - 1); }
} // namespace constTimersNS
static constexpr uint32_t operator "" _clk(const char * s) { return constTimersNS::__s2ul(s); }
static constexpr uint32_t operator "" _us(const char * s) { return operator "" _clk(s) * (FCPU / 1000000ul); }
static constexpr uint32_t operator "" _ms(const char * s) { return operator "" _us(s) * 1000ul; }
static constexpr uint32_t operator "" _sec(const char * s) { return operator "" _ms(s) * 1000ul; }
//
//////////////////////////////////////////////////////////////////
static constexpr uint8_t prescalerBitsByPeriod(const int8_t nTimer, const uint32_t period) {
return constTimersNS::getBits(constTimersNS::getPrescalerId(0x1FFFFFul, constTimersNS::absError(period, 0, nTimer), 0, 0, period, nTimer), nTimer);
}
static constexpr uint16_t timerTicksByPeriod(const int8_t nTimer, const uint32_t period, const int8_t allowableError = 0) {
return constTimersNS::getTimerTicksIntT(nTimer, period, constTimersNS::getPrescalerId(0x1FFFFFul, constTimersNS::absError(period, 0, nTimer), 0, 0, period, nTimer), allowableError);
}
static constexpr uint8_t prescalerBitsByFrequency(const int8_t nTimer, const uint32_t freq) {
return prescalerBitsByPeriod(nTimer, constTimersNS::getPeriod(freq));
}
static constexpr uint16_t timerTicksByFrequency(const int8_t nTimer, const uint32_t freq, const int8_t allowableError = 0) {
return constTimersNS::getTimerTicksIntF(nTimer, freq,
constTimersNS::getPrescalerId(0x1FFFFFul, constTimersNS::absError(constTimersNS::getPeriod(freq), 0, nTimer), 0, 0,
constTimersNS::getPeriod(freq), nTimer), allowableError);
}
static constexpr int16_t prescalerValue(const uint8_t nTimer, const uint8_t bits) {
return constTimersNS::timerParameters[nTimer].prescalers[bits-1];
}
#endif // CONSTTIMERS_H
Вот пример моргания 9-ым пином по заданной частоте:
/////////////////////////////////////////////////
//
// Получаем меандр с частотой 10Гц на 9-ом пине
// для этого заводим таймер на СТС c инвертированием
// на частоте 20Гц (как раз 20/2 = 10)
//
#include <ConstTimers.h>
#define TIMER 1
#define FREQUENCY 20
void setup() {
constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY);
constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY);
static_assert(timerTicks, "The required frequency is unattainable");
pinMode(9, OUTPUT);
TCCR1A = bit(COM1A0); // Инвертирование пина 9 по сравнению
TCCR1B = bit(WGM12) | prescalerBits; // Установить СТС режим и делитель частоты
OCR1A = timerTicks; // установить TOP равным timerTicks
}
void loop() {}
А вот тоже самое – по временному интервалу (периоду):
/////////////////////////////////////////////////
//
// Получаем меандр с частотой 10Гц на 9-ом пине
// для этого заводим его на СТС c инвертированием
// на частоте 20Гц (как раз 20/2 = 10)
// Таким образом, период равен 50_ms
//
#include <ConstTimers.h>
#define TIMER 1
#define PERIOD 50_ms
void setup() {
constexpr uint8_t prescalerBits = prescalerBitsByPeriod(TIMER, PERIOD);
constexpr uint16_t timerTicks = timerTicksByPeriod(TIMER, PERIOD);
static_assert(timerTicks, "The required frequency is unattainable");
pinMode(9, OUTPUT);
TCCR1A = bit(COM1A0); // Инвертирование пина 9 по сравнению
TCCR1B = bit(WGM12) | prescalerBits; // Установить СТС режим и делитель частоты
OCR1A = timerTicks; // установить TOP равным timerTicks
}
void loop() {}
Подробности использования и метод генерации ошибки компиляции см. в комментарии к библиотеке.
для полноты щастя видимо нужна поддержка WAVGAT и ATMEGA328PB
Чьего счастья? Моего - не надо. Твоего надо - ждём расширений :)
сей код я могу в полной мере созерцать и, в некоторой степени использовать, я жеж не настоящий сталевар )))
ЗЫ и там и там есть третий таймер в первом он 16 битный, во втором все таймеры 16 битные, если я ничего не путаю, железяка пока в пути
Вы всегда можете проверить сами. Для этого запускаете тривиальный скетч (последняя ("воротная") версия библиотеки)
#include <Printing.h>
#include <ConstTimers.h>
#define TIMER 2
#define FREQUENCY 300000ul
static constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY);
static constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY, 1);
static_assert(timerTicks, "The required frequency with a desired accuracy is unattainable for timer/counter");
void setup() {
Serial.begin(57600);
Serial << "Prescaler=" << prescalerValue(TIMER, prescalerBits) << "; Ticks=" << timerTicks << "\r\n";
}
void loop() {}
Обратите внимание на 1 в строке №8. Если там поставить 0 или убрать её вовсе (что тоже самое), то будет ошибка компиляции, т.к. точно 300кГц сделать невозмжно. Единица означает, что 1% ошибки допустим - тогда всё компилируется.
Результат
Prescaler=1; Ticks=53
Проверяем. Точный период для 300кГц равен 3,33333 микросекунды. У нас же период получается (в микросекундах) 53 / 16 = 3,3125.
Погрешность менее 1% - значит всё правильно.
Т.е. Вы всегда можете сами проверить, если сомневаетесь.
А что уж там дальше у Вас происходит - это Ваши дела. Эта библиотека только считает эти два числа.
существенное дополнение по применению, в образце этого нет )))
Ну, как, нет, смотрите текст библиотеки в посте #102. Строки №№32-33 и пример с описанием, начиная со строки №65. Там написано и про возвращение нуля, и показано как static_assert вставить.
Нет в маленьких примерах, да (недоработка), но в "документации" всё написано.
Сорри, добавил проверку на 0 в маленькие примеры (специально для нечитающих описание :--))).
да не, я читал, но меня приучили, что время жизни десантника - 2 часа, стока патронов в РД, БМД тоже снимается ограничитель и 120 по пересечённой,... а это на всю жизнь )))
Сказал жеж, скачу по кочкам
вот это для WAVGAT и Atmega328PB где найти? - defined(__AVR_ATtiny25__)
Atmega328PB имеет пять таймеров, TC0 и TC2 восьмибитные, TC1,3,4 - 16 битные...
Для TC2 прескалер 1, 8, 32, 64, 128, 256 и 1024
Для TC0, 1, 3, 4 - 1, 8, 64, 256, 1024
Оказалось!!! Этот нехороший аддон WAVGAT NANO V3 притворяется полноценной 328 )))
Переключился на аддон LGT8F328P м все четыре таймера заработали, правильность настройки делителей пока не проверил
Значит Вы неправильно вставили WAVGAT. Покажите, как вставляли.
выше, моя вставка для WAVGAT
визуально 3-й таймер тикает раза в два-четыре быстрее, есть подозрение, что тактируется не от того генератора, Дмитрий, подскажи, что в коде поправить для третьего таймера
Я говорю, если не компилировался, значит Вы неправильно вставили. Покажите полнотсью библиотеку (только этот огромный комментарий выбростье, а то его листа задолбаешься)
Вроде нормально, завтра посмотрю, что не компилируется. Только обозначьте чётко какой именно скетч не компилируется, а то в Вашем прошлом посте больно много букв и несколько скетчей.
А, так уже заработало. В общем, если проблема останется, внятно изложите, однозначно и без лишнего.
И еще один вопрос по применению таймеров.
Устанавливать разрешение порта на выход можно разными командами одна из которых приведена в ниже приведённой конструкции, проблема в следующем и обозначена в скетче, вопрос, что там компилятор делает не так:
DDRB|=(1<<DDB3)|(1<<DDB2); // так работает
DDRB=(1<<DDB3)|(1<<DDB2); // а так для платы WAVGAT для таймеров отличных от нулевого не работает
TCCR2A=(1<<COM2A0)|(1<<COM2B0)|(1<<WGM21);
TCCR2B=1<<CS20 | prescalerBits;
OCR2A=timerTicks; //b3,b2 - тикаем с уст.частотой
Ну, Вы разницу между строками 1 и 2 понимаете? Видимо, в вавгате в порте DDRB есть что-то, что нельзя нагло устанавливать в 0. Я не знаю вавгата, но разница только в этом.
Как и обещал, поковырялся вчера. Действительно, тяжко с одними return'ами, надо переходить на С++14 или 17.
В общем, сделал следующее:
1. К работе с частотами добавлена работа с периодами/интервалами;
2. Добавлено задание максимальной допустимой погрешности количества тактов;
3. Появилась возможность выдавать ошибку компиляции в случае выхода за допустимую погрешность;
4. Добавлены суффиксы для работы с временными интервалами (на основе другого кода от ЕвгенийП);
5. Добавлена поддержка Мега, Леонардо и ATmega32A
6. Все «внутренние» функции спрятаны в своё пространство имён.
Вот библиотека:
#ifndef CONSTTIMERS_H #define CONSTTIMERS_H /////////////////////////////////////////////////////////////////////////////// // // Модификация недобиблиотеки от ЕвгенийП. // Выполнена: Ворота, 11.07.2019. // // Основные изменения: // 1. К работе с частотами добавлена работа с периодами/интервалами; // 2. Добавлено задание максимальной допустимой погрешности количества тактов; // 3. Появилась возможность выдавать ошибку компиляции в случае выхода за допустимую погрешность; // 4. Добавлены суффиксы для работы с временными интервалами (на основе другого кода от ЕвгенийП); // 5. Добавлена поддержка Мега, Леонардо и ATmega32A // 6. Все «внутренние» функции спрятаны в своё пространство имён. // // --------------- // // Определяются биты конфигурации делителя частоты таймера и количество тактов с данным делителем для // получения нужного интервала срабатывания таймера. Интервал задаётся либо частотой, либо периодом // (длительностью, если речь идёт об одиночном сигнале, например, по переполнению). // Соответственно, имеются четыре функции: // // uint8_t prescalerBitsByPeriod(int8_t nTimer, uint32_t period); // uint16_t timerTicksByPeriod(int8_t nTimer, uint32_t period, int8_t error = 0); // // uint8_t prescalerBitsByFrequency(int8_t nTimer, uint32_t frequency); // uint16_t timerTicksByFrequency(int8_t nTimer, uint32_t frequency, int8_t error = 0); // // Первый параметр у всех функций – номер таймера. Параметры period и frequency – соответственно // требуемые период в тактах микроконтроллера (см. ниже о суффиксах) и частота (в герцах). // Параметр error задаёт допустимое отклонение от запрошенных характеристик в процентах. // Если не удаётся получить решение в пределах допустимого отклонения, то timerTicksByХХХ вернут 0. // // Также имеется функция, возвращающая значение делителя частоты заданного таймера по битам конфигурации, // полученным от функций prescalerBitsByХХХ. // // int16_t prescalerValue(uint8_t nTimer, uint8_t bits); // // Для удобства работы с временными интервалами добавлены суффиксы _clk, _us, _ms и _sec. Таким образом, // второй параметр функций prescalerBitsByPeriod и timerTicksByPeriod (время в тактах микроконтроллера) // можно задавать при помощи суффиксов, например: // // 100 или 100_clk – сто тактов микроконтроллера; // 100_us – сто микросекунд; // 100_ms – сто миллисекунд; // 2_sec – две секунды. // // Допускаются также арифметические операции, например, запись // // 2_ms + 50_us // // вполне допустима и означает 2050 микросекунд. // // ИСПОЛЬЗОВАНИЕ // // Для использования необходимо включить файл «ConstTimers.h» и определить константы с // модификатором constexpr для нужных конфигурационных битов и количества тиков, которым // присвоить значения, возвращаемые функциям prescalerBitsByХХХ и timerTicksByХХХ соответственно. // // Если использовать именно так, то код библиотеки целиком исполняется во время компиляции // и не оказывает никакого влияния ни на размер занимаемой памяти, ни на код программы. // В коде программы будут вставлены готовые (вычисленные на этапе компиляции) константы. // // Это позволяет организовать проверку полученного на этапе компиляции значения (функции // timerTicksByХХХ возвращают 0 в случае невозможности соблюсти необходимую точность) // и прервать компиляцию с соответствующим сообщением об ошибке при помощи static_assert. // // Пример рекомендуемого использования: // // ///////////////////////////////////////////////// // // // // Получаем меандр с частотой 50Гц на 9-ом пине // // для этого заводим его на СТС и инвертированием // // на частоте 100Гц (как раз 100/2 = 50) // // // #include <ConstTimers.h> // // #define TIMER 1 // #define FREQUENCY 100 // // static constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY); // static constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY); // // // проверка установилась ли частота (например, при частоте 101 будет ошибка компиляции) // static_assert(timerTicks, "The required frequency with a desired accuracy is unattainable for timer/counter"); // // void setup() { // pinMode(9, OUTPUT); // TCCR1A = bit(COM1A0); // Инвертирование пина 9 по сравнению // TCCR1B = bit(WGM12) | prescalerBits; // Установить СТС режим и делитель частоты // OCR1A = timerTicks; // установить TOP равным timerTicks // } // // void loop() {} // //Результат работы будет точно такой же, как если написать константы, вместо вычислений: // // void setup() { // pinMode(9, OUTPUT); // TCCR1A = bit(COM1A0); // TCCR1B = bit(WGM12) | 2; // OCR1A = 20000; // } // void loop() {} // // Ни на один байт код не изменится. // // КОНФИГУРАЦИЯ: // // 1. расчёт производится для текущей тактовой частоты микроконтроллера. Если нужно // считать для какой-то другой частоты, измените константу FCPU. // // 2. STimerParameters - массив конфигурации таймеров. Количество элементов массива // соответствует количеству таймеров. Нулевой элемент описывает нулевой таймер, // первый элемент – первый таймер и т.д. Если требуется расширить недобиблиотеку для других // микроконтроллеров, нужно изменить именно этот массив и больше изменять ничего не надо. // // В массиве для каждого таймера указано: // 1) разрядность таймера в виде максимально возможного значения количества тиков // (для 8-разрядных таймеров – 0xFF, для 16-разрядных – 0xFFFF. // 2) указатель на массив делителей частоты. Делители начинаются с 1 (делитель 0 писать не нужно) // 3) количество делителей частоты у данного таймера. // // ЛИЦЕНЗИЯ // // Данный код поставляется по лицензии ПНХ. // // 1. Вы можете свободно использовать или не использовать его в коммерческих, // некоммерческих, и любых иных, не запрещённых законом, целях. // // 2. Автор не несёт решительно никакой ответственности за любые положительные // или отрицательные результаты использования или неиспользования данного кода. // // 3. Если Вам таки хочется сделать автору предъяву, то Вы знаете, куда // Вам следует обратиться. А если не знаете, то см. название лицензии. // // 4. Если данный код вдруг Вам пригодился (как учебник или ещё как что) и Вам // почему-либо (ну, приболели, может) захотелось отблагодарить автора рублём, // то это всегда пожалуйста – WebMoney, кошелёк № R626206676373 // // 5. Возникновение или невозникновение у Вас желаний, обозначенных в п.4 // настоящей лицензии никак не связано с п.1, который действует безусловно // и независимо от п.4. // // 6. Если данный код нужен Вам с какой-либо другой лицензией, например, с // сопровождением или Вы нуждаетесь во внесении изменений, свяжитесь с автором // на предмет заключения договора гражданско-правового характера. // /////////////////////////////////////////////////////////////////////////////// #define ATtiny85Detected (defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)) #define ATmega328Detected (defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || defined(__AVR_ATmega88A__) \ || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) \ || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)) #define ATmega2561Detected (defined(__AVR_ATmega640__) || defined(__AVR_ATmega640V__) || defined(__AVR_ATmega1280__) \ || defined(__AVR_ATmega1280V__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1281V__) \ || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2560V__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega2561V__)) #define ATmega32U4Detected (defined(__AVR_ATmega32U4__)) #define ATmega32ADetected (defined(__AVR_ATmega32A__)) #define FCPU F_CPU namespace constTimersNS { struct STimerParameters { const uint32_t maxValue; const int16_t * prescalers; const uint8_t totalPrescalers; }; static constexpr uint32_t bits8 = 0x000000FFul; static constexpr uint32_t bits10 = 0x000003FFul; static constexpr uint32_t bits16 = 0x0000FFFFul; #if ATmega328Detected || ATmega32ADetected static constexpr int16_t prescalers01[] = { 1, 8, 64, 256, 1024 }; static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 }; static constexpr STimerParameters timerParameters[] = { { bits8, prescalers01, sizeof(prescalers01) / sizeof(prescalers01[0]) }, { bits16, prescalers01, sizeof(prescalers01) / sizeof(prescalers01[0]) }, { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) } }; #elif ATmega32U4Detected static constexpr int16_t prescalers013[] = { 1, 8, 64, 256, 1024 }; static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 }; static constexpr int16_t prescalers4[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 }; static constexpr STimerParameters timerParameters[] = { { bits8, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) }, { bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) }, { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) }, { bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) }, { bits10, prescalers4, sizeof(prescalers4) / sizeof(prescalers4[0]) } }; #elif ATmega2561Detected static constexpr int16_t prescalers01345[] = { 1, 8, 64, 256, 1024 }; static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 }; static constexpr STimerParameters timerParameters[] = { { bits8, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) }, { bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) }, { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) }, { bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) }, { bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) }, { bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) } }; #elif ATtiny85Detected static constexpr int16_t prescalers0[] = { 1, 8, 64, 256, 1024 }; static constexpr int16_t prescalers1[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 }; static constexpr STimerParameters timerParameters[] = { { bits8, prescalers0, sizeof(prescalers0) / sizeof(prescalers0[0]) }, { bits8, prescalers1, sizeof(prescalers1) / sizeof(prescalers1[0]) } }; #else #error The library does not seem to support your MCU #endif constexpr int8_t totalTimers = sizeof(timerParameters) / sizeof(timerParameters[0]); static constexpr uint32_t getPeriod(const uint32_t frequency) { return (FCPU + frequency / 2) / frequency; } static constexpr uint16_t prValue(const int8_t prescalerId, const int8_t nTimer) { return timerParameters[nTimer].prescalers[prescalerId]; } static constexpr uint32_t getDesiredTicks(const uint32_t period, const int8_t prescalerId, const int8_t nTimer) { return (period + prValue(prescalerId, nTimer) / 2) / prValue(prescalerId, nTimer); } static constexpr uint32_t correctTicks(uint32_t dTicks, const uint32_t maxValue) { //if (dTicks > maxValue) return maxValue; else return dTicks; // начиная с C++14 return dTicks > maxValue ? maxValue : dTicks; } static constexpr uint32_t getTicks(const uint32_t period, const int8_t prescalerId, const int8_t nTimer) { return prescalerId >= timerParameters[nTimer].totalPrescalers ? 0x1FFFFFFF : correctTicks(getDesiredTicks(period, prescalerId, nTimer), timerParameters[nTimer].maxValue); } static constexpr uint32_t getBits(const int8_t prescalerId, const int8_t nTimer) { return prescalerId >= timerParameters[nTimer].totalPrescalers ? timerParameters[nTimer].totalPrescalers : prescalerId + 1; } static constexpr int32_t absErrorTicks(const uint32_t period, const uint32_t ticks) { return period > ticks ? period - ticks : ticks - period; } static constexpr int32_t absError(const uint32_t period, const int8_t prescalerId, const int8_t nTimer) { return prescalerId >= timerParameters[nTimer].totalPrescalers ? 0x1FFFFFFF : absErrorTicks(period, getTicks(period, prescalerId, nTimer) * prValue(prescalerId, nTimer)); } static constexpr uint8_t getPrescalerId(const uint32_t error, const uint32_t newError, const uint8_t prId, const uint8_t candidate, const uint32_t period, const int8_t nTimer) { return (prId >= timerParameters[nTimer].totalPrescalers) ? candidate : getPrescalerId(newError, absError(period, prId + 1, nTimer), prId + 1, (error <= newError) ? candidate : prId, period, nTimer); } static constexpr double calcErrorPercentage(const double fcpu, const double perc) { return (fcpu < perc ? 1.0 - fcpu / perc : fcpu / perc - 1.0) * 100.0; } static constexpr uint16_t returnTicksOrZero(const uint32_t left, const uint32_t right, const int8_t allowableError, const uint32_t ticks) { return left == right || calcErrorPercentage(left, right) <= allowableError ? ticks : 0; } static constexpr uint16_t getTimerTicksIntFTicks(const uint32_t ticks, const int8_t nTimer, const uint32_t freq, uint8_t prescalerId, const int8_t allowableError) { return returnTicksOrZero(FCPU, freq * ticks * timerParameters[nTimer].prescalers[prescalerId], allowableError, ticks); } static constexpr uint16_t getTimerTicksIntF(const int8_t nTimer, const uint32_t freq, uint8_t prescalerId, const int8_t allowableError) { return getTimerTicksIntFTicks(getTicks(getPeriod(freq), prescalerId, nTimer), nTimer, freq, prescalerId, allowableError); } static constexpr uint16_t getTimerTicksIntTTicks(const uint32_t ticks, const int8_t nTimer, const uint32_t period, uint8_t prescalerId, const int8_t allowableError) { return returnTicksOrZero(period, ticks * timerParameters[nTimer].prescalers[prescalerId], allowableError, ticks); } static constexpr uint16_t getTimerTicksIntT(const int8_t nTimer, const uint32_t period, uint8_t prescalerId, const int8_t allowableError) { return getTimerTicksIntTTicks(getTicks(period, prescalerId, nTimer), nTimer, period, prescalerId, allowableError); } ////////////////////////////////////////////////////////////////// // // Суффиксы литералов для задания времени // 100 или 100_clk - время в тактах контроллера (100 тактов) // 100_us - время в микросекундах (100 микросекунд) // 100_ms - время в милисекундах (100 милисекунд) // 5_sec - время в секундах (5 секунд) // static constexpr int8_t __sLen(const char * str, const int8_t candidate = 0) { return (!*str) ? candidate : __sLen(str + 1, candidate + 1); } static constexpr bool __isFin(const char * str, const int8_t lInd) { return lInd < 0 || !isdigit(str[lInd]); } static constexpr uint32_t __toDig(const char * str, const uint32_t lg, const int8_t lInd) { return (str[lInd] - '0') * lg; } static constexpr uint32_t ___s2ul(const char * str, const uint32_t, const int8_t); static constexpr uint32_t __nextL(const char * str, const uint32_t lg, const int8_t lInd) { return __toDig(str, lg, lInd) + ___s2ul(str, lg * 10, lInd - 1); } static constexpr uint32_t ___s2ul(const char * str, const uint32_t lg, const int8_t lInd) { return __isFin(str, lInd) ? 0 : __nextL(str, lg, lInd); } static constexpr uint32_t __s2ul(const char * str) { return ___s2ul(str, 1, __sLen(str) - 1); } } // namespace constTimersNS static constexpr uint32_t operator "" _clk(const char * s) { return constTimersNS::__s2ul(s); } static constexpr uint32_t operator "" _us(const char * s) { return operator "" _clk(s) * (FCPU / 1000000ul); } static constexpr uint32_t operator "" _ms(const char * s) { return operator "" _us(s) * 1000ul; } static constexpr uint32_t operator "" _sec(const char * s) { return operator "" _ms(s) * 1000ul; } // ////////////////////////////////////////////////////////////////// static constexpr uint8_t prescalerBitsByPeriod(const int8_t nTimer, const uint32_t period) { return constTimersNS::getBits(constTimersNS::getPrescalerId(0x1FFFFFul, constTimersNS::absError(period, 0, nTimer), 0, 0, period, nTimer), nTimer); } static constexpr uint16_t timerTicksByPeriod(const int8_t nTimer, const uint32_t period, const int8_t allowableError = 0) { return constTimersNS::getTimerTicksIntT(nTimer, period, constTimersNS::getPrescalerId(0x1FFFFFul, constTimersNS::absError(period, 0, nTimer), 0, 0, period, nTimer), allowableError); } static constexpr uint8_t prescalerBitsByFrequency(const int8_t nTimer, const uint32_t freq) { return prescalerBitsByPeriod(nTimer, constTimersNS::getPeriod(freq)); } static constexpr uint16_t timerTicksByFrequency(const int8_t nTimer, const uint32_t freq, const int8_t allowableError = 0) { return constTimersNS::getTimerTicksIntF(nTimer, freq, constTimersNS::getPrescalerId(0x1FFFFFul, constTimersNS::absError(constTimersNS::getPeriod(freq), 0, nTimer), 0, 0, constTimersNS::getPeriod(freq), nTimer), allowableError); } static constexpr int16_t prescalerValue(const uint8_t nTimer, const uint8_t bits) { return constTimersNS::timerParameters[nTimer].prescalers[bits-1]; } #endif // CONSTTIMERS_HВот пример моргания 9-ым пином по заданной частоте:
///////////////////////////////////////////////// // // Получаем меандр с частотой 10Гц на 9-ом пине // для этого заводим таймер на СТС c инвертированием // на частоте 20Гц (как раз 20/2 = 10) // #include <ConstTimers.h> #define TIMER 1 #define FREQUENCY 20 void setup() { constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY); constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY); static_assert(timerTicks, "The required frequency is unattainable"); pinMode(9, OUTPUT); TCCR1A = bit(COM1A0); // Инвертирование пина 9 по сравнению TCCR1B = bit(WGM12) | prescalerBits; // Установить СТС режим и делитель частоты OCR1A = timerTicks; // установить TOP равным timerTicks } void loop() {}А вот тоже самое – по временному интервалу (периоду):
///////////////////////////////////////////////// // // Получаем меандр с частотой 10Гц на 9-ом пине // для этого заводим его на СТС c инвертированием // на частоте 20Гц (как раз 20/2 = 10) // Таким образом, период равен 50_ms // #include <ConstTimers.h> #define TIMER 1 #define PERIOD 50_ms void setup() { constexpr uint8_t prescalerBits = prescalerBitsByPeriod(TIMER, PERIOD); constexpr uint16_t timerTicks = timerTicksByPeriod(TIMER, PERIOD); static_assert(timerTicks, "The required frequency is unattainable"); pinMode(9, OUTPUT); TCCR1A = bit(COM1A0); // Инвертирование пина 9 по сравнению TCCR1B = bit(WGM12) | prescalerBits; // Установить СТС режим и делитель частоты OCR1A = timerTicks; // установить TOP равным timerTicks } void loop() {}Подробности использования и метод генерации ошибки компиляции см. в комментарии к библиотеке.
Критическую частоту в этом скетче рассчитывает правильно )))
для полноты щастя видимо нужна поддержка WAVGAT и ATMEGA328PB
#include "ConstTimers.h" #define TIMER 2 #define FREQUENCY 300000 #define pinINT1 3 #define PIN_LED 13 volatile unsigned long old_millis = 0; volatile unsigned long sch = 0; void start_Sch(){ digitalWrite(PIN_LED,HIGH); attachInterrupt(1, Sch, RISING ); // analogWrite(pinINT1,0x80); old_millis = millis(); } void end_Sch(){ detachInterrupt(1); digitalWrite(PIN_LED,LOW); } void Sch(void){ sch++; } void setup() { constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY); constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY); Serial.begin(115200); pinMode(PIN_LED,OUTPUT); pinMode(11, OUTPUT); TCCR2A = 0x42; // Инвертирование пина 11 по сравнению и режим CTC то OCR2A TCCR2B = 0x00 | prescalerBits; // Установить СТС режим и делитель частоты OCR2A = timerTicks; // установить TOP равным topValue Serial.print("TCCR2B = 0x00 | timerBits2 = "); Serial.println(prescalerBits); Serial.print("OCR2A = timerTicks2 : = "); Serial.println(timerTicks); Serial.println(); start_Sch(); } void loop() { if(millis() - old_millis >=1000){ end_Sch(); Serial.print("Счетчик = "); Serial.println(sch); Serial.println(); delay(1000); sch=0; start_Sch(); } }// ENDдля полноты щастя видимо нужна поддержка WAVGAT и ATMEGA328PB
Чьего счастья? Моего - не надо. Твоего надо - ждём расширений :)
для полноты щастя видимо нужна поддержка WAVGAT и ATMEGA328PB
Чьего счастья? Моего - не надо. Твоего надо - ждём расширений :)
сей код я могу в полной мере созерцать и, в некоторой степени использовать, я жеж не настоящий сталевар )))
ЗЫ и там и там есть третий таймер в первом он 16 битный, во втором все таймеры 16 битные, если я ничего не путаю, железяка пока в пути
В чём "первом", в чём "втором" - ничего не понял.
Ты ж вроде вавгат уже добавил? Чего не поделишься?
В чём "первом", в чём "втором" - ничего не понял.
Ты ж вроде вавгат уже добавил? Чего не поделишься?
первый WAVGAT второй ATMEGA328PB
для WAVGAT код скетча был такой:
// Если define ниже закомментировать, то работает библиотека // Если же оставить, то простое присваивание числовых констант //#define CONSTANTS #include "lgtx8p.h" #ifndef CONSTANTS #include "ConstTimers.h" // Параметры для работы таймера/счётчика №3 на частоте 73Гц // constexpr uint8_t timerBits3 = getPrescalerBits(1, 73); constexpr uint16_t timerTicks3 = getTimerTicks(1, 73); // // Параметры для работы таймера/счётчика №2 на частоте 1кГц // constexpr uint8_t timerBits2 = getPrescalerBits(2, 1000); constexpr uint8_t timerTicks2 = getTimerTicks(2, 1000); // // Параметры для работы таймера/счётчика №1 на частоте 500Гц // constexpr uint8_t timerBits1 = getPrescalerBits(1, 500); constexpr uint16_t timerTicks1 = getTimerTicks(1, 500); #endif void setup(void) { Serial.begin(115200); #ifdef CONSTANTS TCCR3B = 4; OCR3A = 250; TCCR2B = 1; OCR2A = 32000; TCCR1B = 1; OCR1A = 32000; #else TCCR3B = timerBits3; if(timerTicks3 > 256){ uint8_t r3ah = timerTicks3 / 256; OCR3AH = r3ah; uint8_t r3al = timerTicks3 % 256; OCR3AL = r3al; }else{ OCR3AH = 0x00; uint8_t ss = timerTicks3; OCR3AL = ss; } TCCR2B = timerBits2; OCR2A = timerTicks2; TCCR1B = timerBits1; OCR1A = timerTicks1; #endif } void loop(void) { Serial.print("TCCR3B = "); Serial.println(timerBits3); Serial.print("OCR3A = "); Serial.println(timerTicks3); Serial.print("TCCR2B = "); Serial.println(timerBits2); Serial.print("OCR2A = "); Serial.println(timerTicks2); Serial.print("TCCR1B = "); Serial.println(timerBits1); Serial.print("OCR1A = "); Serial.println(timerTicks1); Serial.print("Считанное из OCR3A = "); Serial.println(OCR3A); Serial.println(); delay(5000); }Так не скетч нужен, а расширение библиотеки для вавгата и pb. давайте. поучаствуйте в общем деле :)
Так не скетч нужен, а расширение библиотеки для вавгата и pb. давайте. поучаствуйте в общем деле :)
думаете одолею?
Что, составить массив таймеров и константу прописать? Там же больше ничего не надо. Чего там одолевать? Попробуйте.
Ворота, я вроде прогнал тесты, всё нормально. Положу на гитхаб.
Ok
на втором таймере на нано 300кгц можете проверить, то вроде работало все теперь заливаю и зависает
Вы всегда можете проверить сами. Для этого запускаете тривиальный скетч (последняя ("воротная") версия библиотеки)
#include <Printing.h> #include <ConstTimers.h> #define TIMER 2 #define FREQUENCY 300000ul static constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY); static constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY, 1); static_assert(timerTicks, "The required frequency with a desired accuracy is unattainable for timer/counter"); void setup() { Serial.begin(57600); Serial << "Prescaler=" << prescalerValue(TIMER, prescalerBits) << "; Ticks=" << timerTicks << "\r\n"; } void loop() {}Обратите внимание на 1 в строке №8. Если там поставить 0 или убрать её вовсе (что тоже самое), то будет ошибка компиляции, т.к. точно 300кГц сделать невозмжно. Единица означает, что 1% ошибки допустим - тогда всё компилируется.
Результат
Prescaler=1; Ticks=53
Проверяем. Точный период для 300кГц равен 3,33333 микросекунды. У нас же период получается (в микросекундах) 53 / 16 = 3,3125.
Погрешность менее 1% - значит всё правильно.
Т.е. Вы всегда можете сами проверить, если сомневаетесь.
А что уж там дальше у Вас происходит - это Ваши дела. Эта библиотека только считает эти два числа.
существенное дополнение по применению, в образце этого нет )))
существенное дополнение по применению, в образце этого нет )))
Ну, как, нет, смотрите текст библиотеки в посте #102. Строки №№32-33 и пример с описанием, начиная со строки №65. Там написано и про возвращение нуля, и показано как static_assert вставить.
Нет в маленьких примерах, да (недоработка), но в "документации" всё написано.
Так меня потихонечку, шаг за шагом и приучат начинать написание скетчей с ТЩАТЕЛЬНОГО изучения библиотек, а то скачу по кочкам )))
ЗЫ меня при конспектировании материалов учили делать выжимки так, что основные моменты должны быть зафиксированы...(типа оправдываюсь)
Сорри, добавил проверку на 0 в маленькие примеры (специально для нечитающих описание :--))).
Сорри, добавил проверку на 0 в маленькие примеры (специально для нечитающих описание :--))).
да не, я читал, но меня приучили, что время жизни десантника - 2 часа, стока патронов в РД, БМД тоже снимается ограничитель и 120 по пересечённой,... а это на всю жизнь )))
Сказал жеж, скачу по кочкам
вот это для WAVGAT и Atmega328PB где найти? -
defined(__AVR_ATtiny25__)Atmega328PB имеет пять таймеров, TC0 и TC2 восьмибитные, TC1,3,4 - 16 битные...
Для TC2 прескалер 1, 8, 32, 64, 128, 256 и 1024
Для TC0, 1, 3, 4 - 1, 8, 64, 256, 1024
ua6em, __AVR_ATmega328PB__ __LGT8FX8P__
http://www.lgtic.com/upload/lgt8fx8p/LGT8FX8P_databook_v1.0.4.pdf
ua6em, __AVR_ATmega328PB__ __LGT8FX8P__
час продолбался добавляя эти процессора, по WAVGAT - ан нет, на третьем таймере не компилировался:
проверочный скетчик:
// Скетч проверки таймеров для платы на чипе WAVGAT #include "ConstTimers.h" #include "lgtx8p.h" #define TIMER 3 #define FREQUENCY 1600 uint8_t t, p; const byte delta = 1; //отклонение частоты от расчетной в % unsigned int counter = 0; uint8_t r3ah; uint8_t r3al; void setup() { constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY); constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY, delta); static_assert(timerTicks, "The required frequency is unattainable"); pinMode(13, OUTPUT); t=TIMER; if(t==0){ p=6; pinMode(p, OUTPUT); TCCR0A = 0x42; // Инвертирование пина 6 по сравнению и режим CTC то OCR0A TCCR0B = 0x00 | prescalerBits; // Установить СТС режим и делитель частоты OCR0A = timerTicks; // установить TOP равным topValue } if(t==1){ p=9; pinMode(p, OUTPUT); TCCR1A = bit(COM1A0); // Инвертирование пина 9 по сравнению TCCR1B = bit(WGM12) | prescalerBits; // Установить СТС режим и делитель частоты OCR1A = timerTicks; // установить TOP равным timerTicks } if(t==2){ p=11; pinMode(p, OUTPUT); TCCR2A = 0x42; // Инвертирование пина 11 по сравнению и режим CTC то OCR2A TCCR2B = 0x00 | prescalerBits; // Установить СТС режим и делитель частоты OCR2A = timerTicks; // установить TOP равным topValue } if(t==3){ p=2; if(timerTicks >256){ r3ah = timerTicks / 256; r3al = timerTicks % 256; }else{ r3ah = 0; r3al = timerTicks; } DDRF = 1<<2 | 1<<1; // Разрешаем вывод в порты D1 и D2 OCR3AH=r3ah; // Важно, вначале необходимо загрузить верхний регистр!!! OCR3AL=r3al; // затем нижний // Нельзя как для Atmega328 - OCR3A = topValue; // TCCR3A=1<<COM3A0; // ПИН TXI TCCR3A=1<<COM3B0; // ПИН D2 // TCCR3A=1<<COM3A0 | 1<<COM3B0; // ПИН D2 + TXI TCCR3B=1<<WGM32 | prescalerBits; // Режим СТС WGM3[3:0]=4 или 12 } } void loop() { while(digitalRead(p)==LOW); counter++; while(digitalRead(p)==HIGH); if(counter==FREQUENCY/4){ // Blink 250мсек digitalWrite(13,!digitalRead(13)); counter = 0;} } /* * Enter desired frequency in Hz * (use decimal point for fractions. I.e. 0.12 means 0,12Hz): * Results for frequency: 1600.00Hz * (1,3) Prescaler: 1; MaxValue: 4999; Frequency: 1600.00Hz; Diff: 0.00Hz * (1,3) Prescaler: 8; MaxValue: 624; Frequency: 1600.00Hz; Diff: 0.00Hz * (2) Prescaler: 128; MaxValue: 38; Frequency: 1602.56Hz; Diff: 2.56Hz * (0,1,2,3) Prescaler: 64; MaxValue: 77; Frequency: 1602.56Hz; Diff: 2.56Hz * (2) Prescaler: 32; MaxValue: 155; Frequency: 1602.56Hz; Diff: 2.56Hz * (0,1,2,3) Prescaler: 256; MaxValue: 19; Frequency: 1562.50Hz; Diff: 37.50Hz * (0,1,2,3) Prescaler: 1024; MaxValue: 4; Frequency: 1562.50Hz; Diff: 37.50Hz * Enter desired frequency in Hz * (use decimal point for fractions. I.e. 0.12 means 0,12Hz): */моя вставка для WAVGAT:
#define Wavgatlgtx8PDetected (defined(__LGT8FX8P32__)) #if Wavgatlgtx8PDetected static constexpr int16_t prescalers013[] = { 1, 8, 64, 256, 1024 }; static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 }; static constexpr STimerParameters timerParameters[] = { { bits8, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) }, { bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) }, { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) }, { bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) }А заработало, добавив сюда еще один таймер и, как тут не быть... )))
#elif ATmega328Detected || ATmega32ADetected static constexpr int16_t prescalers01[] = { 1, 8, 64, 256, 1024 }; static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 }; static constexpr STimerParameters timerParameters[] = { { bits8, prescalers01, sizeof(prescalers01) / sizeof(prescalers01[0]) }, { bits16, prescalers01, sizeof(prescalers01) / sizeof(prescalers01[0]) }, { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) }, { bits16, prescalers01, sizeof(prescalers01) / sizeof(prescalers01[0]) } };Добавил и это - __LGT8FX8P__ (не взлетело)
Оказалось!!! Этот нехороший аддон WAVGAT NANO V3 притворяется полноценной 328 )))
Переключился на аддон LGT8F328P м все четыре таймера заработали, правильность настройки делителей пока не проверил
Значит Вы неправильно вставили WAVGAT. Покажите, как вставляли.
Значит Вы неправильно вставили WAVGAT. Покажите, как вставляли.
выше, моя вставка для WAVGAT
визуально 3-й таймер тикает раза в два-четыре быстрее, есть подозрение, что тактируется не от того генератора, Дмитрий, подскажи, что в коде поправить для третьего таймера
выше, моя вставка для WAVGAT
Я говорю, если не компилировался, значит Вы неправильно вставили. Покажите полнотсью библиотеку (только этот огромный комментарий выбростье, а то его листа задолбаешься)
ATmega328PB тоже заработала (компилируется), осталось 3-й и 4-й 16 битные таймеры добавить, в WAVGAT 3-й не совпадает
Правил вашу библиотеку как-то так
#ifndef CONSTTIMERS_H #define CONSTTIMERS_H /////////////////////////////////////////////////////////////////////////////// // // Модификация недобиблиотеки от ЕвгенийП. // Выполнена: Ворота, 11.07.2019. // Проба: UA6EM 12.07.2019 (Atmega328PB, WAVGAT, LGT8FX8P) // // Основные изменения: // 1. К работе с частотами добавлена работа с периодами/интервалами; // 2. Добавлено задание максимальной допустимой погрешности количества тактов; // 3. Появилась возможность выдавать ошибку компиляции в случае выхода за допустимую погрешность; // 4. Добавлены суффиксы для работы с временными интервалами (на основе другого кода от ЕвгенийП); // 5. Добавлена поддержка Мега, Леонардо и ATmega32A // 6. Все «внутренние» функции спрятаны в своё пространство имён. // // --------------- // // Определяются биты конфигурации делителя частоты таймера и количество тактов с данным делителем для // получения нужного интервала срабатывания таймера. Интервал задаётся либо частотой, либо периодом // (длительностью, если речь идёт об одиночном сигнале, например, по переполнению). // Соответственно, имеются четыре функции: // // uint8_t prescalerBitsByPeriod(int8_t nTimer, uint32_t period); // uint16_t timerTicksByPeriod(int8_t nTimer, uint32_t period, int8_t error = 0); // // uint8_t prescalerBitsByFrequency(int8_t nTimer, uint32_t frequency); // uint16_t timerTicksByFrequency(int8_t nTimer, uint32_t frequency, int8_t error = 0); // // Первый параметр у всех функций – номер таймера. Параметры period и frequency – соответственно // требуемые период в тактах микроконтроллера (см. ниже о суффиксах) и частота (в герцах). // Параметр error задаёт допустимое отклонение от запрошенных характеристик в процентах. // Если не удаётся получить решение в пределах допустимого отклонения, то timerTicksByХХХ вернут 0. // // Также имеется функция, возвращающая значение делителя частоты заданного таймера по битам конфигурации, // полученным от функций prescalerBitsByХХХ. // // int16_t prescalerValue(uint8_t nTimer, uint8_t bits); // // Для удобства работы с временными интервалами добавлены суффиксы _clk, _us, _ms и _sec. Таким образом, // второй параметр функций prescalerBitsByPeriod и timerTicksByPeriod (время в тактах микроконтроллера) // можно задавать при помощи суффиксов, например: // // 100 или 100_clk – сто тактов микроконтроллера; // 100_us – сто микросекунд; // 100_ms – сто миллисекунд; // 2_sec – две секунды. // // Допускаются также арифметические операции, например, запись // // 2_ms + 50_us // // вполне допустима и означает 2050 микросекунд. // // ИСПОЛЬЗОВАНИЕ // // Для использования необходимо включить файл «ConstTimers.h» и определить константы с // модификатором constexpr для нужных конфигурационных битов и количества тиков, которым // присвоить значения, возвращаемые функциям prescalerBitsByХХХ и timerTicksByХХХ соответственно. // // Если использовать именно так, то код библиотеки целиком исполняется во время компиляции // и не оказывает никакого влияния ни на размер занимаемой памяти, ни на код программы. // В коде программы будут вставлены готовые (вычисленные на этапе компиляции) константы. // // Это позволяет организовать проверку полученного на этапе компиляции значения (функции // timerTicksByХХХ возвращают 0 в случае невозможности соблюсти необходимую точность) // и прервать компиляцию с соответствующим сообщением об ошибке при помощи static_assert. // // Пример рекомендуемого использования: // // ///////////////////////////////////////////////// // // // // Получаем меандр с частотой 50Гц на 9-ом пине // // для этого заводим его на СТС и инвертированием // // на частоте 100Гц (как раз 100/2 = 50) // // // #include <ConstTimers.h> // // #define TIMER 1 // #define FREQUENCY 100 // // static constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY); // static constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY); // // // проверка установилась ли частота (например, при частоте 101 будет ошибка компиляции) // static_assert(timerTicks, "The required frequency with a desired accuracy is unattainable for timer/counter"); // // void setup() { // pinMode(9, OUTPUT); // TCCR1A = bit(COM1A0); // Инвертирование пина 9 по сравнению // TCCR1B = bit(WGM12) | prescalerBits; // Установить СТС режим и делитель частоты // OCR1A = timerTicks; // установить TOP равным timerTicks // } // // void loop() {} // //Результат работы будет точно такой же, как если написать константы, вместо вычислений: // // void setup() { // pinMode(9, OUTPUT); // TCCR1A = bit(COM1A0); // TCCR1B = bit(WGM12) | 2; // OCR1A = 20000; // } // void loop() {} // // Ни на один байт код не изменится. // // КОНФИГУРАЦИЯ: // // 1. расчёт производится для текущей тактовой частоты микроконтроллера. Если нужно // считать для какой-то другой частоты, измените константу FCPU. // // 2. STimerParameters - массив конфигурации таймеров. Количество элементов массива // соответствует количеству таймеров. Нулевой элемент описывает нулевой таймер, // первый элемент – первый таймер и т.д. Если требуется расширить недобиблиотеку для других // микроконтроллеров, нужно изменить именно этот массив и больше изменять ничего не надо. // // В массиве для каждого таймера указано: // 1) разрядность таймера в виде максимально возможного значения количества тиков // (для 8-разрядных таймеров – 0xFF, для 16-разрядных – 0xFFFF. // 2) указатель на массив делителей частоты. Делители начинаются с 1 (делитель 0 писать не нужно) // 3) количество делителей частоты у данного таймера. // // ЛИЦЕНЗИЯ // // Данный код поставляется по лицензии ПНХ. // // 1. Вы можете свободно использовать или не использовать его в коммерческих, // некоммерческих, и любых иных, не запрещённых законом, целях. // // 2. Автор не несёт решительно никакой ответственности за любые положительные // или отрицательные результаты использования или неиспользования данного кода. // // 3. Если Вам таки хочется сделать автору предъяву, то Вы знаете, куда // Вам следует обратиться. А если не знаете, то см. название лицензии. // // 4. Если данный код вдруг Вам пригодился (как учебник или ещё как что) и Вам // почему-либо (ну, приболели, может) захотелось отблагодарить автора рублём, // то это всегда пожалуйста – WebMoney, кошелёк № R626206676373 // // 5. Возникновение или невозникновение у Вас желаний, обозначенных в п.4 // настоящей лицензии никак не связано с п.1, который действует безусловно // и независимо от п.4. // // 6. Если данный код нужен Вам с какой-либо другой лицензией, например, с // сопровождением или Вы нуждаетесь во внесении изменений, свяжитесь с автором // на предмет заключения договора гражданско-правового характера. // /////////////////////////////////////////////////////////////////////////////// #define ATtiny85Detected (defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)) #define ATmega328Detected (defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || defined(__AVR_ATmega88A__) \ || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) \ || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)) #define ATmega2561Detected (defined(__AVR_ATmega640__) || defined(__AVR_ATmega640V__) || defined(__AVR_ATmega1280__) \ || defined(__AVR_ATmega1280V__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1281V__) \ || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2560V__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega2561V__)) #define ATmega32U4Detected (defined(__AVR_ATmega32U4__)) #define ATmega32ADetected (defined(__AVR_ATmega32A__)) #define ATmega328PBDetected (defined(__AVR_ATmega328PB__)) #define Wavgatlgtx8PDetected (defined(__LGT8FX8P32__)) || (defined(__LGT8FX8P__)) #define FCPU F_CPU namespace constTimersNS { struct STimerParameters { const uint32_t maxValue; const int16_t * prescalers; const uint8_t totalPrescalers; }; static constexpr uint32_t bits8 = 0x000000FFul; static constexpr uint32_t bits10 = 0x000003FFul; static constexpr uint32_t bits16 = 0x0000FFFFul; #if Wavgatlgtx8PDetected static constexpr int16_t prescalers013[] = { 1, 8, 64, 256, 1024 }; static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 }; static constexpr STimerParameters timerParameters[] = { { bits8, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) }, { bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) }, { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) }, { bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) } }; #elif ATmega328PBDetected static constexpr int16_t prescalers0134[] = { 1, 8, 64, 256, 1024 }; static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 }; static constexpr STimerParameters timerParameters[] = { { bits8, prescalers0134, sizeof(prescalers0134) / sizeof(prescalers0134[0]) }, { bits16, prescalers0134, sizeof(prescalers0134) / sizeof(prescalers0134[0]) }, { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) }, { bits16, prescalers0134, sizeof(prescalers0134) / sizeof(prescalers0134[0]) }, { bits16, prescalers0134, sizeof(prescalers0134) / sizeof(prescalers0134[0]) } }; #elif ATmega328Detected || ATmega32ADetected static constexpr int16_t prescalers01[] = { 1, 8, 64, 256, 1024 }; static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 }; static constexpr int16_t prescalers3[] = { 1, 8, 64, 256, 1024 }; static constexpr STimerParameters timerParameters[] = { { bits8, prescalers01, sizeof(prescalers01) / sizeof(prescalers01[0]) }, { bits16, prescalers01, sizeof(prescalers01) / sizeof(prescalers01[0]) }, { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) }, { bits16, prescalers3, sizeof(prescalers3) / sizeof(prescalers3[0]) } // для WAVGAT }; #elif ATmega32U4Detected static constexpr int16_t prescalers013[] = { 1, 8, 64, 256, 1024 }; static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 }; static constexpr int16_t prescalers4[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 }; static constexpr STimerParameters timerParameters[] = { { bits8, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) }, { bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) }, { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) }, { bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) }, { bits10, prescalers4, sizeof(prescalers4) / sizeof(prescalers4[0]) } }; #elif ATmega2561Detected static constexpr int16_t prescalers01345[] = { 1, 8, 64, 256, 1024 }; static constexpr int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 }; static constexpr STimerParameters timerParameters[] = { { bits8, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) }, { bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) }, { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) }, { bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) }, { bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) }, { bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) } }; #elif ATtiny85Detected static constexpr int16_t prescalers0[] = { 1, 8, 64, 256, 1024 }; static constexpr int16_t prescalers1[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 }; static constexpr STimerParameters timerParameters[] = { { bits8, prescalers0, sizeof(prescalers0) / sizeof(prescalers0[0]) }, { bits8, prescalers1, sizeof(prescalers1) / sizeof(prescalers1[0]) } }; #else #error The library does not seem to support your MCU #endif constexpr int8_t totalTimers = sizeof(timerParameters) / sizeof(timerParameters[0]); static constexpr uint32_t getPeriod(const uint32_t frequency) { return (FCPU + frequency / 2) / frequency; } static constexpr uint16_t prValue(const int8_t prescalerId, const int8_t nTimer) { return timerParameters[nTimer].prescalers[prescalerId]; } static constexpr uint32_t getDesiredTicks(const uint32_t period, const int8_t prescalerId, const int8_t nTimer) { return (period + prValue(prescalerId, nTimer) / 2) / prValue(prescalerId, nTimer); } static constexpr uint32_t correctTicks(uint32_t dTicks, const uint32_t maxValue) { //if (dTicks > maxValue) return maxValue; else return dTicks; // начиная с C++14 return dTicks > maxValue ? maxValue : dTicks; } static constexpr uint32_t getTicks(const uint32_t period, const int8_t prescalerId, const int8_t nTimer) { return prescalerId >= timerParameters[nTimer].totalPrescalers ? 0x1FFFFFFF : correctTicks(getDesiredTicks(period, prescalerId, nTimer), timerParameters[nTimer].maxValue); } static constexpr uint32_t getBits(const int8_t prescalerId, const int8_t nTimer) { return prescalerId >= timerParameters[nTimer].totalPrescalers ? timerParameters[nTimer].totalPrescalers : prescalerId + 1; } static constexpr int32_t absErrorTicks(const uint32_t period, const uint32_t ticks) { return period > ticks ? period - ticks : ticks - period; } static constexpr int32_t absError(const uint32_t period, const int8_t prescalerId, const int8_t nTimer) { return prescalerId >= timerParameters[nTimer].totalPrescalers ? 0x1FFFFFFF : absErrorTicks(period, getTicks(period, prescalerId, nTimer) * prValue(prescalerId, nTimer)); } static constexpr uint8_t getPrescalerId(const uint32_t error, const uint32_t newError, const uint8_t prId, const uint8_t candidate, const uint32_t period, const int8_t nTimer) { return (prId >= timerParameters[nTimer].totalPrescalers) ? candidate : getPrescalerId(newError, absError(period, prId + 1, nTimer), prId + 1, (error <= newError) ? candidate : prId, period, nTimer); } static constexpr double calcErrorPercentage(const double fcpu, const double perc) { return (fcpu < perc ? 1.0 - fcpu / perc : fcpu / perc - 1.0) * 100.0; } static constexpr uint16_t returnTicksOrZero(const uint32_t left, const uint32_t right, const int8_t allowableError, const uint32_t ticks) { return left == right || calcErrorPercentage(left, right) <= allowableError ? ticks : 0; } static constexpr uint16_t getTimerTicksIntFTicks(const uint32_t ticks, const int8_t nTimer, const uint32_t freq, uint8_t prescalerId, const int8_t allowableError) { return returnTicksOrZero(FCPU, freq * ticks * timerParameters[nTimer].prescalers[prescalerId], allowableError, ticks); } static constexpr uint16_t getTimerTicksIntF(const int8_t nTimer, const uint32_t freq, uint8_t prescalerId, const int8_t allowableError) { return getTimerTicksIntFTicks(getTicks(getPeriod(freq), prescalerId, nTimer), nTimer, freq, prescalerId, allowableError); } static constexpr uint16_t getTimerTicksIntTTicks(const uint32_t ticks, const int8_t nTimer, const uint32_t period, uint8_t prescalerId, const int8_t allowableError) { return returnTicksOrZero(period, ticks * timerParameters[nTimer].prescalers[prescalerId], allowableError, ticks); } static constexpr uint16_t getTimerTicksIntT(const int8_t nTimer, const uint32_t period, uint8_t prescalerId, const int8_t allowableError) { return getTimerTicksIntTTicks(getTicks(period, prescalerId, nTimer), nTimer, period, prescalerId, allowableError); } ////////////////////////////////////////////////////////////////// // // Суффиксы литералов для задания времени // 100 или 100_clk - время в тактах контроллера (100 тактов) // 100_us - время в микросекундах (100 микросекунд) // 100_ms - время в милисекундах (100 милисекунд) // 5_sec - время в секундах (5 секунд) // static constexpr int8_t __sLen(const char * str, const int8_t candidate = 0) { return (!*str) ? candidate : __sLen(str + 1, candidate + 1); } static constexpr bool __isFin(const char * str, const int8_t lInd) { return lInd < 0 || !isdigit(str[lInd]); } static constexpr uint32_t __toDig(const char * str, const uint32_t lg, const int8_t lInd) { return (str[lInd] - '0') * lg; } static constexpr uint32_t ___s2ul(const char * str, const uint32_t, const int8_t); static constexpr uint32_t __nextL(const char * str, const uint32_t lg, const int8_t lInd) { return __toDig(str, lg, lInd) + ___s2ul(str, lg * 10, lInd - 1); } static constexpr uint32_t ___s2ul(const char * str, const uint32_t lg, const int8_t lInd) { return __isFin(str, lInd) ? 0 : __nextL(str, lg, lInd); } static constexpr uint32_t __s2ul(const char * str) { return ___s2ul(str, 1, __sLen(str) - 1); } } // namespace constTimersNS static constexpr uint32_t operator "" _clk(const char * s) { return constTimersNS::__s2ul(s); } static constexpr uint32_t operator "" _us(const char * s) { return operator "" _clk(s) * (FCPU / 1000000ul); } static constexpr uint32_t operator "" _ms(const char * s) { return operator "" _us(s) * 1000ul; } static constexpr uint32_t operator "" _sec(const char * s) { return operator "" _ms(s) * 1000ul; } // ////////////////////////////////////////////////////////////////// static constexpr uint8_t prescalerBitsByPeriod(const int8_t nTimer, const uint32_t period) { return constTimersNS::getBits(constTimersNS::getPrescalerId(0x1FFFFFul, constTimersNS::absError(period, 0, nTimer), 0, 0, period, nTimer), nTimer); } static constexpr uint16_t timerTicksByPeriod(const int8_t nTimer, const uint32_t period, const int8_t allowableError = 0) { return constTimersNS::getTimerTicksIntT(nTimer, period, constTimersNS::getPrescalerId(0x1FFFFFul, constTimersNS::absError(period, 0, nTimer), 0, 0, period, nTimer), allowableError); } static constexpr uint8_t prescalerBitsByFrequency(const int8_t nTimer, const uint32_t freq) { return prescalerBitsByPeriod(nTimer, constTimersNS::getPeriod(freq)); } static constexpr uint16_t timerTicksByFrequency(const int8_t nTimer, const uint32_t freq, const int8_t allowableError = 0) { return constTimersNS::getTimerTicksIntF(nTimer, freq, constTimersNS::getPrescalerId(0x1FFFFFul, constTimersNS::absError(constTimersNS::getPeriod(freq), 0, nTimer), 0, 0, constTimersNS::getPeriod(freq), nTimer), allowableError); } static constexpr int16_t prescalerValue(const uint8_t nTimer, const uint8_t bits) { return constTimersNS::timerParameters[nTimer].prescalers[bits-1]; } #endif // CONSTTIMERS_HВроде нормально, завтра посмотрю, что не компилируется. Только обозначьте чётко какой именно скетч не компилируется, а то в Вашем прошлом посте больно много букв и несколько скетчей.
А, так уже заработало. В общем, если проблема останется, внятно изложите, однозначно и без лишнего.
WAVGAT работает, осталось только с таймерами ATmega328PB разобраться, чтобы пример для всех таймеров выложить
Для ATmega328PB как-то так, правильность не гарантируется ))) (знающие поправят надеюсь)
// Скетч проверки таймеров для платы на чипе ATmega328PB #include "ConstTimers.h" #define TIMER 0 #define FREQUENCY 1600 uint8_t t, p; const byte delta = 1; //отклонение частоты от расчетной в % unsigned int counter = 0; void setup() { constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY); constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY, delta); static_assert(timerTicks, "The required frequency is unattainable"); pinMode(13, OUTPUT); t=TIMER; if(t==0){ p=6; pinMode(p, OUTPUT); TCCR0A = 0x42; // Инвертирование пина 6 по сравнению и режим CTC то OCR0A TCCR0B = 0x00 | prescalerBits; // Установить СТС режим и делитель частоты OCR0A = timerTicks; // установить TOP равным timerTicks } if(t==1){ p=9; pinMode(p, OUTPUT); TCCR1A = bit(COM1A0); // Инвертирование пина 9 по сравнению TCCR1B = bit(WGM12) | prescalerBits; // Установить СТС режим и делитель частоты OCR1A = timerTicks; // установить TOP равным timerTicks } if(t==2){ p=11; pinMode(p, OUTPUT); TCCR2A = 0x42; // Инвертирование пина 11 по сравнению и режим CTC то OCR2A TCCR2B = 0x00 | prescalerBits; // Установить СТС режим и делитель частоты OCR2A = timerTicks; // установить TOP равным timerTicks } if(t==3){ p = 0; pinMode(p, OUTPUT); TCCR3A=1<<COM3A0 | 1<<COM3B0; TCCR3B=1<<WGM32 | prescalerBits; // Режим СТС WGM3[3:0]=4 или 12 OCR3A = timerTicks; // установить TOP равным timerTicks } if(t==4){ p = 1; pinMode(p, OUTPUT); TCCR4A=1<<COM4A0 | 1<<COM4B0; TCCR4B=1<<WGM42 | prescalerBits; // Режим СТС WGM4[3:0]=4 или 12 OCR4A = timerTicks; // установить TOP равным timerTicks } } void loop() { while(digitalRead(p)==LOW); counter++; while(digitalRead(p)==HIGH); if(counter==FREQUENCY/4){ // Блинк 250 мсек ;-))) digitalWrite(13,!digitalRead(13)); counter = 0;} } /* * Enter desired frequency in Hz * (use decimal point for fractions. I.e. 0.12 means 0,12Hz): * Results for frequency: 1600.00Hz * (1,3) Prescaler: 1; MaxValue: 4999; Frequency: 1600.00Hz; Diff: 0.00Hz * (1,3) Prescaler: 8; MaxValue: 624; Frequency: 1600.00Hz; Diff: 0.00Hz * (2) Prescaler: 128; MaxValue: 38; Frequency: 1602.56Hz; Diff: 2.56Hz * (0,1,2,3) Prescaler: 64; MaxValue: 77; Frequency: 1602.56Hz; Diff: 2.56Hz * (2) Prescaler: 32; MaxValue: 155; Frequency: 1602.56Hz; Diff: 2.56Hz * (0,1,2,3) Prescaler: 256; MaxValue: 19; Frequency: 1562.50Hz; Diff: 37.50Hz * (0,1,2,3) Prescaler: 1024; MaxValue: 4; Frequency: 1562.50Hz; Diff: 37.50Hz * Enter desired frequency in Hz * (use decimal point for fractions. I.e. 0.12 means 0,12Hz): */И еще один вопрос по применению таймеров.
Устанавливать разрешение порта на выход можно разными командами одна из которых приведена в ниже приведённой конструкции, проблема в следующем и обозначена в скетче, вопрос, что там компилятор делает не так:
Ну, Вы разницу между строками 1 и 2 понимаете? Видимо, в вавгате в порте DDRB есть что-то, что нельзя нагло устанавливать в 0. Я не знаю вавгата, но разница только в этом.
Вопрос снят, буду разбираться в особенностях вывода сигналов на оба пина таймера одновременно