Многоканальный USB-Термометр (Обновленно)

Когда то давно я написал статью о том, как сделать USB Термометр и разместил ее на двух сайтах. Девайс очень простой, но спустя пару дней, на мой имейл повалилось огромное количество сообщений с разнообразными вопросами и предложениями. С момента написания прошло уже около 2 лет, а мне все еще как минимум, раз в неделю приходит подобное письмо, но я уже давно перестал на них отвечать, так как вопросы порой слишком примитивны. Но вот примерно 70% народа интересуются двумя вопросами: можно ли подключить второй датчик и можно ли сделать в термометре функцию термостата. Сейчас у меня появилось немного свободного времени и я решил создать термометр с этими функциями.

Добавлено 31.10.2011: В устройство добавил новые полезные функции, подробности ЗДЕСЬ.

Характеристики такие:

  • Максимальное количество датчиков — 32, один датчик установлен прямо на устройстве, все остальные подключаются к отдельному разъему.
  • Пределы измерения от -55С до +125°C, точность при 85°C и ниже не менее 0,5°C.
  • 2 канала управления внешними нагрузками. Возможно ручное и автоматическое (для термостата) управление.
  • Работа на операционных системах Windows 2000 и выше (включая Vista и 7).
  • Сохранение настроек программы в реестре.
  • Возможность задавать отображаемое имя датчика.
  • Мини-окно с возможностью установки размера и отображения поверх всех окон. NEW!
  • Отображение программы в трее. NEW!
  • Запуск программы вместе с Windows. NEW!
  • Перепрошивка через USB без использования внешнего программатора.

В качестве датчиков — DS18B20 — это трехвыводные (или 8 если в SO). Подключаются параллельно. Микроконтроллер — ATmega8, работающий на частоте 16МГц.
Схема:
Обычно, DS18B20, как и остальные однопроводные устройства, подключается к одной ножке МК, которая является как входом, так и выходом, но тут есть явные недостатки — ток ножки МК очень маленький, поэтому много датчиков на него навешать не получиться, поэтому, для большей надежности, ножку МК подключают через транзистор. Но есть еще одна проблема: интерфейс 1-wire требует очень точных задержек, а у нас параллельно работает софтовый USB, для которого задержки должны быть не менее точными. В  инете видел схемы где комп давал МК команду Измерить температуру, ждал некоторое время, пока 1-wire освободится, и потом запрашивал данные. Это вариант глючный и тормознутый. К счастью, эмулировать работу 1-wire можно с помощью UARTa, что я и сделал. На схеме ножка TXD подключена к транзисторам, выход с которых подключен к шине 1-wire (OW_DQ), вместо транзисторов можно просто соединить TXD и OW_DQ через резистор 2-3кОм.
Перемычка BOOTLOADER активирует встроенный загрузчик, чтобы для перепрошивки не нужен был программатор. Светодиод USB_RQ мигает, когда МК отвичает на запросы с компа.
Распиновка 5 контактного разъема:
  1. GND.
  2. Канал 1
  3. Канал 2
  4. 1-Wire. Сюда подключаем сигнальную линию DS18B20.
  5. +5V.
Печатная плата:
Готовое устройство:
Теперь нам нужно написать прошивку для микроконтроллера и компа.

Микроконтроллер.

Очень советую прочитать статью Управление электрическими цепями через USB, только в этом устройстве уже нужны будут драйверы. Большинство всех процессов я сделал в отдельных функциях, чтобы код был более наглядным.

Содержимое функции main, до бесконечного цикла:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
DDRB = 0b00000110; PORTB = 0b00111000;
DDRC = 0b00000001; PORTC = 0b11111110;
DDRD = 0b00000010; PORTD = 0b11100010;
 
TCCR0 = (1<<CS02) | (1<<CS00); // prescaler = 1024
TCNT0 = 0;
 
usbInit();
usbDeviceDisconnect();
timerDelayMs(250);
usbDeviceConnect();	
 
sei();
 
nSensors = search_sensors(); // ищем датчики
 
