Цифровой термометр на Attiny13A и датчике ds18b20

Вот сидел сегодня целый день, думал, а не пора ли запилить постик :) И все таки решился. В технической тематике — это мой первый пост, надеюсь пинать не будут за ворованные идеи, я лишь учусь.

Для оригинальности выбрал AVR studio 5 в качестве среды, писал на C.
вот сам микроконтроллер

Ножек мало, а выводить надо минимум на 3 сегментных дисплея, еще и датчик подключить кудато, в итоге на кнопочку даже места не останется. А теперь посмотрим на выдержку из даташита...
1 килобайт — не густо… и компилятор не компилил больше 1.5килобайта без оптимизации.

немного почитав матчасти и покумекав башкой, выродил вот такую схему

PB0 — управление 3 сдвиговыми регистрами
PB1 — управление 2 светодиодами(знак температуры)
PB2 — свободен
PB3 — свободен
PB4 — подключение самого датчика DS18B20(на схеме изображены штырьки, если хочется — можно наглухо припаять его туда :) )
PB5 — reset
VCC — питание
GND — земля

точки справа с надписями — тоже штырьки(для тех кто захочет модуль с дисплеями и регистрами отдельно по проводу соединить(в этом случае не забудьте про питание и землю))

По поводу питания я не заморачивался, на картинке не нарисовал канеш, в реале у меня там на 100 микрофарад стоит кондер на землю — иначе МК ловит жесткие глюки; а вообще и от 2-х AA работает нормально.
p.s. мне понравился L7805 — очень удобный стабилизатор — используйте его всегда :)

Управление 3 регистрами по 1 проводу — изврат, но этот изврат работает и не жрет я бы сказал много памяти, зато в итоге аж 2 ноги свободные… а резет тупо можно сказать подтянул к питанию, если надо сбросить — заполняем единицами(!!!) и все будет ништяк… а почему единицами? да потому что мои сегментные дисплеи особенные, зажигаются от нулей :)


Kingbright SA04-11GWA — вполне себе приличные дисплейчики, радует что всего 1 резюк к ним подключать надо :)
Сдвиговые регистры самые обычные 74HC164
Велосипед изобретать не пришлось — просто подключил буквы на регистрах к буквам на дисплеях, только точку подключил не к среднему, а к последнему регистру в связке(на рисунке этот момент выделен достаточно жирно), остальные точки оставил висеть в воздухе — они не нужны.
Не забывайте про токоограничительные резисторы на светодиоды — 1 от питания, другой от мк, иначе попрощаетесь с диодом, или хуже того — с контроллером.

Теперь пришло время перейти к особенностям кода:
(опишу лишь некоторые функции, над которыми сам кропел)

void shiftreg(signed char num,char zpt)//разбиение по разрядам
{	
		
		if(num<0)//если значение отрицательное
		{num=-num; // инвертируем его, знак у нас отдельно выносится
                 zpt=9-zpt;// знаки после запятой тоже инвертировать надо
		}		 
		tochka=1; //включаем точку(в функции это условие учтется)
		regout(zpt); // посылаем на обработку дробную часть
		regout(num%10);//посылаем единицы на обработку(остаток от деления на 10)
		char tmp=num; //запоминаем нум
		num/=10;//делим на 10
		regout(num%10);//отсылаем десятки
		tmp/=100;//делим нум на 100
		if(tmp>0)regout(tmp%10);//посылаем сотни,замещают дробный остаток если их >0
		
}

Интересного в коде — выделение разрядов от числа, может кому-то будет полезно.


void zero(void)//вывод 0 в сегмент
{ 	
 PORTB=1<<0 ;//держим линию
 _delay_us(5);//курим 5 микросекунд
 	  PORTB=0<<0 ;//выдаем строб
	  PORTB=1<<0 ;//
}
void one(void)//вывод 1 в сегмент
{
	PORTB=0<<0 ;//опускаем линию
	 _delay_us(5);//курим 5 микросекунд
	  PORTB=1<<0 ;//поднимаем линию
}

