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

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

Вот и Блинк на 3-ем Таймере на плате WAVGAT на вашей библиотеке:
 

// Пример использования Таймера 3  (Блинк на таймере) для платы WAVGAT
// (с) UA6EM на основе заимствований на arduino.ru у DIMAX и ЕвгенийП
// используется библиотека ЕвгенийП  "ConstTimers.h"

#include "lgtx8p.h"

#ifndef CONSTANTS
  #include "ConstTimers.h"
  // Параметры для работы таймера/счётчика №3 на частоте 1Гц
  //
  constexpr uint8_t timerBits3 = getPrescalerBits(1, 1);
  constexpr uint16_t timerTicks3 = getTimerTicks(1, 1);
  //
#endif

void setup() {

   #ifdef CONSTANTS
    TCCR3B = 4;
    OCR3A = 62500; 
   #else
    TCCR3B =1<<WGM32 |timerBits3; // Режим СТС WGM3[3:0]=4 или 12
    
    if(timerTicks3 > 255){
    uint8_t r3ah = timerTicks3 / 256; 
    OCR3AH = r3ah;
    uint8_t r3al = timerTicks3 % 256;
    OCR3AL = r3al;
    }else{
    OCR3AH = 0x00;
    uint8_t ss = timerTicks3;
    OCR3AL = ss;
    }   
  #endif
 DDRF = 1<<2 | 1<<1;   // Разрешаем вывод в порты D1 и D2 
 TCCR3A=1<<COM3A0 | 1<<COM3B0;  // ПИН D2 + TXI
 pinMode(13,OUTPUT);
 }// end-Setup

void loop(){
  digitalWrite(13,!digitalRead(2));
 }

 

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

Ситуёвина следующая:
Загружаю калькулятор, считаю делители для частоты 100 кГц.
 

Enter desired frequency in Hz
(use decimal point for fractions. I.e. 0.12 means 0,12Hz):

Results for frequency: 100000.00Hz
(0,1,2,3) Prescaler: 8; MaxValue: 9; Frequency: 100000.00Hz; Diff: 0.00Hz
(0,1,2,3) Prescaler: 1; MaxValue: 79; Frequency: 100000.00Hz; Diff: 0.00Hz
(2) Prescaler: 32; MaxValue: 2; Frequency: 83333.34Hz; Diff: 16666.66Hz
(0,1,2,3) Prescaler: 64; MaxValue: 0; Frequency: 125000.00Hz; Diff: 25000.00Hz
(2) Prescaler: 128; MaxValue: 0; Frequency: 62500.00Hz; Diff: 37500.00Hz
Prescaler: 256 - Not possible
Prescaler: 1024 - Not possible

Enter desired frequency in Hz
(use decimal point for fractions. I.e. 0.12 means 0,12Hz):

 

Далее использую этот скетч:
 

#ifndef CONSTANTS
  #include "ConstTimers.h"
  // Параметры для работы таймера/счётчика №2 на частоте 100kГц
  //
  constexpr uint8_t timerBits2 = getPrescalerBits(2, 100000);
  constexpr uint8_t timerTicks2 = getTimerTicks(2, 100000);
  //
#endif

unsigned long counter = 0;

void setup() {
  Serial.begin(115200);
   pinMode(13, OUTPUT);
   pinMode(11, OUTPUT);
   TCCR2A = 0x42;                  // Инвертирование пина 11 по сравнению и режим CTC то OCR2A
   TCCR2B = 0x00 | timerBits2;     // Установить СТС режим и делитель частоты
   OCR2A = timerTicks2;            // установить TOP равным topValue
   Serial.print("TCCR2B = 0x00 | timerBits2 = ");
   Serial.println(timerBits2);
   Serial.print("OCR2A = timerTicks2 : = ");
   Serial.println(timerTicks2);
   Serial.println();
  }
   
void loop() {
 while(digitalRead(11)==LOW);
  counter++;
  if(counter==100000){
  digitalWrite(13,!digitalRead(13));
  counter = 0;}
}

И смотрю вывод в порт. Вижу когнитивный диссонанс.

TCCR2B = 0x00 | timerBits2 = 1
OCR2A = timerTicks2 : = 160

Как говорил DIMAX если что-то может не заработать, оно у вас обязательно не заработает.

