В данной статье мы рассмотрим подключение датчика температуры LM35 к микроконтроллеру PIC. Измеряемое значение температуры мы будем выводить на экран ЖК дисплея 16x2. Датчик LM35 является простым и дешевым устройством для измерения температуры, не требующим никакой внешней калибровки. Выходное напряжение датчика пропорционально окружающей температуре в градусах Цельсия и изменяется на 10mV на каждый °C.
Также на нашем сайте мы рассматривали подключение датчика температуры LM35 к другим микроконтроллерам (платам):
Необходимые компоненты
- Микроконтроллер PIC16F877A (купить на AliExpress).
- Датчик температуры LM35 (купить на AliExpress).
- Держатель микросхем на 40 контактов (купить на AliExpress).
- Программатор PICkit 3 (купить на AliExpress).
- Кварцевый генератор 20 МГц (купить на AliExpress).
- Конденсаторы 22 пФ (2 шт.) (купить на AliExpress).
- Потенциометр 10 кОм (купить на AliExpress).
- Регулятор напряжения 7805 (купить на AliExpress).
- Адаптер 12V.
- ЖК дисплей 16х2 (купить на AliExpress).
- Светодиод (купить на AliExpress).
- Перфорированная плата.
- Макетная плата.
- Соединительные провода.
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Датчик температуры LM35
Датчик температуры LM35 имеет нулевой сдвиг напряжения, что означает что при 0°C напряжение на его выходном контакте равно 0V. Его максимальное выходное напряжение равно 1.5V – это означает что максимальное значение температуры, которое он способен измерять, равно 150°C (1.5V / 10mV).
Внешний вид и распиновка датчика LM35 представлены на следующем рисунке.
Номер контакта | Функция | Обозначение |
1 | Питающее напряжение; 5V (+35V to -2V) | Vcc |
2 | Выходное напряжение (+6V to -1V) | Output |
3 | Земля (0V) | Ground |
Поскольку датчик LM35 имеет аналоговый выход, это означает, что мы его должны подключать к аналоговому контакту (входу АЦП) микроконтроллера PIC.
АЦП в микроконтроллере PIC16F877A
В настоящее время существует много типов различных АЦП, и каждый из них имеет свою собственную скорость и разрешение. Наиболее распространенными типами АЦП являются АЦП с последовательным приближением и типа "сигма-дельта". АЦП, используемый в микроконтроллере PIC16F877A, называется АЦП последовательного приближения или сокращенно SAR (Successive approximation).
Последовательный аппроксимационный АЦП (SAR) работает с помощью компаратора и нескольких логических преобразований. Данный тип АЦП использует опорное напряжение (которое является переменным) и сравнивает входное напряжение с опорным напряжением с помощью компаратора, и разность этих напряжений, которая и будет цифровым выходом данного АЦП, сохраняется из самого значащего (старшего) бита (MSB). Скорость сравнения зависит от тактовой частоты (Fosc), на которой работает микроконтроллер PIC.
Теперь, когда мы знаем основы АЦП, давайте откроем даташит на микроконтроллер PIC16F877A и посмотрим какие возможности аналого-цифрового преобразования есть у него. Как мы можем увидеть из даташита, микроконтроллер PIC16F877A содержит 10-битный 8-канальный АЦП. Это значит, что у него есть 8 каналов АЦП, представленных на рисунке ниже. Разрешение каждого канала АЦП составляет 10 бит, что означает что диапазон его выходных значений составляет 0-1024 (2^10).
На представленном рисунке подсвечены каналы АЦП микроконтроллера PIC16F877A – с AN0 до AN7. Только на этих контактах микроконтроллер может считывать аналоговые значения напряжений.
Более подробно об использовании АЦП в микроконтроллерах PIC можно прочитать в этой статье.
Схема проекта
Схема подключения датчика температуры LM35 к микроконтроллеру PIC представлена на следующем рисунке.
Датчик температуры LM35 подключен к аналоговому входу AN4 микроконтроллера PIC. ЖК дисплей подключен к микроконтроллеру в 4-битном режиме, более подробно о его подключении к микроконтроллеру PIC можно прочитать в этой статье.
Для сборки конструкции проекта мы использовали перфорированную плату с установленным на нее микроконтроллером PIC из проекта мигания светодиодом.
Объяснение программы для микроконтроллера PIC
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
В программе мы будем считывать значение с выхода АЦП и затем на его основе определять аналоговое значение напряжения с выхода датчика LM35, после чего это значение напряжения мы будем конвертировать в значение температуры. После этого полученное значение температуры мы будем разделять на отдельные символы чтобы затем отобразить их на экране ЖК дисплея.
1 2 3 4 5 6 7 8 |
adc = (ADC_Read(4)); // Reading ADC values volt = adc*4.88281; // Convert it into the voltage temp=volt/10.0; // Getting the temperature values temp1 = temp*100; c1 = (temp1/1000)%10; c2 = (temp1/100)%10; c3 = (temp1/10)%10; c4 = (temp1/1)%10; |
И в следующем фрагменте кода мы будем устанавливать на ЖК дисплее необходимую позицию курсора и затем отображать на его экране отдельные символы, комбинация которых составляет измеренное нами значение температуры.
1 2 3 4 5 6 7 8 9 10 11 12 |
Lcd_Clear(); Lcd_Set_Cursor(1,3); Lcd_Print_String("Temperature"); Lcd_Set_Cursor(2,5); Lcd_Print_Char(c1+'0'); Lcd_Print_Char(c2+'0'); Lcd_Print_String("."); Lcd_Print_Char(c3+'0'); Lcd_Print_Char(c4+'0'); Lcd_Print_Char(0xDF); Lcd_Print_String("C"); __delay_ms(3000); |
Тестирование работы цифрового термометра
После сборки схемы и загрузки программы в микроконтроллер PIC подайте на нее питание от адаптера на 12v. Значение с выходного контакта датчика LM35 будет подаваться на аналоговый вход микроконтроллера PIC и на его основе будет определяться измеренное значение температуры (на основе умножения значения с выхода АЦП на коэффициент 4.88281). После этого определенное значение температуры будет отображаться на экране ЖК дисплея.
Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.
Исходный код программы
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
#define _XTAL_FREQ 20000000 #define RS RD2 #define EN RD3 #define D4 RD4 #define D5 RD5 #define D6 RD6 #define D7 RD7 #include <xc.h> #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled) #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) void ADC_Initialize() { ADCON0 = 0b01000001; //ADC ON and Fosc/16 is selected (включаем АЦП и устанавливаем частоту Fosc/16) ADCON1 = 0b11000000; // для работы АЦП выбираем внутреннее опорное напряжение } unsigned int ADC_Read(unsigned char channel) { ADCON0 &= 0x11000101; //очищаем биты выбора канала АЦП ADCON0 |= channel<<3; //выбираем необходимый канал АЦП __delay_ms(2); //Acquisition time to charge hold capacitor GO_nDONE = 1; //начинаем процесс АЦП while(GO_nDONE); //ждем пока процесс АЦП не завершится return ((ADRESH<<8)+ADRESL); //возвращаем результат } //LCD Functions Developed by Circuit Digest. void Lcd_SetBit(char data_bit) //Based on the Hex value Set the Bits of the Data Lines { if(data_bit& 1) D4 = 1; else D4 = 0; if(data_bit& 2) D5 = 1; else D5 = 0; if(data_bit& 4) D6 = 1; else D6 = 0; if(data_bit& 8) D7 = 1; else D7 = 0; } void Lcd_Cmd(char a) { RS = 0; Lcd_SetBit(a); //Incoming Hex value EN = 1; __delay_ms(4); EN = 0; } Lcd_Clear() { Lcd_Cmd(0); //очищаем экран ЖК дисплея Lcd_Cmd(1); //устанавливаем курсор в 1-ю позицию } void Lcd_Set_Cursor(char a, char b) { char temp,z,y; if(a== 1) { temp = 0x80 + b - 1; //80H is used to move the curser z = temp>>4; //младшие 8 бит y = temp & 0x0F; //старшие 8 бит Lcd_Cmd(z); //устанавливаем строку Lcd_Cmd(y); //устанавливаем столбец } else if(a== 2) { temp = 0xC0 + b - 1; z = temp>>4; // младшие 8 бит y = temp & 0x0F; // старшие 8 бит Lcd_Cmd(z); // устанавливаем строку Lcd_Cmd(y); // устанавливаем столбец } } void Lcd_Start() { Lcd_SetBit(0x00); for(int i=1065244; i<=0; i--) NOP(); Lcd_Cmd(0x03); __delay_ms(5); Lcd_Cmd(0x03); __delay_ms(11); Lcd_Cmd(0x03); Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD Lcd_Cmd(0x08); //выбираем строку 1 Lcd_Cmd(0x00); // очищаем строку 1 Lcd_Cmd(0x0C); // выбираем строку 2 Lcd_Cmd(0x00); // очищаем строку 2 Lcd_Cmd(0x06); } void Lcd_Print_Char(char data) //Send 8-bits through 4-bit mode { char Lower_Nibble,Upper_Nibble; Lower_Nibble = data&0x0F; Upper_Nibble = data&0xF0; RS = 1; // => RS = 1 Lcd_SetBit(Upper_Nibble>>4); //Send upper half by shifting by 4 EN = 1; for(int i=2130483; i<=0; i--) NOP(); EN = 0; Lcd_SetBit(Lower_Nibble); //Send Lower half EN = 1; for(int i=2130483; i<=0; i--) NOP(); EN = 0; } void Lcd_Print_String(char *a) { int i; for(i=0;a[i]!='\0';i++) Lcd_Print_Char(a[i]); //разделяем строку на отдельные символы с помощью указателей и последовательно выводим каждый символ на экран ЖК дисплея } int main() { float adc; float volt, temp; int c1, c2, c3, c4, temp1; ADC_Initialize(); unsigned int a; TRISD = 0x00; Lcd_Start(); while(1) { adc = (ADC_Read(4)); // считываем значение с выхода АЦП volt = adc*4.88281; // конвертируем его в значение напряжения temp=volt/10.0; // определяем на его основе значение температуры temp1 = temp*100; c1 = (temp1/1000)%10; c2 = (temp1/100)%10; c3 = (temp1/10)%10; c4 = (temp1/1)%10; Lcd_Clear(); Lcd_Set_Cursor(1,3); Lcd_Print_String("Temperature"); Lcd_Set_Cursor(2,5); Lcd_Print_Char(c1+'0'); Lcd_Print_Char(c2+'0'); Lcd_Print_String("."); Lcd_Print_Char(c3+'0'); Lcd_Print_Char(c4+'0'); Lcd_Print_Char(0xDF); Lcd_Print_String("C"); __delay_ms(3000); } return 0; } |