Измерительные устройства

Термометр на микроконтроллере PIC12F629. Альтернативная программа

  • Печать

Термометр на PIC12F629

Термометр на микроконтроллере PIC12F629 уже неоднократно повторялся читателями сайта, что очень радует. Подтверждение тому следующая статья, за которую огромное спасибо Дмитрию.

Давно собирался попробовать освоить программирование микроконтроллеров но как-то руки не доходили и было непонятно с чего начинать. В какой-то момент нашел описание термометра, очень понравилась сама конструкция, но программа работала не совсем так, как мне бы хотелось. Просить переделать программу под себя неудобно, ставить микропаскаль тоже не хотелось, поэтому решил что вот он, удачный момент попробовать написать свою прошивку.

Что изначально не устраивало в оригинальной прошивке:

  •     - Мигание сегментов во время передачи данных в регистры.
  •     - Алгоритм, не позволяющий использовать регистры 74595.
Отличия моей прошивки:
  • Написано на HiTech PicC, без использования библиотек. Возможно именно за счет этого программа начинает выводить корректные данные быстрее, оригинальная у меня и в железе и в протеусе несколько раз выводит на индикатор значение "85" перед тем как начинает показывать реальную температуру.
  • Индикация не замедлена, значения на экране сменяются без перебора сегментов и практически без засветки даже на регистрах 74164, я бы сказал что мгновенно (хотя замедлить для красоты не проблема).
  • Программа адаптирована для регистров сдвига 74595 и будет с ними работать без внесения изменений, SCLK при этом подключается к Q4. Различие с оригинальной программой в том, что оригинальная работает по алгоритму "подача питания - опрос датчика 1 - опрос датчика 2 - снятие питания", при этом импульс на SCLK для индикации температуры второго датчика взять неоткуда. Моя версия работает по алгоритму "подача питания - опрос датчика 1 - снятие питания - подача питания - опрос датчика 2 - снятие питания".
  • В случае если значение температуры менее 10, на индикаторе гасится незначащий ноль
  • Если температура отрицательна и ее значение менее 10, дополнительный светодиод индикации минуса не используется, символ минуса выводится на индикаторе.
Прошивка проверена на устройстве, собранном на плате из статьи и полностью с ним совместима.

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

Понять принцип работы с датчиками очень помогла статья "PIC мк. Эксперимент №16. One-wire на примере DS18b20." с сайта http://diymicro.ru , откуда и были взяты функции работы с датчиками. При этом, если кто-нибудь соберется использовать примеры из этой статьи, сразу хочу предупредить что формула расчета полученной температуры в ней неправильная. По этой формуле если полученная с датчика температура отрицательна и при этом не является целым числом, т-е имеет какую-либо дробную часть, значение температуры считается верно, если же дробной части нет, занижается на единицу.
Т-е если на датчике -1.1 — на экране -1.1
если на датчике -1.0 — на экране уже 0. Причем именно 0, ноль после запятой в этом случае не отображается.

В моей программе температура считается корректно при любом значении.

Во вложении файл прошивки и исходник.

С уважением, Дмитрий.
Этот адрес электронной почты защищен от спам-ботов. У вас должен быть включен JavaScript для просмотра.

 Управляющая программа на С 

#include <pic.h>
#include "delay.h" 
#define _XTAL_FREQ 4000000
#define OUT   GPIO0 // выход данных
#define TAKT  GPIO1 // тактирование
#define STATE1 TRIS5 //порт датчика 1
#define STATE2 TRIS2 //порт датчика 2
#define PIN1 GPIO5 //пин датчика 1
#define PIN2 GPIO2 //пин датчика 2
#define POWERPIN GPIO4 //состояние питания датчиков, так же используется для управления защелками//
#define PIN RA2
//__CONFIG (INTIO & UNPROTECT & LVPDIS & BOREN & MCLRDIS & PWRTEN & WDTDIS);

__CONFIG (INTIO & UNPROTECT & BOREN & MCLRDIS & PWRTEN & WDTDIS);

unsigned char temperature, temp_drob, sign, buf; //глобальные переменные: температура,
дробная часть, признак минуса, буфер отображения цифр,