PS скетч ваял из этой старой заготовки:
 

enum Prescalers {
   PRESCALER_STOP = 0,
   PRESCALER_1 = 1, 
   PRESCALER_8 = 2, 
   PRESCALER_32 = 3, 
   PRESCALER_64 = 4, 
   PRESCALER_128 = 5, 
   PRESCALER_256 = 6, 
   PRESCALER_1024 = 7  
};
unsigned long counter = 0;

void setup() {
   pinMode(13, OUTPUT);
   
   uint8_t prescaler = PRESCALER_1;
   uint8_t topValue = 79;
   pinMode(11, OUTPUT);
   TCCR2A = 0x42;              // Инвертирование пина 11 по сравнению и режим CTC то OCR2A
   TCCR2B = 0x00 | prescaler;  // Установить СТС режим и делитель частоты
   OCR2A = topValue;           // установить TOP равным topValue
  }
   
void loop() {
 while(digitalRead(11)==LOW);
  counter++;
  if(counter==100000){
  digitalWrite(13,!digitalRead(13));
  counter = 0;}
}

 

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

Не понял в чём именно Ваш когнитивный диссонанс. Вроде всё правильно. Ну, разве что в строке 6 должно быть по идее 80, а не 79, ну там всё во float считается, где-то неаккуратно огругляется, можно полезть посмотреть. А так, с точнотью до этого округлённого тика, всё правильно. В чём проблема-то?

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

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

 В чём проблема-то?

Так библиотека рассчитала и загрузила 160 как бы )

Мой асилограф-милипильметр показывает частоту 50 килогерц...

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

Вы путаете два понятия. Тот старый калькулятор и это библиотека считаю разные вещи. Они всегда отличаются в два раза.

Тот старый калькулятор был для "меандров", т.е. он считал через какое время надо "инвертировать" пин, чтобы получить нужную частоту меандра. Вот он и насчитал 80.

Эта же библиотека просто считает задержку для прерываний с нужной частотой. Вот у этой библиотеки получается 160 (=80х2). Т.е. она считает задержку не для меандра нужной частоты, а для прерываний с нужной частотой.

Вы же осциллографом измеряете опять же меандр. Получается, что Вы с частотой 100кГц инверитуете пин. Ну и какова частота меандра? Правильно - 50 кГц.

Понятно?

Правильность величины 160 легко проверить даже в уме. Давайте. При частоте 100кГц каким будет период? 10 микросекунд. Сколько тиков укладывается в 10мкс при тактовой 16МГц? 160. Всё правильно, как видите.

Просто эти две программы разные вещи считают.

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

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

Просто эти две программы разные вещи считают.

я то думал, что это одно и тоже, то-есть если нам надо сделать меандр частотой 100 кгц, значение должно быть 200000?!
Ок!

 

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

Ну, таки да. Для 200 она Вам выдаст не 160, а 80. Но само прерывание будет тикать именно с частотой 200кГц. ну, Вы уже поняли, так ведь?

sadman41
Offline
Зарегистрирован: 19.10.2016

А это.. может я, конечно, не совсем по теме спрошу... Ежели таймером нога перекидывается на хардварном уровне (flip-flop) и происходит остановка генерации (через зануление COM1A1 и COM1A0, например), то нога же остаётся в текущем состоянии? Есть какой-то волшебный регистр, который инструктирует МК перевести её в какой-то совершенно определённый LOW или HIGH?

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

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

Ну, таки да. Для 200 она Вам выдаст не 160, а 80. Но само прерывание будет тикать именно с частотой 200кГц. ну, Вы уже поняли, так ведь?

я не совсем безнадёжный )))

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

sadman41, dimax его знает!

sadman41
Offline
Зарегистрирован: 19.10.2016

Зарапортовался немного. COM1A1 + COM1A0 таймер не останавливают, конечно, а просто ногу отстёгивают от управления. 

Не знаю, насколько это корректно, но я пока придумал только изменить режим генерации через COM1A1; - это должно на следующем совпадении ногу в LOW перевести. 

Типа того, вобщем:

    TCCR1A = 1 << COM1A1;
    OCR1A = 1;
    TCNT1 = 0;

 

Green
Offline
Зарегистрирован: 01.10.2015

