Казалось бы, зачем писать про 1-wire и ds18b20, когда на дворе уже как никак 2017 год? Куча библиотек, тонны информации в гугле. Вроде причин для этого нет, но тем не менее.

На самом деле, еще давным давно, во времена написания первой статьи про датчик температуры, я изучал информацию про таймслоты и шину в целом и хотел подробно ее рассмотреть. Даже черновик статьи был написан. Однако все и так работало, температура в большинстве случаев штука инертная, поэтому частый опрос датчиков редко где нужен. Плюс если учитывать, что шина сама по себе тормозная, да и датчик долго преобразовывает значения, то софтварной либы на задержках зачастую достаточно.

С той поры, появилось много статей про использование 1wire через Uart, с прикручиванием этого на stm32 через DMA. В общем сошлись звезды на небе, поэтому я решил отдать дань моде, заодно разобраться с мелочами, чтобы уже закрыть это вопрос основательно.

Прежде всего нужно разобраться в самим интерфейсом. Тут все просто. Всего 4 операции:
1. Запись бита 1
2. Запись бита 0
3. Чтение бита
4. Сброс

В официальной документации maxim можно найти такую картинку. Циферки взяты из того же документа.
1-wire
Однако если порыться поглубже, то цифры слегка разнятся. А если порыться совсем глубоко, то можно найти адовую табличку excel с лютыми расчетами. Поэтому будем ориентироваться что стандартный таймслот 60-68мкс, сброс 480-640мкс.

Напомню, для тех кто не в теме того как все это работает, шина всегда подтянута на единицу, устройства юзают open drain выходы, т.е. могут управлять только подачей нуля. Все посылки кодируются таймслотами, 1 таймслот = 1 биту информации. Бит кодируется длительностью импульса. Короткая подача нуля = лог1, длинная подача нуля = лог0.

Если внимательно присмотреться, то данный интерфейс сродни UARTу в режиме полудуплекса, т.е. одна и таже ножка используется и для передачи и для приема. Теперь, немного математики касательно стандартных скоростей UART:
1/115200 = 8,7мкс на передачу одного бита на скорости 115200
1/9600 = 104мкс на передачу одного бита на скорости 9600

Чтобы сформировать сброс, нужно использовать скорость 9600 и послать 0xF0 = 0b11110000, т.е. вначале пойдут 4 нуля данных и один ноль это старт бит, итого в течение передачи 5бит данных нога прижмется на = 5*104мкс = 520мкс. Затем пойдут единицы и нога подымется, тем самым давая возможность устройствам ответить. Сразу же читаем на той же скорости ответ. Если в ответ пришло не 0xF0, то значит на шине кто то есть.

Пример реального ответа датчика.
ds18b20

Теперь попробуем разобраться в записью одного бита. Замечательные картинки, которые все проясняют. Старт бит будет выдавать на линию 0 в течение 8,7мкс, в обоих случаях. Далее если передаем 0, то посылаем 0x00 на скорости 115200.
1wire_write0

Если передаем 1, то посылаем 0xFF на скорости 115200.
1wire_write1

И остался последний момент, это чтение. Отправляем 0xFF, читаем. Если пришло 0xFF, то бит = 1, иначе бит = 0.
read_1wire

Как уже было описано выше, таймслот кодирует всего 1бит, для передачи байта понадобится передать 8бит, т.е. 8 байт UART. Вполне логично использовать DMA если таковой имеется.

Теперь перейдем непосредственно к ds18b20.
Каждый датчик имеет 64битный серийный номер = Код семейства 0x28 + 48бит уникальный серийный номер + 8бит CRC.

Основные команды:
1. Skip Rom 0xCC. Позволяет общаться с всеми датчиками без выбора конкретного, например может быть полезна для одновременного запуска преобразования температуры.
2. Search ROM 0xF0. Используется для поиска датчиков на шине.
3. ROM Read Rom 0x33, позволяет прочитать серийный номер, если на шине всего один датчик.
4. Match Rom 0x55, позволяет общаться с конкретным датчиком, т.е. выбор датчика.
обмен данными
5. Запуск преобразования 0x44, т.е. начать измерение температуры.
6. Copy scratchpad 0x48, получить преобразованную температуру.

Все транзакции начинаются с инициализации, т.е. сброса, если датчик присутствует, то он отвечает, затем уже начинаем слать команды.

Единственная не очевидная команда это Search ROM 0xF0. Кидаем на шину команду поиска, затем читаем 2 бита, первый бит это основное значение, второй комплементарный, т.е. если в адресе устройства 1, то первый бит будет 1, а второй 0. В случае если оба бита 1, то значит устройств нет на шине. Однако, если устройств несколько и у первого в адресе 1, у второго 0, тогда оба бита прочитаем как 0. Это означает что устройства имеют разные биты в адресе. В этом случае отсылаем либо 1, либо 0 и продолжаем общаться только с одним из устройств. Как видите, пройтись по команде поиска придется ровно столько раз, сколько датчиков на шине.

Еще один тонкий момент это преобразование значения температуры. Температуру мы получаем из двух байт: 0-3 биты это значения после запятой, 4-12 собственно значение температуры, 12-16 знак. Если разрешение 12бит, то биты значащие, если 11бит, то нулевой не используется, если 9бит, то не используются с 0-2. Если температура отрицательная, то нужно инвертировать биты, добавить 1 и вычесть из нуля, чтобы получить отрицательное значение.