В этом коде показано как по 1 проводу слать биты в регистры, зажигая тем самым сегменты
СЛЕДУЕТ ПОМНИТЬ, ЧТО Я ВЫВОЖУ ИНВЕРСНЫЕ КОДЫ, А В КОМЕНТАХ НАПИСАНО ТО, ЧТО БУДЕТ НА ДИСПЛЕЕ
(т.е. чтобы на сегменте был 0 — надо выдать 1, и наоборот)
Более подробно можно прочитать в переводе немецкой статьи от DI-HALT(ссылка будет в конце)


void digitp(char digit)//Преобразование значений под сегментные дисплеи
{
	    if(tochka==1)digit|=0x80;
		char j=8;
		char tmp;
			while (j)
			{  
			  tmp=digit&0x80;
			  if(tmp==0)zero();
			  else one();
			  digit<<=1;
			  j--;
			}
			tochka=0;
}
void regout(char numb)//таблица значений под сегментные регистры
{

	asm("cli");
	switch(numb)
	{
		case 1:
		digitp(0x06);			
		break;
	case 2:
	digitp(0x5B);			
	break;
		case 3:
		digitp(0x4F);			
		break;
	case 4:
	digitp(0x66);			
	break;
		case 5:
		digitp(0x6D);			
		break;
	case 6:
	digitp(0x7D);			
	break;
		case 7:
		digitp(0x07);			
		break;
	case 8:
	digitp(0x7F);			
	break;		
		case 9:
		digitp(0x6F);			
		break;
	case 0:
	digitp(0x3F);			
	break;
		
		default:
		digitp(0x00);
		
	}
	asm("sei");
}	

Тут обойдусь без комментариев, в кратце — если точка нужна, вставляем 8 бит(он при сдвиге будет последним) и последовательно сдвигаем бит за битом в порт
Преобразование кода чисел в код дисплеев сделано в лоб… думать не хотелось, но памяти вроде не много сожрало(делал в бинарном виде, преобразовывал в шестнадцатеричный)

Саму работу с градусником, может к счастью, может к грусти мне особо осваивать не пришлось… прочитал только принципы, чтобы понимать код, а сам код взял отсюда
www.teslabs.com/openplayer/docs/docs/other/ds18b20_pre1.pdf
Тут в прицнципе на английском все прекрасно написано… но я убрал функцию задержки
и использовал стандартную _delay_us(); Еще немного подправил код

Функция чтения температуры

void therm_read_temperature(void){
	//void therm_read_temperature(char *buffer){ - убрал этот буфер - много памяти
	asm("cli");

uint8_t temperature[2];
signed char digit; //а тут знак надо
unsigned short decimal; // тут побольше надо памяти, делить на тыщу будем епт

//int8_t digit;//а про эти типы я ниче не знаю
//uint16_t decimal;//

//Резет, пропуск проверки CRC и запуск считывания температуры
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_CONVERTTEMP);
//Ждем пока датчик одуплица
while(!therm_read_bit());
//резет, пропуск проверки CRC, чтение скрэчпада(там наши показания и лежат)
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_RSCRATCHPAD);
//Читаем только 2 первых байта, остальное нам ненадо
temperature[0]=therm_read_byte();
temperature[1]=therm_read_byte();
therm_reset();//резетаем
//Сохраняем целую часть
digit=temperature[0]>>4;
digit|=(temperature[1]&0xf)<<4;
digit++;
//Сохраняем вещественную часть, преобразовываем попутно в чисто от 0 до 9(десятые доли)
decimal=temperature[0]&0xf;
decimal*=THERM_DECIMAL_STEPS_12BIT;
decimal/=1000;
//
asm("sei");
//пуляем эти числа в глобальные переменные, а они уже пойдут на дисплеи
digitemp=digit;
decimtemp=decimal;
}