Если отключаешь режим toggle переходом в нормальный режим, то уровень на выходе определяется состояние бита порта. К примеру, OC1A = PB1.

Ну да, свиду норм. Ну и наверно TCCR1A |= 1<<COM1A1, всё ж таки.)

sadman41
Offline
Зарегистрирован: 19.10.2016

Green пишет:

Если отключаешь режим toggle переходом в нормальный режим, то уровень на выходе определяется состояние бита порта. К примеру, OC1A = PB1.

Ну, digitalWrite(.., LOW) любой напишет. Я хотел чисто таймером поманипулировать.

Green пишет:

Ну и наверно TCCR1A |= 1<<COM1A1, всё ж таки.

Так-то там ещё надо COM1A0 сбросить, иначе нога в HIGH пойдёт.

 

Green
Offline
Зарегистрирован: 01.10.2015

sadman41 пишет:

Так-то там ещё надо COM1A0 сбросить, иначе нога в HIGH пойдёт.

Значит 2 действия для low, либо весь TCCR1A за раз.)
 

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

sadman41 пишет:

 Есть какой-то волшебный регистр, который инструктирует МК перевести её в какой-то совершенно определённый LOW или HIGH?

Волшебный регистр есть, но только для не-PWM режимов ,  FOC "Force Output Compare". С помощью него удобно делать всякие одиночные импульсы, типа как тут

sadman41
Offline
Зарегистрирован: 19.10.2016

dimax, накинул такого вот на вентилятор...

void setup() {
  Serial.begin(115200);
  pinMode(9, OUTPUT);
  Serial.println("Timer #1 on");
  TCCR1A = 0; TCCR1B = 0;
  OCR1A = 2500; TCCR1A = 1 << COM1A0;
  TCCR1B = (1 << CS11) | (1 << CS10) | (1 << WGM12);
  delay(10000);
  Serial.println("Timer #1 off");
  TCCR1A = (1 << COM1A1);
  TCCR1C = (1 << FOC1A);
}

void loop(){}

Субъективно - нога в 0 скидывается с запозданием в секунду-две. Вроде и не PWM-mode и FOC применён... Или это цифро-осциллограф притормаживает?

UPD:

Сделал так и вторым лучом на D3 присел:

void setup() {
  pinMode(9, OUTPUT);
  pinMode(3, OUTPUT);
  digitalWrite(3, LOW);
  TCCR1A = 0; TCCR1B = 0;
  OCR1A = 20000; TCCR1A = 1 << COM1A0;
  TCCR1B = (1 << CS11) | (1 << WGM12);
  delay(5000);
  TCCR1A = (1 << COM1A1);
  TCCR1C = (1 << FOC1A);
  digitalWrite(3, HIGH);
}

Похоже, что всё ОК, просто Джихан долго думает.

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

sadman41 пишет:

Похоже, что всё ОК, просто Джихан долго думает.

Вопрос немного не потеме, по твоему осциллографу, можешь порекомендовать к покупке?

sadman41
Offline
Зарегистрирован: 19.10.2016

Ну, так... у меня других не было. Корпус крепкий (можно в гараж взять), два луча. Генератором dimax-а проверял - показания сходятся. Под музыку с линейного выхода тоже бодро дрыгается. Скриншоты делает, но достать их - ещё тот геморрой (быстрее так зафоткать). Управление кнопками, так что для постоянной работы неудобен, но для эпизодических применений - более, чем. Триггеры, развертки - всё на месте. Есть ещё какие-то режимы сложений луча... но я туда не лез, мне не надо пока что.

Основная проблема - аккумулятор литиевый подобрать. Которые с защитой - могут не влезть по длине, а без защиты... Я так и не понял из документации - сам девайс контролирует разряд или нет. Поэтому решил не рисковать и теперь сую прокладку между контактом акк. и бат. блока - он сделан жопоруким проектировщиком каким-то. Комплектное зарядное не советую - рвануло на третий день. Взял LitoKala, ей заряжаю.

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

да мой С1-65 загудел, а ремонтировать приборы то ещё дело )))
Есть приставка Хантек, двухлучевая, но там всё кривое, начиная от щупов,

вот неспешно подбираю, чтобы на столе вертикально стояло, брать как ЕвгенийП дороговато

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

dimax пишет:
типа как тут.
Спасибо, мне очень понравилось.