float ds18b20_tconvert(uint8_t LSB, uint8_t MSB)
{
    float data;
 
    uint16_t temperature;
 
    temperature = LSB | (MSB << 8);
 
    if (temperature & 0x8000) {
	temperature = ~temperature + 1;
        data = 0.0 - (temperature / 16.0);
        return data;
   }
    data = temperature / 16.0;
 
    return data ;
}

Теперь что касается программно-аппаратной реализации. В своих тестах я использовал stm32f100, подключал к UART1 в режиме half duplex, т.е. ножка PA9, с подтяжкой на 4.7кОм, собственно по схеме все.

По поводу программной части, тут довольно таки не просто, учитывая что кто то юзает hal, кто то spl, а кто то свои велосипеды. В общем на мой взгляд, так как 1-Wire часть сильно платформозависимая, то тут в любом случае придется вникать в суть происходящего, для разных процов. Я в свою очередь именно в этом проекте использовал SPL, поэтому за основу брал исходники из статьи steel_ne из сообщества easyelectronics. Кое где по мелочи поправил и добавил поиск датчиков из официальных примеров maxim. Опрос самого датчика в отдельном файле, упростил насколько смог. Код не вылизывал, поэтому как есть. Проверено работает с несколькими датчиками.

Как это юзать в своих программах?

int main(void)
{
    float  t1, t2;           
    if(ds18b20_init() == 0)  {
        //ERROR NO SENSORS
        while(1);
    }
 
    while(1){
        ds18b20_start_convert();    //start t convert
        for (uint32_t i=0; i<1000000; i++);     //wait 1 sec
        t1 = ds18b20_get_temp(0);   //get temp from 0 sensor
        t2 = ds18b20_get_temp(1);   //get temp from 1 sensor
    }
}

Забрать все это дело можно с github

14 комментариев: Stm32 + Ds18b20

  • Приветствую, почитал статьи, изложенное воспринимается хорошо. Хотел предложить Вам задачку, а именно запрограммировать ШИМ с возможностью смещения фаз по каналам и одновременно наличие возможности изменения частоты и скважности. 😆 Насколько я понимаю нужно подключать друг за другом таймеры…

  • реализация зависит от конечной цели.

  • Например реализация подачи топлива поочередно в цилиндры, частота это вращение двигателя, заполнение ШИМ это количество топлива.

  • думаю можно на одном таймере, софтово сделать.

  • Хорошая библиотека, но я так понял под 3х проводное подключение DS18B20.На EasyElectronics было продолжение для 2х проводного подключения. Сам попробую допилить и сделаю комит на GitHub.
    Вопрос: зачем было делать #define на выбор номера USART, если инициализация жёстко прописана под USART1 и ножку PA9?

  • Если про двухпроводную это вы имеете ввиду OW_out_set_as_Power_pin, то нет этого я не стал делать, добавить можно да. С дефайнами, вначале я хотел сделать универсально, но с кучей разных стмок, cmsis, hal, spl и докучи ремапами, все это теряет смысл, все равно где то, что то придется править под свой камень. Хотя конечно, можно заморочиться,

  • Кто-нибудь смог переписать работу с ds18b20 на CMSIS, а то у меня что-то не получается, не хочет работать.

  • Тоже запустил через uart, только без dma. С одним датчиком работает все норм с использованием команды SKIP_ROM. Но когда пытаюсь прочитать ROM код, всегда получаю нули. Логическим анализвтором посмотрел:
    — первый слот чтения — 0
    — второй слот чтения — 1
    — посылаю естественно 0
    И так вся процедура. Соотвественно получаю нули. Датчики рабочие, их ROM коды вычитывал старым драйвером «ногодрыгом».
    Вообще понять не могу в чем может быть дело…
    Может кто подскажет…

  • Вопрос решен!!!
    Дело было в том, что при отправке бита нужно было вычитать буфер uart-а оказывается. После того как это прописал все заработало. На самом деле немного странно, почему это происходило…
    В драйвере из статьи все сделано на DMA, и приемный буфер вычитываеся аппаратно. Но на DMA я так и не решился перейти, избыточно для данной задачи. Особенно передавать один байт))))))

  • Уважаемый автор, а можно Вас попросить на(пере)писать 1-wire секцию на HAL, пожалуйста?

  • Так и не понял нафига здесь DMA и почему не использовать ноги с выходами на таймер, вместо USARTов.

  • зависит от задачи. таймер это прерывание, это процессорное время. Если у вас куча датчиков висит на одной шине, то дма будет тратить значительно меньше процессорного времени.

  • у меня два вопроса вот вы написали что для приёма одна скорость а для передачи другая.А как настраивать или перестраивать USART в майне? Если использовать DMA то нужно использовать два буфера.Просто на порте мне понятно.А на USART нужно переходник а комады эти Skip Rom 0xCC и тд без функций как выполняются?

  • Если честно не понятен вопрос, какая разница где перенастраивать скорость? В целом можно и без дма обойтись.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Последние комментарии
  • Загрузка...
Счетчик
Яндекс.Метрика