Полный код со всеми функциями и дефайнами хорошо портируется на любой МК… рассказывать более подробно не вижу смысла, т.к. функция съема температуры — главная задача на данный момент.

Демонстрация работы

фотки жести :)



Исходник на avr studio 5
http://depositfiles.com/files/294abwsun
Датащиты:
tiny13a — www.atmel.com/dyn/resources/prod_documents/doc8126.pdf
ds18b20 — datasheets.maxim-ic.com/en/ds/DS18B20.pdf
mm74hc164 — www.fairchildsemi.com/ds/MM/MM74HC164.pdf
SA04-11GWA — www.us.kingbright.com/images/catalog/SPEC/SA04-11GWA.pdf
Прочее:
Управление дисплеями по 1 проводу
easyelectronics.ru/upravlenie-semisegmentnymi-indikatorami-po-odnomu-provodu.html#more-143
Описание работы с ds18b20 с примерами на Си(англ)
www.teslabs.com/openplayer/docs/docs/other/ds18b20_pre1.pdf

p.s. по поводу того, как BLS обжимать быстро напишу в другом посте :)
p.p.s. время 3 ночи щас, потому могу лажануть орфографией или пунктуацией — не до этого ))
  • +2
  • 16 апреля 2011, 00:03
  • Defvyb

Комментарии (27)

RSS свернуть / развернуть
… ну и как пятая студия?, она вроде еще как бета версия раздается
P.S. — сколько памяти потратил?
0
Device: attiny13a
Program: 740 bytes (72.3% Full)
(.text + .data + .bootloader)
Data: 3 bytes (4.7% Full)
(.data + .bss + .noinit)

5 студия очень понравилась… сэкономил кучу времени и получил на 40 байт больше, чем ожидал(хотя думаю если оптимизировать получше, то можно меньше 700 получить)
0
… подключал к студии какой-нибудь Си-шный компилятор или все уже интегрировано?
0
Все интегрировано, при установке устанавливается фреймворк 4, и вижуал студио 2010 шелл.
0
p.s. мне понравился L7805 — очень удобный стабилизатор — используйте его всегда :)
В данном случае (батарейное питание) крайне неудачный вывбор т.к. он ест энергию всегда и почем зря. Батарейки прослужат ой как недолго.

Kingbright SA04-11GWA — вполне себе приличные дисплейчики, радует что всего 1 резюк к ним подключать надо :)
Какое наивное заблуждение :))) С одним общим резюком яркость горения одного сегмента будет в семь раз ярче горения всех сегментов. Некрасиво :) Поэтому резюк ставят на каждый сегмент
0
Это заметно только когда единица горит :) 1 цифра — эт допустимо (да и что мешает добавить еще 3 резюка для единицы, всяко меньше чем 7).
0
Даже на видео, рядом с ярким светодиодом, свет от единички забивает всё :)

