Аппаратной реализацией интерфейса 1Wire я называю совместное использование UART и DMA для приема/отправки таймслотов. Эта тема уже очень много где обсуждалась, очень хорошая статья есть на изиэлктрониксе. Собственно оттуда я и взял исходники и немного переделал для работы с серией f0. Основные отличия заключаются в настройках DMA, так как он устроен немного по другому, чем в в f1. Также вынес все функции работы с железом в отдельные инлайн функции-обертки. Как мне кажется это поможет при переносе на другие семейства. Можно было бы наверное изловчиться и написать более универсально и красиво, но я не стал сильно заморачиваться.
Подробное и понятное описание самого протокола 1 Wire можно посмотреть например тут.
Все же повторю суть аппаратной реализации. Настроив определенную скорость UART, мы получаем возможность аппаратно отправлять и принимать тайм-слоты 1Wire. Один тайм слот будет равняться одной посылке по UART. Соответственно, для приема/отправки одного байта 1Wire нужно отправить/принять 8 байт UART. Контроллер DMA есть даже в самой простой серии f0, то думаю задействовать его будет оптимальным решением. Скорость для приема и отправки тайм слотов данных является 115200. Для формирования на линии сброса и приема импульса присутствия используется скорость 9600. UART STM32 имеет полудуплексный режим работы по одному проводу ( Single-wire half-duplex communication). Также есть возможность перевести ножку приемопередатчика UART в режиме открытого коллектора (ОК). Как по мне все эти возможности позволяют удобно, без всякой возни с таймслотами работать с интерфейсом 1Wire.
// функция инициализирует UART_OW __inline static void _ow_usart_init(void) // функция инициализации UART_OW с указанной скоростью __inline static void _ow_usart_set_speed(uint32_t speed) //функция отправки по UART 1 байта __inline static void _ow_uart_byte_send(uint8_t data) // обертка функция приема по UART 1 байта __inline static uint8_t _ow_uart_byte_recv(void) //функция отправки/приема по UART через DMA __inline static uint32_t _ow_uart_dma_send_recv(uint8_t* data, uint32_t cnt)
Функции обертки для работы с железом.
Модификатор static использовал для того чтобы область видимости данных функции была только в файле onewire.c. Т.к. функции служебные, не стоит, чтобы они были видны из других модулей. По своей сути данные функции являются обертками, то вполне оправдано использовать модификатор __inline. Потому как обертки вызываются всего лишь в нескольких местах модуля onewire, да и по сути своей реализации являются низкоуровневым исполнительным кодом. Поэтому, как мне, кажется, целесообразности в обычном вызове данных функций нет.
//функция приема по UART 1 байта __inline static uint8_t _ow_uart_byte_recv(void) { uint8_t data; HAL_UART_Receive(&_huart, &data, 1, 100); return data; }
Функция приема байта.
В моем случае я использую функции библиотеки HAL. Она конечно не оптимальна и бывает довольно глючной, но в простых проектах считаю возможным ее использовать, да и для переносимости кода между разными семействами STM32 она тоже годится. Хотя при глубоком задействовании возможностей периферии предпочитаю ее не использовать. Как мне, кажется, если использовать CubeMX и HAL с умом, они могут неплохо сэкономить время на разработке или помочь в быстрой проверки каких-нибудь идей. Во всяком случаи возможности CubeMX визуально назначать те или иные пины или наглядная настройка дерева тактовой частоты, считаю очень полезными. Как бы то ни было, данную функцию-обертку легко переписать используя лишь например интерфейс CMSIS. Остальные реализации оберток аналогичны.
Как обычно прикладываю пример, выполненный в Keil v.5. Пример этот содержит код для контроллера травильной ванночки. Сам алгоритм прима/отправки onewire пакетов не трогал. Благодарю авторов данных исходников, которыми они щедро поделились.
Я так понимаю, запустить одновременно приём и передачу по юарт средствами HAL всё-таки не получается?
Воспользовался Вашей библиотекой. Адаптировав ее под stm32f103. Но моя аппаратная часть была сделана несколько иначе(была дана готовая схема ) Я работал с полноценным UART. FullDuplex.
К Вашей библиотеке возник ряд вопросов но которые были успешно решены. Могу прислать Вам файлы если хотите.
И я читал «таблетку » была добавлена ф=ция подсчета CRC.
Спасибо за отзыв, очень рад, что библиотека пригодилась. Можно на ты). Да было бы интересно посмотреть, что получилось. А в будущем, если вы не против, мог бы ее добавить к статье
Куда кинуть?? Напишите мне в почту которая указана я отвечу.
Меня тоже можно на ТЫ
Добрый день Kos, поделитесь пожлайста вашей реализацией. Заранее спасибо! kossdm(сАбАкА)gmail(ТочЕка)КОМ
Kos Где можно скачать вашу реализацию, хочу сделать на Atmege..
Здравствуйте, подскажите ламеру, пожалуйста: на stm32f103 компилятор ругается на эти строчки:
WRITE_REG(DMA_Channel->CPAR, (uint32_t)&(USART->TDR));
WRITE_REG(DMA_Channel->CPAR, (uint32_t)&(USART->RDR));
вот так:
‘USART_TypeDef {aka struct }’ has no member named ‘TDR’; did you mean ‘DR’?
Что это за регистры такие TDR и RDR и на что их заменить в stm32f103?
Спасибо!
Здравствуйте, это строчка подсказывает ‘USART_TypeDef {aka struct }’ has no member named ‘TDR’; did you mean ‘DR’?, что возможно, стоит заменить TDR на DR. К, сожалению, я мало работал с stm32f103 и точно не помню название его регистров. В данном куске кода идет настройка DMA. Я бегло глянул доки на f103 и похоже его USART имеет только регистр DR (DATA REGISTER). На него и стоит настраивать каналы DMA
stm32f103 Поправил, но как-то криво работает.
Отправляем
OW_Send(OW_SEND_RESET, (uint8_t*)»\xCC\x44″, 2, 0, 0, OW_NO_READ);
На лог анализаторе вижу 0xCD 0x45
Выполняем
status=OW_Send(OW_SEND_RESET,(uint8_t*) «\xcc\xBE\xff\xff», 4, buf,2, 2);
Анализатор выдает 0xCC 0xBF 0xFF 0xFF
Ну естественно датчик ни чего не отвечает.
Почему-то после 0xCC некоторые байты изменяют последний бит на 1
Ну уже тупо взял такую строку отправил.
OW_Send(OW_SEND_RESET, (uint8_t*)»\xCC\x44\x44\xDD\xEE\xFF\x01\x02\x03\x03\x22\x33\x44\x44\x55″, 15, 0, 0, OW_NO_READ);
Анализатор кажет: 0xcc, 0x45, 0x44, 0xDC, 0xEF , 0xFF , 0x01 , 0x02 , 0x02 , 0x02 , 0x22 , 0x32 , 0x44 , 0x44 , 0x54
Столкнулся с той же проблемой при портировании на STM32F103. Удалось выяснить, что последний бит портит функция uart_dma_rx_link. В теле функции _ow_uart_dma_send_recv перенёс строчку uart_dma_rx_link(OW_USART, OW_DMA_CH_RX, data, cnt); после uart_dma_tx(OW_DMA_CH_TX, data, cnt);
Данные отправляются нормально, но при чтении портятся уже принимаемые данные, сдвигает на один бит влево. Не стал заморачиваться, добавил костыль в виде сдвига при обработке. Температура считывается!
Есть, правда, ещё один неприятный момент. Я обращаюсь к датчику по прерыванию таймера динамической индикации 4-разрядного 7-сегментника, и каждый раз при обращении к датчику он едва заметно мигает. Почти не видно, но всё равно неприятно, специально ведь выбрал библиотеку с DMA, чтобы такого не было. Причём если вызывать датчик в бесконечном цикле, мерцания нет. Кроме того, в таймере индикации есть обращение к I2C датчику DS1624 (можно выбирать тип датчика кнопкой), и с ним всё отображается и не мигает.