RGB термометр на микроконтроллере ATtiny2313 и ds18b20

Трехцветные светодиоды хороши тем, что с их помощью можно отобразить любой оттенок цвета. Мне пришла в голову идея, почему не собрать простенький термометр на микроконтроллере например ATtiny13 и отображать температуру в виде оттенков цвета с помощью этого же RGB светодиода.

Проблемы реализации устройства:
Цвет генерируется при помощи ШИМ, оттенок формируется разной интенсивностью свечения трех основных цветов, синего, зеленого и красного. То есть для того, что бы отобразить оттенок необходимо иметь три канала ШИМ.

Для опроса датчика температуры необходимо время, на это время микроконтроллер не будет заниматься генерированием ШИМ и светодиод моргнет. Так как отобразить сразу три цвета с разной интенсивностью при помощи микроконтроллера семейства AVR нельзя. Для отображения разных оттенков при помощи ШИМ используется хитрость, инерционность человеческого глаза.

На данном этапе в коде расположенном ниже реализован термометр, который выдает информацию о температуре на RGB светодиод не используя все возможные оттенки. Для отображения используется всего 3 степени свободы (три режима). Логика следующая: при достижении определенного значения температуры, термометр зажигает соответствующий цвет их трех. Таким образом термометр может отображать только три диапазона температур, которые должны быть заранее заданы.

