STM32: Шина 1-Wire и термометр DS18B20

Последний из термодатчиков, про который я хочу написать — известнейший цифровой термометр DS18B20, который подключается по шине 1-Wire.

Он довольно удобен: подключается всего тремя проводами (или двумя в режиме паразитного питания), достаточно точен, а шина 1-Wire позволяет подключать множество таких датчиков и других устройств всего лишь через общие два провода: земля и данные/питание.

Команды

Каждое устройство 1-Wire откликается на общие команды (которые поддерживаются всеми устройствами) и на некоторый набор своих специфических команд. К общим командам относятся:

  • 0×F0 — перечисление ID устройств
  • 0×33 — чтение ID единственного подключенного устройства
  • 0×55 — поиск устройства по ID
  • 0×CC — обращение ко всем устройствам (пропуск ID)
  • 0×EC — поиск устройств, установивших флаг «тревога»

К специальным командам термодатчика DS18B20 относятся:

  • 0×44 — запуск измерения температуры
  • 0×4E — запись в регистры
  • 0×BE — чтение регистров
  • 0×48 — запись содержимого регистров в backup — внутренний EEPROM (операция push,)
  • 0×B8 — восстановление содержимого регистров из backup (операция pull)
  • 0×B4 — определить состояние питания: настоящее или паразитное.

Чтение температуры

Для простого чтения температуры с одного подключенного DS18B20 нам необходимо сделать три вещи:

Настройка регистров — чувствительность термометра (разрядность АЦП)

  1. 0×CC (обращаемся к единственному устройству на линии)
  2. 0×4E (запись в регистры)
  3. 0×4B (верхний порог тревоги)
  4. 0×46 (нижний порог тревоги)
  5. 0×5F (разрядность 11 бит)

Запуск измерения температуры

  1. 0xCC (обращаемся к единственному устройству на линии)
  2. 0x44 (запускаем измерение)

Нужно дать датчику около полсекунды на измерения, время зависит от точности измерения. Для разрядности 11 бит это 375 миллисекунд.

Чтение результата

  1. 0×CC (обращаемся к единственному устройству на линии)
  2. 0×BE (читаем регистры)
  3. читаем 16 бит

Результат будет в шестнадцатых долях градуса, то есть необходимо умножить его на 16 — или просто обрезать последние 4 бита, если доли градуса не нужны.

Протокол общения

Старт общения (сигнал presence): притяните DQ к земле на 500 мкс и отпустите. Через 20 мкс датчик ответит, притянув DQ к земле на 150 мкс.

Передача битов:

0 — притяните DQ к земле на 60 мкс, отпустите и подождите 30 мкс.

1 — притяните DQ к земле на 10 мкс, отпустите и подождите 80 мкс.

Я использую контакт PA3 в качестве DQ.

void delay(uint32_t del)
{
for(volatile uint32_t i = 0; i<del; i++); } void send_presence() {  GPIOA->ODR = GPIO_Pin_3;
delay(100);
GPIOA->ODR = 0;
delay(3500); //420us
GPIOA->ODR = GPIO_Pin_3;
}

void one_wire_write_bit(uint8_t bit)
{
GPIOA->ODR = 0;
delay(bit ? 150 : 500);
GPIOA->ODR = GPIO_Pin_3;
delay(bit ? 650 : 200);
}

uint8_t one_wire_read_bit()
{
uint8_t bit = 0;
GPIOA->ODR = 0;
delay(80);
GPIOA->ODR = GPIO_Pin_3;
delay(50);
GPIOA->CRL &= ~GPIO_CRL_MODE3;
GPIOA->CRL &= ~GPIO_CRL_CNF3;
GPIOA->CRL |=  GPIO_CRL_CNF3_0;
bit = (GPIOA->IDR&GPIO_Pin_3?1:0);
GPIOA->CRL |=  GPIO_CRL_MODE3;
GPIOA->CRL |=  GPIO_CRL_CNF3_0;
delay(600);
return bit;
}

void one_wire_write_byte(uint8_t data)
{
for(uint8_t i = 0; i<8; i++)   one_wire_write_bit(data>>i & 1);
}

int main()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

GPIO_InitTypeDef  GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIOA, &GPIO_InitStructure);

send_presence();
delay(5500);
one_wire_write_byte(0xCC);
one_wire_write_byte(0x4E);
one_wire_write_byte(0x4B);
one_wire_write_byte(0x46);
one_wire_write_byte(0x5F);

send_presence();
delay(5500);
one_wire_write_byte(0xCC);
one_wire_write_byte(0x44);
delay(6000000);

send_presence();
delay(5500);
one_wire_write_byte(0xCC);
one_wire_write_byte(0xBE);
delay(4000);
uint16_t data = 0;
for(uint8_t i = 0; i<16; i++) data += (uint16_t)one_wire_read_bit()<<i;
float temp = data/16.0;
}

Обязательно прочитайте памятку по подводным камням в 1-Wire и DS18B20.

Ссылка на основную публикацию