Arduino, похоже, считывает неверные аналоговые данные ввода-вывода. Я что-то делаю неправильно?

Я использую ATTiny88 для измерения температуры с помощью термистора сопротивлением 470 Ом, подключенного к порту A3 на Arduino.

Термистор подключен последовательно с резистором сопротивлением 1870 Ом, подключенным к Vcc. При комнатной температуре напряжение на термисторе составляет примерно 1,5 В, а Vcc — 5,1 В, что соответствует цифровому преобразованию примерно в 0x012°C.

Однако, когда я обращаюсь к Arduino, он возвращает 0x0288. Если я ничего не упускаю, это соответствует более чем 3 вольтам. Конечно, значение меняется со временем, но суть в том, что возвращаемое значение отличается примерно в 2 раза. Это число подозрительно, но оно может быть не в 2 раза. Для проверки, 0x012C очень близко к тому, что я должен получить по показаниям эталонного термометра, учитывая кривую сопротивления термистора.

Это просто сводит с ума. В этом нет никакого смысла. Я модернизировал печатную плату, чтобы подавать напряжения на A6, A2 и A3, которые, по моим расчётам, должны быть аналоговыми входами 11, 15 и 16 соответственно. Я подаю напряжение PTC — около 1,3 вольта — на A3, опорное напряжение источника питания 5 В — на A2, а напряжение основного питания, делённое на четыре, — на A0. В нормальном режиме работы основное питание составляет около 12 В, что даёт напряжение на выводе A0 примерно 3 В. На основном питании стоит суперконденсатор, поэтому напряжение там падает медленно, и требуется около 7 минут, чтобы опуститься ниже предельного значения 5 В, после чего вся система отключается. Вот зарегистрированные значения в нормальном режиме работы:

0xaa 0x02 0xaa 0x02 0x57 0x02 0xfa 0x00 0x00 0x00 0x01 0x01 0x00 0x01

Это должно соответствовать следующим значениям:

Temperature 3.33V (Should be ~1.3V)
Reference Voltage 3.33V (Should be 5V)
Input Voltage 2.92V (Reasonable value, equates to around 11.73V)

Напряжение основного питания составляет 11,75 В. Когда я отключаю питание, напряжение сразу падает до 11,56 В и начинает медленно падать, но выходное напряжение теперь:

0xa8 0x02 0xa9 0x02 0x97 0x02 0x58 0x04 0x00 0x00 0x01 0x01 0x00 0x00

что соответствует

Temperature 3.32V
Reference Voltage 3.33V
Input Voltage 3.24V (Has gone up!)

Сообщаемое напряжение не только возросло с 11,73 В до 13,03 В, но и остаётся практически неизменным, хотя входное напряжение медленно падает до 8 В

Что здесь происходит? Никакого смысла. Вот новый код, соответствующий новой плате:

#include <Wire.h>

#define Cool    0   // Охладитель Пельтье ВКЛ = ВЫСОКИЙ
#define POK 1   // Сбой питания IN
#define Fan 9   // Реле вентилятора ВКЛ = ВЫСОКИЙ
#define PiCtl   14  // Мощность Raspberry Pi
#define ADDR1   15  // Адрес I2C 1
#define ADDR2   16  // Адрес I2C 2
#define SCL 23  // I2C Clock
#define SDA 24  // Данные I2C

#define V12 11  // Аналоговый вход 12 В
#define V5  15  // Аналоговый вход 5 В
#define PTC 16  // Аналоговый вход термопары
#define FanT    655 // Порог вентилятора
#define CoolT   895 // Порог охлаждения
#define TooHot  1000    // Отключение по температуре
#define DelSt   120 // Задержка запуска

int I2C;
bool True = 1;
bool False = 0;
float Temp;
bool FanSet;
bool Responded;
unsigned long timeStamp;
unsigned long heartBeat;

union Response {
    struct {
        int Temperature;    // 2 байта
        int Reference;      // 2 байта
        int Battery;        // 2 байта
        unsigned long Living;   // 4 байта
        uint8_t Command;    // 1 байт
        uint8_t FanValue;   // 1 байт
        uint8_t CoolStat;   // 1 байт
        uint8_t PowerStat;  // 1 байт
        uint8_t padding;    // 1 байт
    };
    uint8_t bytes[15];
};
union Response Reply;

