Embedded HandbookПриложения
Все разделы › XI. Датчики: подключение, схемы, драйверы
STM32F103, STM32F407 · уровень средний · 6 мин чтения
Открыть в интерактивном справочнике

102. Вес: тензодатчик и HX711

Тензодатчик — металлический брусок с наклеенными тензорезисторами, собранными в мост. Под нагрузкой брусок чуть гнётся, и мост выдаёт милливольты — на каждый вольт своего питания. Такой сигнал встроенному АЦП микроконтроллера не по зубам, поэтому ставят HX711: 24-разрядный АЦП с усилителем, сделанный именно для мостов, со своим двухпроводным интерфейсом. На нём четыре места, где весы начинают врать: знак 24-битного числа, усиление, которое действует не сразу, предел в 60 мкс на тактовом проводе и калибровка.

Внутренний АЦП — раздел 14, критические секции — раздел 30, подключение модулей — раздел 95.

Как это называется в документации

Оригинал Перевод
load cell тензодатчик: брусок с наклеенными тензорезисторами
strain gauge тензорезистор
Wheatstone bridge мост Уитстона
excitation voltage напряжение питания моста
sensitivity, mV/V чувствительность: милливольт на вольт питания при полной нагрузке
tare тара, обнуление весов
span calibration калибровка по известному грузу
programmable gain amplifier (PGA) усилитель с выбираемым усилением
two's complement дополнительный код
power-down режим сна

102.1 Мост и его милливольты

Весы: тензодатчик, HX711 и два провода к микроконтроллеру

Сигнал моста — это чувствительность, умноженная на питание и на долю нагрузки. Датчик на 5 кг с чувствительностью 1 мВ/В при питании 5 В на полной нагрузке выдаёт всего 5 мВ. 12-разрядный АЦП STM32 при опоре 3,3 В различает 0,806 мВ — весь сигнал уместился бы в шесть кодов с небольшим. HX711 при усилении 128 меряет ±19,531 мВ 24 битами: один код — 2,328 нВ, 5 мВ — 2 147 483 кода, то есть 429,5 кода на грамм. Диапазон входа — ±0,5 · AVDD / усиление, и ±19,531 мВ выходит при AVDD = 5 В. У готовых модулей AVDD обычно около 4,3 В; мост питается от того же напряжения, поэтому коды на грамм остаются теми же, а милливольты — меньше.

Канал и усиление выбирают числом импульсов после 24 бит:

Импульсов после 24 бит Канал Усиление Вход
25 A 128 ±19,531 мВ
26 B 32 ±78,125 мВ
27 A 64 ±39,062 мВ

102.2 Два провода, но не I²C

У HX711 нет адресов и нет подтверждений. Вывод DOUT падает в ноль, когда отсчёт готов; ведущий подаёт на PD_SCK 24 импульса и после каждого фронта читает очередной бит, старшим вперёд; ещё 1–3 импульса выбирают канал и усиление. Отсчётов — 10 или 80 в секунду, в зависимости от вывода RATE.

int hx711_read(unsigned extra, int32_t *value)
{
    unsigned guard = 0;
    while (hx_dout()) {
        if (++guard > 200000u)
            return 0;                   /* готовности нет: датчика нет или он спит */
        hx_wait_us(1);
    }
    uint32_t raw = 0;
    HX_LOCK();
    for (unsigned i = 0; i < 24u + extra; i++) {
        hx_sck(1);
        hx_wait_us(2);                  /* единица на SCK — не дольше 60 мкс, иначе HX711 уснёт */
        if (i < 24u)
            raw = raw << 1 | (uint32_t)hx_dout();
        hx_sck(0);
        hx_wait_us(2);
    }
    HX_UNLOCK();
    *value = hx711_sign(raw);
    return 1;
}

hx_sck, hx_dout и hx_wait_us — три функции платформы: на плате это GPIO и таймер на 1 МГц, на компьютере — модель чипа, которая отвечает на импульсы так же, как сам HX711.


102.3 Знак 24 бит

Отсчёт — 24-битное число в дополнительном коде, и в 32-битную переменную его надо переносить с расширением знака:

int32_t hx711_sign(uint32_t raw)
{
    return (raw & 0x800000u) ? (int32_t)(raw | 0xFF000000u) : (int32_t)raw;
}

