STM32 з нуля без HAL: Місяць 4, Тиждень 4: Ultrasonic HC-SR04, один рядок −517 і драйвер з нуля. Частина 14

Місяць 4, Тиждень 4. Ultrasonic HC-SR04 як /dev/hcsr04. Але насправді ця стаття не про датчик, а про болі, які виникають коли впираєшся в обмеження досвіду, а тут ще й ця еволюцію Linux Driver Model — і твої приклади з книжок, та інтернету це вже legacy, які не працюють на ядрі 2026 року.

◆ План, який здавався простим

Задача виглядала як класична пригода на вечір: узяти пляшку пива ультразвуковий далекомір HC-SR04, під’єднати два GPIO, зробити символьний пристрій /dev/hcsr04, і щоб cat виводив диистанцію в сантиметрах.

Userspace
    │  cat /dev/hcsr04
    ▼
  read()
    │
    ▼
Trigger GPIO ──► HC-SR04 ──► Echo GPIO
                                 │
                                 ▼
                       Відстань у сантиметрах

Сам алгоритм вимірювання — тривіальний:

  1. сформувати 10 мкс імпульс на Trigger;
  2. дочекатися фронту Echo;
  3. виміряти скільки Echo тримається у HIGH;
  4. поділити тривалість (мкс) на 58;
  5. повернути сантиметри.

Формула distance_cm = duration_us / 58 — це швидкість звуку (~343 м/с) з поправкою на те, що сигнал іде туди й назад. Класика, ардуінщика HC-SR04, що робиться 5 хвилин. Я взяв рівно той підхід, що демонструють сотні туторіалів — legacy GPIO API:

gpio_request();
gpio_direction_output();
gpio_direction_input();
gpio_get_value();
gpio_set_value();

І тут почались ні не гулі, а справжні болі. та давайте йти послідовно і спочатку підключимо залізо. Класичний HC-SR04: echo видає 5V, а Pi може витрамати 3.3V. Я не пробував та пишуть, що якщо подати echo напряму на GPIO то згорить пін. Тому на echo тре обовʼязковий дільник напруги. Trigger же на Pi видає 3.3V, сенсору цього досить, має бути все нормально.

◆ Перший запуск: компілюється чисто, але одразу падає

Збірка проходить без єдиного warning’а:

make
sudo insmod hcsr04.ko
insmod<!--TgQPHd||[]--> (від англ. insert module) — це стандартна команда Linux, яка використовується для ручного завантаження окремого модуля безпосередньо в ядро операційної системи. На відміну від більш розумної команди modprobe<!--TgQPHd||[]-->, insmod<!--TgQPHd||[]--> потребує точного шляху до файлу модуля (із розширенням .ko<!--TgQPHd||[]-->) та не завантажує інші модулі, від яких він залежить.

А insmod одразу викидає такі коні:

insmod: ERROR: could not insert module hcsr04.ko: Unknown error 517
Утиліта dmesg (від англ. diagnostic message) у Linux — це потужний інструмент для перегляду та керування кільцевим буфером повідомлень ядра. Вона дозволяє відстежувати процеси завантаження системи, ініціалізації драйверів та виявляти апаратні або системні помилки.

І в dmesg:

hcsr04: loading out-of-tree module taints kernel.
hcsr04: gpio_request(23) failed

Ніяких пояснень. Просто «failed» і загадкове число 517. Цікаво що про це число скаже Соломія мій бот нумеролог.

У нумерології число 517 є потужним символом особистісної свободи, духовного пробудження та позитивних життєвих змін. Воно поєднує енергію трьох цифр:
  • 5 — відповідає за зміни, пригоди та адаптивність.
  • 1 — символізує нові починання, лідерство та створення власної реальності.
  • 7 — уособлює духовність, мудрість та глибокий самоаналіз.

Сума цих цифр (5 + 1 + 7 = 13, а 1 + 3 = 4) зводить число 517 до вібрації четвірки, яка додає енергію стабільності, працездатності та побудови міцного фундаменту. Якщо ви часто бачите 517, це знак від Всесвіту (або ваших ангелів-охоронців), що ваші нещодавні рішення були правильними, і вас чекає період духовного зростання. Ангели постійно показуватимуть вам число 517, коли захочуть привернути вашу увагу. Вони дуже цікавляться вашим життям. Тому не турбуйтеся про речі, які ви не можете контролювати. Нехай з ними розуміються ваші ангели. Зосередьтеся на тому, в чому ви найкраще знаєтеся. Ангели допоможуть вам процвітати незалежно від поточної ситуації.