void setup()
{
    pinMode(Cool, OUTPUT);      // Установить охлаждающий контакт
    digitalWrite(Cool, 0);      // Выключить охлаждение
    pinMode(POK, INPUT);        // Установить контакт датчика питания
    pinMode(Fan, OUTPUT);       // Установить контакт вентилятора
    analogWrite(Fan, 0);        // Выключить вентилятор
    pinMode(PiCtl, OUTPUT);     // Установить вывод питания Pi
    digitalWrite(PiCtl, LOW);   // Включаем Raspberry Pi
    pinMode(ADDR1, INPUT_PULLUP);   // Смещение адреса 0 или 1
    pinMode(ADDR2, INPUT_PULLUP);   // Смещение адреса 0 или 2
    I2C = (2 * digitalRead(ADDR2)) + digitalRead(ADDR1) + 8;    // Установить адрес I2C 8 - 11
    Wire.begin(I2C);        // Инициализация связи I2C
    Wire.onRequest(requestEvent);   // Вызвать requestEvent при запросе данных
    Wire.onReceive(receiveEvent);   // Вызвать receiveEvent при получении данных
    Reply.PowerStat = 1;        // Сбросить состояние питания
    Reply.FanValue = 1;     // Установить статус вентилятора Вкл.
    Reply.CoolStat = 0;     // Отключить статус Cool
    sDelay (DelSt);
}

void HeartBeat()
{
    if (millis() - heartBeat > 30000)   // Если Raspberry Pi не разговаривает
    {
        digitalWrite(PiCtl, HIGH);  // Выключить Raspberry Pi
        sDelay (10);            // Задержка 10 секунд
        digitalWrite(PiCtl, LOW);   // Включаем Raspberry Pi
        sDelay (DelSt);         // Задержка для запуска
        heartBeat = millis();       // Установить время жизни
    }
}

void TempCheck()
{
    Reply.Temperature = analogRead(PTC);
    if (Reply.Temperature > CoolT)
    {
        Reply.FanValue = 1;     // Установить статус вентилятора Вкл.
        Reply.CoolStat = 1;     // Установить статус Cool вкл.
        digitalWrite(Cool, 1);      // Включить охлаждение
        analogWrite(Fan, 255);      // Включить вентилятор
        while (Reply.Temperature > TooHot)
        {
            Reply.Command = 0;
            sDelay(60);     // Задержка 1 минута
            digitalWrite(PiCtl, HIGH);      // Выключить Raspberry Pi
            Reply.Temperature = analogRead(PTC);
        }
        Reply.Command = 1;
        digitalWrite(PiCtl, LOW);   // Включаем Raspberry Pi
    }
    else if (Reply.Temperature > FanT)
    {
        Reply.FanValue = 1;     // Установить статус вентилятора Вкл.
        Reply.CoolStat = 0;     // Отключить статус Cool
        digitalWrite(Cool, 0);      // Выключить охлаждение
        analogWrite(Fan, 255);      // Включить вентилятор
    }
    else
    {
        Reply.FanValue = 0;     // Установить статус вентилятора Выкл.
        Reply.CoolStat = 0;     // Отключить статус Cool
        digitalWrite(Cool, 0);      // Выключить охлаждение
        analogWrite(Fan, 0);        // Выключить вентилятор
    }
}

void PowerCheck()
{
    bool Power = digitalRead(POK);
    if (Power)
    {
        Reply.Reference = analogRead(V5);
        mDelay(100);
        Reply.Battery = analogRead(V12);
        digitalWrite(PiCtl, LOW);   // Включаем Raspberry Pi
        Reply.Command = 1;      // Сброс команды выключения
        Reply.PowerStat = 1;        // Сбросить состояние питания
    }
    else
    {
        while (!Power)
        {
            Reply.Reference = analogRead(V5);
            mDelay(100);
            Reply.Battery = analogRead(V12);
            Power = digitalRead(POK);   // Проверка входного питания
            Reply.PowerStat = 0;        // Установить состояние питания
            if (Reply.Battery < 360)
            {
                digitalWrite(PiCtl, HIGH);  // Выключить Raspberry Pi
                analogWrite(Fan, 0);        // Выключить вентилятор
            }
            else if (Reply.Battery < 390)
            {
                Reply.Command = 0;  // Установить команду выключения
            }
            mDelay(100);
        }
        Reply.PowerStat = 1;        // Установить состояние питания
        Reply.Command = 1;
        digitalWrite(PiCtl, LOW);   // Включаем Raspberry Pi
    }
}

// Функция, которая выполняется всякий раз, когда данные запрашиваются ведущим устройством
void requestEvent()
{
    Reply.Living = millis() - heartBeat;    // Установить интервал ответа
    heartBeat = millis();           // Сбросить сердцебиение
    Wire.write(Reply.bytes, sizeof Reply);  // ответить сообщением, как ожидает мастер
    Responded = True;           // Устанавливает переменную responded
}

