Неа. Я не могу его скомпилировать без исправлений. Исправленный вариант для ESP32, который компилируется, но время выводить не будет:
#include "float24.h"
void printFloatE(const char *const str, const float &value, const uint8_t digits = 5) {
char buf[16];
Serial.print(str);
Serial.print(" = ");
// dtostre(value, buf, digits, DTOSTR_UPPERCASE); //undeclared here and below
Serial.println(buf);
}
float kff[3][3] = { { 9.9237E-13, -1.2702E-09, 3.6321E-07 },
{ -7.9330E-10, 3.7138E-06, 8.3755E-03 },
{ 1.7514E-07, -8.0434E-04, -7.9905E-01 } };
float24_t kff24[3][3];
float calculatePressure(const uint16_t &nP, const uint16_t &nT) {
#if 0
cli();
TCCR1A = 0; // Normal mode
TCCR1B = (1 << CS11) | (1 << CS10); // Prescaler = 64
TCNT1 = 0; // сброс счётчика
#endif
uint32_t usec = 0; // надо исправить на uint64_t usec = esp_timer_get_time();, что-то заленился
asm volatile ("nop\r\nnop\r\nnop");
float fT = nT;
float fT2 = fT * fT;
float fP = nP;
float fP2 = fP * fP;
float a2 = kff[0][0] * fT2 + kff[0][1] * fT + kff[0][2];
float a1 = kff[1][0] * fT2 + kff[1][1] * fT + kff[1][2];
float a0 = kff[2][0] * fT2 + kff[2][1] * fT + kff[2][2];
float result = a2 * fP2 + a1 * fP + a0;
asm volatile ("nop\r\nnop\r\nnop");
#if 0
TCCR1B = 0; // stop timer
sei();
usec = TCNT1 * 4;
#endif
//usec = esp_timer_get_time() - usec;
Serial.print("duration: ");
Serial.print(usec, 3);
Serial.println(" usec");
return result;
}
float24_t calculatePressure24(const uint16_t &nP, const uint16_t &nT) {
#if 0
cli();
TCCR1A = 0; // Normal mode
TCCR1B = (1 << CS11) | (1 << CS10); // Prescaler = 64
TCNT1 = 0; // сброс счётчика
#endif
asm volatile ("nop\r\nnop\r\nnop");
uint32_t usec = 0;// надо исправить на uint64_t usec = esp_timer_get_time();, что-то заленился
float24_t fT = nT;
float24_t fT2 = fT * fT;
float24_t fP = nP;
float24_t fP2 = fP * fP;
float24_t a2 = kff24[0][0] * fT2 + kff24[0][1] * fT + kff24[0][2];
float24_t a1 = kff24[1][0] * fT2 + kff24[1][1] * fT + kff24[1][2];
float24_t a0 = kff24[2][0] * fT2 + kff24[2][1] * fT + kff24[2][2];
float24_t result = a2 * fP2 + a1 * fP + a0;
asm volatile ("nop\r\nnop\r\nnop");
#if 0
TCCR1B = 0; // stop timer
sei();
usec = TCNT1 * 4;
#endif
//usec = esp_timer_get_time() - usec;
Serial.print("duration: ");
Serial.print(usec, 3);
Serial.println(" usec");
return result;
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
for (uint8_t i = 0; i < 3; i++) {
for (uint8_t j = 0; j < 3; j++) {
kff24[i][j] = kff[i][j];
char buf[16];
//dtostre(kff24[i][j].asFloat(), buf, 5, DTOSTR_UPPERCASE);
Serial.print(buf);
Serial.print(" ");
}
Serial.println();
}
Serial.println();
for (;;) {
while (!Serial.available()) {}
const uint16_t nP = Serial.parseInt();
Serial.print("nP = ");
Serial.println(nP);
while (!Serial.available()) {}
const uint16_t nT = Serial.parseInt();
Serial.print("nT = ");
Serial.println(nT);
Serial.println();
float press = calculatePressure(nP, nT);
Serial.print("Press = ");
Serial.println(press, 5);
Serial.println();
float24_t press24 = calculatePressure24(nP, nT);
Serial.print("Press24 = ");
Serial.println(press24.asFloat(), 5);
Serial.println();
Serial.println();
}
}
void loop() {
// put your main code here, to run repeatedly:
}
А, это ассемблер ЕСП32 такой вот. Вызовы методов вычисляются как смещения от чего-то. Там прибавляется каждый раз циферка разная - типа. указатель на разные методы получается. Я не знаю почему и кому в голову это пришло - сделать так.
Но если вы когда нибудь начнете читать даташыт на есп32 (Xtensa Instruction Set Architecture) у вас волосы дыбом встанут
А почему столько вызовов методов? Ну, как бы умножения, сложения, деления - это все вызовы методов. Которые компилятор причешет, если его попросить через -O2
MMM
13.Октябрь.2025 10:59:45
64
ну скомпилировать-то всегда можно. Поддержка АВР в ИДЕ встроена по умолчанию, а плата для этого не нужна
Попробовал, скомпилировал. Но в ассемблер назад не могу превратить. avr-objdump -d ничего не делает.
Запустил Ghidra, та тоже - а для какого AVR код? А я откуда знаю. Arduino Uno. Не декомпилируется с дефолтовыми настройками.
Странные у Вас результаты тестирования.
То есть не важно, правильно считается или нет, важно только, чтобы побыстрее?
Я бы все-таки начал с оценки погрешности, а также с проверки, накапливается она или нет.
Возьмите кубик с неединичной гранью. Возьмите ортонормированный базис, вектора которого не параллельны сторонам кубика, а начало координат не совпадает с его центром. Повращайте кубик на угол порядка 0.5-1.0 градуса поочередно вокруг каждой из осей базиса. Шагов так порядка 1000-10000.
Проделайте это как для float, так и для float24_t, после чего сравните получившиеся координаты.
Если результаты устроят, можно двигаться дальше.
Только не забывайте повторять этот тест после каждого изменения исходников.
Goshman:
Хотя я просто обычно на 10, 100 или 1000 умножаю число и работаю с ним как с целым, подразумевая, что там еще точка есть.
Удобнее умножать/делить на 2, 4, 8, 16, 32…
vvb333007:
У меня нет АВР, у меня есть ЕСП32, но мне просто интересно глянуть, во что компилируется ваш код с классами
Чтобы скомпилировать под AVR, совершенно необязательно иметь его в железе.
Компилятор воле поступать, как ему заблагорассудится.
Но, как правило, оптимизация в этом случае сводится лишь к двум вариантам:
фрагмент помещается в листинг,
фрагмент выкидывается из листинга.
Goshman
13.Октябрь.2025 11:43:20
68
Ассемблерный код мне сгенерировать удалось, но весь он сюда не влезает. Как его показать?
Goshman
13.Октябрь.2025 11:46:23
69
Точность получилась около 5 знаков. Вот сравнение вычислений с float и float24_t
nP = 215
nT = 700
duration: 12111 usec
Press = 0.99798
duration: 2222 usec
Press24 = 0.99799
Отличается в 5 знаке. Более чем достаточно для датчика
Goshman
13.Октябрь.2025 11:48:52
70
andriano:
Удобнее умножать/делить на 2, 4, 8, 16, 32…
Я так маскировал десятичную точку. При выводе числа на печать просто ставил ее после нужного разряда числа.
Goshman
13.Октябрь.2025 11:54:49
72
andriano:
За сколько шагов?
float24_t calculatePressure24(const uint16_t &nP, const uint16_t &nT) {
cli();
TCCR1A = 0; // Normal mode
TCCR1B = (1 << CS11) | (1 << CS10); // Prescaler = 64
TCNT1 = 0; // сброс счётчика
float24_t fT = nT;
float24_t fT2 = fT * fT;
float24_t fP = nP;
float24_t fP2 = fP * fP;
float24_t a2 = kff24[0][0] * fT2 + kff24[0][1] * fT + kff24[0][2];
float24_t a1 = kff24[1][0] * fT2 + kff24[1][1] * fT + kff24[1][2];
float24_t a0 = kff24[2][0] * fT2 + kff24[2][1] * fT + kff24[2][2];
float24_t result = a2 * fP2 + a1 * fP + a0;
TCCR1B = 0; // stop timer
sei();
uint32_t usec = TCNT1 * 4;
Serial.print("duration: ");
Serial.print(usec, 3);
Serial.println(" usec");
return result;
}
10 умножений и 8 сложений, если я правильно посчитал.
Я не о том спрашивал.
Вы арифметические операции над своим типом проверяли?
Goshman
13.Октябрь.2025 14:13:14
74
Единичные операции (сложение, вычитание, умножение, деление) проверял, в .т.ч. в сравнении с float . Скетч для проверки в 1 посте приводил.
А если Вы об этом,
andriano:
Возьмите кубик с неединичной гранью. Возьмите ортонормированный базис, вектора которого не параллельны сторонам кубика, а начало координат не совпадает с его центром. Повращайте кубик на угол порядка 0.5-1.0 градуса поочередно вокруг каждой из осей базиса. Шагов так порядка 1000-10000.
то кажется понял что имелось в виду. Допишу недостающие методы (sin, cos) и попробую проверочный скетч сделать.