База знаний по трехмерному проектированию в 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
От урока с подключение к EEPROM памяти этот отличается немного другим форматом адреса
Микроконтроллеры STM32 не запускаются при низком уровне на входе NRST. Т.е. нам необходимо включить его подачей напряжения питания, поэтому сделаем через резистор 10 кОм подтяжку к питанию входа NRST, чтобы по умолчанию у нас STM32 все-таки включался. Но соединение с выводом OS датчика STLM75 еще делать рано, т.к. датчик по умолчанию запрограммирован не совсем хорошо для нашего случая. Вот его характеристики при первом включении:
- Термостат работает в режиме компаратора
- Полярность выхода OS — активный низкий уровень
- Температура срабатывания компаратора вверху TOS — 80 °C (включение)
- Температура срабатывания компаратора внизу THYS — 75 °C (гистерезис на отключение)
- Температурный регистр содержит значение 00
Регистры датчика температуры 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.
Номер регистра | 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) | Шестнадцатеричный | Расположение в памяти | |
+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
Чтение интегрального датчика температуры
Открываем сгенерированный проект в 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 */
Теперь попробуем записать в регистры 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 */
/* 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++;
}
Теперь наш боевой микроконтроллер с датчиком температуры можно пересаживать на печатную плату и радоваться копеечной стоимости девайса!
Теги
Поделиться ссылкой на статью