wdt_enable(WDTO_2S);

Все задержки я делаю на таймере, так можно немного повысить эффективность так как во время задержки выполняется какой то код. Функция search_sensors() выполняет поиск датчиков, их адреса записывает в массивы, возвращает количество датчиков.

Бесконечный цикл:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
while(1)
{
	RunTasks(0xFF);
 
	DS18x20_StartMeasure(); // запускаем преобразование на всех датчиках
 
	timerDelayMs(800); // ждем минимум 750 мс.
 
	cbi(LED_PORT, LED_USB); // тушим USB светодиод
 
	for(unsigned char i=0; i<nSensors; i++) { // считаваем результаты с каждого датчика
		RunTasks(0xFF);
		DS18x20_ReadData(gSensorIDs[i], gSensorData[i]);
	}
 
}

DS18x20_StartMeasure() запускает преобразование на всех датчиках, после запуска нужно подождать минимум 750 мс(пока измеряется температура), и только потом считывать данные.

Теперь разберем, как микроконтроллер обрабатывает запросы с компа. С ПК мы можем передать микроконтроллеру 3 параметр  (bRequestwIndex и wValue), а также, буфер с данными.  После запроса вызывается вот эта функция:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
usbMsgLen_t usbFunctionSetup(uchar data[8])
{
	usbRequest_t    *rq = (void *)data;
	static uchar    dataBuffer[4];
 
	unsigned char	wIndex = rq->wIndex.bytes[0];
	unsigned char	wValue = rq->wValue.bytes[0];
 
	switch(rq->bRequest)
	{
	case USBRQ_HID_SET_REPORT:
			//wIndex - номер канала (1 или 2), wValue - новое состояние (0 или 1)
			if (wValue) sbi(PORTB, wIndex);
			else  cbi(PORTB, wIndex);
		return 0;
 
	case USBRQ_HID_GET_REPORT:
		switch(wIndex)
		{
			case USB_GET_nSensors: usbMsgPtr = &nSensors;	return 1;
			case USB_GET_gSensorIDs: usbMsgPtr = gSensorIDs[0];	return (nSensors*8);
			case USB_GET_gSensorData: usbMsgPtr = gSensorData[0];	return (nSensors*2);
			case USB_GET_Chanels: usbMsgPtr = &channels_port;	return 1;
		}
 
	return 0;
}

Чтобы изменить состояние канала, нужно передать с ПК в качестве параметра bRequest = USBRQ_HID_SET_REPORT, wIndex = номер канала (1 или 2), wValue = значение (0 или 1).

А чтобы запросить какие то данные, нужно в качестве параметра bRequest  передать USBRQ_HID_SET_REPORT, wIndex = название того, что мы хотим получить (гляньте на код, та все понятно). В программе микроконтроллера нужно установить указатель usbMsgPtr на начало буффера, который нужно передать, и вернуть (return) размер буффера.

Чтобы не приходилось постоянно мучаться с внешним программатором, загрузим в Атмегу8 бутлоадер. Подключите микроконтроллер к программатору, установите фьюзы как на скрине:

В прикрепленном архиве, в папке MCU, лежит файл bootloader.hex, залейте его в МК. Установите на устройстве перемычку BOOTLOADER и подключите к ПК, если комп нашел новое HID устройство, то бутлоадер прошит успешно, внешний программатор больше не нужен. В папке MCU\default\ запустите boot.bat чтобы прошить микроконтроллер прошивкой USB Термометра, после успешной прошивки уберите перемычку. Комп найдет новое устройство, когда запросит драйверы, укажите папку Soft\windows-driver\, после успешной установки в диспетчере появится новое устройство.

Софт для ПК.

Я не буду подробно описывать, как работает программа, хотя бы потому что код небольшой и с комментариями. Я расскажу как запрашивать данные с МК и как работать с программой.

Драйвер основан на библиотеке LibUSB-Win32, взглянув на код, можно понять, как работает функция открытия устройства, а вот на счет запроса чуть посложней.

Для любого запроса, нужно воспользоваться функцией usb_control_msg

1
2
usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE |USB_ENDPOINT_IN,
		тип_запроса, wValue, wIndex, буффер, длина буффера, 5000)
  • тип_запроса — USBRQ_HID_GET_REPORT или USBRQ_HID_SET_REPORT.
  • буффер — массив, в который будут записаные данные при запросе.
  • wValue, wIndex и длина буффера думаю объяснять не надо))))

