Казалось бы, зачем писать про 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

4 комментария: Stm32 + Ds18b20

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

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

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

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

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

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

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

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