Не сразу дошло, почему вместо строк №№ 12-13 нельзя просто в HIGH 9-ый пин загнать. Но, потом таки вроде устаканилось.

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

Добавил поддержку ATtiny 25/45/85 и чуток причесал код. Теперь, там кстати, видно как добавлять новые микроконтроллеры, если кому надо.

#ifndef	CONSTTIMERS_H
#define	CONSTTIMERS_H

///////////////////////////////////////////////////////////////////////////////
//
//	Недобиблиотека вычисления битов конфигурации делителя частоты и 
//	количества тиков таймера по заданной частоте.
//
//	Предназначена для использования с микроконтроллером ATmega328P 
//	(например, в Ардуино или в AVR-студии). Модификация для других 
//	микроконтроллеров возможна и несложна, как будет показано ниже.
//
//	Основная особенность: ВСЕ ВЫЧИСЛЕНИЯ ПРОИСХОДЯТ ВО ВРЕМЯ КОМПИЛЯЦИИ. 
//	В РЕЗУЛЬТИРУЮЩИЙ КОД НЕ ПОПАДАЕТ НИ ОДНОГО БАЙТА НИ КОДА, НИ ДАННЫХ.
//
//		замечание о точности: 
//			гарантировать точность произвольной частоты невозможно, т.к. требуемый период 
//			может элементарно не являться делителем тактовой частоты микроконтроллера или 
//			его, может быть, невозможно подобрать имеющимися делителями частоты. 
//			Недобиблиотека ВСЕГДА выдаёт наилучший из возможных результатов для заданной частоты
//			на заданном таймере. Но при этом нет никакой возможности узнать насколько хорош
//			результат и какова погрешность. Если требуется инструмент для «зрячего» выбора
//			частот, следует взять «калькулятор таймеров» (их много, например, есть и у автора).
//		конец замечания о точности.
//
//	ИСПОЛЬЗОВАНИЕ
//
//	Обязательна опция  -std=c++11 или  -std=gnu++11 (или больше - 14, 17). В свежих IDE она 
//	стоит по умолчанию, а в AVR Studio 7.0 - нет. Если нет, то надо поставить.
//
//	Для использования необходимо включить файл «ConstTimers.h» и определить константы с 
//	модификатором constexpr для нужных конфигурационных битов и количества тиков, которым 
//	присвоить значения, возвращаемые функциям getPrescalerBits и getTimerTicks соответсвенно. 
//	Обе функции принимают два параметра – номер таймера и требуемую частоту. Функция 
//	getPrescalerBits возвращает результат типа uint8_t. Функция getTimerTicks возвращает результат 
//	типа uint16_t, т.к. таймер может быть 16-битным, для 8-битных таймеров значение не превышает 255.
//
//	Например:
//
//		#include <ConstTimers.h>
//		//
//		// Параметры для работы таймера/счётчика №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);
//		.............
//		//
//		// Конфигурация таймеров
//		// таймер №2
//		TCCR2B = timerBits2;
//		OCR2A = timerTicks2;
//		// таймер №1
//		TCCR1B = timerBits1;
//		OCR1B = timerTicks1;
//
//Результат работы будет точно такой же, как если написать константы вместо вызовов функций:
//
//	TCCR2B = 4;
//	OCR2A = 250;
//	TCCR1B = 1;
//	OCR1B = 32000;
//
// Ни на один байт код не изменится.
//
//	КОФИГУРАЦИЯ:
//
//	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	FCPU	F_CPU

struct STimerParameters {
	const uint32_t maxValue;
	const int * prescalers;
	const uint8_t totalPrescalers;
};

static constexpr uint32_t	bits8	= 0x000000FFul;
static constexpr uint32_t	bits16	= 0x0000FFFFul;