// Функция, которая выполняется при получении данных от мастера
void receiveEvent(int howMany)
{
    while (Wire.available()) { // цикл по всем, кроме последнего
        char c = Wire.read(); // получить байт как символ
        }
    Responded = True;           // Устанавливает переменную responded
    Reply.Living = millis() - heartBeat;    // Установить интервал ответа
    heartBeat = millis();           // Сбросить сердцебиение
}

// функция mDelay
void mDelay(long mSeconds)
{
    long dSeconds = millis();           // Количество миллисекунд с момента включения
    while (millis() < dSeconds + mSeconds){}    // Задержка Секунды Миллисекунды
}

// Функция sDelay
void sDelay(long Seconds)
{
    Seconds = Seconds * 1000;
    long dSeconds = millis();       // Количество миллисекунд с момента включения
    while (millis() < dSeconds + Seconds){} // Задержка Секунды Миллисекунды
}

void loop()
{
    PowerCheck();
    TempCheck();
    HeartBeat();
    sDelay(1);
}

, 👍0

Обсуждение

непонятно, как подключены резисторы... пожалуйста, добавьте схему... вы можете нажать на кнопку, которая выглядит как схема... нарисовать схему, затем нажать «сохранить и вставить»... или нарисовать схему на бумаге и вставить картинку, @jsotola

Резистор 1870 Ом подключен к Vcc, а PTC — к земле, а Arduino подключен к общей точке. Как ещё можно устроить делитель напряжения? Я также не совсем понимаю, какое это имеет значение. Фактическое напряжение составляет 1,5 В, в то время как заявленное — 3 В, независимо от схемы., @Leslie Rhorer

Если вы прочитаете свой вопрос, то увидите, что вы ничего не сказали о подключении к заземлению., @jsotola

Ваша проблема связана с аналоговым считыванием напряжения? Это выражение даёт неверный результат analogRead(PTC)? Это выражение: #define PTC 16 также относится к выводу A3, на который вы ссылаетесь в тексте? Совпадает ли оно с выражением: #define ADDR2 16? Если вы считываете аналоговый вывод, какое отношение имеет i2ctransfer -y 1 r10@0x0a в вашем тексте? Попробуйте подать на вывод A3 различные напряжения от 0 до 5 В (используя резистивные делители), чтобы увидеть, попадает ли диапазон от 0 до 1024 В. Если нет, проверьте конфигурацию источника опорного напряжения., @6v6gt

Нумерация выводов на вашей схеме выглядит странно, поскольку она, по-видимому, относится к нижней части микросхемы и не соответствует ATTiny88, у которого 28 или 32 вывода в зависимости от корпуса. Укажите, какое ядро Arduino вы используете, чтобы, например, можно было сопоставить вывод A3 с определениями в вашей программе., @6v6gt

Это плата: https://www.amazon.com/QCCAN-ATTINY88-Development-ATmega328-Compatible/dp/B0B71FLZ4X/ref=sr_1_3?crid=1WPMLC2L6NQKB&dib=eyJ2IjoiMSJ9.NEwnS1IVFmzprb50H5C-tug_7yTOqnCJcN2fRd6O46ZF_CWO_tpuS0hHp5AWR-JioRVlo6yxRd1hjeOYd66OEXclEkvK7GWM87rNu05UnZeJyjPc lnymcEI4Ao8TcID9pAJwkXjt6sG7Wwx4Yff1L5Iaw9hOi5LWoAdqs8fx8B_XfBPPqKuLMGSA_59bwGIjNXNdFCuL2bsO4ioCsFxu8LM6nXwmKQlUaiqKLO4jCP I.SgMxou8CSExZ5fwOckECv7thaKj5zJuVx-h3W3xXfjM&dib_tag=se&keywords=attiny88&qid=1731339694&sprefix=attiny%2Caps%2C143&sr=8-3, @LesRhorer

Я думал, это понятно. Я считываю данные с нескольких выводов, один из которых аналоговый, а также время, прошедшее с момента последнего запроса от внешнего хоста, и сохраняю значения в структуре «Reply». Я извлекаю эти значения на удалённый хост, выполняя команду i2ctransfer -y 1 r10@0x0a в BASH-скрипте. Сейчас у меня нет простого способа изменить напряжение на выводе, но через несколько дней прибудет новый прототип печатной платы, что упростит задачу., @LesRhorer

Почему вы используете два аккаунта?, @the busybee


1 ответ


1

Последовательное соединение 1870 Ом и термистора 470 Ом даёт коэффициент деления на термисторе 0,201. Умножьте на приложенное напряжение 5,1, и получите 1,02 В, а не 1,5 В.

Поскольку я пока не уполномочен комментировать, я отзову этот ответ, если кто-то оставит комментарий в этом направлении.

,