База знаний по трехмерному проектированию в Pro/Engineer, Creo, Solidworks, электронике на STM32

Обучение STM32. Подключаем датчик температуры STLM75 по шине I2C


В этом уроке по STM32 вы научитесь:

  • подключать датчик температуры по шине I2C
  • считывать показания с датчика температуры
  • просматривать значения переменных в режиме отладки
  • конфигурировать датчик температуры

 

Разбираемся с датчиком

 

Характеристики интегрального датчика температуры STLM75 (даташит здесь):

  • Измеряет температуру от –55 ° C до + 125 ° C ( –67 ° F ... + 257 ° F)

    • Типовая точность ± 0,5 ° C
    • Максимальная точность ± 2 ° C в пределах от –25 ° C до + 100 ° C
  • Низкий рабочий ток: 125 мкА (типовой)
  • Не требуются внешние компоненты
  • 2-х проводный последовательный интерфейс I2C / SMBus
    • Поддерживает функцию таймаута шины
    • Настройка адреса устройства в шине (до восьми устройств)
  • Широкий диапазон напряжения питания: от 2,7 В до 5,5 В
  • Время преобразования 150 мс (макс.)
  • Программируемый температурный порог срабатывания TOS и гистерезиса THYS
  • Полная совместимость по выводам и программированию с LM75 от компаний Texas Instruments, NXP
  • Уставки по умолчанию при включении позволяют работу в автономном режиме с функцией термостата
  • Присутствует режим отключения, чтобы минимизировать потребление
  • Выходной транзистор (открытый сток) может быть настроен в режиме прерывания или компаратора / термостата
  • Корпуса:
    • SO8
    • MSOP8 (TSSOP8)

 

Подключение датчика температуры по шине I2C

 

В данном уроке рассматривается датчик STLM75 в корпусе MSOP8 (TSSOP8) и подключать мы его будем к микроконтроллеру STM32F030F4P6, которых в Китае можно купить по 35 руб за штуку при партии 5 шт. Для этого нам понадобятся переходные платы и штыревые соединители к ним, которые тоже легко купить в Китае. STM32 и STLM75 паяем без всяких дополнительных конденсаторов и осцилляторов (будем для тактирования использовать внутренний генератор STM). Все это соединяем тренировочными шлейфами и тестируем софт на плохих и длинных соединениях.

