Ви не увійшли.
Або якщо просто додати в масив якийсь перший байт та останній, які не співпадають з основними. А в приймачеві розділити по байтах та брати інформаційні після першого "кодового" і останній для перевірки.
Так проканає?
Serial передає потік даних (stream), сам по собі він безперервний. Ви хочете передавати датаграми, тобто окремі посилки з початком і кінцем.
Є два основних метода:
1. Відокремлювати початок посилки по часу. На передавачі слати дані з певною затримкою між датаграмами (у вас уже є пауза 50 мс). На приймачі, якщо даних не було довше певного періоду, вважати нові дані початком посилки.
2. Відокремлювати початок (та/або кінець) посилки певним маркером. На приймачі сканувати потік на наявність цього маркера. Майте на увазі, що у загальному випадку всередині датаграми також можуть зустрітись дані, які співпадають зі значенням маркера. Щоб уникнути хибної синхронізації бажано додати контрольну суму, хоча б CRC8. При неспівпадінні контрольної суми або маркера кінця посилки не відкидати всі данні, що надійшли, а продовжити сканування з наступного символа після маркера. Правильне рішення цієї задачі не таке просте, як здається на перший погляд.
Кожен метод має свої переваги і недоліки. Можна використовувати і обидва методи одночасно.
А це:
Serial.write(buff[2]);
спроба доступа за межі масива buff. Це невизначена поведінка.
Почитайте основи про масиви в C (у C++ також використовуються C-шні масиви).
https://www.arduino.cc/reference/en/lan … readbytes/:
Serial.readBytes(buffer, length)
Пришвидшити закривання можна просто прибравши резистор із кола затвора. Але тоді зросте струм керування на високих частотах, також може з'явитись "дзвін". Для запобігання цьому і ставлять резистор, а щоб він не впливав на закривання, шунтують його діодом. Також в мостових схемах важливо закривати один транзистор швидше ніж відкривається інший, щоб запобігти наскрізному струму.
А в тій схемі де діод "навпаки", транзистор часом не зворотньої провідності?
Може залежати від різних факторів, у тому числі особливостей виходу схеми управління. Якщо немає необхідності обмежувати струм що втікає у вихід управління, то діод із затвора. Якщо немає необхідності обмежувати струм що витікає з виходу, то навпаки.
Коли транзистор повністю відкритий (у стані насичення), напруга коллектор-еміттер складає приблизно менше одного вольта (залежить від струму і температури), а не 250 вольт.
Але коли ми припаркувались і не виключили задню передачу, а зразу виключили запалення статус передачі зник, нажати кнопку щоб виключити аварійку немає кому
Хм, для вимкнення запалення ключ повертається з положення ON в положення ACC. Можна знімати напругу з лінії, яка підключена тільки в положенні ON, але не в ACC.
dimich пише:Цікавості починаються через 24 або 49 діб, при знаковому або беззнаковому переповненні лічильника,
Ще один адепт секти Свідків Переповнення Великого Міліс?
"якщо код кривий" пропустили? Звісно, при нормально написаному коді переповнення ні до яких збоїв не призводить.
Йде обробка сигналів з кан-шини, потрібно корректно завершити запрограмовані процедури у разі вимикання двигуна.
Цікаво. А нема якихось більш-менш стандартизованих індикаторів роботи двигуна? Наприклад від датчика положення колінвала? Той же OBD-II зчитує оберти, можливо з тієї ж самої CAN. Я не спеціаліст в автоелектроніці, просто розмірковую.
Або "хардварний" сигнал, напруга з генератора чи щось подібне.
Ще обдумую такий вариант
Здається, такий метод буде більш надійним, аніж вимір напруги в мережі.
вообще millis(); очень неудобная функция для 8ми битных микроконтроллеров , мало того что не точная, так еще и занимает кучу времени на обработку 32-х битной математики.
Так вся ця ардуіна - навчальний проект для початківців. Яка там ефективність чи оптимізація...
Що може бути простіше "кількість мілісекунд від початку роботи"? Цікавості починаються через 24 або 49 діб, при знаковому або беззнаковому переповненні лічильника, якщо код кривий
Щодо точності - у них є компенсація лічильника, яка ціла для 8 і 16 МГц, тобто довгострокова точність відповідає кварцу. Але джиттер.
Что мешало разрабам добавить для пользователей глобальный флаг в обработчик прерывания по таймеру0 не понятно...
Хотя это решается включением прерывания по совпадению TIMER0_COMPA_vect .
На AVRках замість флага можна читати молодший байт timer0_overflow_count, якщо трошки похуліганити:
extern volatile unsigned long timer0_overflow_count;
static inline uint8_t overflows() {
return *reinterpret_cast<volatile uint8_t *>(&timer0_overflow_count);
}
Ну а там, де потрібна оптимізація за швидкодією або розміром, то бібліотеці ардуіно взагалі не місце.
спробував також і ваш код і також лед мигає навпаки
![]()
https://wokwi.com/projects/392817187868217345
Так ви позаміняли там затримки і додали ще один стан. То вже не мій код.
case 0: if (now - last_time >= 10) { // LED має світити 2000 мс? вірно? digitalWrite(13, HIGH);
Після старту LED не світить 10 мс, потім вмикається. Навряд чи ви помітите цю затримку в 10 мс після старту.
case 1: if (now - last_time >= 4000) { // LED має не світити 200 мс? вірно? digitalWrite(13, LOW);
Продовжує світитись 4 секунди. Вимикається.
case 2: if (now - last_time >= 1000) { // LED має світити 500 мс? вірно? digitalWrite(13, HIGH);
Через 1 секунду вмикається
case 3: if (now - last_time >= 2000) { // LED має не світити 2000 мс? вірно? digitalWrite(13, LOW); last_time = now; state = 4; // переходим в початковий стан "0" } break;
І через 2 секунди вимикається.
case 4: if (now - last_time >= 2000) { // LED має не світити 2000 мс? вірно? digitalWrite(13, LOW); last_time = now; state = 0; // переходим в початковий стан "0" }
Продовжує бути вимкненим ще 2 секунди.
В станах 0 і 4 світлодіод вимкнено, вони зливаються в один період 2 с 10 мс, коли світлодіод не світить. Паттерн виходить такий:
4 с світить, 1 с не світить, 2 с світить, 2.01 с не світить.
в цьому прикладі точно така ж біла в мене, перший цикл проходить все вірно а потім є блимання лед які зовсім по інтервалу не заявлені в масиві, можливо то глюк цієї віртуалки? чи я десь все ж таки щось не зрозумів?
https://wokwi.com/projects/392819629072839681
dur[state] вказує, скільки триває стан state.
led[state] вказує, яке значення має подаватись на пін світлодіода при переході в наступний, в state+1 стан.
Ви замінили початкове значення світлодіода на HIGH, і при переході зі стану "0" в "1" також виставляєься HIGH. В самій першій ітерації в станах "0" і "1" світлодіод HIGH, вони зливаються. Далі працює як там і написано: короткий блим в 200 мс, пауза 1.5 с, довгий блим 2 с, пауза 3 с і т.д..
Ця конструкція:
if (!on) { ... } else if (on) { ... } else if (!on) { ... } else if (on) { ... }
не має сенсу. Якщо перша умова "if (!on)" виконалась, то решта вже не виконуються. А якщо не виконалась, то обовʼязково виконається друга - "if (on)", бо вона протилежна першій. А дві останні - ніколи не виконаються.
В попередньому прикладі у вас було всього два стани: світлодіод вимкнено, і світлодіод увімкнено. Тому було достатньо змінної типу bool, у якої всього два можливих значення.
В останньому прикладі у вас чотири стани:
* вимкнено перший раз (на 2000 мс)
* увімкнено перший раз (на 200 мс)
* вимкнено другий раз (на 500 мс)
* увімкнено другий раз (на 2000 мс)
Тому для збереження стану потрібна змінна такого типу, щоб могла приймати як мінімум 4 значення. Для простоти візьмем int. Стани будем нумерувати від 0 до 3. І для ясності перейменуєм змінну з "on" на "state".
int state = 0; // поточний стан. з початку - "0";
void loop() {
unsigned long now = millis();
if (state == 0) { // в стані "0"?
if (now - last_time >= 2000) {
digitalWrite(13, HIGH);
last_time = now;
state = 1; // переходим в стан "1"
}
} else if (state == 1) { // в стані "1"?
if (now - last_time >= 200) {
digitalWrite(13, LOW);
last_time = now;
state = 2; // переходим в стан "2"
}
} else if (state == 2) { // в стані "2"?
if (now - last_time >= 500) {
digitalWrite(13, HIGH);
last_time = now;
state = 3; // переходим в стан "3"
}
} else if (state == 3) { // в стані "3" ?
if (now - last_time >= 2000) {
digitalWrite(13, LOW);
last_time = now;
state = 0; // переходим в початковий стан "0"
}
}
}
Абсолютно те ж саме, тільки switch/case замість if/else. Так більш читабельно:
int state = 0; // поточний стан. з початку - "0";
void loop() {
unsigned long now = millis();
switch (state)
{
case 0:
if (now - last_time >= 2000) {
digitalWrite(13, HIGH);
last_time = now;
state = 1;
}
break;
case 1:
if (now - last_time >= 200) {
digitalWrite(13, LOW);
last_time = now;
state = 2;
}
break;
case 2:
if (now - last_time >= 500) {
digitalWrite(13, HIGH);
last_time = now;
state = 3;
}
break;
case 3:
if (now - last_time >= 2000) {
digitalWrite(13, LOW);
last_time = now;
state = 0; // переходим в початковий стан "0"
}
break;
}
}
Тепер зверніть увагу на те, що дії при переході між станами практично однакові. Відрізняються тільки
тривалості: 2000, 200, 500, 2000
значення, що передається у digitalWrite: HIGH, LOW, HIGH, LOW
номер наступного стану: 1, 2, 3, 0, 1, 2 ...
Таким чином можна використати один і той же код для циклічного переходу між станами. Тривалості та значення для digitalWrite помістимо у масиви, а значення з масивів вибиратимем по номеру стану:
unsigned int dur[4] = { 2000, 200, 500, 2000 }; // масив тривалостей (duration) для кожного стану
byte led[4] = { HIGH, LOW, HIGH, LOW }; // масив значень digitalWrite для кожного стану
int state = 0; // поточний стан. з початку - "0";
void loop() {
unsigned long now = millis();
if (now - last_time >= dur[state]) { // якщо час поточного стану вийшов
digitalWrite(13, led[state]); // вмикаєм або вимикаєм світлодіод
last_time = now;
state = state + 1; // переходим у наступний стан
// але максимально можливий номер стану - "3"
// якщо це був останній - переходим у початковий стан "0"
if (state > 3) {
state = 0;
}
}
}
Тепер зверніть увагу, що в масиві led всього два варіанти значень для digitalWrite: HIGH і LOW, і вони чергуються. Можна обійтись без цього масиву. Як його позбутись - вам в якості самостійного завдання
підкажіть будь-ласка чому він падлюка не працює? :-)
Тому що після того як пройшло 300 мс завжди спрацьовує перша умова:
if (millis() - last_time >= 300)
і last_time оновлюється поточним значенням millis(). Таким чином друга умова
if (millis() - last_time >= 1000)
ніколи не спрацьовує.
Програма має зберігати свій поточний стан і перемикатись в залежності від нього.
Також рекомендую зчитувати millis() один раз на початку ітерації і надалі використовувати це зчитане значення.
bool on = false; // поточний стан. з початку - вимкнено
void loop() {
unsigned long now = millis();
if (!on) { // світлодіод вимкнено ?
if (now - last_time >= 1000) { // пройшло 1000 мс ?
digitalWrite(13, HIGH); // вмикаєм
last_time = now;
on = true; // зберігаєм поточний стан, що увімкнено
}
} else { // світлодіод увімкнено ?
if (now - last_time >= 300) { // пройшло 300 мс ?
digitalWrite(13, LOW); // вимикаєм
last_time = now;
on = false; // зберігаєм поточний стан, що вимкнено
}
}
}
Тю, та то ж гайвер?! З цього й потрібно було починати.
Якась широко відома у вузьких колах особа? Не слідкую за ардуіно комʼюніті, тим паче запорєбріковським.
Такий код я би посоромився на гітхаб викладати.
UPD: код знайшовся на гітхабі.
Питання щодо помилок компіляції краще задавайте автору того коду. У мене, наприклад, він теж не компілиться. Схоже, що microLED, яка ставиться в Arduino IDE, не сумісна з тією, під яку код написаний.
По-перше, у приведенному виводі компілятора тільки попередження (warning), повідомлення про помилку має бути десь нижче. Покажіть весь вивод компілятора.
По-друге, звідки ми можемо знати, як у вас обʼявлено curEffect і в якому контексті воно використовується? Покажіть код.
По-третє, це питання швидше в "Програмування Arduino", а не в "Апаратні питання".
По першому питанню наприклад якщо я возьму резистори 24кОм та 4,3кОм я від 15в отримаю на вході А0 меньше 2в. Чи потрібно додатково ставити з А0 на землю стабілітрон 4,7?
Куди подаватиметься напруга з дільника? На I/O пін мікроконтроллера? Там має бути захисний діод, і спонтанні слаботочні імпульси вище напруги живлення гаситимуться цим діодом. А при такому дільнику, щоб перевищити 5В, на вході потрібно 33 вольта. При такій напрузі в мережі, думаю, виникнуть проблеми серйозніше ніж згорівший мікроконтролер.
передивився декілька схем, але так і не зрозумів як правильно виміряти напругу бортмережі авто. Чи досить 2 резистори чи додавати стабілітрон? Задача відслітковувати тільки чи запущений двигун чи ні
В чому конкретно задача? Визначати наявність будь-якої напруги 11-15В чи вимірювати значення цієї напруги? Або визначати, чи перевищує напруга певний поріг? Навіть при вимкненому двигуні, але свіжозарядженому акумуляторі в мережі може бути всі 14.4В, а при працюючому двигуні, але увімкнених споживачах, може бути менше 13В.
Або інший варіант - переплутали піни для червоного і зеленого. Ми ж не знаєм, які значення в redLed і greenLed, і як підключено насправді.
знімати з неї показники напруги які коливаються від 0 - 1.23В
В чому сенс вимірювати напругу без навантаження? Використовувати її як датчик освітлення? Там нелінійність велика, буде або максимальне значення, або біля нуля. Якісь більш-менш адекватні значення будуть тільки у вузькому діапазоні.
Якщо я спробую так, як на фото. Це буде правельно?
Не спалите, якщо не будете пін на OUTPUT конфігурувати. Але сенсу від такого підключення небагато. Поставте хоча б 1 МОм резистор паралельно.
Пробую підключити хоч одну через порт AREF, але щось недуже виходить. Може десь стикались з такою темою?
Не дуже зрозумів питання.
На Aref - подається зовнішня опорна напруга, відносно якої виміряє АЦП. Також АЦП може виміряти відносно внутрішнього джерела опорної напруги 1.1В або відносно напруги живлення. В такому разі до Aref нічого підключати не потрібно.
Але я не розумію, щому так?
Світлодіод можна підключити двома способами: або щоб з піна струм через світлодіод тік в мінус живлення, тоді світлодіод вмикається високим рівнем на піні. Або щоб струм з плюса живлення через світлодіод втікав в пін. Тоді він вмикається низьким рівнем.
Програма з інтернету розрахована на один спосіб підключення, а у вас, певно, світлодіоди підключені другим способом.
Можливо вам цей лог щось скаже, бо я тут нічого не розумію:
На майбутнє: на форумі можна завантажити файл і вставити на нього посилання в повідомленні. В тексті зворотні слеші зʼїдає чомусь.
Компілювання скетчу..."D:ProgrammingArduino 1.8.16datapackagesarduinotoolsavr-gcc7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -flto -fno-reorder-blocks -ffixed-r2 -ffixed-r3 -ffixed-r4 -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=attiny13a -DF_CPU=1200000L -DARDUINO=10816 -DARDUINO_attiny -DARDUINO_ARCH_AVR "-ID:ProgrammingArduino 1.8.16datapackagesMicroCorehardwareavr2.3.0coresmicrocore" "-ID:ProgrammingArduino 1.8.16datapackagesMicroCorehardwareavr2.3.0variantsattiny13a" "C:UsersuserAppDataLocalTemparduino_build_416861sketchAttiny_PWM.ino.cpp" -o "C:UsersuserAppDataLocalTemparduino_build_416861sketchAttiny_PWM.ino.cpp.o"
IDE передає компілятору, що частота 1200000 Гц. А у вас 9600000 Гц, якщо фʼюз дільника скинуто.
Хм, можливо тому й спрацювало на тестері сервомашикок розділення значень 1200 та 1800 навпіл (600 і 900) на частоті 9.6МГц.
Навряд чи це через переривання, там не такий вплив.
Але ж чомусь в відеоуроках з ютубу в людей одразу виходить, що аттіні зчитує PWM сигнал коректно на цій частоті, без розділення значень сигналу два.
Ну я тих відеоуроків не бачив, не знаю, що там за core package використовується, якої версії, яка конфігурація фʼюзів на attiny, і що за сигнали аналізуються.
А підскажете на майбутнє як це зробити в коді? Це потрібно в дужках вписати якесь значення?
Так, в попередньому повідомленні є в прикладі:
clock_prescale_set(clock_div_1); // вимикаєм дільник F_CPU
А як можна виміряти значення PWM напряму без таймера?
"Напряму" я мав на увазі без pulseIn() з ардуінівської бібліотеки. pulseIn() якраз і виміряє тривалість імпульсу без таймера, покладаючись на те, що ітерація цикла виконується за заздалегідь відому кількість тактів процесора.
Особисто на відеосигналі не перевіряв, але у людей наче працює (якщо не фейк): https://www.youtube.com/watch?v=AkHmghx4CzU.
Єдине, що викликає занепокоєння - це відносно великий опір в увімкненому стані (on-resistance). Якщо виходи/входи обладнання 75 Ом, то без буферів рівень сигналу може неприпустимо зменшитись. Але треба перевіряти на практиці з конкретним обладнанням.
Але якось це роблять навіть звичайні китайські автомобільні камери, які аналізуючи зображення переміщують лінії паркування. Правда незнаю на основі чого вони зроблені
Думаю, там з самого початку зображення з сенсора в цифровій формі заходить. Потім обробляється і генерується відеосигнал.
Аналоговий сигнал теж можна оцифровувати, обробляти програмно і генерувати вже новий модифікований аналоговий сигнал. Але це обчислювальні ресурси.
Такі не пробували?
https://arduino.ua/prod6234-modyl-analo … -74hc4051d
https://arduino.ua/prod1307-analogovii- … cd74hc4067
Можливо ще знадобляться буферні повторювачі на вході та/або виході для компенсації on-resistance, а може і не знадобляться.