Да , я в лаптях хожу, не в курсе. Не пользуюсь, не интересно. Разве что когда гугл/яндекс что сам выдаёт.
А так, просто мысль пришла - где гарантия, что ИИ даёт, или даже хотя-бы пытается дать , именно правильный, “чистосердечный”, ответ? А вдруг у него свой умысел?)))
Вот с чем-чем, а с целеполаганием у него полная напряжёнка. Умысел надо не там искать ![]()
Согласен, но почему не представить возможной ситуацию, когда ИИ по запросу “срисует” вопрошающего, определит в нём, скажем лентяя-студента, или , скажем, педофила, и выдаст не общий ответ, а особый,. “целевой” ответ …
А вообще, не мне особо рассуждать об этом, т.к. я не очень в теме.
Прошу мои ответы считать более шуткой ![]()
Это-то запросто! Но, без особого умысла.
У яндексов как-то спросили почему Алиса частенько хамит в ответах. Они честно ответили, что она учится во многом по диалогам в соц. сетях и просто" считает" такой стиль общения нормальным.
Так что если какой-то ИИ будет требовать схему, код и начнёт глумиться – это совершенно нормально. Но, повторяю, без умысла.
Однако, над ее воспитанием явно поработали. Раньше на этот вопрос она честно признавалась, что бывает несдержанна, а сегодня вот так:
Хотя, может это просто женские странности ))))
Ну не знаю. Как возможно без умысла? Ведь программа не может работать без ранее заложенного алгоритма. А для программы это и есть умысел.(ИМХО)
Значит у ИИ в этом случае есть умысел “нормально общаться”))
А что в это “нормально” может войти со временем… ![]()
В этом то и особенность ИИ - что он может!
Не поверю. Что сам может обновить алгоритм - это да, но, чтоб без уже существующего на данный момент алгоритма - в моей скромной башке это не укладывается
ну это я в ЫЫ все закинул, все сообщения из темы))) а автор не говорил как он этот код писал, хоть и похоже на ии))
а писал я потому что вы не хотите за других даташит читать, а мне лениво))) а если мне лениво, то может там ии сам разберется)))
если вы видели недавно прикол где то, то это скорее всего благодаря стараниям мастера при работе с ии, сам ии так отказывается глумиться)))
но на всякий случай, ии должно быть 2, один серьезный, а второго можно шуткам над другими обучать!)))
говорят когда ИИ grok задолбать, он может начать угрожать и шантажировать))) ну я его не тестил
)))))
ИНС – это НЕ фон-неймановская машина. Там понятие алгоритм (в фон-неймановском смысле) неприменимо. Алгоритм там один на все случаи жизни – это отработка синаптических связей. Конечно, и сами связи могут быть разными (фиксированные, динамические, прямые и т.п.) и особенности их обработки, но в пределах одной ИНС (уж с теми связями, какие есть) алгоритм всегда один. И совершенно неважно чем занимается нейросеть в данный момент – пишет Вам скетч или рисует картинку фантастического мира, она исполняет тот же самый алгоритм.
Может Вам будет интересно, этот алгоритм иногда зашивают прямо в железо. Например, IBM выпускает серию процессоров с т.н. ZISC архитектурой – процессоры без системы команд (Zero Instruction Set Computer). Это специальный процессор, который не программируется в фон-неймановском смысле – он на аппаратном уровне реализует сеть Кохонена и работает непосредственно с данными.
Кстати, решил добавить. Очень давно я описывал здесь на форуме забавную игрушку “Машинки Брайтенберга”. Так вот, это как раз ИНС (с пороговой передаточной функцией и прямым распространением сигнала) в чистом виде, а именно – разновидность персептрона.
Моего знакомого дипсик послал на.
ЕвгенийП скрыто или прямо ? и он при этом сам не просил его прямо послать ?))) если есть переписка, я бы почитал…
дип сик вроде самый универсальный, довольно часто к нему обращаюсь, но все же редко, и как я не извращался, он никогда не может сказать ответ я не смогу сделать то то, а тем более послать)))
это похоже что то нечто))) я бы посмотрел что к этому привело…
Никогда такого не было и вот опять… ![]()
Я понял, что прямо.
Я спрошу, но боюсь, что он меня пошлёт ту да же
У него в ноябре докторская защита и ему явно не до того, чтобы искать протоколы старых чатов.
lilik нет никаких противоречий))) оба условия истина!)))
работаю с другим ии, но например кашу из чатов туда тащить не хочу, что бы ии не отупел))) и обращаюсь иногда к дип сику за быстрым ответом…
Спасибо за подробные разъяснения
Байда этот ДипСик.
Скормил два pdf Claude со словами “напиши мне библиотеку для Ардуино для этого датчика” и вот, что он выдал:
Спойлер
/**
MIS3600.h - Библиотека для работы с датчиком давления MIS-3600
Поддерживаемые модели:
- MIS-3600-C50DI/SI/DS/SS (0.5 psi)
- MIS-3600-001DI/DS (1 psi bipolar)
- MIS-3600-001SI/SS (1 psi unipolar)
- MIS-3600-006DI/SI/DS/SS (5.8 psi)
- MIS-3600-015DI/SI/DS/SS (15 psi)
- MIS-3600-030DI/SI/DS/SS (30 psi)
Автор: Your Name
Дата: 2025
Лицензия: MIT
*/
#ifndef MIS3600_H
#define MIS3600_H
#include <Arduino.h>
#include <Wire.h>
// Определение архитектуры
#if defined(ARDUINO_ARCH_ESP32)
#define MIS3600_ESP32
#include "driver/ledc.h"
#elif defined(__AVR__)
#define MIS3600_AVR
#else
#error "Unsupported platform. Only AVR and ESP32 are supported."
#endif
// Типы датчиков
enum MIS3600_SensorType
{
MIS3600_05PSI, // 0.5 psi
MIS3600_1PSI_BI, // 1 psi bipolar
MIS3600_1PSI_UNI, // 1 psi unipolar
MIS3600_58PSI, // 5.8 psi
MIS3600_15PSI, // 15 psi
MIS3600_30PSI // 30 psi
};
// Адреса I2C (зависит от подключения CS)
#define MIS3600_I2C_ADDR_CS_HIGH 0x77 // CS -> VDD
#define MIS3600_I2C_ADDR_CS_LOW 0x76 // CS -> GND
// Время конвертации (мс)
#define MIS3600_CONVERSION_TIME 35
// Целевая частота MCLK
#define MIS3600_MCLK_FREQ 32768UL
// Конфигурация пинов по умолчанию для разных платформ
#ifdef MIS3600_AVR
// Для AVR используем Timer2 на пине OC2A (Arduino UNO - pin 11, MEGA - pin 10)
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
#define MIS3600_DEFAULT_MCLK_PIN 11 // OC2A on Arduino UNO/Nano
#elif defined(__AVR_ATmega2560__)
#define MIS3600_DEFAULT_MCLK_PIN 10 // OC2B on Arduino MEGA
#else
#define MIS3600_DEFAULT_MCLK_PIN 11
#endif
#define MIS3600_DEFAULT_SDA_PIN SDA
#define MIS3600_DEFAULT_SCL_PIN SCL
#endif
#ifdef MIS3600_ESP32
// Для ESP32 пины можно выбирать любые
#define MIS3600_DEFAULT_MCLK_PIN 25
#define MIS3600_DEFAULT_SDA_PIN 21
#define MIS3600_DEFAULT_SCL_PIN 22
#endif
/**
Класс для расчета параметров таймера в compile-time
*/
class MIS3600_TimerCalc
{
public:
// Вычисление делителя предварительного делителя для AVR
static constexpr uint8_t calculateAVRPrescaler()
{
#ifdef MIS3600_AVR
// Возможные делители для Timer2: 1, 8, 32, 64, 128, 256, 1024
if ((F_CPU / (2UL * MIS3600_MCLK_FREQ)) <= 256) return 1;
if ((F_CPU / (2UL * MIS3600_MCLK_FREQ * 8)) <= 256) return 2;
if ((F_CPU / (2UL * MIS3600_MCLK_FREQ * 32)) <= 256) return 3;
if ((F_CPU / (2UL * MIS3600_MCLK_FREQ * 64)) <= 256) return 4;
if ((F_CPU / (2UL * MIS3600_MCLK_FREQ * 128)) <= 256) return 5;
if ((F_CPU / (2UL * MIS3600_MCLK_FREQ * 256)) <= 256) return 6;
return 7; // 1024
#else
return 0;
#endif
}
// Получение реального значения делителя
static constexpr uint16_t getPrescalerValue (uint8_t prescaler)
{
#ifdef MIS3600_AVR
const uint16_t values[] = {1, 8, 32, 64, 128, 256, 1024};
return (prescaler <= 6) ? values[prescaler] : 1024;
#else
return 1;
#endif
}
// Вычисление значения OCR для AVR
static constexpr uint8_t calculateAVROCR()
{
#ifdef MIS3600_AVR
uint8_t prescaler = calculateAVRPrescaler();
uint16_t prescalerValue = getPrescalerValue (prescaler);
return (uint8_t) ((F_CPU / (2UL * MIS3600_MCLK_FREQ * prescalerValue)) - 1);
#else
return 0;
#endif
}
// Вычисление фактической частоты
static constexpr uint32_t calculateActualFreq()
{
#ifdef MIS3600_AVR
uint8_t prescaler = calculateAVRPrescaler();
uint16_t prescalerValue = getPrescalerValue (prescaler);
uint8_t ocr = calculateAVROCR();
return F_CPU / (2UL * prescalerValue * (ocr + 1));
#else
return MIS3600_MCLK_FREQ;
#endif
}
// Вычисление погрешности в процентах
static constexpr float calculateError()
{
uint32_t actual = calculateActualFreq();
return ((float)actual - (float)MIS3600_MCLK_FREQ) / (float)MIS3600_MCLK_FREQ * 100.0f;
}
};
class MIS3600
{
public:
/**
Конструктор с указанием пина MCLK
@param sensorType - тип датчика
@param i2cAddress - I2C адрес
@param mclkPin - пин для генерации MCLK (по умолчанию из define)
@param sdaPin - пин SDA (только для ESP32)
@param sclPin - пин SCL (только для ESP32)
*/
#ifdef MIS3600_ESP32
MIS3600 (MIS3600_SensorType sensorType,
uint8_t i2cAddress = MIS3600_I2C_ADDR_CS_HIGH,
int8_t mclkPin = MIS3600_DEFAULT_MCLK_PIN,
int8_t sdaPin = MIS3600_DEFAULT_SDA_PIN,
int8_t sclPin = MIS3600_DEFAULT_SCL_PIN);
#else
MIS3600 (MIS3600_SensorType sensorType,
uint8_t i2cAddress = MIS3600_I2C_ADDR_CS_HIGH,
int8_t mclkPin = MIS3600_DEFAULT_MCLK_PIN);
#endif
/**
Инициализация датчика
@param wire - указатель на объект Wire
@param enableMCLK - включить генерацию MCLK
@return true если инициализация успешна
*/
bool begin (TwoWire *wire = &Wire, bool enableMCLK = true);
/**
Запуск генерации MCLK
@return true если успешно
*/
bool startMCLK();
/**
Остановка генерации MCLK (для экономии энергии)
*/
void stopMCLK();
/**
Получить фактическую частоту MCLK
@return частота в Гц
*/
uint32_t getActualMCLKFreq();
/**
Получить погрешность частоты MCLK в процентах
@return погрешность в %
*/
float getMCLKError();
/**
Проверка, запущен ли MCLK
@return true если MCLK работает
*/
bool isMCLKRunning();
// Остальные методы без изменений
bool readCalibrationData();
bool startPressureConversion();
bool startTemperatureConversion();
uint16_t readRawPressure();
uint16_t readRawTemperature();
bool measure();
float getPressure();
float getTemperature();
bool performZeroing();
float getRelativePressure();
bool reset();
bool isConnected();
uint16_t getCalibrationCoefficient (uint8_t index);
void printCalibrationData();
void printMCLKInfo();
private:
TwoWire *_wire;
uint8_t _i2cAddress;
MIS3600_SensorType _sensorType;
int8_t _mclkPin;
bool _mclkRunning;
#ifdef MIS3600_ESP32
int8_t _sdaPin;
int8_t _sclPin;
ledc_channel_t _ledcChannel;
ledc_timer_t _ledcTimer;
#endif
// Калибровочные коэффициенты C1-C13
uint16_t _coeff[14];
// Сырые данные
uint16_t _D1;
uint16_t _D2;
// Вычисленные значения
float _temperature;
float _pressure;
float _pressureZero;
bool _zeroingDone;
// Промежуточные переменные
float _dT;
float _Sens;
float _Offset;
// Внутренние методы
bool sendCommand (uint8_t cmd1, uint8_t cmd2);
uint16_t read16bit();
uint16_t readCoefficient (uint8_t cmd1, uint8_t cmd2);
void calculate_05PSI();
void calculate_1PSI_BI();
void calculate_1PSI_UNI();
void calculate_58PSI();
void calculate_15PSI();
void calculate_30PSI();
// Инициализация MCLK для разных платформ
#ifdef MIS3600_AVR
bool initMCLK_AVR();
void stopMCLK_AVR();
#endif
#ifdef MIS3600_ESP32
bool initMCLK_ESP32();
void stopMCLK_ESP32();
#endif
};
#endif // MIS3600_H
Спойлер
/**
MIS3600.cpp - Реализация библиотеки для датчика MIS-3600
*/
#include "MIS3600.h"
// Конструктор
#ifdef MIS3600_ESP32
MIS3600::MIS3600 (MIS3600_SensorType sensorType, uint8_t i2cAddress,
int8_t mclkPin, int8_t sdaPin, int8_t sclPin)
{
_sensorType = sensorType;
_i2cAddress = i2cAddress;
_mclkPin = mclkPin;
_sdaPin = sdaPin;
_sclPin = sclPin;
_ledcChannel = LEDC_CHANNEL_0;
_ledcTimer = LEDC_TIMER_0;
#else
MIS3600::MIS3600 (MIS3600_SensorType sensorType, uint8_t i2cAddress, int8_t mclkPin)
{
_sensorType = sensorType;
_i2cAddress = i2cAddress;
_mclkPin = mclkPin;
#endif
_wire = nullptr;
_mclkRunning = false;
_D1 = 0;
_D2 = 0;
_temperature = 0.0;
_pressure = 0.0;
_pressureZero = 0.0;
_zeroingDone = false;
for (uint8_t i = 0; i < 14; i++)
_coeff[i] = 0;
}
bool MIS3600::begin (TwoWire *wire, bool enableMCLK)
{
_wire = wire;
#ifdef MIS3600_ESP32
// Инициализация I2C с пользовательскими пинами
if (!_wire->begin (_sdaPin, _sclPin))
return false;
#else
// Для AVR используются стандартные пины SDA/SCL
_wire->begin();
#endif
// Запуск MCLK если требуется
if (enableMCLK)
{
if (!startMCLK())
return false;
// Даем время на стабилизацию тактового сигнала
delay (10);
}
// Проверка связи с датчиком
if (!isConnected())
{
if (enableMCLK)
stopMCLK();
return false;
}
// Задержка после включения
delay (50);
// Чтение калибровочных коэффициентов
if (!readCalibrationData())
{
if (enableMCLK)
stopMCLK();
return false;
}
return true;
}
bool MIS3600::startMCLK()
{
if (_mclkRunning)
return true;
if (_mclkPin < 0)
return false;
#ifdef MIS3600_AVR
return initMCLK_AVR();
#elif defined(MIS3600_ESP32)
return initMCLK_ESP32();
#else
return false;
#endif
}
void MIS3600::stopMCLK()
{
if (!_mclkRunning)
return;
#ifdef MIS3600_AVR
stopMCLK_AVR();
#elif defined(MIS3600_ESP32)
stopMCLK_ESP32();
#endif
_mclkRunning = false;
}
#ifdef MIS3600_AVR
bool MIS3600::initMCLK_AVR()
{
// Compile-time расчеты
constexpr uint8_t prescalerBits = MIS3600_TimerCalc::calculateAVRPrescaler();
constexpr uint8_t ocrValue = MIS3600_TimerCalc::calculateAVROCR();
// Проверка, что мы используем правильный пин
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
if (_mclkPin != 11) // OC2A
return false;
#elif defined(__AVR_ATmega2560__)
if (_mclkPin != 10) // OC2B
return false;
#endif
// Настройка пина как выход
pinMode (_mclkPin, OUTPUT);
// Отключаем прерывания Timer2
TIMSK2 = 0;
// Режим CTC (Clear Timer on Compare Match)
TCCR2A = _BV (COM2A0) | _BV (WGM21); // Toggle OC2A on compare match, CTC mode
// Установка OCR2A
OCR2A = ocrValue;
// Установка предделителя и запуск таймера
switch (prescalerBits)
{
case 0:
TCCR2B = _BV (CS20);
break; // No prescaling
case 1:
TCCR2B = _BV (CS21);
break; // clk/8
case 2:
TCCR2B = _BV (CS21) | _BV (CS20);
break; // clk/32
case 3:
TCCR2B = _BV (CS22);
break; // clk/64
case 4:
TCCR2B = _BV (CS22) | _BV (CS20);
break; // clk/128
case 5:
TCCR2B = _BV (CS22) | _BV (CS21);
break; // clk/256
case 6:
TCCR2B = _BV (CS22) | _BV (CS21) | _BV (CS20);
break; // clk/1024
default:
return false;
}
_mclkRunning = true;
return true;
}
void MIS3600::stopMCLK_AVR()
{
// Остановка Timer2
TCCR2B = 0;
TCCR2A = 0;
// Установка пина в LOW
digitalWrite (_mclkPin, LOW);
}
#endif
#ifdef MIS3600_ESP32
bool MIS3600::initMCLK_ESP32()
{
// Конфигурация LEDC таймера
ledc_timer_config_t ledc_timer;
ledc_timer.speed_mode = LEDC_LOW_SPEED_MODE;
ledc_timer.duty_resolution = LEDC_TIMER_1_BIT; // 1 bit = 50% duty cycle
ledc_timer.timer_num = _ledcTimer;
ledc_timer.freq_hz = MIS3600_MCLK_FREQ;
ledc_timer.clk_cfg = LEDC_AUTO_CLK;
if (ledc_timer_config (&ledc_timer) != ESP_OK)
return false;
// Конфигурация LEDC канала
ledc_channel_config_t ledc_channel;
ledc_channel.gpio_num = _mclkPin;
ledc_channel.speed_mode = LEDC_LOW_SPEED_MODE;
ledc_channel.channel = _ledcChannel;
ledc_channel.intr_type = LEDC_INTR_DISABLE;
ledc_channel.timer_sel = _ledcTimer;
ledc_channel.duty = 1; // 50% duty cycle (1 из 2 для 1-bit resolution)
ledc_channel.hpoint = 0;
if (ledc_channel_config (&ledc_channel) != ESP_OK)
return false;
_mclkRunning = true;
return true;
}
void MIS3600::stopMCLK_ESP32()
{
// Остановка LEDC канала
ledc_stop (LEDC_LOW_SPEED_MODE, _ledcChannel, 0);
// Установка пина в LOW
pinMode (_mclkPin, OUTPUT);
digitalWrite (_mclkPin, LOW);
}
#endif
uint32_t MIS3600::getActualMCLKFreq()
{
#ifdef MIS3600_AVR
return MIS3600_TimerCalc::calculateActualFreq();
#else
return MIS3600_MCLK_FREQ;
#endif
}
float MIS3600::getMCLKError()
{
uint32_t actual = getActualMCLKFreq();
return ((float)actual - (float)MIS3600_MCLK_FREQ) / (float)MIS3600_MCLK_FREQ * 100.0f;
}
bool MIS3600::isMCLKRunning()
{
return _mclkRunning;
}
void MIS3600::printMCLKInfo()
{
Serial.println (F ("=== MCLK Configuration ==="));
Serial.print (F ("Target frequency: "));
Serial.print (MIS3600_MCLK_FREQ);
Serial.println (F (" Hz"));
Serial.print (F ("Actual frequency: "));
Serial.print (getActualMCLKFreq());
Serial.println (F (" Hz"));
Serial.print (F ("Error: "));
Serial.print (getMCLKError(), 4);
Serial.println (F (" %"));
Serial.print (F ("MCLK Pin: "));
Serial.println (_mclkPin);
Serial.print (F ("Status: "));
Serial.println (_mclkRunning ? F ("Running") : F ("Stopped"));
#ifdef MIS3600_AVR
Serial.print (F ("CPU Frequency: "));
Serial.print (F_CPU);
Serial.println (F (" Hz"));
constexpr uint8_t prescaler = MIS3600_TimerCalc::calculateAVRPrescaler();
constexpr uint16_t prescalerValue = MIS3600_TimerCalc::getPrescalerValue (prescaler);
constexpr uint8_t ocr = MIS3600_TimerCalc::calculateAVROCR();
Serial.print (F ("Timer Prescaler: "));
Serial.println (prescalerValue);
Serial.print (F ("OCR2A value: "));
Serial.println (ocr);
#endif
#ifdef MIS3600_ESP32
Serial.print (F ("I2C SDA Pin: "));
Serial.println (_sdaPin);
Serial.print (F ("I2C SCL Pin: "));
Serial.println (_sclPin);
Serial.print (F ("LEDC Channel: "));
Serial.println (_ledcChannel);
Serial.print (F ("LEDC Timer: "));
Serial.println (_ledcTimer);
#endif
Serial.println (F ("=========================="));
}
bool MIS3600::isConnected()
{
_wire->beginTransmission (_i2cAddress);
return (_wire->endTransmission() == 0);
}
bool MIS3600::sendCommand (uint8_t cmd1, uint8_t cmd2)
{
_wire->beginTransmission (_i2cAddress);
_wire->write (cmd1);
_wire->write (cmd2);
return (_wire->endTransmission() == 0);
}
uint16_t MIS3600::read16bit()
{
uint16_t value = 0;
_wire->requestFrom (_i2cAddress, (uint8_t)3); // Запрос 3 байта (dummy + 2 data)
if (_wire->available() >= 3)
{
_wire->read(); // Dummy byte
uint8_t msb = _wire->read();
uint8_t lsb = _wire->read();
value = ((uint16_t)msb << 8) | lsb;
}
return value;
}
uint16_t MIS3600::readCoefficient (uint8_t cmd1, uint8_t cmd2)
{
if (!sendCommand (cmd1, cmd2))
return 0;
delay (5); // Небольшая задержка перед чтением
return read16bit();
}
bool MIS3600::readCalibrationData()
{
// Чтение всех 13 коэффициентов
const uint8_t commands[][2] =
{
{0x0E, 0x20}, // C1
{0x0E, 0x28}, // C2
{0x0E, 0x30}, // C3
{0x0E, 0x38}, // C4
{0x0E, 0x40}, // C5
{0x0E, 0x48}, // C6
{0x0E, 0x50}, // C7
{0x0E, 0x58}, // C8
{0x0E, 0x60}, // C9
{0x0E, 0x68}, // C10
{0x0E, 0x70}, // C11
{0x0E, 0x78}, // C12
{0x0E, 0x80} // C13
};
for (uint8_t i = 0; i < 13; i++)
{
_coeff[i + 1] = readCoefficient (commands[i][0], commands[i][1]);
delay (5);
// Проверка на валидность
if (_coeff[i + 1] == 0 || _coeff[i + 1] == 0xFFFF)
return false;
}
return true;
}
bool MIS3600::startPressureConversion()
{
uint8_t cmd1, cmd2;
// Выбор команды в зависимости от типа датчика
if (_sensorType == MIS3600_58PSI || _sensorType == MIS3600_15PSI)
{
cmd1 = 0x0F;
cmd2 = 0x49;
}
else
{
cmd1 = 0x0F;
cmd2 = 0x59;
}
return sendCommand (cmd1, cmd2);
}
bool MIS3600::startTemperatureConversion()
{
return sendCommand (0x0F, 0x21);
}
uint16_t MIS3600::readRawPressure()
{
return read16bit();
}
uint16_t MIS3600::readRawTemperature()
{
return read16bit();
}
bool MIS3600::measure()
{
// Запуск конвертации давления
if (!startPressureConversion())
return false;
delay (MIS3600_CONVERSION_TIME);
_D1 = readRawPressure();
// Запуск конвертации температуры
if (!startTemperatureConversion())
return false;
delay (MIS3600_CONVERSION_TIME);
_D2 = readRawTemperature();
// Расчет компенсированных значений в зависимости от типа датчика
switch (_sensorType)
{
case MIS3600_05PSI:
calculate_05PSI();
break;
case MIS3600_1PSI_BI:
calculate_1PSI_BI();
break;
case MIS3600_1PSI_UNI:
calculate_1PSI_UNI();
break;
case MIS3600_58PSI:
calculate_58PSI();
break;
case MIS3600_15PSI:
calculate_15PSI();
break;
case MIS3600_30PSI:
calculate_30PSI();
break;
default:
return false;
}
return true;
}
void MIS3600::calculate_05PSI()
{
// Расчет температуры
if (_temperature < 10.0 || _coeff[8] == 0) // T < 10°C
{
_dT = ((float)_D2 - (float)_coeff[1]) / ((float)_coeff[3] / 100.0);
_temperature = _dT + (float)_coeff[2] / 10.0;
_Sens = ((float)_D2 - (float)_coeff[1]) * ((float)_coeff[5] + 20000.0) / 1000000.0
+ ((float)_coeff[4] - 70000.0) / 10.0;
_Offset = ((float)_D2 - (float)_coeff[1]) * ((float)_coeff[7] + 30000.0) / 1000000.0
+ (float)_coeff[6];
}
else // T >= 10°C
{
_dT = ((float)_coeff[8] * pow (((float)_D2 - (float)_coeff[1]), 2)) / 1000000000000.0
+ (float)_coeff[9] * ((float)_D2 - (float)_coeff[1]) / 10000000.0;
_temperature = _dT + (float)_coeff[2] / 10.0;
_Sens = ((float)_coeff[10] - 50000.0) * pow (((float)_D2 - (float)_coeff[1]), 2) / 100000000000.0
+ (float)_coeff[11] * ((float)_D2 - (float)_coeff[1]) / 1000000.0
+ ((float)_coeff[4] - 70000.0) / 10.0;
_Offset = ((float)_coeff[12] - 50000.0) * pow (((float)_D2 - (float)_coeff[1]), 2) / 10000000000.0
+ (float)_coeff[13] * ((float)_D2 - (float)_coeff[1]) / 1000000.0
+ (float)_coeff[6];
}
// Расчет давления
_pressure = ((float)_D1 - _Offset) / _Sens;
}
void MIS3600::calculate_1PSI_BI()
{
// Аналогично calculate_05PSI (используются те же формулы)
calculate_05PSI();
}
void MIS3600::calculate_1PSI_UNI()
{
// Расчет температуры
if (_temperature < 10.0 || _coeff[8] == 0) // T < 10°C
{
_dT = ((float)_D2 - (float)_coeff[1]) / ((float)_coeff[3] / 100.0);
_temperature = _dT + (float)_coeff[2] / 10.0;
_Sens = ((float)_D2 - (float)_coeff[1]) * ((float)_coeff[5] + 20000.0) / 1000000.0
+ ((float)_coeff[4] - 90000.0) / 10.0;
_Offset = ((float)_D2 - (float)_coeff[1]) * ((float)_coeff[7] + 30000.0) / 1000000.0
+ (float)_coeff[6];
}
else // T >= 10°C
{
_dT = ((float)_coeff[8] * pow (((float)_D2 - (float)_coeff[1]), 2)) / 1000000000000.0
+ (float)_coeff[9] * ((float)_D2 - (float)_coeff[1]) / 10000000.0;
_temperature = _dT + (float)_coeff[2] / 10.0;
_Sens = ((float)_coeff[10] - 50000.0) * pow (((float)_D2 - (float)_coeff[1]), 2) / 100000000000.0
+ ((float)_coeff[11] + 10000.0) * ((float)_D2 - (float)_coeff[1]) / 1000000.0
+ ((float)_coeff[4] - 90000.0) / 10.0;
_Offset = ((float)_coeff[12] - 110000.0) * pow (((float)_D2 - (float)_coeff[1]), 2) / 100000000000.0
+ ((float)_coeff[13] + 20000.0) * ((float)_D2 - (float)_coeff[1]) / 1000000.0
+ (float)_coeff[6];
}
// Расчет давления
_pressure = ((float)_D1 - _Offset) / _Sens;
}
void MIS3600::calculate_58PSI()
{
// Расчет температуры
if (_temperature < 10.0 || _coeff[8] == 0) // T < 10°C
{
_dT = ((float)_D2 - (float)_coeff[1]) / ((float)_coeff[3] / 100.0);
_temperature = _dT + (float)_coeff[2] / 10.0;
_Sens = ((float)_D2 - (float)_coeff[1]) * ((float)_coeff[5] - 20000.0) / 1000000.0
+ ((float)_coeff[4] - 50000.0) / 10.0;
_Offset = ((float)_D2 - (float)_coeff[1]) * ((float)_coeff[7] - 20000.0) / 1000000.0
+ (float)_coeff[6];
}
else // T >= 10°C
{
_dT = ((float)_coeff[8] * pow (((float)_D2 - (float)_coeff[1]), 2)) / 1000000000000.0
+ (float)_coeff[9] * ((float)_D2 - (float)_coeff[1]) / 10000000.0;
_temperature = _dT + (float)_coeff[2] / 10.0;
_Sens = ((float)_coeff[10] - 20000.0) * pow (((float)_D2 - (float)_coeff[1]), 2) / 100000000000.0
+ (float)_coeff[11] * ((float)_D2 - (float)_coeff[1]) / 1000000.0
+ ((float)_coeff[4] - 50000.0) / 10.0;
_Offset = ((float)_coeff[12] - 100000.0) * pow (((float)_D2 - (float)_coeff[1]), 2) / 100000000000.0
+ (float)_coeff[13] * ((float)_D2 - (float)_coeff[1]) / 1000000.0
+ (float)_coeff[6];
}
// Расчет давления
_pressure = ((float)_D1 - _Offset) / _Sens;
}
void MIS3600::calculate_15PSI()
{
// Расчет температуры
if (_temperature < 10.0 || _coeff[8] == 0) // T < 10°C
{
_dT = ((float)_D2 - (float)_coeff[1]) / ((float)_coeff[3] / 100.0);
_temperature = _dT + (float)_coeff[2] / 10.0;
_Sens = ((float)_D2 - (float)_coeff[1]) * ((float)_coeff[5] + 20000.0) / 10000000.0
+ ((float)_coeff[4] - 100000.0) / 100.0;
_Offset = ((float)_D2 - (float)_coeff[1]) * (float)_coeff[7] / 1000000.0
+ (float)_coeff[6];
}
else // T >= 10°C
{
_dT = ((float)_coeff[8] * pow (((float)_D2 - (float)_coeff[1]), 2)) / 10000000000000.0
+ (float)_coeff[9] * ((float)_D2 - (float)_coeff[1]) / 10000000.0;
_temperature = _dT + (float)_coeff[2] / 10.0;
_Sens = ((float)_coeff[10] - 80000.0) * pow (((float)_D2 - (float)_coeff[1]), 2) / 1000000000000.0
+ (float)_coeff[11] * ((float)_D2 - (float)_coeff[1]) / 10000000.0
+ ((float)_coeff[4] - 100000.0) / 100.0;
_Offset = ((float)_coeff[12] - 100000.0) * pow (((float)_D2 - (float)_coeff[1]), 2) / 100000000000.0
+ (float)_coeff[13] * ((float)_D2 - (float)_coeff[1]) / 1000000.0
+ (float)_coeff[6];
}
// Расчет давления
_pressure = ((float)_D1 - _Offset) / _Sens;
}
void MIS3600::calculate_30PSI()
{
// Расчет температуры
if (_temperature < 10.0 || _coeff[8] == 0) // T < 10°C
{
_dT = ((float)_D2 - (float)_coeff[1]) / ((float)_coeff[3] / 100.0);
_temperature = _dT + (float)_coeff[2] / 10.0;
_Sens = ((float)_D2 - (float)_coeff[1]) * (float)_coeff[5] / 10000000.0
+ ((float)_coeff[4] - 70000.0) / 100.0;
_Offset = ((float)_D2 - (float)_coeff[1]) * ((float)_coeff[7] - 20000.0) / 1000000.0
+ (float)_coeff[6];
}
else // T >= 10°C
{
_dT = ((float)_coeff[8] - 30000.0) * pow (((float)_D2 - (float)_coeff[1]), 2) / 1000000000000.0
+ (float)_coeff[9] * ((float)_D2 - (float)_coeff[1]) / 10000000.0;
_temperature = _dT + (float)_coeff[2] / 10.0;
_Sens = ((float)_coeff[10] - 80000.0) * pow (((float)_D2 - (float)_coeff[1]), 2) / 1000000000000.0
+ (float)_coeff[11] * ((float)_D2 - (float)_coeff[1]) / 10000000.0
+ ((float)_coeff[4] - 70000.0) / 100.0;
_Offset = ((float)_coeff[12] - 50000.0) * pow (((float)_D2 - (float)_coeff[1]), 2) / 100000000000.0
+ (float)_coeff[13] * ((float)_D2 - (float)_coeff[1]) / 1000000.0
+ (float)_coeff[6];
}
// Расчет давления
_pressure = ((float)_D1 - _Offset) / _Sens;
}
float MIS3600::getPressure()
{
return _pressure;
}
float MIS3600::getTemperature()
{
return _temperature;
}
bool MIS3600::performZeroing()
{
if (!measure())
return false;
_pressureZero = _pressure;
_zeroingDone = true;
return true;
}
float MIS3600::getRelativePressure()
{
if (!_zeroingDone)
return _pressure;
return _pressure - _pressureZero;
}
bool MIS3600::reset()
{
// Для I2C интерфейса сброс не требует специальной команды
// Можно просто переинициализировать датчик
delay (50);
return readCalibrationData();
}
uint16_t MIS3600::getCalibrationCoefficient (uint8_t index)
{
if (index < 1 || index > 13)
return 0;
return _coeff[index];
}
void MIS3600::printCalibrationData()
{
Serial.println (F ("=== Calibration Coefficients ==="));
for (uint8_t i = 1; i <= 13; i++)
{
Serial.print (F ("C"));
Serial.print (i);
Serial.print (F (": "));
Serial.println (_coeff[i]);
}
Serial.println (F ("================================"));
}
Спойлер
# MIS3600 Arduino Library
Библиотека для работы с датчиками давления и температуры серии MIS - 3600 производства MEMSensing через интерфейс I2C.
## Поддерживаемые модели
```
- **MIS - 3600 - C50DI / SI / DS / SS** - 0.5 psi
- **MIS - 3600 - 001DI / DS** - 1 psi bipolar (двухполярный)
- **MIS - 3600 - 001SI / SS** - 1 psi unipolar (однополярный)
- **MIS - 3600 - 006DI / SI / DS / SS** - 5.8 psi
- **MIS - 3600 - 015DI / SI / DS / SS** - 15 psi
- **MIS - 3600 - 030DI / SI / DS / SS** - 30 psi
```
## Возможности
```
- ✅ Чтение температуры и давления
- ✅ Автоматическая температурная компенсация
- ✅ Калибровочные коэффициенты из OTP памяти
- ✅ Процедура обнуления (zeroing)
- ✅ Поддержка всех датчиков серии MIS - 3600
- ✅ Простой и понятный API
```
## Установка
### Через Arduino IDE
1. Скачайте библиотеку как ZIP файл
2. В Arduino IDE: **Sketch → Include Library → Add .ZIP Library...* *
3. Выберите скачанный ZIP файл
4. Перезапустите Arduino IDE
### Вручную
1. Создайте папку `MIS3600` в директории `Arduino / libraries / `
2. Распакуйте библиотеку в папку
3. Перезапустите Arduino IDE
4. Библиотека появится в меню **Sketch → Include Library → MIS3600**
## Подключение датчика
```
MIS - 3600 Arduino
-------- ------ -
VDD ---- 3.3V или 5V
GND ---- GND
SDA ---- A4 (Uno) или SDA
SCL ---- A5 (Uno) або SCL
CS ---- VDD (адрес 0x77) или GND (адрес 0x76)
```
⚠️ **Важно:** Обязательно используйте pull - up резисторы 10 кОм на линиях SDA и SCL!
Датчик MIS-3600 требует внешний тактовый сигнал 32768 Гц на входе MCLK для работы АЦП.
Библиотека автоматически генерирует этот сигнал.
### Подключение MCLK
#### Arduino (AVR)
На платформе AVR используется аппаратный Timer2:
- **Arduino UNO/Nano:** Pin 11 (OC2A)
- **Arduino MEGA:** Pin 10 (OC2B)
Пин фиксирован аппаратно и не может быть изменен.
```
MIS3600 sensor(MIS3600_15PSI); // MCLK на стандартном пине
```
#### ESP32
На ESP32 используется LEDC PWM, можно выбрать любой GPIO:
```
MIS3600 sensor(MIS3600_15PSI, 0x77,
25, // MCLK pin
21, // SDA pin
22); // SCL pin
```
#### Точность MCLK
Библиотека использует compile-time вычисления для максимальной точности:
```
// Получить фактическую частоту
uint32_t freq = sensor.getActualMCLKFreq();
// Получить погрешность в процентах
float error = sensor.getMCLKError();
// Вывести подробную информацию
sensor.printMCLKInfo();
```
Для большинства частот CPU (16 МГц для AVR, 240 МГц для ESP32) погрешность составляет менее 0.5%.
#### Режим низкого энергопотребления
MCLK можно включать только во время измерений:
```
// Инициализация без автозапуска MCLK
sensor.begin(&Wire, false);
// Включить MCLK перед измерением
sensor.startMCLK();
delay(50); // Стабилизация
// Измерение
sensor.measure();
// Выключить MCLK для экономии
sensor.stopMCLK();
Копировать
Проверка MCLK
C++
if (sensor.isMCLKRunning()) {
Serial.println("MCLK работает");
}
```
#### Ограничения
AVR: Только один датчик может использовать аппаратный MCLK
ESP32: Можно использовать до 8 независимых MCLK (разные GPIO)
Погрешность частоты зависит от F_CPU и может достигать 1-2% при нестандартных частотах
## Быстрый старт
```
#include <Wire.h>
#include <MIS3600.h>
// Создание объекта датчика (15 psi, адрес 0x77)
MIS3600 sensor (MIS3600_15PSI, MIS3600_I2C_ADDR_CS_HIGH);
void setup()
{
Serial.begin (9600);
// Инициализация датчика
if (!sensor.begin())
{
Serial.println ("Ошибка инициализации!");
while (1);
}
// Опционально: обнуление
sensor.performZeroing();
}
void loop()
{
// Измерение
if (sensor.measure())
{
float temp = sensor.getTemperature();
float pressure = sensor.getPressure();
Serial.print ("Температура: ");
Serial.print (temp);
Serial.print (" °C, Давление: ");
Serial.print (pressure);
Serial.println (" PSI");
}
delay (1000);
}
```
## Основные функции
### Инициализация
```
MIS3600 sensor (MIS3600_15PSI); // CS подключен к VDD (0x77)
MIS3600 sensor (MIS3600_15PSI, 0x76); // CS подключен к GND (0x76)
sensor.begin(); // Использовать Wire
sensor.begin (&Wire1); // Использовать Wire1
```
### Чтение данных
```
sensor.measure(); // Выполнить измерение
float temp = sensor.getTemperature(); // Получить температуру в °C
float pres = sensor.getPressure(); // Получить давление в PSI
```
### Обнуление (Zeroing)
```
sensor.performZeroing(); // Сохранить текущее давление как ноль
float rel = sensor.getRelativePressure(); // Получить относительное давление
```
### Калибровка
```
sensor.printCalibrationData(); // Вывести все коэффициенты
uint16_t c1 = sensor.getCalibrationCoefficient (1); // Получить коэффициент C1
```
### Диагностика
```
bool connected = sensor.isConnected(); // Проверить связь с датчиком
sensor.reset(); // Программный сброс
```
## Типы датчиков
При создании объекта укажите тип вашего датчика:
```
MIS3600_05PSI // 0.5 psi
MIS3600_1PSI_BI // 1 psi bipolar
MIS3600_1PSI_UNI // 1 psi unipolar
MIS3600_58PSI // 5.8 psi
MIS3600_15PSI // 15 psi
MIS3600_30PSI // 30 psi
```
## Расчет давления
Библиотека автоматически применяет все необходимые формулы компенсации в зависимости от:
- Типа датчика
- Текущей температуры (выше или ниже 10°C)
- Калибровочных коэффициентов из OTP памяти
Все расчеты выполняются согласно документации производителя.
## Примеры
В папке `examples / ` вы найдете:
- **ReadPressureTemperature** - Базовое чтение данных
- Другие примеры будут добавлены позже
## Технические характеристики
- **Интерфейс:** I2C (400 кГц max)
- **Адреса:** 0x76 или 0x77
- **Напряжение питания:** 3.0 - 5.5V
- **Время конвертации:** 35 мс
- **Разрешение:** 16 бит
- **Диапазон температур:** -40°C... + 85°C
## Преобразование единиц
```
float psi = sensor.getPressure();
float bar = psi * 0.0689476; // PSI в бары
float kpa = psi * 6.89476; // PSI в килопаскали
float mmHg = psi * 51.7149; // PSI в мм рт.ст.
float atm = psi * 0.068046; // PSI в атмосферы
```
## Устранение неполадок
### Ошибка инициализации
1. Проверьте подключение SDA / SCL
2. Убедитесь в наличии pull - up резисторов
3. Проверьте правильность I2C адреса
4. Проверьте питание датчика (3.0 - 5.5V)
### Неверные данные
1. Дайте датчику прогреться 1 - 2 минуты
2. Выполните процедуру обнуления
3. Проверьте калибровочные коэффициенты (printCalibrationData)
### Нестабильные показания
1. Используйте более короткие провода
2. Добавьте конденсаторы фильтрации питания (0.1 мкФ + 10 мкФ)
3. Увеличьте интервал между измерениями
## Лицензия
MIT License
## Автор
Создано для сообщества Arduino
## Ссылки
- [Документация MIS - 3600] (https://sensorsandpower.angst-pfister.com/en/products/pressure-sensors-load-sensors/product/mis-3600/)
- [Репозиторий GitHub] (#)
## История версий
### v1.0.0 (2024)
- Первый релиз
- Поддержка всех моделей MIS - 3600
- Полная температурная компенсация
- Процедура обнуления
## Вклад в проект
Приветствуются pull requests и сообщения об ошибках!
## FAQ
**Q: Какой датчик выбрать ? **
A : Зависит от диапазона измеряемого давления. Для медицинских применений часто используют 0.5 - 1 psi, для промышленных - 15 - 30 psi.
**Q : Можно ли использовать несколько датчиков ? **
A : Да, подключите CS одного к VDD (адрес 0x77), другого к GND (адрес 0x76).
**Q : Нужно ли выполнять обнуление ? **
A : Рекомендуется, если нужны относительные измерения (например, измерение перепада давления).
**Q : Как часто можно читать данные ? **
A : Минимальный интервал около 100 мс (время конвертации + запас). Рекомендуется 500 - 1000 мс.
-- -
## Структура файлов (итоговая)
```
MIS3600 /
├── src /
│ ├── MIS3600.h
│ └── MIS3600.cpp
├── examples /
│ │
│ └── ReadPressureTemperature.ino
│ └── MultiSensorWithMCLK.ino
│ └── LowPowerMode.ino
│ └── MCLKDiagnostics.ino
├── keywords.txt
├── library.properties
└── README.md
```
Я начинаю бояться.
Намного лучше чем у ТС, но ошибки все равно есть
Да это понятно. Только прогресс на месте не стоит. Пару лет назад даже представить было трудно. А сейчас он мне выдал полноценную библиотеку: src, примеры, readme. Хоть сразу на Гитхаб размещай.
Годик-другой и без ошибок будет писать.