Интерфейс квадратной шины I2C довольно глючный, поэтому лучше все соединения на этой шине делать аккуратно. Но для нашего случая будет специально делать все плохо, чтобы с помощью программных методов сделать работоспособное устройство. О работе и подключению к шине I2C можно узнать более подробно из этого урока: STM32. Подключаем к STM32 энергонезависимую EEPROM память.. Только здесь мы будем использовать в дефайнах (#define I2C1_WRITE_ADDRESS 0x90h) уже готовый адрес датчика (со смещением) = 0x90h, что означает подключение выводов A2, A1, A0 к земле. Итак, нарисуем схему подключения датчика к микроконтроллеру.

От урока с подключение к EEPROM памяти этот отличается немного другим форматом адреса

Адресация STLM75 в шине I2C
Рис.2. Адресация STLM75 в шине I2C

 

 

Как сообщалось выше мы не будем устанавливать фильтрующих конденсаторов по питанию датчика и микроконтроллера. Установим только необходимые для работы шины I2C резисторы 10 кОм. Также реализуем такой функционал, как сброс микроконтроллера при достижении определенной температуры на датчике. Например, нижняя температура эксплуатации микроконтроллера -40 °C, если брать индустриальные экземпляры. Т.е. при достижении -35°C он гарантировано должен работать. Эту температуру можно записать в интегральный датчик в порог срабатывания TOS (задать также гистерезис THYS) и включать микроконтроллер только при температуре -35°C.

Микроконтроллеры STM32 не запускаются при низком уровне на входе NRST. Т.е. нам необходимо включить его подачей напряжения питания, поэтому сделаем через резистор 10 кОм подтяжку к питанию входа NRST, чтобы по умолчанию у нас STM32 все-таки включался. Но соединение с выводом OS датчика STLM75 еще делать рано, т.к. датчик по умолчанию запрограммирован не совсем хорошо для нашего случая. Вот его характеристики при первом включении:

  • Термостат работает в режиме компаратора
  • Полярность выхода OS — активный низкий уровень
  • Температура срабатывания компаратора вверху TOS — 80 °C (включение)
  • Температура срабатывания компаратора внизу THYS — 75 °C (гистерезис на отключение)
  • Температурный регистр содержит значение 00
Диаграммы событий TOS и THYS
Рис.4. Диаграммы событий TOS и THYS. Выход OS (открытый исток) в режиме компаратора и режиме коротких импульсов

 

 

Регистры датчика температуры STLM75

 

Всего существует 4 регистра, обращение к которым идет по номеру. Как видно из таблицы ниже, все регистры 16 битные, кроме конфигурационного (8 бит).

В регистре конфигурации нас интересует младшие 3 бита: 0 — SD (shutdown control bit — бит выключения датчика: 1 = выключить датчик), 1 — M (режим работы: 0 = компаратор,1 = короткие импульсы при любом событии), 2 — POL (output polarity — полярность выхода OS: 0 = активный низкий, 1 = активный верхний).

По умолчанию все биты равны нулям. Для работы нам потребуется изменить только бит 2 — полярность, чтобы микроконтроллер STM32 включался при росте температуры выше заданной в регистре TOS.

Таблица описания регистров STLM75
Номер регистра P1 P0 Наименование Описание Ширина (бит) Тип (R/W) Значения при включении Комментарии
0x00 0 0 TEMP Температурный регистр 16 Только для чтения - Результат измерения температуры
0x01 0 1 CONF Регистр конфигурации 8 Чтение/запись 00  
0x02 1 0 THYS Регистр гистерезиса (нижний порог) 16 Чтение/запись 0x4B00 По умолчанию 75 °C
0x03 1 1 TOS Регистр превышения температуры 16 Чтение/запись 0x5000 По умолчанию 80 °C

 

Формат хранения температуры в STLM75 это по сути обычно однобайтное целое число со знаком + 1 младший бит — точность = 0.5 °C (если это бит равен 1, то это повышение температуры на 0.5 °C относительно целого числа). Итого получается 9 бит, которые необходимо хранить в 2-х байтах. Отсюда и ширина регистров температуры — 2 байта. Причем однобайтное целое значение температуры хранится в старшем байте, а оставшийся бит (0.5 °C) — в верхнем бите нижнего младшего байта. Т.е. температура +0.5 °C разбивается на байты таким образом: 00000000 10000000.

Если точность 0.5 °C не интересует, можно брать сразу верхний байт и пользоваться. Если точность важна, то просто смещаем двухбайтное число вправо на 7 и умножаем на 0.5 (или делим на 2). Получится уже переменная со знаком и с плавающей точкой. Например в датчике LM75 от NXP температура сохраняется в 11 битном формате, где 3 бита отведены под точность 0.125 °C. Поэтому для получения числа с такой точностью нужно сместить двухбайтное число вправо на 5 и умножать на 0.125 (или делить на 8). Получится уже переменная со знаком и с плавающей точкой с тремя цифрами после запятой.

 

Таблица представления температуры в разных форматах (жирным выделен верхний байт)
Температура Представление в регистрах
Двоичный (последний бит это точность = 0.5 °C) Шестнадцатеричный Расположение в памяти
+125 °C 01111101 0 0x0FA 01111101 00000000
+25 °C 00011001 0 0x032 00011001 00000000
+0.5 °C 00000000 1 0x001 00000000 10000000
0 °C 00000000 0 0x000 00000000 00000000
–0.5 °C 11111111 1 0x1FF 11111111 10000000
–25 °C 11100111 0 0x1CE 11100111 00000000
–40 °C 11011000 0 0x1B0 11011000 00000000
–55 °C 11001001 0 0x192 11001001 00000000

 

Если температурный регистр TEMP доступен только для чтения, то в регистры THYS и TOS можно записывать нужные нам температуры. С регистрами разобрались, теперь приступим к настройке CubeMX.

 

Разбираемся с STM32

 

Настройка выводов в CubeMX

В CubeMX назначим функции SCL и SDA на выводы PA9 и PA10. Выводы PA13 и PA14 используем для обмена информацией с дебаггером по протоколу SWD (Serial Wire Debug). Естественно, для прошивки берем тот же китайский программатор за $2. Настройки шины I2C оставляем без изменений.

Далее переходим на вкладку Clock Configuration. Настройку тактового генератора STM32 оставляем без изменений, внешнего кварца нет. Тактируемся от внутреннего тактового генератора HSI 8 МГц. То, что он нестабилен от температуры нас не волнует — мы не в космосе! Вот и все генерируем проект для MDK-ARM V5.

 

Чтение интегрального датчика температуры

Открываем сгенерированный проект в Keil. В секции /* USER CODE BEGIN PV */ … /* USER CODE END PV */ запишем наши определения и переменные:

/* USER CODE BEGIN PV */

#define I2C1_WRITE_ADDRESS      0x90  	/*7-битный адрес датчика на шине I2C (три младших бита задаются на выводах A2,A1,A0 микросхемы): 1001000(A2+A1+A0)=48h<<1=90h -> A0 = A1 = A2 = 0 */
#define REG_TEMP      			0x00	//Адрес регистра текущей температуры
#define REG_CONF      			0x01	//Адрес регистра конфигурации
#define REG_T_HYS      			0x02	//Адрес регистра гистерезиса (нижний порог отключения)
#define REG_T_OS      			0x03	//Адрес регистра включения выхода OS

uint8_t xBuffer[2], xBuffer_current[2];	//вспомогательные буферы 
float tempcurrent = 0;					//текущая температура в формате float
float temphyst 	  = 0;					//температура гистерезиса в формате float
float tempos	  = 0;					//температура включения OS в формате float


typedef union {							//объединение для более удобной работы с представлениями числа с памяти
	uint8_t Bites[2];
	int16_t Word;
} _TwoBites_int;

_TwoBites_int Result_t;					//см. выше

HAL_StatusTypeDef eI2C_status;			//ошибки I2C

/* USER CODE END PV */

 

В бесконечном цикле main() запишем основные алгоритмы чтения регистров температуры THYS, TOS и TEMP. Очень удобно пользоваться объединением Result_t для чтения из буфера xBuffer_current байтов в обратном порядке. В Result_t необходимо сделать необходимое смещение на 7 вправо для перемещения числа в правильную позицию (для датчика LM75A от NXP нужно сместить на 5 бит, т.к. в этого датчика точность выше — 11 бит). Далее число делим на 2 и температура у нас получается в нормальном float представлении со знаком. Для температур THYS и TOS просто читаем первый байт вспомогательного буфера temphyst = (int8_t) xBuffer[0]; tempos = (int8_t) xBuffer[0]. Этой точности нам вполне хватит. Переменные temphyst и tempos можно было сделать типа int8_t — целое со знаком.

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
		eI2C_status = HAL_I2C_Mem_Read(&hi2c1, (uint16_t) I2C1_WRITE_ADDRESS, REG_T_HYS, I2C_MEMADD_SIZE_8BIT, xBuffer, 2, 10); /*REG_T_HYS - читаем регистр нижнего порога отключения*/
		if (eI2C_status != HAL_OK)	//Перезапускаем I2C в случае ошибки, иначе могут быть зависания
		{
			HAL_I2C_DeInit(&hi2c1);
			HAL_Delay(5);
			HAL_I2C_Init(&hi2c1);
			HAL_Delay(5);
			//NVIC_SystemReset();
		}		
		temphyst = (int8_t) xBuffer[0]; //преобразуем в целое со знаком

		
		eI2C_status = HAL_I2C_Mem_Read(&hi2c1, (uint16_t) I2C1_WRITE_ADDRESS, REG_T_OS, I2C_MEMADD_SIZE_8BIT, xBuffer, 2, 10); /*REG_T_OS - читаем регистр верхнего порога включения*/
		if (eI2C_status != HAL_OK)	//Перезапускаем I2C в случае ошибки, иначе могут быть зависания
		{
			HAL_I2C_DeInit(&hi2c1);
			HAL_Delay(5);
			HAL_I2C_Init(&hi2c1);
			HAL_Delay(5);
			//NVIC_SystemReset();
		}		
		tempos = (int8_t) xBuffer[0]; //преобразуем в целое со знаком		
		
		
		eI2C_status = HAL_I2C_Mem_Read(&hi2c1, (uint16_t) I2C1_WRITE_ADDRESS, REG_TEMP, I2C_MEMADD_SIZE_8BIT, xBuffer_current, 2, 10); /*0x00*/
		if (eI2C_status != HAL_OK)	//Перезапускаем I2C в случае ошибки, иначе могут быть зависания
		{
			HAL_I2C_DeInit(&hi2c1);
			HAL_Delay(5);
			HAL_I2C_Init(&hi2c1);
			HAL_Delay(5);
			//NVIC_SystemReset();
		}
		
	
		Result_t.Bites[1] = xBuffer_current[0];
		Result_t.Bites[0] = xBuffer_current[1];
		
		//Простое получение целого числа со знаком
		//tempcurrent = (int8_t) xBuffer_current[0]; //в xBuffer_current[0] содержится целое число, а в xBuffer_current[1] - 1 цифра после запятой (самый верхний бит: 1 = 0.5°C, 0 = 0°C)
		
		/* Алгоритм получения температуры из 9 битного числа со знаком:
		1) Result_t(2byte) сдвигаем на 7 бит вправо для правильного расположения числа в памяти 
		2) Делим число на 2 для получения 1 знака после запятой*/
		tempcurrent = ((Result_t.Word>>7) & 0x1FF) * 0.5 ; 		//= (9  digits + & 0x1FF(фильтр))/2 (сдвигаем показания (или точку) на 3 разряда, ибо точность 0.5   градуса)
	//tempcurrent = ((Result_t.Word>>5) & 0x1FF) * 0.125 ;	//= (11 digits + & 0x1FF(фильтр))/8 (сдвигаем показания (или точку) на 3 разряда, ибо точность 0.125 градуса) - для LM75A от NXP
		
  }
  /* USER CODE END 3 */

 

