ну как раз про много речь и была. пока накидаешь нормальную прогу, можно и на пенсию выходить.
Режим всех пинов 0-31 (ввод-вывод) можно включать общим регистром на 32 бита. А тонкая настройка - подтяжки и альтернативные функции - на каждый пин свой регистр. Это общий подход, у большинства других контроллеров также, есп не одинок.
Все-таки смена тонких настроек - штучная операция, перевод кучи пинов в режим , например, СПИ, разом не делается ![]()
ну как общий, на старых мк это делается за один такт для всего порта. например, надо прочесть за раз 16 бит данных с какой-то параллельной шины (с того же плис или памяти какой…), не имея никакой подтяжки, кроме этой самой внутренней. получается включаем на вход одной командой, а резисторы еще 16 команд за ней. На осциллографе будет ступенчатая картника. Тут причина не в тонкой настройке, а этом самом MUX, который умеет перебрасывать пины, потому для каждого пина свой настроечный регистр.
Режим чтения с подтяжкой включить заранее?
И потом читать пины параллельно (хоть все 32 ) можно за один раз, как и на старых МК
это да, но по этой же шине нужно и записывать. в общем, для таких задач есп не подходит и я такие штуки на нем даже не буду пытаться строить.
ИМХО, момент переключения такой шины с приема на передачу обычно совсем не “моментальный”, можно и побитно.
я, честно, ЕСП вообще не знаю, для чего он подходит - подтвердить или опровергнуть не могу.
Но что могу сказать - для таких веще отлично подходят ПИО-машины в РП2040/2350 ![]()
да, но тут уже вступает человеческий фактор, когда смотришь на такой прибор, вроде как и рабочий, но на самом деле знаешь что там пулапы шаг за шагом включаются, уже начинает коробить. ))) (мы ж не цап строим)
Плюс только один - вифи и блупуп, в остальном это тот-же рп2040, только без пио.
вот пио это вещь, пусть и скорость ниже, пусть без вифи, но зато всратой операционки не надо, от которой в есп нельзя отказаться.
Какая красивая штука!
Да, именно в этом и заключается главная прелесть Forth. Вы можете запустить отправку UDP-пакетов в фоновом режиме, и консоль (REPL) останется полностью доступной для интерактивной работы.
В ESP32forth встроен кооперативный многозадачник (multitasker). Чтобы перевести программу в фоновый режим, нужно объявить задачу (task), связать её с кодом и использовать слово pause внутри цикла. Слово pause временно передает управление консоли и другим задачам. [1]
Ниже обновленный код. Вставьте его целиком в консоль:
\ --- Настройки сети (замените на свои) ---
z" Твоя_Имя_Сети_WiFi" constant MY_SSID
z" Твой_Пароль_WiFi" constant MY_PASS
44444 constant UDP_PORT
z" 255.255.255.255" constant BROADCAST_IP
WiFiUDP new constant my_udp
\ Переменная-флаг для управления циклом из консоли
variable udp-run
1 udp-run ! \ по умолчанию включено
\ Подключение к Wi-Fi (однократное при старте)
: connect-wifi
MY_SSID MY_PASS WiFi.begin
begin WiFi.status 3 = not while 500 ms repeat
;
\ Функция отправки одного пакета
: send-broadcast { message_str -- }
BROADCAST_IP UDP_PORT my_udp .beginPacket drop
message_str my_udp .print drop
my_udp .endPacket drop
;
\ --- Код фонового процесса ---
: udp-background-worker
connect-wifi
begin
udp-run @ if
z" Background Hello from ESP32 Forth!" send-broadcast
then
\ КРИТИЧЕСКИ ВАЖНО:
\ Используем 2000 ms, так как в ESP32forth слово 'ms'
\ автоматически вызывает внутри себя 'pause' для многозадачности!
2000 ms
again
;
\ --- Создание и запуск фоновой задачи ---
\ Выделяем память под задачу (стеки данных и возвратов)
0 0 0 task udp_task
: start-udp-bg
\ Привязываем слово udp-background-worker к задаче udp_task
['] udp-background-worker udp_task construct
\ Запускаем задачу в фоновое исполнение
udp_task start-task
cr ." UDP broadcast background task started!" cr
;
Как теперь этим управлять прямо из консоли:
- Запуск фона:
Введите командуstart-udp-bg. Пакеты начнут уходить в сеть, но консоль мгновенно вернет вам ответokи продолжит принимать команды. - Проверка работоспособности:
Пока плата шлет UDP в фоне, вы можете вводить любые команды, например:2 2 + .(выведет 4)v.words(покажет список доступных слов)
- Приостановка отправки:
Вы можете на лету поменять переменную флага:0 udp-run !— отправка UDP прекратится, но задача продолжит «дышать» в фоне.1 udp-run !— отправка возобновится.
Примечание: Если вы захотите посмотреть список всех запущенных задач, в ESP32forth можно ввести команду .tasks. [2]
Хотите ли вы, чтобы этот скрипт автоматически запускался в фоне каждый раз при включении или перезагрузке ESP32 (без необходимости вводить команду вручную)?
Я могу подсказать, как записать этот код в энергонезависимый файл автозапуска autoexec.fs внутри платы. [3]
Наличие FreeRTOS - главное достоинство ESP32 и семейства, конкурентное преимущество даже. Поэтому это МК №1 в IoT. Даже выбор платформы не испортил репутацию этих МК.
Ты начинаешь походить на NMi с ассемблером, о котором он пишет ни хрена не понимая ![]()
Также и ты про контроллер, надеюсь ошибиться.
В надежде, что не нарвусь на демагогию, я прошу показать мне ситуацию, в которой тебе помешало наличие FreeRTOS.
Не, я прямой как угол дома. операционная система - это сторонний программный продукт, который не всегда нужен для поставленной задачи. Все производители выпускают голое железо, хочешь ставь ОС, хочешь нет. Тут же, в силу того, что у них есть вифи, кой собственно под лицензией и контролем, они заранее упаковали этот участок кода в бинарники, чтобы вася типа меня не делал на нем всякие жучки и пульты, и теперь без ос эта хрень не стартует. Вот в стм и рп2040 нет ос, но ее за две минуты можно прикрутить. Или у всех на домашних ПК винда или линукс гвоздями к процессору прибита? Вот из за вифи он и главный в iot, без нее он никому бы не всрался.
и кстати, xtensa тоже не идеал. ща они s31 выпустили на risc-v, посмотрим че умеет.
Примера не будет? Я так и думал. Ок. Удачи!
ниче не понял. какого примера?
Чиво?
![]()
отож, исполнительный код для PIC в 500 байт выливает в текстовик в 30 килобайт
По большей части, да.
PS: Для любителей Rust я всегда предлагаю прстую задачу - “Покажите мне двусвязанный список на Rust”. Тем, кому интересно, как это выглядит (безопасно!!!111 my ass)![]()
use std::cell::RefCell;
use std::rc::{Rc, Weak};
type Link<T> = Option<Rc<RefCell<Node<T>>>>;
type Prev<T> = Option<Weak<RefCell<Node<T>>>>;
struct Node<T> {
value: T,
prev: Prev<T>,
next: Link<T>,
}
pub struct LinkedList<T> {
head: Link<T>,
tail: Link<T>,
len: usize,
}
impl<T> LinkedList<T> {
pub fn new() -> Self {
Self {
head: None,
tail: None,
len: 0,
}
}
pub fn push_front(&mut self, value: T) {
let node = Rc::new(RefCell::new(Node {
value,
prev: None,
next: self.head.clone(),
}));
match self.head.take() {
Some(old_head) => {
old_head.borrow_mut().prev = Some(Rc::downgrade(&node));
self.head = Some(node);
}
None => {
self.tail = Some(node.clone());
self.head = Some(node);
}
}
self.len += 1;
}
pub fn push_back(&mut self, value: T) {
let node = Rc::new(RefCell::new(Node {
value,
prev: self.tail.as_ref().map(Rc::downgrade),
next: None,
}));
match self.tail.take() {
Some(old_tail) => {
old_tail.borrow_mut().next = Some(node.clone());
self.tail = Some(node);
}
None => {
self.head = Some(node.clone());
self.tail = Some(node);
}
}
self.len += 1;
}
pub fn remove(&mut self, node: &Rc<RefCell<Node<T>>>) {
let prev = node.borrow().prev.clone();
let next = node.borrow().next.clone();
match prev.as_ref().and_then(Weak::upgrade) {
Some(prev) => {
prev.borrow_mut().next = next.clone();
}
None => {
self.head = next.clone();
}
}
match next {
Some(next) => {
next.borrow_mut().prev = prev;
}
None => {
self.tail = prev.and_then(|p| p.upgrade());
}
}
self.len -= 1;
}
pub fn len(&self) -> usize {
self.len
}
}
Неохота спросонья разбираться в коде, не скажете кратко, словами, что там не так со списком на расте?
Сложность и непонятность кода.
а потом тоже самое на АСМе