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

  • Автор
i2c - шина данных для обмена информацией между устройствами. Представлена двумя линиями - линия данных SDA (второй вывод в колодке GPIO) и тактовая линия SCL (третий вывод в колодке GPIO).  




Как передаются данные по i2c на электрическом уровне я описывать не буду, это всё можно прочитать в гугле, поэтому перейдём сразу к практической части. Нам потребуется  чип датчика температуры LM75A:

13604520055116d9a5723e0.jpg

Поскольку чип выполнен в очень неудобном для домашнего использования форм-факторе soic-8 (очень мелкий), то нам также потребуется переходник на DIP-8,
1360674018511a3ce2e1edb.jpg
чтобы можно было сделать проводное соединение с  Raspberry Pi. Припаиваем чип к переходнику. Линии SDA и SCL необходимо подтянуть резисторами 1кОм к питанию.В итоге конструкция должна выглядеть примерно так:
1360672968511a38c827015.jpg
1360672950511a38b6a1a5d.jpg

Я использовал Raspbian по 2 причинам:
1. В дистрибутив включены i2c драйвера в виде модулей ядра, которые остаётся лишь подгрузить командой modprobe
2. в репозитории есть i2c-tools, которые нам потребуются для работы с датчиком температуры Итак, подгружаем модули ядра, которые позволят нам работать с i2c:
sudo modprobe i2c-dev
sudo modprobe i2c-bcm2708

Устанавливаем i2c-tools из репозитория: sudo apt-get install i2c-tools
В i2c-tools входят следующие утилиты:
i2cdetect - для определения устройств, подключенных к шине i2c
i2cget - для чтения данных из регистров подключенных устойств
i2cset - запись данных в регистры подключённых устройств
Для начала проверим, что драйвера успешно подгрузились и шина данных i2c видна.
i2c-detect -l
Если в выводе команды отобразились доступные шины i2c (i2c-0, i2c-1), то значит можно двигаться дальше.
Будем работать с i2c-0. Подключим датчик температуры к линиям SDA0 и SCL0,  5V питания и GND для датчика также будем брать с колодки GPIO.

Если датчик правильно подключён, то в ответ на команду i2cdetect -y 0 мы увидим сетку, в одной из ячеек которой будет стоять адрес датчика (в моём случае 48).
К одному ведущему (master) устройству по i2c можно подключить множество ведомых (slave), поэтому каждому ведомому устройству необходим адрес, по которому к нему будет обращаться ведущее устройство. Адрес датчика LM75A задаётся в регистре Conf
1360679012511a50640c40b.jpg
A2,A1,A0 - выводы 7,6,5 чипа LM75A(см.схему ниже). Если они присоединены к питанию, то принимают значение 1, если к земле, то 0.  У меня А0 A1 A2 посажены на землю, а значит регистр, отвечающий за адрес имеет значение (1001000=0x48), что подтверждается командой i2cdetect
1360679066511a509a38b67.jpg

Теперь получим значение температуры. LM75A проводит замеры температуры каждые 100мс. Её значение хранится в регистре Temp, который состоит из двух байтов.  t=(значение регистра Temp, сдвинутое на 5 битов вправо)*0.125
1360679930511a53fa9c9fd.jpg

 Получим значение регистра:
 i2cget -y 0x48 0x00 w
-y: игнорировать предупреждение о потенциальной опасности i2c-tools для вашего оборудования.
0x48 - адрес датчика на шине i2c
0x00 -  адрес регистра Temp
>w - получить слово данных (поскольку ответ состоит из двух байтов. Для получения одного байта нужно использовать параметр b)

в ответ мы должны увидеть значение регистра Temp. У меня это 0xa014
0xa0 - значение младшего байта (LSByte)0x14 - значение старшего байта (MSByte) записываем в двоичной форме и сдвигаем на 5 битов вправо: 10100101=165
165*0.125 = 20.625 градусов значение температуры на датчике.

Запись в регистры рассмотрим в следующей статье, в которой будем управлять чипом FM приёмника по i2c

Не люблю Android

Комментарии:

AEgorov12
а нельзя ли использовать внутреннюю подтяжку линий к + питания?
Mike3
Можно. На Raspberry Pi реализована внутренняя подтяжка SDA и SCL 1,8kОм резисторами. Просто эта панелька с датчиком температуры у меня валялась давно и подключалась к плате, в которой не было внутренней подтяжки на i2c линиях
AEgorov12
это хорошо. в описании на этоту микросхемку есть фраза, что старший бит старшего байта определяет, положительная температура или отрицательная. как это можно реализовать в программе для вывода реальной температуры?
Mike3
Если температура отрицательная, то бит D10 старшего байта температурного регистра будет равен 1, т.е если значение старшего байта регистра температуры >127.