#if ATmega328Detected

	static constexpr  int prescalers01[] = { 1, 8, 64, 256, 1024 };
	static constexpr  int 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 ATtiny85Detected

	static constexpr  int prescalers0[] = { 1, 8, 64, 256, 1024 };
	static constexpr  int 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 frequency, const int8_t prescalerId, const int8_t nTimer) {
	return (getPeriod(frequency) + 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 frequency, const int8_t prescalerId, const int8_t nTimer) {
	return prescalerId >= timerParameters[nTimer].totalPrescalers ? 0x1FFFFFFF :
	correctTicks(getDesiredTicks(frequency, 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 absError(const uint32_t frequency, const int8_t prescalerId, const int8_t nTimer) {
	return abs(prescalerId >= timerParameters[nTimer].totalPrescalers ? 0x1FFFFFFF :
		static_cast<int32_t>(getTicks(frequency, prescalerId, nTimer) * prValue(prescalerId, nTimer)) -
		static_cast<int32_t>(getPeriod(frequency)));
}

static constexpr uint8_t getPrescalerId(const uint32_t error, const uint32_t newError, const uint8_t prId, const uint8_t candidate, const uint32_t frequency, const int8_t nTimer) {
	return
	(prId >= timerParameters[nTimer].totalPrescalers) ? candidate
	: getPrescalerId(newError, absError(frequency, prId+1, nTimer), prId+1, (error <= newError) ? candidate : prId, frequency, nTimer);
}

static constexpr uint16_t getTimerTicks(const int8_t nTimer, const uint32_t freq) {
	return getTicks(freq, getPrescalerId(0x1FFFFFul, absError(freq, 0, nTimer), 0, 0, freq, nTimer), nTimer);
}

static constexpr uint8_t getPrescalerBits(const int8_t nTimer, const uint32_t freq) {
	return getBits(getPrescalerId(0x1FFFFFul, absError(freq, 0, nTimer), 0, 0, freq, nTimer), nTimer);
}

#endif	//	CONSTTIMERS_H

 

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

неожиданно вдруг узнал, что у 85 с предделителями побогаче

ssss
Offline
Зарегистрирован: 01.07.2016

Так и не понял... нафига весь этот бесконечный и беспросветный Си++ гемор??? В итоге... дело, оказывается, в знаниях камня и даташита... а не в Си++... с которого толку аж никакого... Попытка была конечно очень смешная... но состоявшаяся...

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

Не понял, значит не дано: «Многие вещи нам непонятны не потому, что наши понятия слабы, но потому, что сии вещи не входят в круг наших понятий» (К.П. Прутков).

Во избежания срача, все дальнейшие посты на темы "нахрена это нужно" и т.п., а также ответы на них, будут тереться без предупреждения.

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

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

IMHO не обязательно только дальнейшие.

С++ - это инструмент, а не религия.

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

dimax пишет:

sadman41 пишет:

 Есть какой-то волшебный регистр, который инструктирует МК перевести её в какой-то совершенно определённый LOW или HIGH?

Волшебный регистр есть, но только для не-PWM режимов ,  FOC "Force Output Compare". С помощью него удобно делать всякие одиночные импульсы, типа как тут

поинтересуюсь!
А можно ли этот способ применить для отсчитывания очень точного интервала, к примеру 1 секунда, в том же частотомере, вместо delay(1000)

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

ua6em, этот способ для дрыганья ногой таймера, так что вместо delay() не подойдёт.

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

Почему не подойдёт? Если ждать "дрыга" прерыванием или даже просто while'ом, то вполне подойдёт.

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

ЕвгенийП, тогда получается незачем и ногой  "дрыгать"  ;-)

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

Да, но использовать вместо делэя-то вполне можно.

Green
Offline
Зарегистрирован: 01.10.2015

Для точных ворот лучше использовать что то постабильнее, нежели системный кварц. Хотя бы 32 кгц, лучше с термостабилизацией. Ну и формировать железно, с выхода таймера-делителя.

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

Green, ds3231 ? Точнее него только дорогие TCXO генераторы.

Green
Offline
Зарегистрирован: 01.10.2015

Можно и его, только у SQW ПЕРИОД 1 сек, а значит нужно делить ещё чем то. Это если до герца (двух).

 

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

Green пишет:

Можно и его, только у SQW ПЕРИОД 1 сек, а значит нужно делить ещё чем то. Это если до герца (двух).

Ну, там же есть пин "32kHz Output". Да и частота SQW не всегда 1 Гц - она может быть 1024, 4096 и 8192 Гц если настроить.

Или речь о частотах меньших, чем 1 Гц? Но разве их нельзя смоделировать алармом?

Green
Offline
Зарегистрирован: 01.10.2015

Ну, для того что бы измерить входную частоту с точностью 1 гц (не будем о фазе)) нужны ворота в 1 сек, не менее. ds3231 выдаёт на выходе SQW только период в 1 с, т.е. полупериод будет 500 мс. О длительных интервалах с помощью аларма не задумывался.) Но обычно, индикация (ворота) свыше 2 сек. уже несколько раздражает.

GarryC
Offline
Зарегистрирован: 08.08.2016

Евгений, ни в коей мере на являясь "апологетом идеи неприменимости С++ для МК", тем не менее рискну предположить, что если заменить constexpr на inline и включить оптимизацию, то результат будет точно таким же - все промежуточные константные выражения свернутся и останутся голые результаты.

Но! в случае с inline данный результат ни фига не гарантируется на других компиляторах и в других режимах оптимизации, так что несомненная польза от Вашено подхода наличествует.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Green пишет:

ds3231 выдаёт на выходе SQW только период в 1 с, т.е. полупериод будет 500 мс. 

Вывсёврёти!!!  и килогерц там есть и 4 и 8

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ÐиÑÑ Ð½Ð°ÑÑÑойки ÑаÑÑоÑÑ Ð²Ñвода INT/SQW

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

GarryC пишет:

рискну предположить, что если заменить constexpr на inline и включить оптимизацию, то результат будет точно таким же - все промежуточные константные выражения свернутся и останутся голые результаты.

Неа! По крайней мере при опциях «из коробки». Можете проверить сами и убедиться.

Вполне допускаю, что если поиграться опциями, то, может быть, и получится (а, может, и нет). Но главное здесь не в том, что (как Вы совершенно справедливо отметили) constexpr - стандартизованное средство языка, которое обязано работать по стандарту, а оптимизация – «как получится». Разница гораздо глубже. Разница в том, что здесь открываются новые возможности, которых там нет.

Вот смотрите, например, чтобы сделать эту библиотеку реально полезной, надо бы устранить в ней одну недоработку, которая вполне реализуема на constexpr и абсолютно никак не реализуема на inline.

А доработка такая. В описании я отмечал, что библиотека выдаёт наилучшее возможное приближение к точному временному интервалу. Для каких-то интервалов – оно просто точное, а для каких-то «точнее никак». Так вот хотелось бы иметь возможность контролировать точность. Например, указывать, что если погрешность выходит за некоторую величину, то компиляция должна быть прекращена с соответствующим сообщением.

Согласитесь, полезная фича. Но на inline не делается никак.

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

ЕвгенийП пишет:
надо бы устранить в ней одну недоработку
И хде???

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

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

И хде???

Не знаю, почему Вы до сих пор не сделали и не выложили :)

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

