Подключение датчика температуры 18В20 к микроконтроллеру STM32f103.

Сегодня мы подключим датчик температуры 18B20

к микроконтроллеру STM32f103. 

Подключать датчик будем по трем проводам:

Значение емкости составляет от 10nF до 0,33мкF, если датчик стоит почти рядом с микроконтроллером — емкость можно не ставить.

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

  1. Отсылаем импульс сброса;
  2. Датчик посылает импульсом присутствия;
  3. Отсылаем адресную команду «Skip ROM» (0xCC)( команда актуальная для 1 датчика на линии);
  4. Отсылаем команду начать измерение температуры (0x44); 
  5. Ждем окончания преобразования (для 12 битного преобразования — 800ms)
  6. Отсылаем импульс сброса.
  7. Датчик посылает импульсом присутствия;
  8. Отсылаем адресную команду «Skip ROM» (0xCC);
  9. Отсылаем команду запрос на чтение данных (0хВЕ);
  10. Считываем данные температуры с датчика (два байта).

Датчик подключим к ножке 7 порта С.

Значение выведем на экран с помощью функции printf Урок №15.

Программный код:

#ifndef __18B20_H
#define __18B20_H
#include "stm32f1xx_hal.h"
#define PORT GPIOC //указать порт, к которому подключены датчики
#define TIMER TIM3 //задаем таймер, используемый для формирования задержек

uint8_t ds_start_convert_single(uint8_t PinNumb); //запустить измерение температуры /
signed int ds_read_temperature(uint8_t PinNumb); //прочитать результат измерения
void ini_datcik();

#endif
#include "18B20.h"

void ini_datcik(){
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //Разрешить тактирование порта /
GPIOC->CRL &= ~GPIO_CRL_MODE7; //Очистить биты MODE
GPIOC->CRL &= ~GPIO_CRL_CNF7; //Очистить биты CNF
GPIOC->CRL |= GPIO_CRL_MODE7_1 ; //Выход,частота 2MHz
GPIOC->CRL |= GPIO_CRL_CNF7_0; //Открытый сток общего назначения
GPIOC->ODR |= 1<<7 ; //отпустить шину

RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; //подать тактирование на TIM3 /
TIM3->PSC = 72-1; //настроить делитель для формирования микросекунд
TIM3->ARR = 1000-1; // делаем 1000 раз переполнение и потом выдаем прерывание
TIM3->CR1 = TIM_CR1_CEN; // запускаем прерывание
}

//сброс
//return 0 – устройство обнаружен, 1 – не обнаружено, 2 – к.з. на линии //
uint8_t ds_reset_pulse(uint16_t PinMask){
uint16_t result;
if((PORT->IDR & PinMask)==0) return 2; //проверить линию на отсутствие замыкания
PORT->ODR &= ~PinMask; //потянуть шину к земле
TIMER->CNT=0;
while(TIMER->CNT<480){}; //ждать 480 микросекунд
PORT->ODR |= PinMask; //отпустить шину
while(TIMER->CNT<550){}; //ждать 70 микросекунд
result = PORT->IDR & PinMask; //прочитать шину
while(TIMER->CNT<960){}; //дождаться окончания инициализации
if(result) return 1; //датчик не обнаружен
return 0; //датчик обнаружен
}

//передача бита
void ds_write_bit(uint8_t bit,uint16_t PinMask){
TIMER->CNT=0;
PORT->ODR &= ~PinMask; //потянуть шину к земле
while(TIMER->CNT<2){}; //ждать 2 микросекунду
if(bit) PORT->ODR |= PinMask; //если передаем 1, то отпускаем шину
while(TIMER->CNT<60){}; //задержка 58 микросекунд
PORT->ODR |= PinMask; //отпускаем шину
while(TIMER->CNT<62){} // пауза в 2 мкс для разделения битов !!!!
}

//чтение бита
uint16_t ds_read_bit(uint16_t PinMask){
uint16_t result;
TIMER->CNT=0;
PORT->ODR &= ~PinMask; //потянуть шину к земле
while(TIMER->CNT<2){};
PORT->ODR |= PinMask; //отпускаем шину
while(TIMER->CNT<15){}; //задержка 15 микросекунд
result = PORT->IDR & PinMask; //прочитать шину
while(TIMER->CNT<60){}; //оставшееся время
return result; //возвратить результат
}