В этом случае температура будет вычислять следующим образом:
значение регистра температуры приводится к дополнительному коду (dop_code=~temp_registry_value+1), сдвигается на 5 разрядов вправо и умножается на 0.125:
temp = (dop_code>> 5)*0.125
EGA7
Когда же уже ждать "Запись в регистры рассмотрим в следующей статье, в которой будем управлять чипом FM приёмника по i2c"?
Mike3
Через 2-3 недели, когда я получу пополнение из Китая. Что-то не смог я у себя FM чип найти и выковырять неоткуда.
EGA7
Ясно, будем ждать. А на этом сайте есть какая нибудь возможность личной переписки или отправки сообщений с сайта на элпочту?
Ну или тему на форуме на крайний случай создать, хотелось бы двухстороннее общение вести, без засорения блогов. Весьма интересует работа с i2c.
Mike3
Да, тут даже на форуме ветка есть для обсуждения аспектов GPIO
http://raspberrypi.ru/forum/topics/20/
EGA7
Или по i2c все таки лучше в раздел подключения микросхем http://raspberrypi.ru/forum/topics/21/? Хотя это и не важно. Пойду создам тему.
DaTo0
то есть, про радио не будет??:(
PeterHirt3
да, интересно про i2c, про запись и если можно - популярно про мастер/слейв и подключение нескольких однотипных/разнотипных датчиков. использование второй шины вместе с первой и тп) все очень интересно. расскажите плиз.
I am mehanic1
Сорцы на СИ-градусника с оповещением. Подключение темдатчика, как написано выше в этой ветке...Для подключения свдиода задействован GPIO17 (P1-11) питание взято с P1-17 в файле-исходнике blink.c есть подробно-коменты...Оба файла кладем в одну дирректорию--папку короче Да предварительно ставим bcm2835 у кого нет... как написано здесь http://www.airspayce...835/index.html. Компилим строкой: gcc tbody.c -o tbody -l bcm2835 --есть в комментах в сорце tbody.c.., греем рукой, при 29 и более диод будет мигать 3 раза, затем вывод текущей темп., если равно или более 29 ---3 мига, если менее 29 --- выводит постоянно темп-ру... Уставку по градусам и еще что либо можно поставить свои... См. коменты. Исходники ниже...

//Код tbody.c:
//Hi!!! This mehanical program version. Источник сорцов на СИ http://www.ip-symcon.de/forum/threads/21088-Raspberry-PI-Modbus-TCP-IP-Server. Спасибо --- mibu Senior Member --- за прямой код....
//root@raspberrypi:~/ds# cat /sys/bus/w1/devices/10-000800fb0e06/w1_slave ---путь до девайса --мой случай
// gcc tbody.c -o tbody -l bcm2835 ------компилируем так ---название сорцов (файла), мой случай
//Lets go
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "blink.c"

int main(int argc, char **argv)
{
FILE *ptr_file;
char buf[100];
char *p;
double temp;
//int a=4;
while(1) // поставил в бесконечный цикл (можно так: int a=4; while(a--), здесь а=4 определяет колво циклов, меняем циферку 4 на нужное колво циклов
{
ptr_file = fopen("/sys/bus/w1/devices/10-000800fb0e06/w1_slave", "r"); //мой случай (0-000800fb0e06 -- этот каталог у каждого будет свой)

if (!ptr_file)
return 1;

while (fgets(buf,100, ptr_file)!=NULL)
{};
//printf(" Temp in hex: %s",buf);// можно раском-вать эту строку и добавив для удобства "Temp in hex:" зрить температуру в hex

p = strstr(buf, "t=") + 2;
p[strlen(p)-1] = 0; //remove new line char

temp = atof(p)/1000; //cast to float

printf("\n Temperature: %.3f C\n", temp); //ограничил ширину поля после запятой до трех знаков, даллас точнее тысячных не у меня не кажет.

if( temp>=29.000 ) //сравниваем с нужной константой тем-ры, здесь для тех кто в айболитов будет играть, надо видимо 37 С поставить, для примера стоит 29, чб быстрее остывал..
{return blnk(argc, argv);}

fclose(ptr_file);
}
return 0;
}

/////////////////////////////////////
//Код blink.c :

//Thank you very much this resourse: http://www.airspayce.com/mikem/bcm2835/blink_8c-example.html
// Author: Mike McCauley
#include <bcm2835.h>
// Blinks on RPi Plug P1 pin 11 (which is GPIO pin 17)
#define PIN RPI_GPIO_P1_11

int blnk(int argc, char **argv)
{
// If you call this, it will not actually access the GPIO
// Use for testing
// bcm2835_set_debug(1);
if (!bcm2835_init())
return 1;
// Set the pin to be an output
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP);
// Blink
int a=3; //здесь а=3 определяет колво мигов диода, меняем циферку 3 на нужное колво циклов, можно поставить в бесконечный цикл: while(1)
while (a--)
{
// Turn it on
bcm2835_gpio_write(PIN, LOW); //поменяв местами LOW и HIGH (см.ниже) получаем после return высокий уровень на выходе со светящимся диодом, понятно что кроме случая с while(1)

// wait a bit
bcm2835_delay(500); // изменив например, 500 мс на 10000 получим задержку в 10 сек между миганием диода и т.д

// turn it off
bcm2835_gpio_write(PIN, HIGH);

// wait a bit
bcm2835_delay(500); // то же
}
bcm2835_close();
return main(argc, argv); // здесь после трех мигов диода, возвращаемся в главную функцию и далее покругу. Миги прекращаются при остывании датчика менее 29 С для примера
}
opakak
Люди, подскажите где мы берем коэффициент 0,125 на который умножаем. Никак не могу понять…
raspiman
из документации к датчику



1. If the Temp data MSByte bit D10 = 0, then the temperature is positive and Temp value

(°C) = +(Temp data)×0.125°C.

2. If the Temp data MSByte bit D10 = 1, then the temperature is negative and

Temp value (°C) =−(2’s complement of Temp data)×0.125°C.

shef777
Всем привет!
I2c-detect -l command not found
Как победить?
bro
Надо установить i2c-tools:
 sudo apt-get install i2c-tools

Для написания комментариев необходимо зарегистрироваться