В данном коде трем цветам светодиода соответствуют следующие температуры:
Синий - 20 градусов,
Зеленый - 30 градусов,
Красный - 40 градусов.

  1. //PB0=DS18b20_data
  2.  
  3. #define F_CPU 7372800UL
  4.  
  5. #include<avr/io.h>
  6. #include <util/delay.h>
  7.  
  8. #define TIME 10
  9. #define PORTB_MASK 0x01
  10.  
  11. unsigned int temperature=0;
  12. unsigned char temperature_sign=0;
  13.  
  14. void USART_Init( unsigned int baudrate );
  15. void US_Tr( unsigned char data );
  16.  
  17.  
  18. void USART_Init( unsigned int baudrate ) //Функция инициализации USART
  19. {
  20. UBRRH = (unsigned char) (baudrate>>8);
  21. UBRRL = (unsigned char) baudrate;
  22. UCSRA = (1<<U2X); //Удвоение скорости
  23. UCSRB = ( ( 1 << RXEN ) | ( 1 << TXEN ) ); //Разрешение на прием и н апередачу через USART
  24. UCSRC = (1<<USBS) | (3<<UCSZ0);
  25. }
  26.  
  27.  
  28. void US_Tr( unsigned char data ) //Функция отправки данных
  29. {
  30. while ( !(UCSRA & (1<<UDRE)) ); //Ожидание опустошения буфера приема
  31. UDR = data; //Начало передачи данных
  32. }
  33.  
  34.  
  35. void pause (unsigned int a)
  36. { unsigned int i; for (i=a;i>0;i--);}
  37.  
  38.  
  39. unsigned char present_ds18b20(void)
  40. { unsigned char res;
  41.  
  42. DDRB|= PORTB_MASK;
  43. _delay_loop_2(475); //480ms
  44.  
  45. DDRB&=~PORTB_MASK;
  46. _delay_loop_2(65); //70ms
  47.  
  48. if ((PINB&PORTB_MASK) == 0x00) res=1;
  49. else res=0;
  50. _delay_loop_2(405); // 410ms
  51. return res;
  52. }
  53.  
  54. void send_ds18b20(unsigned char command)
  55. { unsigned char i, data;
  56. data=command;
  57. for(i=0;i<8;i++)
  58. {
  59. if ((data&0x01)==0x01)
  60. { //???????? ???. 1
  61. DDRB|=PORTB_MASK;
  62. _delay_loop_2(2); //6
  63. DDRB&=~PORTB_MASK;
  64. _delay_loop_2(60); //64
  65. }
  66. else
  67. {
  68. DDRB|=PORTB_MASK;
  69. _delay_loop_2(55); //60
  70. DDRB&=~PORTB_MASK;
  71. _delay_loop_2(2); //10
  72. }
  73. data=data>>1;
  74. }
  75. }
  76.  
  77. void receive_ds18b20(void)
  78. { unsigned char i;
  79. temperature_sign=0;
  80. for(i=0;i<16;i++)
  81. {
  82. DDRB|=PORTB_MASK;
  83. _delay_loop_2(2);
  84. DDRB&=~PORTB_MASK;
  85. _delay_loop_1(6);
  86.  
  87. if ((PINB & PORTB_MASK)==0x00) temperature&=~_BV(i);
  88. else {temperature|=_BV(i);
  89. if (i==12) temperature_sign=1;
  90. }
  91. _delay_loop_2(50);
  92. }
  93. }
  94.  
  95. void show_temp (void)
  96. { unsigned int temp_des=0, temp_int=0;
  97. unsigned char h,d,o;
  98.  
  99. US_Tr('T'); US_Tr('e'); US_Tr('m'); US_Tr('p'); US_Tr('=');
  100. //Вывод слова "Temp="
  101.  
  102. if (temperature_sign==1)
  103. {temperature=65536-temperature; US_Tr('-');}
  104. else
  105. US_Tr(' ');
  106.  
  107. temp_des=temperature&0b00001111;
  108. temp_int=temperature>>4;
  109.  
  110. h=temp_int / 100;
  111. d=(temp_int-h*100)/10;
  112. o=temp_int-h*100-d*10;
  113.  
  114. if ((temp_int-h*100)/10==2) PORTB=0xFC; else
  115.  
  116. if ((temp_int-h*100)/10==3) PORTB=0xFA; else
  117.  
  118. if ((temp_int-h*100)/10==4) PORTB=0xF6;
  119.  
  120. if (h!=0) US_Tr(0x30+h); //сотни
  121. if (d!=0) US_Tr(0x30+d); //десятки
  122. US_Tr(0x30+o); //единицы
  123. US_Tr('.');
  124.  
  125. if(temp_des==0) US_Tr(0x30);
  126. else if(temp_des==1 || temp_des==2) US_Tr(0x31);
  127. else if(temp_des==3) US_Tr(0x32);
  128. else if(temp_des==4 || temp_des==5) US_Tr(0x33);
  129. else if(temp_des==6 || temp_des==7) US_Tr(0x34);
  130. else if(temp_des==8) US_Tr(0x35);
  131. else if(temp_des==9 || temp_des==10) US_Tr(0x36);
  132. else if(temp_des==11) US_Tr(0x37);
  133. else if(temp_des==12 || temp_des==13)US_Tr(0x38);
  134. else if(temp_des==14 || temp_des==15)US_Tr(0x39);
  135. // US_Tr(0xdf);
  136. US_Tr('C');
  137.  
  138. US_Tr(0x0d);//переход в начало строки
  139. US_Tr(0x0a);//переход на новую строку
  140. }
  141.  
  142. void no_sensor (void)
  143. { unsigned char i;
  144.  
  145. US_Tr ('N'); US_Tr ('o'); US_Tr (' '); US_Tr ('s');
  146. US_Tr ('e'); US_Tr ('n'); US_Tr ('s'); US_Tr ('o');
  147. US_Tr ('r');
  148.  
  149. US_Tr(0x0d);//переход в начало строки
  150. US_Tr(0x0a);//переход на новую строку
  151.  
  152. for (i=0;i<9;i++)
  153. pause (32000);
  154. }
  155.  
  156. int main(void)
  157. { unsigned char i;
  158.  
  159. PORTB&=~PORTB_MASK;
  160. DDRB&=~PORTB_MASK;
  161.  
  162. DDRB = 0b1111110;
  163.  
  164. USART_Init( 47 );
  165. //Скорость соединения 19200 бит/с 7,3728 MHz
  166.  
  167. while (1)
  168. {
  169. if (present_ds18b20()==1)
  170. {send_ds18b20(0xcc);
  171. send_ds18b20(0x44);
  172. for (i=0;i<6;i++)
  173. pause (32000);
  174.  
  175. if (present_ds18b20()==0) no_sensor();
  176. else
  177. {send_ds18b20(0xcc);
  178. send_ds18b20(0xbe);
  179. receive_ds18b20();
  180. show_temp();} }
  181. else no_sensor();
  182. }
  183. return 0;
  184. };

Если получится реализовать время опроса датчика минимальным, то есть таким за которое глаз не заметит выключения свечения светодиода, тогда и получится реализовать RGB термометр именно таким, как он был описан в начале заметки.

Датчик температуры я использовал ds1b20, который подключен к порту B0 микроконтроллера.

Скачать проект для AVR Studio