Компилируем, прошиваем проект в STM32. Самое время запустить дебаггер CTRL+F5 посмотреть состояние переменных. Переменные в окно просмотра Watch 1 заносим в режиме дебаггера с помощью клика правой кнопки мыши на нужно переменной в тексте программы и выбора в контекстном меню команды Add … to - Watch 1. Теперь можно увидеть оказания нашего датчика.

 

Теперь попробуем записать в регистры THYS и TOS нужные нам температуры. В переменную temphyst запишем -29 °C, а tempos -28 °C. Это нужно сделать 1 раз, т.е. перед бесконечным циклом. Поэтому запишем эти функции в этот раздел /* USER CODE BEGIN 2 */ … /* USER CODE END 2 */. Запускаем и наслаждаемся отображением в дебаггере измененных значений регистров.

 /* USER CODE BEGIN 2 */
	
	
	//temphyst
	xBuffer[0] = -29; //-29°C; ;
	xBuffer[1] = 0;
	
	
	eI2C_status = HAL_I2C_Mem_Write(&hi2c1, (uint16_t) I2C1_WRITE_ADDRESS, REG_T_HYS, I2C_MEMADD_SIZE_8BIT, xBuffer, 2, 10); /*0x00*/
	if (eI2C_status != HAL_OK)	//Перезапускаем I2C в случае ошибки, иначе могут быть зависания
	{
		HAL_I2C_DeInit(&hi2c1);
		HAL_Delay(5);
		HAL_I2C_Init(&hi2c1);
		HAL_Delay(5);
		//NVIC_SystemReset();
	}		

	
	//tempos
	xBuffer[0] = -28; //-28°C; ;
	xBuffer[1] = 0;
	
	
	eI2C_status = HAL_I2C_Mem_Write(&hi2c1, (uint16_t) I2C1_WRITE_ADDRESS, REG_T_OS, I2C_MEMADD_SIZE_8BIT, xBuffer, 2, 10); /*0x00*/
	if (eI2C_status != HAL_OK)	//Перезапускаем I2C в случае ошибки, иначе могут быть зависания
	{
		HAL_I2C_DeInit(&hi2c1);
		HAL_Delay(5);
		HAL_I2C_Init(&hi2c1);
		HAL_Delay(5);
		//NVIC_SystemReset();
	}		
	

  /* USER CODE END 2 */

 

 