Отакої, якось вже не дуже мені весело, невже це знак покинути і йти займатись тим на чому я найкраще знаюсь? Піду заварю чаю.

◆ Перша (хибна) гіпотеза: пін зайнятий

Найлогічніше припущення — GPIO вже кимось захоплений. Перевіряємо:

gpioinfo | grep "input" | grep -v "consumer" | head -10

    line   0:   "ID_SDA"            input
    line   1:   "ID_SCL"            input
    line   2:   "GPIO2"             input
    line   3:   "GPIO3"             input
    line   4:   "GPIO4"             input
    line   5:   "GPIO5"             input
    ...

Лінії вільні. Жодного consumer. Жодного конфлікту. Далі я зробив те, за що мені соромно: почав перебирати піни. GPIO4/5 — failed. GPIO16/17 — failed. GPIO23/24 — failed. Витратив години, міняючи номери в коді, ловлячи то -517, то -16, і не розуміючи чому навіть явно вільні відповідно доgpioinfo піни не беруться.

✏️ Видно ангели дуже серйозно мною зацікавились. Мабуть кажуть мені, друже не займайся херньою йди зроби щось корисне, можеш в кімнаті поприбиратись

Як з’ясувалось пізніше, видно ресурс чисел в ангелів закінчився), проблема була не в тому, які піни. Проблема була в тому, що я читав -517 як «зайнято», а воно ж то означає зовсім інше.

◆ Що насправді означає -517

Помилка Unknown error 517 (або —517 у системних логах) у Linux — це код EPROBE_DEFER<!--TgQPHd||[]-->. Вона означає, що драйвер пристрою або модуль ядра намагається завантажитись, але потрібний йому базовий компонент (наприклад, шина або контролер) ще не ініціалізовано системою. Ядро автоматично перенесе завантаження на пізніше, коли залежність буде готова.

Розшифровка коду:

-517 = EPROBE_DEFER

Це не «зайнято». Це ядро буквально каже:

«Я ще не готове віддати тобі цей ресурс. Повернись пізніше.»

І ось де захована пастка. Legacy-драйвер вантажиться через module_init(), а module_init() викликається рівно один раз:

module_init()
      │
      ▼
gpio_request()  ──►  EPROBE_DEFER (-517)
      │
      ▼
insmod завершується з помилкою

«Пізніше» вже ніколи не настане, краще вже не буде, бо, як зясувалось немає механізму, який би повторив спробу. Драйвер, побудований на голому module_init + gpio_request, на сучасному ядрі приречений — і жоден вибір піна цього не виправить. ⚠ Ключове усвідомлення: тре змінювати не код, тре змінювати себе, бо Ангели вже прям кричать про це).

◆ Як Linux хоче, щоб це робилось у 2026

Колись драйвер міг просто запопросити GPIO по номеру. А от сучасний Linux вимагає іншу модель — з відкладеним, керованим ядром стартом:

Device Tree          ← описує, який пристрій існує і на яких пінах
      │
      ▼
Platform Device      ← ядро створює пристрій з опису DT
      │
      ▼
Platform Driver      ← probe() викликається КОЛИ ресурс готовий
      │
      ▼
GPIO Descriptor      ← devm_gpiod_get(), без номерів

Драйвер більше не повинен знати, що таке «GPIO23». Він просить лінію на ім’я — trig, echo — а ядро само вирішує, коли вона готова. Якщо не готова зараз — ядро само викличе probe() пізніше. Той самий EPROBE_DEFER, але тепер він працює на нас, а не проти.

◆ Переписуємо: platform_driver + Device Tree + gpiod

Сумно. Мені завжди трохи сумно, коли тре щось видаляти. Прибираємо gpio_request, переходимо на gpiod, пишемо власний Device Tree overlay, і оформлюємо модуль як platform_driver.

Device Tree overlay

Тепер піни живуть не в C-коді, а в описі заліза:

// hcsr04-overlay.dts

/dts-v1/;
/plugin/;

/ {
    compatible = "brcm,bcm2835";

    fragment@0 {
        target-path = "/";
        __overlay__ {
            hcsr04: hcsr04 {
                compatible = "alex,hcsr04";
                trig-gpios = <&gpio 23 0>;
                echo-gpios = <&gpio 24 0>;
                status = "okay";
            };
        };
    };
};