unsigned char num [3]; //массив в котором хранится температура по одной цифре
static bit n; //номер датчика для отображения

void DelayS (unsigned int p); //функция задержки в секундах
void convert (void); //обработка значения температуры и помещение ее в буфер

void vyvod (void); //вывода на индикатор из буфера
static bit INIT1(void); //инициализация датчика 1
static bit INIT2(void); //инициализация датчика 2

unsigned char RX1 (void); //чтение датчика 1

unsigned char RX2 (void); //чтение датчика 2

void TX1(unsigned char cmd); //запись в датчик 1

void TX2(unsigned char cmd); //запись в датчик 2

void get_temp1(void); //получение температуры с датчика 1

void get_temp2(void); //получение температуры с датчика 2

void DelayS (unsigned int p){ unsigned int i; for (i=1; i<=p; i=i+1) DelayMs(100); return; }
void convert (void){ const unsigned char digit [10] = { // gfabpcde 0b10110111, 0b00010100, 0b01110011, 0b01110110, 0b11010100, 0b11100110, 0b11100111, 0b00110100, 0b11110111, 0b11110110}; if (temperature<10) { //десятки - гашение незначащего нуля если температура < 10 buf = 0b00000000; if (sign) buf = buf+0b01000000; //и вывод на его место минуса если температура отрицательна } else {num[0] = (temperature/10); //вывод цифры если значение температуры двухзначное buf=digit[num[0]]; if (sign) buf=buf+0b00001000; //тогда минус индицируется отдельным светодиодом } vyvod(); if (temperature<10) { num[1] = temperature; //единицы } else {num[1]=temperature-(num[0]*10);} buf=digit[num[1]]; buf=buf+0b00001000; //добавляем десятичную точку, она там есть всегда vyvod(); num[2]= temp_drob; //дробная часть buf=digit[num[2]]; if (n) buf=buf+0b00001000; //светодиод - индикатор того что температура с датчика 2 vyvod(); return; }
void vyvod (void){ //побитовый вывод на сдвиговые регистры unsigned char nrbit; for (nrbit=1; nrbit<=8; nrbit=nrbit+1){ if (buf&0b0000001==1) OUT=1; else OUT=0; TAKT=1; buf=buf>>1; TAKT=0; } return; }
static bit INIT1(void){ static bit b; STATE1 = 1; STATE1 = 0; //Проваливаем линию PIN1=0; DelayUs(500); //Ждем 500 мкс STATE1 = 1; //Переключаемся на вход DelayUs(65); //Ждем 65 мкс b = PIN1; //Смотрим чего там на линии DelayUs(450); //Дожидаемся до положенного временного интервала return b; //Возвращаем 0 или 1 }
static bit INIT2(void){ static bit b; STATE2 = 1; STATE2 = 0; //Проваливаем линию PIN2=0; DelayUs(500); //Ждем 500 мкс STATE2 = 1; //Переключаемся на вход DelayUs(65); //Ждем 65 мкс b = PIN2; //Смотрим чего там на линии DelayUs(450); //Дожидаемся до положенного временного интервала return b; //Возвращаем 0 или 1 }
unsigned char RX1 (void) { unsigned char d = 0; unsigned char i = 0; for (i=0;i<8;i++){ STATE1 = 0; //прижимаем линию DelayUs(6); //ждем STATE1 = 1; d>>=1; //освобождаем место под новый бит if (PIN1 == 1) d |= 0x80; //если 1 то записываем 1 DelayUs(70); //ждем до положенного времени } return d; }
unsigned char RX2 (void) { unsigned char d = 0; unsigned char i = 0; for (i=0;i<8;i++){ STATE2 = 0; //прижимаем линию DelayUs(6); //ждем STATE2 = 1; d>>=1; //освобождаем место под новый бит if (PIN2 == 1) d |= 0x80; //если 1 то записываем 1 DelayUs(70); //ждем до положенного времени } return d; }
void TX1(unsigned char cmd){ unsigned char temp = 0; unsigned char i = 0; temp = cmd; for (i=0;i<8;i++) { if (temp&0x01) { STATE1 = 0; //передаем 1 DelayUs(5); STATE1 = 1; DelayUs(70); } else { //передаем 0 STATE1 = 0; DelayUs(70); STATE1 = 1; DelayUs(5); } temp >>= 1; } return; }
void TX2(unsigned char cmd){ unsigned char temp = 0; unsigned char i = 0; temp = cmd; for (i=0;i<8;i++) { if (temp&0x01) { STATE2 = 0; //передаем 1 DelayUs(5); STATE2 = 1; DelayUs(70); } else { //передаем 0 STATE2 = 0; DelayUs(70); STATE2 = 1; DelayUs(5); } temp >>= 1; } return; }
void get_temp1() { static bit init; unsigned char temp1; unsigned char temp2; unsigned int temp3; n=0; //номер датчика для индикации init = INIT1(); //инициализация if (!init) { //успешно инициализировались? TX1(0xCC); TX1(0x44); DelayMs(150); //ждем 750 мс DelayMs(150); DelayMs(150); DelayMs(150); DelayMs(150); } init = INIT1(); //повторная инициализация if (!init) { TX1(0xCC); TX1(0xBE); //команда на чтение temp1 = RX1(); //читаем младший байт temp2 = RX1(); //читаем старший байт } temp_drob = temp1 & 0b00001111; //Записываем дробную часть в отдельную переменную temp_drob = ((temp_drob*6)+2)/10; //Переводим в нужное дробное число temp3=temp2; //добавляем старший байт в переменную для расчета температуры temp3<<=8; //задвигаем его на место temp3|=temp1; //добавляем в переменную младший байт sign = temp2 & 0x80; //определяем знак температуры if (sign) { //если минус temperature = (((~temp3)+1)/16); //то считаем по формуле для минуса temp_drob = 10-temp_drob; if (temp_drob>=10) {temp_drob=0;} } else temperature = temp3/16; //иначе по формуле для плюса return; }void get_temp2() { static bit init; unsigned char temp1; unsigned char temp2; unsigned int temp3; //требуется для корректного пересчета температуры согласно даташиту n=1; //номер датчика для индикации init = INIT2(); //инициализация if (!init) { //успешно инициализировались? TX2(0xCC); TX2(0x44); DelayMs(150); //ждем 750 мс DelayMs(150); DelayMs(150); DelayMs(150); DelayMs(150); } init = INIT2(); //повторная инициализация if (!init) { TX2(0xCC); TX2(0xBE); //команда на чтение temp1 = RX2(); //читаем младший байт temp2 = RX2(); //читаем старший байт } temp_drob = temp1 & 0b00001111; //Записываем дробную часть в отдельную переменную temp_drob = ((temp_drob*6)+2)/10; //Переводим в нужное дробное число temp3=temp2; //добавляем старший байт в переменную для расчета температуры temp3<<=8; //задвигаем его на место temp3|=temp1; //добавляем в переменную младший байт sign = temp2 & 0x80; //определяем знак температуры if (sign) { //если минус temperature = (((~temp3)+1)/16); //то считаем по формуле для минуса temp_drob = 10-temp_drob; if (temp_drob>=10) {temp_drob=0;} } else temperature = temp3/16; //иначе по формуле для плюса return; }
void main (void){ unsigned char temp1, temp2; INTCON = 0; // запрет прерываний TRIS0=0; // направление работы ножек порта А TRIS1=0; TRIS4=0; CMCON = 0x07; // отключение компараторов GPIO = 0; // очищаем порт А GPPU = 0; // подтягивающие R (0-вкл, 1-выкл) while (1) // основной цикл { POWERPIN=1; //подаем питание на датчики get_temp1 (); //получаем температуру с датчика 1 POWERPIN=0; //отключаем питание convert (); //конвертируем и передаем температуру на индикатор DelayS(100); //ждем POWERPIN=1; //подаем питание на датчики get_temp2 (); //получаем температуру с датчика 2 POWERPIN=0; //отключаем питание convert (); //конвертируем и передаем температуру на индикатор DelayS(100); //ждем } }