Отлично, запишем в регистры THYS и TOS правильные температуры работы TOS= -35 °C и THYS= -40 °C. Т.е. при -40 °C у нас будет подаваться внешняя команда RESET на STM32 (согласно схеме). А при -35 °C у нас будет запускаться STM32. После этого можно записывать в регистр конфигурации изменения полярности выхода OS — чтобы сброс (логический нуль) выдавался на STM 32 при температурах холоднее -35 °C. Для этого после /* USER CODE BEGIN 2 */ запишем следующее:

  /* USER CODE BEGIN 2 */
	
	int i = 0;
	/*Записываем (3й бит = 1) в регистр конфигурации REG_CONF для реверсирования выхода OS
	Т.е. мы будем не включим STM32 до тех пор, пока датчик не нагреется выше -35 градусов
	
	*/
	eI2C_status = HAL_ERROR; //подготовка к записи
	while ( (eI2C_status != HAL_OK) & (i < 10) )	//Перезапускаем шину I2C в случае ошибки и повторяем запись в регистр 10 раз, если есть ошибки записи
	{
		HAL_I2C_DeInit(&hi2c1);
		HAL_Delay(5);
		HAL_I2C_Init(&hi2c1);
		HAL_Delay(5);
		//NVIC_SystemReset(); //Обойдемся без рестарта STM32
		//Повторяем 10 попыток записи в регистр
		eI2C_status = HAL_I2C_Mem_Write(&hi2c1, (uint16_t) I2C1_WRITE_ADDRESS, REG_CONF, I2C_MEMADD_SIZE_8BIT, (uint8_t*)0x4, 1, 10); /*00000100b=0x4 - OS - reverse polarity*/
		i++;
	}			

 

Теперь наш боевой микроконтроллер с датчиком температуры можно пересаживать на печатную плату и радоваться копеечной стоимости девайса!


Скачать прикрепленный файл main.zip

Скачать пример


Яндекс.Метрика

Поделиться ссылкой на статью

Engio.ru - лучший инженерный опыт, бесплатные уроки и обучение Solidworks, Creo, Pro/Engineer, STM32
Комментировать