C++ в микроконтроллерах, на примере типичной задачи

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Ворота пишет:
задание времени не частотой, а периодом
Очень полезное дополнение. Ждёмс :)

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Как и обещал, поковырялся вчера. Действительно, тяжко с одними 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() {}

Подробности использования и метод генерации ошибки компиляции см. в комментарии к библиотеке.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Критическую частоту в этом скетче рассчитывает правильно )))

для полноты щастя видимо нужна поддержка 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

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

ua6em пишет:

для полноты щастя видимо нужна поддержка WAVGAT и ATMEGA328PB

Чьего счастья? Моего - не надо. Твоего надо - ждём расширений :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Ворота пишет:

ua6em пишет:

для полноты щастя видимо нужна поддержка WAVGAT и ATMEGA328PB

Чьего счастья? Моего - не надо. Твоего надо - ждём расширений :)

сей код я могу в полной мере созерцать и, в некоторой степени использовать, я жеж не настоящий сталевар )))
ЗЫ и там и там есть третий таймер в первом он 16 битный, во втором все таймеры 16 битные, если я ничего не путаю, железяка пока в пути

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

В чём "первом", в чём "втором" - ничего не понял.

Ты ж вроде вавгат уже добавил? Чего не поделишься?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Ворота пишет:

В чём "первом", в чём "втором" - ничего не понял.

Ты ж вроде вавгат уже добавил? Чего не поделишься?

первый 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);          
    }

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Так не скетч нужен, а расширение библиотеки для вавгата и pb. давайте. поучаствуйте в общем деле :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Так не скетч нужен, а расширение библиотеки для вавгата и pb. давайте. поучаствуйте в общем деле :)

думаете одолею?

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Что, составить массив таймеров и константу прописать? Там же больше ничего не надо. Чего там одолевать? Попробуйте.

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Ворота, я вроде прогнал тесты, всё нормально. Положу на гитхаб.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Ok

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

на втором таймере на нано 300кгц можете проверить, то вроде работало все теперь заливаю и зависает

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Вы всегда можете проверить сами. Для этого запускаете тривиальный скетч (последняя ("воротная") версия библиотеки)

#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% - значит всё правильно.

Т.е. Вы всегда можете сами проверить, если сомневаетесь.

А что уж там дальше у Вас происходит - это Ваши дела. Эта библиотека только считает эти два числа.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

существенное дополнение по применению, в образце этого нет )))

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

ua6em пишет:

существенное дополнение по применению, в образце этого нет )))

Ну, как, нет, смотрите текст библиотеки в посте #102. Строки №№32-33 и пример с описанием, начиная со строки №65. Там написано и про возвращение нуля, и показано как static_assert вставить.

Нет в маленьких примерах, да (недоработка), но в "документации" всё написано.

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Так меня потихонечку, шаг за шагом и приучат начинать написание скетчей с ТЩАТЕЛЬНОГО изучения библиотек, а то скачу по кочкам )))
 

ЗЫ меня при конспектировании материалов учили делать выжимки так, что основные моменты должны быть зафиксированы...(типа оправдываюсь)

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Сорри, добавил проверку на 0 в маленькие примеры (специально для нечитающих описание :--))).

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Ворота пишет:

Сорри, добавил проверку на 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

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ua6em,   __AVR_ATmega328PB__   __LGT8FX8P__

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax пишет:

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 м все четыре таймера заработали, правильность настройки делителей пока не проверил

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Значит Вы неправильно вставили WAVGAT. Покажите, как вставляли.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Значит Вы неправильно вставили WAVGAT. Покажите, как вставляли.

выше, моя вставка для WAVGAT

визуально 3-й таймер тикает раза в два-четыре быстрее, есть подозрение, что тактируется не от того генератора, Дмитрий, подскажи, что в коде поправить для третьего таймера

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

ua6em пишет:

выше, моя вставка для WAVGAT

Я говорю, если не компилировался, значит Вы неправильно вставили. Покажите полнотсью библиотеку (только этот огромный комментарий выбростье, а то его листа задолбаешься)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

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

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Вроде нормально, завтра посмотрю, что не компилируется. Только обозначьте чётко какой именно скетч не компилируется, а то в Вашем прошлом посте больно много букв и несколько скетчей.

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

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

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):
*/
 

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

И еще один вопрос по применению таймеров.
Устанавливать разрешение порта на выход можно разными командами одна из которых приведена в ниже приведённой конструкции, проблема в следующем и обозначена в скетче, вопрос, что там компилятор делает не так:
 

 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 - тикаем с уст.частотой

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Ну, Вы разницу между строками 1 и 2 понимаете? Видимо, в вавгате в порте DDRB есть что-то, что нельзя нагло устанавливать в 0. Я не знаю вавгата, но разница только в этом.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Вопрос снят, буду разбираться в особенностях вывода сигналов на оба пина таймера одновременно