Прочитать байт с порта
- Войдите на сайт для отправки комментариев
Чт, 22/02/2018 - 20:07
подскажите как читать нули и единицы поступающие в порт ардуины? дело вот в чем - имеется микросхема, которая на запрос отправляет ответ. на нее имеется даташит согласно которого я ей отправляю команду -
вот такой функцией
void writeByte(byte code) { pinMode(2, OUTPUT); //DDRD |= _BV(2); for (int i = 0; i < 8; i++) { digitalWrite(2, LOW); //PORTD &= ~_BV(2); delayMicroseconds(50); if (code >> i & 0b1){ digitalWrite(2, HIGH); //PORTD |= _BV(2); delayMicroseconds(150); } else { delayMicroseconds(100); digitalWrite(2, HIGH); //PORTD |= _BV(2); delayMicroseconds(70); } } }
работает просто замечательно - сигнал очень ровный и красивый -
если после отправки установить порт на вход
pinMode(2, INPUT); //DDRD &= ~_BV(2);
то можно увидеть ответные данные -
а вот как бы мне их прочитать и вывести допустим в консоль ардуины (Serial.print();)?
я так понимаю что мне надо -
известно ожидаемое кол-во бит (8)
известны тайминги входящих данных
наверное мне нужно при помоши micros() измерять время нахождения порта в каком либо состоянии и согласно таймингам записывать единицу или ноль? так же? иначе зачем бы в даташите указывалось это время? можно конечно попробовать "синхронизироваться" при помощи задержек, но будут сбои? другого выхода я не вижу
Чё надо в конечном итоге?
Когда уже люди научатся излагать свои мысли....
Интерпретировать ответ хотя бы в двоичный код и увидеть его в юарт
А что за микросхема? Как называется, даташит глянуть.
7-бит адрес с битом R/W... Не пахнет ли тут квадратной шиной...
я не прошу написать мне готовый код. мне самому интересно разобраться. вот не имея даташита неужели входных данных не достаточно? да и чем может помочь даташит при чтении байта кроме таймингов? или я не правильно мыслю? сейчас пытаюсь сделать следующий алгоритм -
имеем - если логический 1 длится до 100 микросекунд это 0. если от 160 это 1
соответственно в цикле (while) хочу проверять условие
только не могу понять как измерять время
имеем - если логический 1 длится до 100 микросекунд это 0. если от 160 это 1
только не могу понять как измерять время
Ну вот тебе кусок кода чтения с DHT, по аналогии понятно, как сделать проверку на единичку или нолик:
большое спасибо. значит мысли мои были правильные. все больше не подсказывайте ничего - я надеюсь разберусь дальше сам
сделал так -
получаю в консоль -
при том что данные выглядят так-
где я ошибся?
digitalRead - медленная операция, лучше напрямую из порта читать, см. digitalPinToPort, digitalPinToBitmask, portInputRegister.
изменил строчку 7 на while (PIND & _BV(2) == 1 ) //ждем пока появится логическая 1 на порте atmega 328 PD2 (2 нога ардуино UNO)
теперь в консоле
end bit
end bit
Таймаут пока уберите.
ничего не изменилось
Не сравнивайте с единицей результат побитового & ;)
изменил
while
(PIND & _BV(2) !=LOW ) теперь в консоль ничего не выводится
При приеме пакета битов не сбрасывайте результат сразу в консоль. Пишите в массив. А окончился прием пакета и сбрасывайте тогда весь массив.
почему то у меня вот так while (PIND & _BV(2) != LOW ) не может выйти из цикла
почему то у меня вот так while (PIND & _BV(2) != LOW ) не может выйти из цикла
Потому что в PIND может быть выставлен другой бит, например, 5 & 4 != LOW == 4
так. это уже интересно. я искренне верил в то что запись PIND & _BV(2) означает что мы хотим считать значение 0 или 1 с порта D вывода 2. если не сложно не могли бы вы обьяснить более подробно что за другой бит может быть выставлен?
получается что мое недопонимание мешает мне закончить функцию
_BV(2) это 0b00000100 когда нужный вам второй бит выставлен в 1 результатом побитового И будет 4, а если выставлен 0 то будет 0.
iopq, вы не путайте лог.состояния и весовые значения. В PIND & _BV(2) может лежать либо 0 либо 4
так. это уже интересно. я искренне верил в то что запись PIND & _BV(2) означает что мы хотим считать значение 0 или 1 с порта D вывода 2. если не сложно не могли бы вы обьяснить более подробно что за другой бит может быть выставлен?
получается что мое недопонимание мешает мне закончить функцию
Порт PIND: b00000011 - выставлены два младших бита, в DEC это число 3. Вы проверяете второй бит, маска b00000010, в DEC это число 2. Конструкция if(3 & 2) == 1) никогда не сработает, т.к. результат вычислений будет равен 2. Так понятней ?
Более того: в PIND у нас b00000101, т.е. 5 DEC. Мы проверяем второй и третий бит: b00000110 (6 DEC). Результатом 5 & 6 будет 4.
Не запутал?
не ну то что у портов есть регистры я конечно знаю, просто не ожидал что запись PIND & _BV(2) будет читать 3 регистра а не один. или не так?
b00000000 = PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0
нам же нужен только PD2?
Смотрите: строго говоря, конструкция
совершенно валидная, т.к. LOW == 0, и эта конструкция означает ровно следующее: Ждать, пока бит 2 в порту(байте) не будет сброшен. На примере: 3 (11 BIN) & 2 (10 BIN) == 2, бит 2 установлен. 4 (100 BIN) & 2 (10 BIN) == 0, бит 2 сброшен.
Валидна и обратная конструкция:
А вот сравнивать с HIGH, т.е. с 1, результат битового "и" - неверно ;)
И даже b11111111 = PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0 . Регистры это ячейки памяти связанные с тем или иным устройством. У порта три регистра PIN*,PORT*,DDR* . Регистр как ячейка памяти состоит из бит. Про конкретное назначение можно прочитать а даташите http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_Datasheet.pdf
Запись PIND & _BV(2) читает один регистр а потом выделяет один бит. Что бы не думать какой лучше сравнивать с нулём. Если не равен нулю ( PIND & _BV(2) !=0 ) то бит установлен.
подскажите как читать нули и единицы поступающие в порт ардуины? дело вот в чем - имеется микросхема, которая на запрос отправляет ответ. на нее имеется даташит согласно которого я ей отправляю команду -
работает просто замечательно - сигнал очень ровный и красивый -
если после отправки установить порт на вход
то можно увидеть ответные данные -
а вот как бы мне их прочитать и вывести допустим в консоль ардуины (Serial.print();)?
Здравствуйте. Слежу за темой, очень надеюс, что у вас получиться прочитать все верно. А, что за данные считываете, это из общеизвестных устройств параметры???
почему то у меня вот так while (PIND & _BV(2) != LOW ) не может выйти из цикла
Скобочки ещё одни добавьте: while ( ( PIND & _BV(2) ) != LOW ).
Это обязательно. Насчёт остального - не вникал, но вроде да, всё правильно сказали. Как минимум, насчёт сравнения с единицей. ))
да со скобочками хоть как то пошло. имею на данный момент вот такой код -
в консоль поступают следующие данные -
Скобочки ещё одни добавьте: while ( ( PIND & _BV(2) ) != LOW ).
Йоп, старею, про приоритет операций забыл, когда примеры писал :) Щас поправлю, чо уж там - дабы не вводить в заблуждение будущих читателей. Причём код, который давал, выдравши из проекта - оно со скобочками, как положено. Вот что значит в спешке писать :(
я не понимаю почему она не хочет читать правильно тайминги. по логике все должно работать. если менее 50 мкс это единица а если более это 0
я не понимаю почему она не хочет читать правильно тайминги. по логике все должно работать. если менее 50 мкс это единица а если более это 0
Ну как минимум потому, что у вас внутри цикла - вывод в Serial, все тайминги херятся.
я его убирал- ничего не меняется
Да и вообще - там ещё ошибки:
byte b[] - это какая такая неизвестная размерность массива, с учётом того, что вы его не инициализируете даже? Вы куда-то пишете в память, а куда - хз.
Короче:
она мне возращает 127 что равно 01111111 которые я получал своим кодом
она мне возращает 127 что равно 01111111 которые я получал своим кодом
Ну допишите код, чтобы после выставления бита ждала смены уровня, не проблема же ж:
Это как вариант, что называется, а конкретно - зависит от протокола общения. Например, у того же DHT надо ждать 50us, прежде чем пойдёт следующий бит - просто ждём, пока уровень не сменится.
теперь возращает 0
Вот, по-моему как-то так. Ну и проверку тайм-аутов конечно добавить.
А ещё, решите всё-таки, что функция возвращает - прочитанный байт, или признак ошибки/не_ошибки. И то и другое, одновременно, в результат типа uint8_t вряд ли уместится
теперь возращает 0
Ну я же писал - всё зависит от протокола, понимаете? В зависимости "от" - надо сначала дождаться какого-либо уровня. Потом - читать длительность уровня. Потом - перейти к следующей итерации, или - дождаться паузы между битами - всё зависит от протокола. Навскидку можно сколько угодно примеров накидать, на деле - протоколы передачи бит от устройства к устройству - различаются.
Вот, по-моему как-то так. Ну и проверку тайм-аутов конечно добавить.
А ещё, решите всё-таки, что функция возвращает - прочитанный байт, или признак ошибки/не_ошибки. И то и другое, одновременно, в результат типа uint8_t вряд ли уместится
В моём примере сверху просто переместить второй цикл ожидания наверх - и будет то, что вы описали. Но это не обязано работать в принципе, т.к. что за протокол - хз, поэтому получается - вольные фантазии на тему.
В моём примере сверху просто переместить второй цикл ожидания наверх - и будет то, что вы описали
Да, смысл тот же - ожидания должно быть два - для фронта и для спада. Просто не успел прочитать то сообщение ))
По одному фронту фиксируем micros, по другому сравниваем. Если и долго 1 или долго 0 то таймаут.
функция должна возвращать ситуацию - байт принят правильно, или была ошибка. Принятый байт должен быть в отдельной ячейке.
http://www.ti.com/lit/an/slua408a/slua408a.pdf вот даташит.
ясно же написано. Меряйте размеры ям. По свалу фиксируйте по подъему определяйте что у вас 0,1 или Break. точнее если появился Break, то у вас Адрес.
А ещё написано: Выставляйте скорость UART 57600 и читайте 8 байт. Если байт больше 0xf8, то бит единица, если равен или меньше то 0. Посылать можнотакже.
все что я понял я сделал вот так
получаю
как я это понимаю -
1. прочитать бит 1 (H0)
2. прочитать бит 0 (L0)
3. прочитать бит 1 (H1)
4. if (H1 == H0) result LOW;
else
5. прочитать бит 0 (L1) result HIGH;
я на картинке обозначил все возможные 0 и 1 цифрами. подскажите - взглядом я вижу что там содержится 01011000 а преобразовать с помощью алгоритма не могу. чтение бита H0 начинается с цифры 1 на рисунке? допустим это так и читаем бит L0 под цифрой 2 и бит H1 под цифрой 3. допустим тайминги 1 и 3 цифры на картинке одинаковы следовательно пишем в переменную 0. а вот дальше мы запускаем инструкцию сначала т.е пропускаем бит под цифрой 4, читаем 5, 6, 7 - 5 и 7 не равны следовательно читаем 8 и записываем 1? вроде пока логично и совпадает с реальностью. далее опять сначала - читаем 9, 10, 11 => 9 и 11 равны записываем 0. снова пропускаем 12, читаем 13, 14, 15 => 13 и 15 равны записываем 1 ну а дальше уже и читать то нечего. хрень какая то. да и странно что в даташите описана процедура чтения для 16 бит а у меня все же 8 бит. а про 8 бит ничего и не сказано
мне кажется я на верном пути
что-то опять не догоняю откуда берется бит 1 с картинки. ладно я опять напутал единицы и нули но поменяв их местами стало только хуже.
мне ведь бит (на картинке 1) вообще не нужен. для меня гораздо ценнее 17ый бит. не понимаю ведь по условию функции
у меня должен прочитаться только второй бит с картинки и далее...
http://forum.arduino.cc/index.php?action=dlattach;topic=262365.0;attach=...
В последнем сообщении ссылка на зип с библиотекой и примером.
Поэтому я и спрашивал про даташит. Берете библиотеку и разбираетесь если Вам интересно.
спасибо конечно но я что зря третью ночь сижу что бы вот так взять библиотеку? у меня не стоит задача "что бы работало". хочу понимать как оно работает и как подобное создавать не имея даташитов.