#include <limits.h>
static const double fCPU = F_CPU;
// Всего у таймера/счётчика 1 пять делителей частоты
#define TOTAL_PRESCALERS 5
// Потоковая печать в Serial
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }
////////////////////////////////////////////
//
// Класс, для расчёта количества тактов и делителя
//
// Расчёт производится в функции Calculate по формуле
// со стр.123 ATmega48A/PA/88A/PA/168A/PA/328/P [DATASHEET]
// Сначала производится прямой расчёт для данного делителя,
// Затем, после округления, обратный и определяется разница
// желаемой и полученной частоты.
//
class CalcResult : public Printable {
public:
CalcResult(uint16_t p) {
prescaler = p;
valid = false;
}
void Calculate(const double freq) {
frequency = floor(fCPU / (2.0 * prescaler * freq) - 0.5);
if (frequency < 0.0 || frequency > (double)UINT_MAX) return;
valid = true;
counter = (uint16_t) frequency;
frequency = fCPU / (2.0 * prescaler * (1.0 + counter));
difference = fabs(frequency - freq);
}
protected:
size_t printTo(Print& p) const {
size_t res = p.print("Prescaler: ");
res += p.print(prescaler);
if (! valid) return res + p.println(" - Not possible");
res += p.print("; MaxValue: ");
res += p.print(counter);
res += p.print("; Frequency: ");
res += p.print(frequency);
res += p.print("Hz; Diff: ");
res += p.print(difference);
return res += p.println("Hz");
}
private:
uint16_t counter;
int16_t prescaler;
double frequency;
double difference;
bool valid;
friend int cmp(const void *, const void *);
};
/////////////////////////////////////////////////////////
//
// Функция сравнения двух результатов для qsort
// Правила:
// 1. если для одного делителя результат получен, а для другого нет, то первый меньше второго
// 2. Из двух результатов меньше тот, у которого меньше difference (погрешность частоты)
//
static int cmp(const void * va, const void * vb) {
const CalcResult * a = (const CalcResult *) va;
const CalcResult * b = (const CalcResult *) vb;
if (a->valid && ! b->valid) return -1;
if (! a->valid && b->valid) return 1;
if (! a->valid && ! b->valid) return 0;
if (a->difference - b->difference < 0) return -1;
if (a->difference - b->difference > 0) return 1;
return 0;
}
////////////////////////////////////////////////////////////////||||||
//
// расчёт для пяти делителей, сотрировка и вывод результатов в Serial
//
void CalculateParameters(const double frequency) {
CalcResult results [TOTAL_PRESCALERS] = {
CalcResult(1), CalcResult(8), CalcResult(64), CalcResult(256), CalcResult(1024)
};
for (int8_t i = 0; i < TOTAL_PRESCALERS; i++) results[i].Calculate(frequency);
qsort(results, TOTAL_PRESCALERS, sizeof(results[0]), cmp);
for (int8_t i = 0; i < TOTAL_PRESCALERS; Serial << results[i++]);
}
////////////////////////////////////////////////////////////////||||||
//
// инициализация
//
void setup() {
Serial.begin(115200);
Serial.setTimeout(LONG_MAX);
}
////////////////////////////////////////////////////////////////||||||
//
// На каждом шаге производим расчёт для одного значения частоты
//
void loop() {
Serial << "\nEnter desired frequency in Hz\n(use decimal point for fractions. I.e. 0.12 means 0,12Hz):\n";
const double frequency = Serial.parseFloat();
Serial << "\nResults for frequency: " << frequency << "Hz\n";
if (frequency < 0) {
Serial << "ERROR: frequency cannot be negative.\n";
} else if (frequency > fCPU / 2.0) {
Serial << "ERROR: frequency should bot be greater then " << fCPU / 2.0 << "Hz\n";
} else CalculateParameters(frequency);
}
// собственно. всё.