Функция возвращает размер буффера, переданного с МК (то, что возвращает функция usbFunctionSetup).

Работа с устройством.

В результате недолгих мучений, я написал програмку, которую назвал USB Thermometer.

При запуске программа запрашивает количество термодатчиков и их адреса, затем, каждые 500мс запрашивает температуру и состояние каналов. если прокрутить табличку вправо, то можно увидеть максимальную и минимальную температуру для каждого датчика с момента запуска программы, а также дату и время, когда они зафиксированны. 

Для наглядности, каждому датчику можно назначить имя, для этого, кликните по колонке «Название», напротив нужного датчика, выскочит вот такое окошко:Введите сюда новое название и нажмите ОК.

Название поменяется, а настройки сохранятся в реестре, при следующем запуске название останется такое же. Название назначается не по номеру, а по адресу.

Теперь разберемся с управлением каналами.

Если индикатор красного света, то канал выключен, зеленого — включен. Управлять ими можно вручную или автоматически. Выберите метод управления «Вручную» и нажмите «Изменить» — индикатор засветится зеленым цветом.Теперь выберите метод управления «Автоматически«:

Установите номер датчика, с которым будет сравниваться температура. Далее установите граничную температуру(только целые значения, без запятой) и условие управления, их всего 4:

  1. Включать выше граничной температуры.
  2. Включать ниже граничной температуры.
  3. Включать когда температура равна граничной.
  4. Включать когда температура не равна граничной.

Нажмите кнопку «Установить«, настройки сохранятся в реестре.

Если, к примеру, вы выбрали первый датчик, граничная температура 30 и условие «Включать выше граничной температуры», то канал будет включаться когда температура на первом датчике будет выше 30 , после понижения опять отключиться.

Как это может пригодиться в реальной жизни? к примеру, есть у вас обогреватель без термостата. Подключите канал к обогревателю (естественно не на прямую, а через реле например) разместите термодатчик где то рядом с обогревателем. Установите граничную температуру 25, условие «Включать ниже граничной температуры» нажмите кнопку «Установить». Теперь обогреватель будет включаться, когда температура упадет ниже 25 градусов и выключаться, когда достигнет 25.

Оба каналы работают независимо.

Дополнение в новой версии.

При запуске программа сразу сворачивается в трей:

Нажмите по значку чтобы открылось главное окно. При сворачивании программа сворачивается в трей.

Теперь температура может отображаться постоянно у вас на мониторе в виде небольшого прозрачного окошка. Нажмите на кнопку «Мини-окно«, вот что вы увидите:

Это небольшое окошко, которое можно разместить на мониторе в любом месте, просто перетянув его мышкой. Сверху отображается название выбранного датчика, посередине — текущая температура, снизу слева — минимальная, справа — максимальная. Чтобы изменить отображаемый датчик, покрутите колесико мыши вверх или вниз (следующий/предыдущий). Размер окна можно изменять. Нажмите «Настройки«:

При минимальном размере, окно будет вот таким:

При максимальном:

Даже бабушка увидит)))).

Также, окно можно сделать поверх всех окон (соответствующая опция).

Если окно где то потерялось (например, было на втором мониторе и вы этот монитор отключили), нажмите кнопку «Установить первоначальное положение» — мини-окно появится в левом верхнем углу монитора.

Еще в программу добавил Запуск вместе в Windows.

Кстати, в мини окно, для наглядности применен шрифт terminator_cyr_v4, он находится в архиве с программой.

Приобрести готовое устройство можно здесь.

Скачать файлы статьи (1,62 Mb).

108 комментариев Многоканальный USB-Термометр (Обновленно)

Leave a Reply