Ви не увійшли.
Основною фішкою рінгбуфера (якщо не псувати "оптимізаціями" стандартну реалізацію) є можливість виконувати запис і читання в двох окремих потоках без будь-яких синхронізацій між ними.
Здається, спосіб організації контейнера та властивість lock-free — ортогональні поняття. Хіба що в рінгбуфері lock-free досягається відносно просто за рахунок правильного порядку операцій. А синхронізація присутня в будь-якому разі, просто в lock-free вона без блокувань, за рахунок атомарності деяких операцій і впорядкування доступу до памʼяті, що в більшості архітектур реалізовано апаратно.
Якщо цікаво, примітивний варіант реалізації ring buffer фіксованого розміру з моєї відповіді на StackOverflow:
template <typename T>
class ring
{
T *data;
std::size_t size;
std::size_t front { 0 };
std::size_t back { 0 };
bool full { false };
public:
ring(std::size_t _size) : data{new T[_size]}, size{ _size } {}
~ring() {
delete [](data);
}
bool enqueue(T value) {
if (full) {
return false;
}
data[back] = value;
back = (back + 1) % size;
if (back == front) {
full = true;
}
return true;
}
T dequeue() {
if ((front == back) && !full) {
return {};
}
full = false;
std::size_t old_front = front;
front = (front + 1) % size;
return data[old_front];
}
};
Ініціалізацію з initializer_list та інший синтаксичний цукор за бажанням прикрутити не складе труднощів.
Імовірність перестановки в початку і в кінці масиву відрізняється.
Не відрізняється.
Ймовірність, що 0-й елемент залишиться на своєму місці: 1/N.
Ймовірність, що 1-й елемент залишиться на своєму місці після першого кроку: (N-1)/N, на другому кроці: 1/(N-1).
Тобто після двох кроків його шанс залишитись на своєму місці: ((N-1)/N) * (1/(N-1) = 1/N.
Для 2-го елемента ймовірність залишитить на своєму місці після 1-го кроку: (N-1)/N, після другого кроку: (N-2)/(N-1), на третьому кроці: 1/(N-2). Після всіх трьох кроків: ((N-1)/N) * ((N-2)/(N-1)) * (1/(N-2)) = 1/N.
Далі за індукцією.
Якщо не довіряєте аналітичним методам, можете самі написати програмку та прогнати результати через статистичні тести.
Так що непогано було б прогнати цикл перестановок N раз, із зсувом масиву на 1 позицію.
І що це дасть?
Але краще старатися робити красиво; як попало воно само вийде
Саме так. Тільки "молоді та амбітні" не хотять красиво, хотять "%#як-%#як, і в продакшн".
У цьому алгоритмі, мені здається, є недолік. Деякі перестановки можуть не спрацювати, тому що j може виявитись рівним i.
Випадкова перестановка на те і випадкова, що елемент може залишитись на своєму місці з ймовірністю 1/N.
Он в Енігмі, наприклад, вхідна літера теж ніколи не транслювалась сама в себе
Можна придумати таку ідею
Такий алгоритм теж існує. Тільки він вимагає, щоб допоміжні елементи були унікальними, інакше розподіл вже не буде випадковим. А генерація випадкових унікальних елементів потребує випадкової перестановки
Недолік - потрібно в 2 рази більше пам'яті.
І алгоритмічна швидкодія обмежена обраним алгоритмом сортування. Для сортування вставкою найгірший випадок О(n²).
А результат такий самий: елемент також із ймовірністю 1/N може залишитись на своєму місці.
Інша справа, що ардуінівска random(long) реалізована некоректно і не дає рівномірного розподілу. Але якщо не потрібна криптографічна надійність, то для невеликих діапазонів цей ефект не дуже суттєвий.
Чи можете Ви допомогти та зробити приклад?
Оголошуєм константу з розміром масиву та сам масив:
const size_t N = 16;
uint8_t cols[N];
Набираєм ентропію для генерації випадкових чисел. Достатньо один раз на початку, десь в setup():
unsigned long seed = 0;
for (size_t i = 0; i < sizeof(seed)*8; i++) {
seed <<= 1;
seed |= analogRead(10) & 1;
}
randomSeed(seed ? seed : 1);
Заповнюємо масив послідовними значеннями:
for (size_t i = 0; i < N; i++) {
cols[i] = i;
}
і перемішуємо:
for (size_t i = 0; i < N-1; i++) {
size_t j = random(i, N);
auto tmp = cols[i];
cols[i] = cols[j];
cols[j] = tmp;
}
Далі можете послідовно вибирати значення з масиву і робити з ними, що вам там потрібно. Наприклад, вивод в послідовний порт:
Serial.println();
for (auto i : cols) {
Serial.print("X: ");
Serial.print(i % 4);
Serial.print(", Y: ");
Serial.print(i / 4);
Serial.println();
}
Якщо потрібна ще одна випадкова перестановка, можна не заповнювати послідовними значеннями заново, а лише перемішати існуючу.
З електрикою треба бути уважно взагалі. 1 лишній рух - і білий дим, транзистори в чіпі вибирають нового папу
Я більше про проектування схеми, а не про монтаж і техніку безпеки. Була ситуація, коли керуюча схема запускалась і нормально собі працювала без зовнішнього живлення, коли обертали вал колекторного двигуна у зворотній бік, і він працював як генератор.
Тому, щоб отримати корисні поради, потрібно давати більше інформації про проблему.
Якщо там кнопка напряму дає живлення на двигун, то можливо краще замість кнопки поставити ключ на мосфеті або й реле, а кнопкою вже керувати і тим ключем, і тиристорами. Як вже зазначили, ніяке ардуіно там, мабуть, взагалі не потрібне.
29 В - скоріше за все силовуха, скоріше за все двигун. Я за оптронну розв"язку.
З оптроном і двигуном теж треба уважно. При певних умовах його можна заставити спрацьовувати без подачі живлення, просто обертаючи двигун
Можно ли с кнопки на пин кинуть с кнопки один провод, минус в итоге все равно общий ну и при этом как сделать что бы ардуино не сгорел. Спасибо)
Правильно розумію, що кнопка послідовно зі споживачем, "входом" до живлення 29 В, які з "вихода" при натисненні подаються на споживач? Споживач має реактивну складову чи суто активний? Відбуваються якісь перехідні процеси при відпусканні кнопки? Чи допустимий невеликий струм (порядка десятків мікроампер) через споживач у вимкненому стані?
Є різні варіанти, в кожного свої переваги і недоліки, в залежності від схеми підключення вашої кнопки, характеру навантаження та інших вимог. Наприклад:
1) Дільник напруги на резисторах.
2) Діод і резистор.
3) Перетворювач рівня на транзисторі (ймовірно, знадобиться ще стабілітрон).
3.5) Комбінація попередніх.
4) Оптопара.
Так вот вопрос.
Чому відповіддю в іншій темі, а не окремою темою? В "Апаратних питаннях", наприклад.
3 екземпляра на микросхемах от разных прозводителей ведут себя одинаково.
Чудес не буває, скоріш за все проблема в монтажі. Продзвоніть КЗ між входами.
Поставте потенціометр приблизно на середину. Відʼєднайте інвертуючий вхід від зворотнього звʼязку взагалі, закоротіть його на землю. Заміряйте вихід. Підʼєднайте інвертуючий вхід напряму на Vcc, заміряйте вихід.
https://ibb.co/qg2mKCB
Зі схемою наче все ок. Про всяк випадок, другий операційник, що в цьому ж корпусі, встановили у детермінований стан?
Якщо прибрати резистори і вихід подати напряму на інвертуючий вхід, працює як повторювач?
Якщо вимкнути - буде єдина доступна таймзона UTC. Це корисно хіба що для імітації сумусності. Підняти свій сервер - це якийсь аццький оверінжинірінг
Хм, дійсно, здається, там не можна просто захардкодити свою таймзону. Зате і автоапдейт, і NTP, і форматування, і якісь евенти. Хороший приклад, як НЕ треба проектувати бібліотеки
Робоче - це якщо можна взяти файл з iana.org і вкрутити в прошивку.
"Стандартна" Timezone для цього майже підходить.
У файлі континента з архіва IANA знайти діючий на даний момент запис для Zone (UNTIL пустий). Там STDOFF - зміщення відносно UTC, RULES - правила переходу. Знайти діючі на правила у записах Rules (TO==max) і на їх основі створити параметри для обʼєктів TimeChangeRule.
Або компілити таймзони за допомогою zic у бінарний формат, але прийдеться парсити бінарний формат у рантаймі.
Можна і автоматизувати цей процес при збірці прошивки, але як інтегрувати це конкретно в platformio, того вже не знаю.
ezTime мацав, не сподобалось. Це якраз та сама подєлка, зав"язана на якийсь дивний сервер timezoned.rop.nl.
Так то сервер, який використовується автором для підтримання бази на цільових пристроях в актуальному стані. Наскільки бачу, його використання можна вимкнути, прибравши EZTIME_NETWORK_ENABLE. Або підняти свій аналогічний.
Якщо апдейтити прошивку з базою вручну, то для конвертації часу доступу до мережі не потрібно.
І, враховуючи що там не в курсі, що Kiev вже давно Kyiv - бази там не свіжі.
В сучасній базі теж є Kiev, бо зворотня сумісність. Kyiv та Kiev - два файла з однаковим вмістом.
Актуальна база розміщується на https://www.iana.org/time-zones, також доступна по FTP та rsync. Звідти її і потрібно брати.
Хм, наприклад? Всі існуючі рішення кимсь перевірені.
Я більше маю на увазі в загальному. Наприклад, якщо потрібна аутентифікація чи інші повʼязані з криптографією задачі, то вигадувати свій велосипед не те що не варто, а і небезпечно. Наполегливо рекомендується використовувати відкриті реалізації існуючих алгоритмів.
Щодо часових поясів, то самому не було потреби з ними працювати в ардуіноподібних фреймворках. Ось знаходиться Timezone, ezTime.
Знову ж, основна проблема здається не в конвертації локального часу в UTC і навпаки, а в підтримці zoneinfo в актуальному стані.
А щодо автоматичної підтримки літнього часу - цей геморой не вартий тих свічок
Обчислення для поточного часу не дуже складні. Це ж не обчислення, наприклад, періоду між моментами локального часу в минулому, де потрібно враховувати всі зміни, що відбулись за цей період. Основна проблема - це підтримка zoneinfo в актуальному стані.
Як компроміс, можна конвертувати час в UTC засобами браузера при налаштуванні будильника, а сам контроллер працюватиме лише з UTC. Тільки тоді, якщо zoneinfo зміниться, то будильник "не знатиме" про ці зміни до наступного налаштування.
Але звісно, якщо функция не потрібна, то і заморочуватись не варто.
uint8_t tz_offset;
Хе-хе. Тільки що звернув увагу, в західній півкулі нас чекає облом
Саме тому для типових задач рекомендується використовувати існуючі перевірені рішення. Хоча бібліотек ардуіно це не стосується, бо там зустрічається і не таке
Не маю на меті критикувати, технічна творчість - це завжди добре. Респект вам. Але не можу втриматись і не вказати на можливі підводні камені.
Наскільки розумію, вмикання і вимикання здійснюється однією і тією ж командою? Тобто якщо прилад був уже увімкнений, то по настанню часу будильника, навпаки, вимкнеться? А якщо в момент вмикання ІЧ-приймач виявиться засліпленим, то так і залишиться вимкненим? Якщо є можливість додати зворотній звʼязок (який-небудь датчик поточного стану приладу), то ці недоліки можна обійти.
Думав запиляти ще й автоматичне розпізнавання зимового часу
Зимового часу не буває, є стандартний час і літній. Але ж перехід на літній наче скасували? Так що вже мабуть не актуально
взято attiny85 замість ардуіно
Який саме board package використовуєте для attiny85? Ви впевнені, що в ньому піни нумеруються константами з avr/io.h ( pinMode(PB3, INPUT) ) і в той же час ардуінівськими ( pinMode(A1, INPUT) )?
Sketch.rar
Форматування коду навмисно прибране, щоб складніше було читати?
Із назвами змінних Flag, Flag2, Flag3 та значеннями '1' і '2' задуману логіку зрозуміти досить непросто. Намалюйте діаграму переходів між станами, визначте умови переходів. Зробіть enum зі зрозумілими назвами.
pulseIn() повертає unsigned long (діапазон ≈ 0 .. 4295 секунд), ви його присвоюєте в int (діапазон ≈ -33 .. 33 мілісекунди).
Не викликайте millis() кожний раз. Прочитайте значення один раз на ітерацію і використовуйте його:
void loop() {
unsigned long now = millis();
...
timer1 = now;
timer2 = now;
...
Використовуйте SoftwareSerial.available()
Якщо читати посимвольно, то і available() не потрібно.
int c = serial.read();
if (c != -1) {
...
}
У деяких прикладах при роботі з analogRead(A0) використовували delay(10) перед зчитуванням.
Затримка перед читанням ADC мала би сенс після вмикання внутрішнього джерела опорної напруги, щоб воно встигло стабілізуватись. Даташит говорить про час стабілізації 40-70 мікросекунд.
Ардуіно, по-перше, в якості опорної напруги за замовчуванням використовує Vcc; по-друге, конфігурує ADMUX всередині analogRead(). Так що затримка перед analogRead() не має жодного сенсу. Просто зробіть одне читання в setup() та проігноруйте його результат.
Якщо передавач має зчитувати та відправляти дані з певною частотою, то краще вже використовуйте millis().
На приймачі взагалі ніяких затримок не потрібно.
Використання serial.println() потрібно було для контролю, у готовому приладі використовуватись не буде.
Просто майте на увазі, що відправлені в Serial дані хоч і буферизуються, але їх передача з буфера потребує часу. Щоб мінімізувати вплив дебажного вивода на роботу, використовуйте вищий бітрейт, наприклад 115200.
Тип float - під час випробувань приєдннував 1602, простіше(без перетворювання типів змінних) у використанні.
1602 - це алфавітно-цифровий дисплей? Не дуже зрозумілий його звʼязок з float. Ну то таке.
Якщо замінити на delay(100), тоді затримка становить 10 секунд.
Навіщо там взагалі delay()? В 99.9% випадків, якщо в коді delay(), значить щось не так із кодом або алгоритмом в цілому.
Код дуже простий.
Простий не значить правильний.
1. В приймачі ви намагаєтесь читати дані навіть коли їх нема. SofSoftwareSerial::read() при цьому повертає -1.
2. В передавачі затримка між посилками 10мс (+ якийсь час на виконання інших функцій). В приймачі затримка між спробами читання 200 мс. Приймач навіть теоретично не встигатиме читати всі відправлені передавачем дані. Навіщо взагалі в приймачі ця затримка 200 мс?
3. Кожну ітерацію в UART пишеться більше десятка байт ("Zadanie = " плюс саме значення та r). На 9600 бод їх передача займає більше 10 мс. В передавачі з часом внутрішній буфер Serial заповнюється і Serial.print() блокує виконання поки буфер не звільниться.
До проблеми не відноситься, але все ж:
4. Навіщо там використання типу float?
Я би порадив для початку відлагодити комунікацію при безпосередньому TTL-зʼєднанні приймача з передавачем. Тільки після того як все працюватиме правильно, зʼєднувати по RS485.
MAX485 не містить ніякої логіки і буферів. Якщо затримка 20 секунд, але дані таки приходять, то вони десь мають зберігатись. Це явно програмна помилка. Потрібно розуміти, на якій із сторін відбувається ця затримка. Не завадило би подивитись на код приймача і передавача.
Все повинно працювати "іскаропкі". Обираєш свою плату і все
А репозиторій Espressif уже підключений "іскаропкі"? Я не в курсі, може вже й додали.
Контроллер плата ESP8266 boards/LOLIN Wemos D1 & R2 mini.
В File -> Preferences -> Settings -> Additional boards manager URLs додайте
https://arduino.esp8266.com/stable/package_esp8266com_index.json
Далі як звичайно, оберіть плату і порт.
Платка arduino nano rf.
Є схема тієї платки? Як на ній організоване живлення NRF24 чіпа?
При під'єднанні через type-c дуже гріється кристал.
Який саме кристал? Атмега чи NRF24? Чи гріється, коли атмега в ресеті?
Яка версія датчика? Який режим роботи сконфігуровано на платі? Для версії 2.0 описано 3 режими, а для
версії 3.0 цілих пʼять.
Крім того, в режимі UART передається 4 байти: 0xFF, high data, low data і контрольна сума, а ви читаєте тільки два.
Взагалі можна і пасивний без додаткових елементів підключити, але щоб не спалити вихід прийдеться генерувати високочастотні імпульси. З активним набагато простіше з програмної точки зору.