Лицензия не позволяет :)

Green
Offline
Зарегистрирован: 01.10.2015

DetSimen пишет:

Вывсёврёти!!!  и килогерц там есть и 4 и 8

Там много чего есть. Но нам то нужна 1 сек.

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

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

Лицензия не позволяет :)

Вы всё врёте, лицензия позволяет, просто не все тут танцоры )))

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

Сами Вы фсёврёти! Там WM указана. Мне надо её либо удалять, либо "работать на дядю" :)

Green
Offline
Зарегистрирован: 01.10.2015

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

Сами Вы фсёврёти!

Вот так и думал, не нужно упоминать ворота всуе.)

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

А чё не так с лицензией? Там же сказано, что импользовать или не использовать можно с любыми целями, кроме незаконных. Так что модифицируйте на здоровье, в WM удаляйте, если мешает.

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

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

А чё не так с лицензией? Там же сказано, что импользовать или не использовать можно с любыми целями, кроме незаконных. Так что модифицируйте на здоровье, в WM удаляйте, если мешает.

ВОРОТА хочет, чтобы там его WM был )))

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

Не возражаю. Я уже не в первый код на форуме WM вставляю. На сегодняшний день, общая сумма полученых транзакций 0 рублей и столько же копеек. Пусть теперь и Ворота разбогатеет, не всё ж мне одному.

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

Всё б вам на бедном мне наживаться :(

Ладно, застыдили, попробую сегодня добавить контроль точности, а заодно и задание времени не частотой, а периодом (в смысле просто временным интервалом). А то нужно, скажем 150мс интервал, а хрен его задашь - частота нецелая получается. Лучше иметь возможность задавать и так, и так - как удобнее в данный момент.