0xFFFFFF — это −1, 0x800000 — −8 388 608, 0x7FFFFF — 8 388 607. Без расширения знака тот же −1 превращается в 16 777 215 кодов — при 429,5 кода на грамм это 39 кг на пустых весах.


102.4 Усиление — для следующего отсчёта

Лишние импульсы выбирают усиление не для того отсчёта, который сейчас читается, а для следующего. Модель: код при усилении 128 — −12345. Чтение с просьбой «×64» ещё отдаёт −12345, следующее — −6172, уже при ×64, а после просьбы вернуть ×128 следующий отсчёт снова −12345. Значит, после смены усиления или канала первый отсчёт — от старой настройки, и его выбрасывают.


102.5 Шестьдесят микросекунд

Если на PD_SCK единица держится дольше 60 мкс, HX711 засыпает. В программе это случается само: прерывание приходит, пока SCK в единице, и спад откладывается на время обработчика. Модель: «прерывание» на 80 мкс на десятом импульсе — и вместо −12345 читается −1, а чип уснул. Поэтому пачку импульсов не прерывают:

#define HX_LOCK()   uint32_t hx_pm = __get_PRIMASK(); __disable_irq()
#define HX_UNLOCK() __set_PRIMASK(hx_pm)

С запретом прерываний то же «прерывание» ждёт конца пачки, и отсчёт верен: −12345. Пачка короткая — 27 импульсов по 4 мкс, 108 мкс, — и для большинства приборов такая пауза в прерываниях незаметна. PRIMASK сохраняют и восстанавливают, а не просто разрешают прерывания: иначе функция включила бы их и там, где вызывающий их выключил.

HX711: 24 импульса читают отсчёт, лишние — выбирают следующий


102.6 Тара и калибровка

Код моста без нагрузки не ноль, а масштаб у каждого датчика свой. Поэтому весы настраивают дважды: пустые — это тара, с известным грузом — масштаб:

int hx711_average(unsigned n, int32_t *avg)
{
    int64_t sum = 0;
    for (unsigned i = 0; i < n; i++) {
        int32_t v;
        if (!hx711_read(HX_A128, &v))
            return 0;
        sum += v;
    }
    *avg = (int32_t)(sum / (int64_t)n);
    return 1;
}

void scale_calibrate(scale_t *s, int32_t tare, int32_t loaded, int32_t mass_g)
{
    s->offset = tare;
    s->per_kg = (int32_t)((int64_t)(loaded - tare) * 1000 / mass_g);
}

int32_t scale_dg(const scale_t *s, int32_t reading)
{
    return (int32_t)((int64_t)(reading - s->offset) * 10000 / s->per_kg);
}

Модель весов: смещение моста 84 000 кодов, 429,5 кода на грамм, шум ±200 кодов, то есть ±0,47 г на один отсчёт. Тара по 16 отсчётам — 83 973, с грузом 1000 г — 513 528, масштаб — 429 555 кодов на килограмм. Груз 250 г весы показывают как 249,9 г по среднему из 16 отсчётов и 250,1 г по одному. Среднее из 16 отсчётов уменьшает шум вчетверо. Тара уходит с температурой, поэтому обнуляют весы перед взвешиванием, а не один раз при сборке.


102.7 Грабли

Пустые весы показывают 39 кг. 24-битный код без расширения знака: −1 стал 16 777 215.

После смены усиления первый отсчёт «не тот». Усиление действует со следующего отсчёта. Первый выбросить.

Изредка — дикие значения и пауза. Прерывание растянуло единицу на SCK дольше 60 мкс, и HX711 уснул. Запрещать прерывания на пачку импульсов.

После остановки в отладчике весы молчат. Программа встала, пока SCK был в единице, — чип спит. Опустить SCK и дождаться готовности.

Вес ползёт. Тара уходит с температурой. Обнулять перед взвешиванием, дать датчику прогреться.


102.8 Итоги

Дальше: раздел 103 «Свет и газ: фоторезистор, BH1750, MQ» — делитель с фоторезистором, цифровой датчик освещённости и газовые датчики с нагревателем.

Открыть в интерактивном справочнике