А вообще не понятно, почему производители не интегрируют в эти индикаторы обвязку. Допустим подвести туда VCC, GND, и логические уровни на каждый сегмент, а ключи и резисторы внутри. Красота! А если сдвиговый регистр туда засунуть — вообще…
0
и ведь черт возьми… не один я оказывается об этом подумал :)
0
Да я люблю везде семисегментники лепить. Чётко, ярко, красиво, в отличии от мутных ЖК. Но вот эти резисторы, разводка и прочие прелести напрягают.
0
А вообще не понятно, почему производители не интегрируют в эти индикаторы обвязку
… потому что не так легко получить резистор определенного номинала на кристале
… если замечали в разных даташитах написано… такойта резистор имеет номинал между 10К и 100К, чтоб получить точные номиналы например как в прецизионных ОУ, применяются всякие дорогостоющие технологии, за которые — естественно платит покупатель.
0
… да и вообще яркость дело вкуса, производитель предоставляет выбор покупателю — вешать тот или иной резюк
0
Ну, во первых, светодиоды со строенными резисторами бывают. Там как раз на кристалле AFAIK.
Во вторых, индикатор — это микросборка. Туда вполне можно нанести вполне нормальные резисторы, как в гибридных ИМС.
А вообще, прикольно было бы, если бы туда ставились драйверы вроде MBI*. Это многоканальные генераторы тока с одним задающим резистором на все каналы. Тогда можно и ток задать, и обойтись одним резистором на индикатор (а вместо разрядного ключа — вывод Е драйвера).
0
Я думаю такие сегменты где-то и есть… может просто нужно поискать?
0
Эти дисплейчики сожрут намного больше, чем 7805 — на их фоне ее потребление будет незаметно.
А, вообще, проще было применить ATMega48 — выводов бы хватило, а корпусов меньше, программа проще и конструкция дешевле.
0
Чем больше потребляемый ток через 7805 и чем больше разница напряжений на выходе и входе тем больше этот стабилизатор рассеивает в виде тепла. На Разнице в 9-5 вольт и токе в 300мА он уже разогревается как утюг.
0
Зато на практике попробовал несколько хитрых приемов, пощупал си(особенно в условиях нехватки памяти)… вроде и говорилось в начале поста, что я только учусь :)
0
А, вообще, проще было применить ATMega48 — выводов бы хватило, а корпусов меньше, программа проще и конструкция дешевле.
Во-во. У них разница в цене 10-15 рублей, а фарша как в целой корове :)
0
Работу с мегами я оставлю на то время, когда появится возможность ЛУТить :) в принципе — глаз у меня зоркий, думаю с планарными микросхемами все будет покрасивше и поменьше.
0
У меня вопрос касательно калибровки. Вот вы в обзоре говорите что градусник показывает температуру вашего тела 36.6 градусов. А этот источник температуры стандартизирован, поверен? Вы уверены что там на выходе верные данные?
0
Я просто чего спрашиваю. У меня тело человеческое выдает немного другие температуры. От 34.5 до 39.8 поэтому не знаю, может у кого-то взять и на том теле проверить?
0
Я уверен в правильности показаний датчика, так же как и уверен в том, что я относительно здоров и измерения провожу не в жерле вулкана или морозильнике, а при обычной комнатной температуре.

p.s.
Для таких как вы, в даташитах пишут данные о точности.
• Measures temperatures from –55°C to
+125°C (–67°F to +257°F)
• ±0.5°C accuracy from –10°C to +85°C
0
Ну я вообще-то пытался пошутить…
0
а я, блин, испугался… вдруг я не здоров O_O и на всякий случай проверил ртутным градусником )
0
В самом-самом конце видео был кадр, когда градусник показал 36,7.
0
В библиотеке вроде как ошибочка — если температура выше 0, то показывается температура на 1 градус больше чем в реале. Тестировал в протеусе.

Очевидно, что для строчки " digit++; " нужно ещё добавить проверку и инкрементировать только если ниже 0.

P.S. Спасибо за труд, очень классный пример по написанию собственной библиотеки и ряд интересных (для меня) приемов кодинга! Все заработало сразу. Использовал AVR Studio 4.19.
0
как же стыдно щас на быдлокод свой смотреть :)))) можно было вообще не использовать глобальные переменные, а вернуть указатель на массив значений целой и дробной частей, ну и да… проверка нужна :)
0
Фейспалм. Я только что пытался собрать проект DS18b20 + tiny13A в CodeVision.
Написал 3 строки кода, опросить термометр записать целую часть температуры в регистр совпадения, подождать 5сек. Скомпилил в 660слов и конечно же пошел лесом. Правда там все функции библиотечные, встроенные. Решил поискать… и вот оно. Я использовал лицензионный кодвижн. Для чего, спрашивается? Хорошо что не я его покупал.
0
  • avatar
  • XOR
  • 19 октября 2012, 16:13
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.