compatible = "alex,hcsr04" — це «замок», до якого драйвер підбере «ключ». trig-gpios / echo-gpios — імена, які драйвер шукатиме через gpiod.

Драйвер: probe замість module_init

static int hcsr04_probe(struct platform_device *pdev)
{
    struct hcsr04_dev *data;

    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;

    /* беремо лінії за ІМЕНЕМ, не за номером */
    data->trig = devm_gpiod_get(&pdev->dev, "trig", GPIOD_OUT_LOW);
    if (IS_ERR(data->trig))
        return PTR_ERR(data->trig);

    data->echo = devm_gpiod_get(&pdev->dev, "echo", GPIOD_IN);
    if (IS_ERR(data->echo))
        return PTR_ERR(data->echo);

    /* ... character device як у статті 13 ... */
}

static const struct of_device_id hcsr04_of_match[] = {
    { .compatible = "alex,hcsr04" },   /* той самий "замок" */
    { }
};
MODULE_DEVICE_TABLE(of, hcsr04_of_match);

static struct platform_driver hcsr04_driver = {
    .probe  = hcsr04_probe,
    .remove = hcsr04_remove,
    .driver = {
        .name = DRIVER_NAME,
        .of_match_table = hcsr04_of_match,
    },
};

module_platform_driver(hcsr04_driver);

Зверни увагу: немає gpio_request, немає номерів пінів, немає ручного module_init. devm_gpiod_get(&pdev->dev, "trig", ...) бере лінію trig, опис якої ядро витягло з overlay. devm_ означає, що ядро само звільнить ресурс при вивантаженні — менше ручного cleanup, менше шансів залишити висіти GPIO.

