Ви не увійшли.
Вставив картинкою бо форумний двіжок зʼїдає бекслеші в тексті
Ставте два бекслеша підряд. При використанні "попередній перегляд" один бекслеш зникає в вікні вводу тексту, тому доводиться ще раз розставляти дублі.
Оффтоп: може кому пригодиться така ідея конвертера логічних рівнів для ESP-01 на основі цієї платки, використовував її при розробці прошивки, також можна використати для отримання 5-вольтового 1-wire.
Зарезервований коментар, якщо тема розростеться, щоб робити тут посилання по темі.
Для тих, хто працює з 1-wire під Linux, доступні два способи роботи з адаптером (майстром шини 1-wire): з простору користувача (найпопулярнішим ПЗ є OWFS) і через драйвер в ядрі. В OWFS реалізована робота майже з усіма існуючими адаптерами, а от в ядрі не густо, є драйвери GPIO-адаптера (w1-gpio), USB-адаптера (ds2490), I2C-адаптера (ds2482), але чомусь не було UART-адаптера (ds2480b).
Коли я вибирав, на якій мікросхемі зробити готовий пристрій, то, незважаючи на це, вибрав UART-інтерфейс, оскільки для моїх задач була необхідна гальванічна розв'язка і зробити її значно простіше на однонаправлених лініях, а з драйвером вирішив "розібратися" пізніше. Є ще й друга причина вибору саме послідовного інтерфейсу, але про це згодом.
Отже, Linux-драйвер для ось такого готового майстра шини 1-wire на мікросхемі ds2480b вже є і його можна взяти звідси. В цій темі намагатимусь допомагати з компіляцією драйвера.
Якщо адаптер підключено до комп'ютера з Linux через USB-UART або до пінів Raspberry Pi ось так:
Тоді "приєднати" драйвер до відповідного послідовного порта (/dev/ttyUSB0 або /dev/ttyAMA0) можна командою:
ser1wm_attach /dev/ttyUSB0
Виконувати цю команду можна доручити udevd, щоб він її виконував щоразу, коли до USB підключається USB-UART, до якого підключено майстер шини 1-wire. Наприклад так:
ACTION=="add", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", SUBSYSTEMS=="usb",\
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A50285BI",\
RUN+="/usr/local/bin/ser1wm_attach /dev/%k"
В Linux є така утиліта socat, за допомогою якої послідовний порт по TCP можна "передати" на інший хост:
1) на боці реального послідовного порта піднімаєм сервер на TCP-порту:
socat tcp-l:4232,bind=10.0.0.4,reuseaddr /dev/ttyUSB0,raw,echo=0,b9600,cs8
2) на іншому боці підключаємось і утворюєм віртуальний послідовний порт:
socat tcp:10.0.0.4:4232 pty,raw,echo=0,link=/dev/ttyvirt0
До такого віртуального послідовного порта також можна приєднати даний драйвер:
ser1wm_attach /dev/ttyvirt0
Але в ser1wm_attach реалізована можливість робити це напряму без другої команди socat (її функціонал вбудовано), ось так:
ser1wm_attach 10.0.0.4:4232
Кмітливі вже здогадалися, що і першу команду socat також можна в щось вбудувати, наприклад реалізувати її на мікроконтролері з мережевим інтейфейсом, до якого підключено майстер шини 1-wire (або навіть і майстер шини реалізувати програмно). Це і є та друга причина, по якій вибрано послідовний інтерфейс, оскільки його без будь-яких алгоритмів і overhead можна передавати по TCP.
В якості proof-of-concept викладаю прошивку, яка перетворить ESP-01 на майстер шини 1-wire (на піні RX), а по TCP дозволяє приєднати даний драйвер за допомогою останньої наведеної команди ser1wm_attach.
Для переведення прошивки в режим конфігурування потрібно при подачі живлення закоротити між собою (але не на землю) піни IO0 та IO2. В режимі конфігурування (на це вказує блимання світлодіодом) підключитися до точки доступу ser1wm_setup, зайти браузером на http://192.168.1.1/ і виконати налаштування.
В планах є також реалізація "Ethernet to 1-wire", тому драйвер назвав не ds2480b а більш загально - ser1wm (скорочення від serial 1-wire master).
Добре, "приєднали" драйвер до послідовного порта чи ESP, а що далі?
В dmesg маємо побачити щось подібне:
serio: Serial port pts9
ser1wm serio3: attaching 1-wire bus master
w1_master_driver w1_bus_master1: Attaching one wire slave 28.0000023ccaeb crc 45
Ядро саме буде періодично (раз на 10 сек) опитувати шину 1-wire і писати в dmesg про знайдені слейви. Кожен слейв, поки він присутній на шині, буде мати свій каталог в /sys/bus/w1/devices в якому будуть файли для роботи з слейвом, які саме файли - залежить від сімейства слейва. Наприклад, для DS18B20:
cat /sys/bus/w1/devices/28-0000023ccaeb/w1_slave
78 01 1e 00 7f ff 08 10 e1 : crc=e1 YES
78 01 1e 00 7f ff 08 10 e1 t=23500
Можу зробити те, що ви хочете, на m8a або m328p, звертайтесь в пошту.
датчик з газ.лічильника - геркон
Можна використати SS49E (аналоговий датчик Холла), але він потребує налаштування threshold-ів, це робиться записом в пам'ять лічильника і я для цієї процедури написав веб-інтерфейс (інструкція), що вже вимагає щоб лічильник був підключений до лінукса на якому має бути запущений owhttpd. Тут один користувач викладав урізану лише для ds2423 "емуляцію" owhttpd на мікроконтролері.
Якщо піни вашого МК не толерантні до 5В, то скористайтесь такою схемою (фактично схема перетворювача логічних рівнів):
Між GPIO4 на схемі (це ваш вихід МК) і +3.3V можна додати резистор 10-100кОм, або програмно використати вбудований в МК.
Тепер, коли буду щось писати в сторінку, то теж, в підрахунок CRC включати байти команди та адреса, я правильно розумію?
Треба дивитися даташит, шукаєте там Memory function flow chart, вам спочатку потрібна буде команда OFh для запису в скретчпад, бачите там "Master RX CRC16 of Command, Address, Data" - це значить, що потрібно включати, наступною командою 55h потрібно скопіювати скретчпад в сторінку.
Я б ось це
#define inBit1Wire(inBit)
LineWire =0; delay_us( 8);
LineWire =1; delay_us( 1);
inBit =LineWire; delay_us(40);
LineWire =1; delay_us(90);
змінив на таке
#define inBit1Wire(inBit)
LineWire =0; delay_us( 8);
LineWire =1; delay_us(11);
inBit =LineWire; delay_us(30);
LineWire =1; delay_us(90);
бо лінія може не встигнути піднятись за 1мкс
Приблизно так (псевдокод):
write_0 {
bus_low
delay 59
bus_hiz
delay 11
}
write_1_read {
bus_low
delay 10
bus_hiz
delay 5
r = bus_read
delay 55
return r
}
У вас трохи неправильні таймінги. Відправка нуля - це ~59мкс нуль на шині і не менше 1мкс одиниця, відправка одиниці - 5..10мкс нуль і ~55мкс одиниця. Слейв робить зчитування шини через 30-35мкс після падаючого фронту (тобто десь посередині) і визначає, там передали 0 чи 1. А якщо слейв хоче передати нуль, то він по падаючому фронту замикає шину на землю на 30-40мкс, тобто мастер повинен робити зчитування десь посередині - приблизно на 15..20й мікросекунді.
Це штатний режим роботи, при напрузі зовнішнього живлення <~4.5V (VCC або паразитного через DQ), лічильник вимикає 1-wire інтерфейс але продовжує рахувати імпульси. Пов'язано це з тим, що споживання лічильника йде з трьох джерел - з батарейки, з VCC, з DQ - кожне через діод, яка напруга більша, звідти і споживання, коли зовнішнє живлення (VCC, DQ) лічильник вважає низьким, то щоб менше споживати від батарейки, він вимикає інтерфейсну частину. Тобто VCC або DQ має бути >4.5V, про це сказано в характеристиках пристрою, що VCC і DQ мають бути в межах 4.5 .. 5.5V.
При паразитному живленні струм споживання йде через резистор підтяжки і напруга DQ, звичайно, просідає. При підтяжці 1кОм можна заживити 1, максимум 2 лічильники (я не робив детальних досліджень). Мінімум, що допускає специфікація 1-wire це підтяжка 500 Ом.
Для вашого прикладу на фото:
#include <stdio.h>
#include <stdint.h>
uint16_t crc16_update(uint16_t crc, uint8_t a)
{
int i;
crc ^= a;
for (i = 0; i < 8; ++i) {
if (crc & 1)
crc = (crc >> 1) ^ 0xA001;
else
crc = (crc >> 1);
}
return crc;
}
int main()
{
uint8_t buf[45] = {
0xa5, 0xc0, 0x01, // READMEMCOUNTER, address
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xbb,0x00,0x00,0x60,0x00,0xed,0x00,0x41,
0x31,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
0xe3, 0x1b
};
uint16_t crc;
int i;
crc = 0;
for (i = 0; i < 43; i++)
crc = crc16_update(crc, buf[i]);
printf("crc = 0x%02x 0x%02xn", (uint8_t)~(crc & 0xff), (uint8_t)~(crc >> 8));
crc = 0;
for (i = 0; i < 45; i++)
crc = crc16_update(crc, buf[i]);
if (crc == 0xb001)
printf("crc okn");
else
printf("crc errorn");
}
Вивід:
crc = 0xe3 0x1b
crc ok
Ось вам приклад, щоб розібратися:
#include <stdio.h>
#include <stdint.h>
uint16_t crc16_update(uint16_t crc, uint8_t a)
{
int i;
crc ^= a;
for (i = 0; i < 8; ++i) {
if (crc & 1)
crc = (crc >> 1) ^ 0xA001;
else
crc = (crc >> 1);
}
return crc;
}
int main()
{
uint8_t buf[10] = {11, 12, 13, 14, 15, 16, 17, 18};
uint16_t crc;
int i;
/* додавання crc до повідомлення */
crc = 0;
for (i = 0; i < 8; i++)
crc = crc16_update(crc, buf[i]);
buf[i++] = ~(crc & 0xff);
buf[i++] = ~(crc >> 8);
/* перевірка повідомлення з crc */
crc = 0;
for (i = 0; i < 10; i++)
crc = crc16_update(crc, buf[i]);
if (crc == 0xb001)
printf("crc okn");
else
printf("crc errorn");
}
Перевіряти контрольну суму можна тим же способом, що і заповнювали, або використати властивість, що контрольна сума повідомлення разом його інвертованою контрольною сумою завжди буде 0xb001.
Звичайно crc16_update() можна оптимізувати, наприклад, як у вашому прикладі з oddparity.
Зверніть увагу, що в ds2423 при першому читанні сторінки контрольна сума обчислюється не лише над даними, чотирма нульовими байтами і чотирма байтами лічильника, але ще спочатку і над самою командою (0xa5) і двома байтами адреси (а для наступних сторінок, якщо читаємо далі підряд, вже лише над всіма байтами сторінки, 4 нульовими байтами і 4 байтами лічильника). Також не обов'язково вичитувати всі 32 байти сторінки, якщо потрібен лише лічильник, можна почати з останнього байту сторінки, ось тут приклад, як найпростіше прочитати лише байти лічильника.
Подивіться Модуль розширення портів з інтерфейсом 1-wire, в ньому є функція відстеження стану порта, призначена для побудови охоронної системи, може це саме те, що вам потрібно. 1-wire дозволяє почепити на одну шину безліч таких модулів, використавши лише один пін мікроконтролера для керування всіми ними. Або 1-wire можна підключити напряму до лінукс, для роботи з такими модулями є драйвер.
а також щоби ця частота була на виходах 26 та 36, як відомо, tone() може працювати одночасно тільки на одному порті, тому треба зробти якесь швидке перекидання чи якийсь інший фокус, щоби вона була на цих двух портах.
припаяйте перемичку
GmmC пише:можливо одночасно буде реалізувати також шім по двух чи одному каналу?
На одному таймері з довільною частотою два канала не вийде: у таймера два регістра-компаратора, і один із них використовується або як один із каналів ШІМ, або для керування частотою.
Подивіться режими, коли верхня межа лічильника задається регістром ICR, тоді обидва регістри-компаратори доступні для ШІМ.
Частоту і коефіцієнт заповнення ШІМ на AVR не вийде встановлювати абсолютно довільно, лише ось такі дискретні значення:
Частота: f=16MHz/N, де N=1..65536
Коеф.заповнення: d=n/N, де N - те ж саме, яке використано для підбору частоти, n=0..N
analogWrite(PIN_RELAY, 0);
Якщо я не помиляюсь, дана команда увімкне ШІМ з коефіцієнтом заповнення 1/256 (а параметр 255 дасть коефіцієнт заповнення 256/256 - завжди на одиничку більше, тобто за допомогою analogWrite неможливо отримати коефіцієнт заповнення 0/256)
Як можна з Вами зв'язатись
Зліва під аватаркою натискаєте на "E-mail" і відправляєте повідомлення.
pinMode(3, INPUT);
замініть на
pinMode(3, INPUT_PULLUP);
Якщо після цього і з тестером перестане працювати, значить спрацьовувало від наводок.
Як Вам радив dimich, виконуйте pulseIn() при вимкнених перериваннях
__builtin_avr_cli();
ch3 = pulseIn(3, HIGH, timeout);
__builtin_avr_sei();
Але прикрий момент у тому, що з іншими пристроями, які генерують ШІМ сигнал аттіні знов не працює, навіть з такими налаштуваннями зчитування сигналу.
Чи є цьому якесь пояснення і чи можна тепер заставити тіні працювати і з іншими пристроями окрім тестера сервомашинок?
А Ви з піном не помилилися? Бо пін в високоімпедансному стані і від наводок щось зловить.
Подавайте PWM на серву, але якщо дуже хочеться і є зайві гроші, звертайтесь, напишу Вам PWM->PDM конвертер.