//запись байта
void ds_write_byte(uint8_t byte, uint16_t PinMask){
uint8_t i;
for(i=0;i<8;i++) ds_write_bit(byte&(1<<i), PinMask);
}

//чтение байта
uint8_t ds_read_byte(uint16_t PinMask){
uint8_t i,result = 0;
for(i=0;i<8;i++)
if(ds_read_bit(PinMask)) result |= 1<<i;
return result;
}

//пуск измерения температуры
//return 0 – пуск выполнен, 1 – датчик не обнаружен, 2 – к.з. на линии //
//*********************************************************************************************
uint8_t ds_start_convert_single(uint8_t PinNumb){
uint8_t result;
result = ds_reset_pulse(1<<PinNumb); //послать импульс сброса
if(result) return result; //если ошибка – возвращаем ее код
ds_write_byte(0xCC,1<<PinNumb); //разрешить доступ к датчику не используя адрес
ds_write_byte(0x44,1<<PinNumb); //запустить преобразование
return 0;
}

//чтение памяти датчика
//return 0 – данные прочитаны, 1 – датчик не обнаружен, 2 – к.з. 3 – ошибка CRC //
uint8_t ds_read_data_single(uint8_t *buff, uint8_t PinNumb){
uint8_t crc = 0;
uint8_t data;
uint8_t i,j;
uint8_t tmp;

tmp = ds_reset_pulse(1<<PinNumb); //послать импульс сброса
if(tmp) return tmp; //если ошибка – возвращаем ее код
ds_write_byte(0xCC,1<<PinNumb); //разрешить доступ к датчику не используя адрес

ds_write_byte(0xBE,1<<PinNumb); //запрос 9 байт памяти

//прочитать 8 байт и вычислить CRC
for( i=0; i<8; i++){
data = ds_read_byte(1<<PinNumb); //прочитать очередной байт
buff[i] = data; //сохранить его в массиве
//вычисление CRC – обрабатываем каждый бит принятого байта
for( j=0; j<8; j++){//CRC = X^8+X^5+X^4+1 
tmp = (crc ^ data) & 0x01;// ^ - побитовое исключающее или
if (tmp==0x01)
crc = crc ^ 0x18;
crc = (crc >> 1) & 0x7F;
if (tmp==0x01)
crc = crc | 0x80;
data = data >> 1;
}
}

data = ds_read_byte(1<<PinNumb); //прочитать CRC датчика
if(crc==data) return 0; //если CRC совпали – значит ошибки нет
return 3; //CRC не совпали, ошибка принятых данных
}

//чтение температуры датчика
//return 1280 – ошибка, иначе – результат измерения //
signed int ds_read_temperature(uint8_t PinNumb){
signed char integer = 0;
signed char frac;
signed int result;
uint8_t buff[8];

//прочитать данные из датчика
if(ds_read_data_single(&buff[0],PinNumb)) return 1280;

frac = buff[0] & 0x0f; //получить дробную часть
integer = (buff[0]>>4) | ((buff[1] & 0x0f)<<4); //получить целую часть

//если температура отрицательная
if(integer<0){
integer = 0 - integer - 1;
result = integer *10; //учитываем целую часть
frac = frac | 0xf0;
frac = 0 - frac ;
}
//если температура положительная
else result = integer *10; //учитываем целую часть

result = result + ((frac*10)/16); //учитываем дробную часть
return result;
}
/* USER CODE BEGIN Includes */
#include "18B20.h"
#include "stdio.h"
/* USER CODE END Includes */

/* USER CODE BEGIN 1 */
signed int tmp_t=0;
/* USER CODE END 1 */


/* USER CODE BEGIN Init */
ini_datcik();

/* USER CODE END Init */

/* USER CODE BEGIN 3 */
printf("Hellow\r\n");
ds_start_convert_single(7); //запустить измерение температуры /
HAL_Delay(800); //время для окончания преобразования
tmp_t = ds_read_temperature(7); //прочитать результат измерения
printf (" T = %d",tmp_t/10);
printf (",");
printf ("%1d \r \n",(tmp_t%10));
}
/* USER CODE END 3 */