// hcsr04.c
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/gpio/consumer.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/mutex.h>
#include <linux/ktime.h>
#include <linux/delay.h>
#define DRIVER_NAME "hcsr04"
#define BUFFER_SIZE 32
struct hcsr04_dev {
    struct gpio_desc *trig;
    struct gpio_desc *echo;
    dev_t dev_num;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct mutex lock;
    char buf[BUFFER_SIZE];
    size_t len;
};
static struct hcsr04_dev *hcsr04;
static ssize_t hcsr04_measure(struct hcsr04_dev *data)
{
    int timeout;
    u64 start_us, end_us, duration_us;
    long distance_cm;
    gpiod_set_value(data->trig, 0);
    udelay(2);
    gpiod_set_value(data->trig, 1);
    udelay(10);
    gpiod_set_value(data->trig, 0);
    timeout = 100000;
    while (!gpiod_get_value(data->echo) && timeout-- > 0)
        cpu_relax();
    if (timeout <= 0)
        return snprintf(data->buf, BUFFER_SIZE, "timeout rising\n");
    start_us = ktime_to_us(ktime_get());
    timeout = 100000;
    while (gpiod_get_value(data->echo) && timeout-- > 0)
        cpu_relax();
    if (timeout <= 0)
        return snprintf(data->buf, BUFFER_SIZE, "timeout falling\n");
    end_us = ktime_to_us(ktime_get());
    duration_us = end_us - start_us;
    distance_cm = duration_us / 58;
    if (distance_cm < 2 || distance_cm > 400)
        return snprintf(data->buf, BUFFER_SIZE, "error %ld\n", distance_cm);
    return snprintf(data->buf, BUFFER_SIZE, "%ld\n", distance_cm);
}
static ssize_t hcsr04_read(struct file *filp, char __user *ubuf,
               size_t count, loff_t *ppos)
{
    ssize_t ret;
    struct hcsr04_dev *data = filp->private_data;
    mutex_lock(&data->lock);
    ret = hcsr04_measure(data);
    if (ret < 0) {
        mutex_unlock(&data->lock);
        return ret;
    }
    data->len = ret;
    if (*ppos >= data->len) {
        mutex_unlock(&data->lock);
        return 0;
    }
    count = min(count, data->len - (size_t)*ppos);
    if (copy_to_user(ubuf, data->buf + *ppos, count)) {
        mutex_unlock(&data->lock);
        return -EFAULT;
    }
    *ppos += count;
    mutex_unlock(&data->lock);
    return count;
}
static int hcsr04_open(struct inode *inode, struct file *filp)
{
    filp->private_data = hcsr04;
    return 0;
}
static const struct file_operations hcsr04_fops = {
    .owner = THIS_MODULE,
    .open = hcsr04_open,
    .read = hcsr04_read,
};
static int hcsr04_probe(struct platform_device *pdev)
{
    int ret;
    struct hcsr04_dev *data;
    dev_info(&pdev->dev, "probe\n");
    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;
    mutex_init(&data->lock);
    data->trig = devm_gpiod_get(&pdev->dev, "trig", GPIOD_OUT_LOW);
    if (IS_ERR(data->trig)) {
        ret = PTR_ERR(data->trig);
        dev_err(&pdev->dev, "failed to get trig gpio: %d\n", ret);
        return ret;
    }
    data->echo = devm_gpiod_get(&pdev->dev, "echo", GPIOD_IN);
    if (IS_ERR(data->echo)) {
        ret = PTR_ERR(data->echo);
        dev_err(&pdev->dev, "failed to get echo gpio: %d\n", ret);
        return ret;
    }
    ret = alloc_chrdev_region(&data->dev_num, 0, 1, DRIVER_NAME);
    if (ret)
        return ret;
    cdev_init(&data->cdev, &hcsr04_fops);
    data->cdev.owner = THIS_MODULE;
    ret = cdev_add(&data->cdev, data->dev_num, 1);
    if (ret)
        goto err_unregister;
    data->class = class_create(DRIVER_NAME);
    if (IS_ERR(data->class)) {
        ret = PTR_ERR(data->class);
        goto err_cdev;
    }
    data->device = device_create(data->class, NULL, data->dev_num, NULL, DRIVER_NAME);
    if (IS_ERR(data->device)) {
        ret = PTR_ERR(data->device);
        goto err_class;
    }
    platform_set_drvdata(pdev, data);
    hcsr04 = data;
    dev_info(&pdev->dev, "/dev/%s ready\n", DRIVER_NAME);
    return 0;
err_class:
    class_destroy(data->class);
err_cdev:
    cdev_del(&data->cdev);
err_unregister:
    unregister_chrdev_region(data->dev_num, 1);
    return ret;
}
static void hcsr04_remove(struct platform_device *pdev)
{
    struct hcsr04_dev *data = platform_get_drvdata(pdev);
    device_destroy(data->class, data->dev_num);
    class_destroy(data->class);
    cdev_del(&data->cdev);
    unregister_chrdev_region(data->dev_num, 1);
    dev_info(&pdev->dev, "removed\n");
}
static const struct of_device_id hcsr04_of_match[] = {
    { .compatible = "alex,hcsr04" },
    { }
};
MODULE_DEVICE_TABLE(of, hcsr04_of_match);
static struct platform_driver hcsr04_driver = {
    .probe = hcsr04_probe,
    .remove = hcsr04_remove,
    .driver = {
        .name = DRIVER_NAME,
        .of_match_table = hcsr04_of_match,
    },
};
module_platform_driver(hcsr04_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alex");
MODULE_DESCRIPTION("HC-SR04 platform driver with gpiod");
MODULE_VERSION("0.3");

Makefile: збираємо і модуль, і overlay

obj-m += hcsr04.o

KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
    make -C $(KDIR) M=$(PWD) modules
    dtc -@ -I dts -O dtb -o hcsr04.dtbo hcsr04-overlay.dts

clean:
    make -C $(KDIR) M=$(PWD) clean
    rm -f hcsr04.dtbo

⚠ Прапорець -@ у dtc критичний — він додає symbols в overlay, без нього посилання &gpio не зарезолвиться. Легко пропустити й потім не розуміти, чому overlay не вантажиться.

◆ Складання і встановлення

which dtc || sudo apt install device-tree-compiler
make clean
make
ls -la hcsr04.ko hcsr04.dtbo

-rw-rw-r-- 1 alex alex   536 Jul  6 17:28 hcsr04.dtbo
-rw-rw-r-- 1 alex alex 14808 Jul  6 17:28 hcsr04.ko

Обидва файли на місці. Кладемо overlay і прописуємо його в конфіг завантажувача:

sudo cp hcsr04.dtbo /boot/firmware/overlays/
echo "dtoverlay=hcsr04" | sudo tee -a /boot/firmware/config.txt
sudo reboot
⚠ Шлях /boot/firmware/overlays/ — це Raspberry Pi OS Bookworm. На старіших версіях це /boot/overlays/. Перевір свій:
ls /boot/firmware/overlays/ >/dev/null 2>&1 && echo "→ /boot/firmware/" \
  || ls /boot/overlays/ >/dev/null 2>&1 && echo "→ /boot/"

Як видно мій результат → /boot/firmware/ чітко підтверджує, що на малинці встановлена нова версія операційної системи (Raspberry Pi OS Bookworm або новіша).

Розділ boot змонтовано саме в /boot/firmware/, тому якщо знадобиться вручну правити конфігураційний файл (наприклад, увімкнути якийсь екран чи апаратний модуль), шукатииму файл config.txt саме там: sudo nano /boot/firmware/config.txt

◆ Момент істини

Після перезавантаження перевіряємо, що overlay створив пристрій, і вантажимо модуль:

ls /proc/device-tree/hcsr04/ 2>/dev/null && echo "overlay OK"
sudo insmod hcsr04.ko
dmesg | tail -5

compatible  echo-gpios  name  phandle  status  trig-gpios
overlay OK
[  431.943354] hcsr04: loading out-of-tree module taints kernel.
[  431.944496] hcsr04 hcsr04: probe
[  431.944845] hcsr04 hcsr04: /dev/hcsr04 ready

Ось воно. probe. /dev/hcsr04 ready. Жодного -517.

Важливо тут те, що тепер ядро само викликає мій probe() — тоді, коли Device Tree буде готовий віддати GPIO. Модель драйвера тепер архітектурно правильною для сучасного ядра. І перший вимір:

cat /dev/hcsr04

16

Ще раз — 18. Ще — 17. Датчик міряє. Працює.

◆ Опису анального програмного болю у всій красі

Софт запрацював, але поки я доводив систему до стабільних замірів, назбирався цілий букет гемору пасток. Кожна виглядала як «GPIO не доступно» або «не працює» і все це мало свою окрему причину. Ось ці причини.

Ґуля № 1: залишений gpiomon тримає лінію → -16 EBUSY

У нумерології число 16 символізує духовний розвиток, трансформацію та пошук балансу. Оскільки сума цифр (1+6=7) дорівнює 7, воно поєднує лідерство одиниці, турботу шістки та глибоку мудрість сімки. В ангельській нумерології число 16 (і його подвоєння 16:16 на годиннику) — це потужне послання від Всесвіту, яке закликає вас переглянути свої пріоритети, відпустити минуле і знайти баланс між матеріальним та духовним

Під час діагностики я запустив gpiomon у фоні (&), щоб подивитись фронти Echo. Потім вивантажив модуль, перезавантажив — і:

hcsr04 hcsr04: probe
hcsr04 hcsr04: failed to get echo gpio: -16
hcsr04 hcsr04: probe with driver hcsr04 failed with error -16

-16 = EBUSY. Але probe цього разу викликався (бачимо в dmesg)! Ресурс реально зайнятий — моїм же фоновим gpiomon, який досі тримав GPIO24. Зверни увагу: помилка інша — -16 EBUSY, а не -517 EPROBE_DEFER. Обидві виглядають як «не можу взяти GPIO», але причини протилежні: -517 = «ще не готове, спробую пізніше», -16 = «зайнято прямо зараз».

Комбінація 16 і 517 — це сильний ангельський знак, який символізує злам старого життя та сприятливі зміни. Всесвіт закликає вас відпустити застарілі страхи або рутини і довіритися новим можливостям, які прийдуть завдяки вашому оптимізму та правильному вибору.

Лікуємо — вбиваючи фонові процеси:

sudo pkill gpiomon
sudo pkill gpioset
ps aux | grep -E "gpiomon|gpioset" | grep -v grep

Ґуля № 2: Permission denied — та сама, що з /dev/mydev

Модуль завантажений, /dev/hcsr04 існує, а cat без sudo:

cat: /dev/hcsr04: Permission denied

device_create створює вузол з правами 0600 — тільки root. Точно як у статті Місяць 4, Тиждень 3: пишемо /dev/mydev — character device driver. Частина 13. Рішення те саме — udev rule:

echo 'KERNEL=="hcsr04", MODE="0666"' | sudo tee /etc/udev/rules.d/99-hcsr04.rules
sudo udevadm control --reload-rules
sudo rmmod hcsr04 && sudo insmod hcsr04.ko
ls -la /dev/hcsr04

Після цього crw-rw-rw- і cat без sudo працює.

Ґуля № 3: читаємо throttled=0x50000 як бітову маску

У логах раз по раз блимав Undervoltage detected!. Тре брати блок живлення від 2А. Замінив блок живлення, перевіряю

vcgencmd get_throttled

throttled=0x50000

Це бітова маска. 0x50000 = біти 16 і 18. Обидва в старшій половині (біти 16+) — а це означає «траплялось у минулому», не «активне зараз»:

БітЗначенняЩо означає
0 (0x1)undervoltage заразактивна проблема
1 (0x2)throttling заразактивна проблема
16 (0x10000)undervoltage траплявсяісторія
18 (0x40000)throttling траплявсяісторія

0x50000 = біти 16+18, тобто вже залиишки. Жодного біта 0–3зараз живлення чисте. Undervoltage був на старому блоці живлення, до того як я його поміняв.

Ґуля № 4: стрибки значень і timeout falling — Linux не real-time

Запускаю цикл замірів:

while true; do
    printf "\rDistance: %3s cm" "$(cat /dev/hcsr04)"
    sleep 0.1
done

Здебільшого рівні числа — 37, 36, 118, 120, 115. Але подекуди зриви: то timeout falling, то дичина 666, 719. І це не баг коду. Це фундамент. Моя polling-версія крутить cpu_relax() у циклі й міряє час через ktime_get(). Планувальник Linux може перервати цей цикл будь-коли — і тоді виміряний інтервал розтягується, даючи фальшиво велике значення. Linux не гарантує таймінг на рівні мікросекунд. Ось той самий контраст, що тягнеться крізь усю серію: на bare-metal STM32 з апаратним input capture ці ж кілька мікросекунд ловились би таймером точно, без участі планувальника. На Linux — ні. Не тому що Linux гірший, а тому що в нього інша задача: він керує сотнею процесів, а не одним датчиком.

◆ Цікава деталь: після reboot пристрій «зникає»

Ще один момент, який спершу лякає. Після перезавантаження Pi:

cat: /dev/hcsr04: No such file or directory

Здається, драйвер «зламався». Насправді ні. Device Tree overlay лише повідомляє ядру про існування пристрою. Сам модуль треба або завантажити вручну (insmod), або встановити в систему, щоб він підхоплювався автоматично:

sudo cp hcsr04.ko /lib/modules/$(uname -r)/extra/
sudo depmod
echo hcsr04 | sudo tee /etc/modules-load.d/hcsr04.conf

Тоді після кожного завантаження overlay створить пристрій, а modules-load підтягне драйвер, і /dev/hcsr04 з’явиться сам.

◆ Висновок

Найцінніший результат цієї статті, як на мене це ангельська нумерологія, хоча може і розуміння того, що більшість навчальних прикладів застарілі, теж цінно, але ж одна помилка. як ми з’ясували -517 виявилась не багом, а ангельською підказкою:

«Не борись із Driver Model. Працюй разом із нею.»

Попереду Місяць 5 — FreeRTOS на STM32. Далі буде...

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось9
До обраногоВ обраному5
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Попереду Місяць 5 — FreeRTOS на STM32

буде з кубом чи без?

Без, буду пробувати на HAl робити

І тут почались ні не гулі, а справжні болі. та давайте йти послідовно і спочатку підключимо залізо. Класичний HC-SR04: echo видає 5V, а Pi може витрамати 3.3V. Я не пробував та пишуть, що якщо подати echo напряму на GPIO то згорить пін. Тому на echo тре обовʼязковий дільник напруги. Trigger же на Pi видає 3.3V, сенсору цього досить, має бути все нормально.

«правильна» схема із діодом, а не на резисторах

дочитав поки що до

Сам алгоритм вимірювання — тривіальний:

сформувати 10 мкс імпульс на Trigger;
дочекатися фронту Echo;
виміряти скільки Echo тримається у HIGH;
поділити тривалість (мкс) на 58;
повернути сантиметри.

ядро ж не RT, як так?

C интересом наблюдаю приключения автора. Но если честно, слишком много пафоса, вставок о нумерологии, словно автор взял на себя роль шута и пробует смешить читателя. Также вставки в духе: «TODO: вставь сюда то-то» говорят о том, что автору лень вычитывать статью после ИИшечке

Спасибо за статью и удачи в развитии. Но очень бы хотелось видеть меньше вставок в дузе «шутка за 300»

Прийнято. Стосовно нумерології, дійсно тим цікавлюсь. Ну а судічи з вашого коментаря, хіба вони не праві? Тре йти і займатись тим що дійсно виходить і не брати на себя «роль шута». Та не можу з тим нічого зробити, такий мій стиль, якщо мені сумно я додаю суму, якщо весело пробую жартувати, хай і невдало. Мої опуси це пригода, а не технічні мануали

Якби ж то тільки знати чим

Підписатись на коментарі