Поигравшись с термометром и часами реального времени DS1307 я решил совместить их в один девайс – часы-термометр. Еще одной причиной создания часов были сломавшиеся китайские настольные часы и я решил, что корпус не должен пропадать просто так.
Получилось что-то такое:
В силу того, что из всех комплектующих первым у меня оказался “расширитель портов” PCA9539. О этой микросхеме упоминалось в эксперименте №13.
Итак, система индикации. Система индикации реализована на двух семисегментных индикаторах (красный часы и синий термометр). Синий пришлось приглушать резисторами ограничителями, он зараза очень уж яркий ночью получился, а шим долепливать мне было уже совсем лень.
Схема системы индикации:
Плата под индикацию:
Вид с обратной стороны можно посмотреть на первой фотке.
Далее была собрана главная плата с часами реального времени DS1307 и термометром DS18b20.
Схема:
и вид платы:
Код проекта:
#include <stdio.h> #include <htc.h> #define _XTAL_FREQ 4000000 #include "usart.h" //функции для работы уарта #include "softi2c.h" //функции для работы i2c #define timeh1 RB7 //3 #define timeh2 RB6 //4 #define timem1 RB4 #define timem2 RB5 #define tempd1 RB3 #define tempd2 RB2 #define tempd3 RB1 #define STATE TRISA2 #define PIN RA2 #define set_min RA3 #define set_hr RA4 #define setup RB0 __CONFIG(LVPDIS & WDTDIS & MCLREN & UNPROTECT & HS); unsigned char temphour = 0; //часы unsigned char tempmin = 0; //минуты char temperature; //температура unsigned char temp_drob = 0; //дробная часть температуры unsigned char sign; //знак температуры volatile unsigned char button = 0; volatile unsigned char flag = 0; const unsigned char tempdigit[11]={ //масив для семисегментника, значения температуры 0b10110111, //ноль 0b10000001, //один 0b00111101, //два 0b10101101, //три 0b10001011, //четыре 0b10101110, //пять 0b10111110, //шесть 0b10000101, //семь 0b10111111, //восемь 0b10101111, //девять 0b00001000 }; const unsigned char tempdigitvspoint[10]={ //значения температуры с точкой 0b11110111, //ноль 0b11000001, //один 0b01111101, //два 0b11101101, //три 0b11001011, //четыре 0b11101110, //пять 0b11111110, //шесть 0b11000101, //семь 0b11111111, //восемь 0b11101111 //девять }; const unsigned char timedigit[10]={ //значения времени 0b11110101, //ноль 0b00100100, //один 0b10111001, //два 0b10101101, //три 0b01101100, //четыре 0b11001101, //пять 0b11011101, //шесть 0b10100100, //семь 0b11111101, //восемь 0b11101101 //девять }; const unsigned char timedigitvspoint[10]={ //значения времени с точкой 0b11110111, //ноль 0b00100110, //один 0b10111011, //два 0b10101111, //три 0b01101110, //четыре 0b11001111, //пять 0b11011111, //шесть 0b10100110, //семь 0b11111111, //восемь 0b11101111 //девять }; /* Объявления функций */ static bit INIT(void); void TX(unsigned char cmd); unsigned char RX(); void get_temp(); unsigned char BCDconv (unsigned char source); unsigned char DCBconv (unsigned char source); void SetMin(unsigned char minutes); unsigned char ReadMin(); void SetHour(unsigned char hours); unsigned char ReadHour(); void SetSeconds(unsigned char seconds); unsigned char ReadSeconds(); void ShowTime(); void SetupTime(); void InitIO(void); void Display(unsigned char time, unsigned char temperaturet); void Displaypoint(unsigned char time, unsigned char temperaturet); void Displaypointminus(unsigned char time, unsigned char temperaturet); void DispAll(unsigned char hour, unsigned char min, unsigned char temperaturet); void main(void){ unsigned char input; unsigned char i=0; CMCON = 0x07; TRISB = 0x00; TRISB0 = 1; TRISA3 = 1; TRISA4 = 1; get_temp(); //берем значения температуры для первого включения /* Служебная установка часов и вывод на комп через уарт */ /* init_comms(); SetHour(15); SetMin(38); SetSeconds(23); get_temp(); ShowTime(); */ InitIO(); //инициализация расширителя портов /* Настраиваем таймер, задающий период обновления температуры и времени */ T1CKPS1 = 1; T1CKPS0 = 1; // предделитель = 8 T1OSCEN = 0; //выключаем внутренний генератор TMR1CS = 0; // Fosc/4 GIE = 1; // глобальные прерывания PEIE = 1; // прерывания перефирии TMR1IE = 1; // прерывание по переполнению TMR1 TMR1ON = 1; // включаем таймер TMR1H = 0b10110000; TMR1L = 0x00; //инициализация таймера со значения 65024 INTE = 0; temphour = ReadHour(); tempmin = ReadMin(); //get_temp(); for(;;){ DispAll(temphour, tempmin , temperature); //отображаем все на дисплее /* Настройка обновления данных */ if (flag == 20) { temphour = ReadHour(); tempmin = ReadMin(); i++; flag = 0; } if (i == 100) { TMR1IE = 0; get_temp(); i = 0; TMR1IE = 1; } /* Обработчик нажатий кнопок */ if (!set_hr) { TMR1IE = 0; __delay_ms(100); if (!set_hr) { if (temphour<24) { temphour++; SetHour(temphour); } else { temphour = 1; SetHour(temphour); } } TMR1IE = 1; } if (!set_min) { TMR1IE = 0; __delay_ms(100); if (!set_min) { if (tempmin<60) { tempmin++; SetMin(tempmin); } else { tempmin = 1; SetMin(tempmin); } } TMR1IE = 1; } if (!setup) { TMR1IE = 0; __delay_ms(100); if (!setup) { SetSeconds(0); } TMR1IE = 1; } /* /* Меню для отображения по уарту */ input = getch(); switch (input) { case 49 : ShowTime(); break; case 50 : SetupTime(); break; case 51 : get_temp(); ShowTime(); break; } if (input == 49) { SetupTime();} */ } } interrupt isr() { //обработчик прерываний if (TMR1IF) { flag++; TMR1H = 0b10110000; TMR1L = 0x00; TMR1IF = 0; //сброс флага } } /* Функции протокола 1-wire */ static bit INIT(void){ static bit b; STATE = 1; STATE = 0; __delay_us(500); STATE = 1; __delay_us(65); b = PIN; __delay_us(450); return b; } void TX(unsigned char cmd){ unsigned char temp = 0; unsigned char i = 0; temp = cmd; for (i=0;i<8;i++) { if (temp&0x01) { STATE = 0; __delay_us(5); STATE = 1; __delay_us(70); } else { STATE = 0; __delay_us(70); STATE = 1; __delay_us(5); } temp >>= 1; } } unsigned char RX() { unsigned char d = 0; unsigned char i = 0; for (i=0;i<8;i++){ STATE = 0; __delay_us(6); STATE = 1; __delay_us(4); d>>=1; if (PIN == 1) d |= 0x80; //printf("\r\n %d", d); __delay_us(60); } return d; } /* Получаем значение температуры */ void get_temp() { static bit init; unsigned char temp1; unsigned char temp2; init = INIT(); if (!init) { TX(0xCC); TX(0x44); __delay_ms(150); __delay_ms(150); __delay_ms(150); __delay_ms(150); __delay_ms(150); } else printf("bug"); init = INIT(); if (!init) { TX(0xCC); TX(0xBE); temp1 = RX(); temp2 = RX(); } temp_drob = temp1 & 0b00001111; //Записываем дробную часть в отдельную переменную temp_drob = ((temp_drob*6)+2)/10; //Переводим в нужное дробное число temp1 >>= 4; sign = temp2 & 0x80; temp2 <<= 4; temp2 &= 0b01110000; temp2 |= temp1; if (sign) { temperature = 127-temp2; temp_drob = 10 - temp_drob; } else temperature = temp2; } /* Функции часов */ unsigned char BCDconv (unsigned char source) { unsigned char temp_min=0; unsigned char temp_maj=0; temp_min = source&15; temp_maj = source >> 4; //printf("\r\n minor - %x", temp_min); //printf("\r\n major - %x", temp_maj); temp_maj *= 10; //printf("\r\n major - %x", temp_maj); return temp_maj+temp_min; } unsigned char DCBconv (unsigned char source) { unsigned char temp_min=0; unsigned char temp_maj=0; temp_maj = source/10 ; temp_min = source - temp_maj*10; temp_maj <<= 4; return temp_maj+temp_min; } void SetMin(unsigned char minutes) { //записываем значение в минуты i2c_start(); i2c_tx(0b11010000); i2c_tx(0x01); i2c_tx(DCBconv(minutes)); i2c_stop(); } unsigned char ReadMin() { unsigned char temp = 0; i2c_start(); //читаем значение минут i2c_tx(0b11010000); i2c_tx(0x01); i2c_start(); i2c_tx(0b11010001); temp = i2c_rx(0); i2c_stop(); return BCDconv(temp); } void SetHour(unsigned char hours) { //записываем значение в часы i2c_start(); i2c_tx(0b11010000); i2c_tx(0x02); i2c_tx(DCBconv(hours)); i2c_stop(); } unsigned char ReadHour() { unsigned char temp = 0; unsigned char temp2 = 0; i2c_start(); //читаем значение часов i2c_tx(0b11010000); i2c_tx(0x02); i2c_start(); i2c_tx(0b11010001); temp = i2c_rx(0); i2c_stop(); /* temp2 = temp&0b00001111; temp /= 10; temp = temp >> 4; temp = temp*10 + temp2;*/ return BCDconv(temp); } void SetSeconds(unsigned char seconds) { //записываем значение в секунды i2c_start(); i2c_tx(0b11010000); i2c_tx(0x00); i2c_tx(DCBconv(seconds)); i2c_stop(); } unsigned char ReadSeconds() { unsigned char temp = 0; i2c_start(); //читаем значение минут i2c_tx(0b11010000); i2c_tx(0x00); i2c_start(); i2c_tx(0b11010001); temp = i2c_rx(0); i2c_stop(); return BCDconv(temp); } /* Функции для работы по протоколу USART */ void ShowTime() { printf("\fTime - %d :", ReadHour()); printf(" %d :", ReadMin()); printf(" %d ", ReadSeconds()); printf("\r\ntemperatura -- "); if (sign) printf("-"); else printf("+"); printf("%d", temperature); printf(".%d", temp_drob); printf("\r\n*********************"); printf("\r\n Menu"); printf("\r\n 1 - Reload time"); printf("\r\n 2 - Setup time"); printf("\r\n 3 - Reload temp"); } void SetupTime() { unsigned char state = 1; unsigned char temp_min = 0; unsigned char temp_maj = 0; unsigned char temp = 0; while(state){ printf("\fEnter hours - "); temp_maj = getch(); printf(" %c", temp_maj); temp_min = getch(); printf("%c", temp_min); temp = getch(); if (temp == 13) { temp_maj -= 48; temp_min -= 48; temp = temp_maj*10 + temp_min; if (temp < 24) { SetHour(temp); state = 0; } } } state = 1; while(state){ printf("\fEnter minutes - "); temp_maj = getch(); printf(" %c", temp_maj); temp_min = getch(); printf("%c", temp_min); temp = getch(); if (temp == 13) { temp_maj -= 48; temp_min -= 48; temp = temp_maj*10 + temp_min; if (temp < 61) { SetMin(temp); state = 0; } } } state = 1; while(state){ printf("\fEnter seconds - "); temp_maj = getch(); printf(" %c", temp_maj); temp_min = getch(); printf("%c", temp_min); temp = getch(); if (temp == 13) { temp_maj -= 48; temp_min -= 48; temp = temp_maj*10 + temp_min; if (temp < 61) { SetSeconds(temp); state = 0; } } } ShowTime(); } /* Функции работы с расширителем портов */ void InitIO(void) { i2c_start(); i2c_tx(0b11101000); i2c_tx(0b00000110); i2c_tx(0x00); i2c_tx(0x00); i2c_stop(); } void Display(unsigned char time, unsigned char temperaturet) { unsigned char timetemp = 0; unsigned char temptemp = 0; timetemp = time; temptemp = temperaturet; i2c_start(); i2c_tx(0b11101000); i2c_tx(0b00000010); i2c_tx(timedigit[timetemp]); i2c_tx(tempdigit[temptemp]); i2c_stop(); } void Displaypoint(unsigned char time, unsigned char temperaturet) { unsigned char timetemp = 0; unsigned char temptemp = 0; timetemp = time; temptemp = temperaturet; i2c_start(); i2c_tx(0b11101000); i2c_tx(0b00000010); i2c_tx(timedigitvspoint[timetemp]); i2c_tx(tempdigitvspoint[temptemp]); i2c_stop(); } void Displaypointminus(unsigned char time, unsigned char temperaturet) { unsigned char timetemp = 0; unsigned char temptemp = 0; timetemp = time; temptemp = temperaturet; i2c_start(); i2c_tx(0b11101000); i2c_tx(0b00000010); i2c_tx(timedigitvspoint[timetemp]); i2c_tx(tempdigit[temptemp]); i2c_stop(); } void DispAll(unsigned char hour, unsigned char min, unsigned char temperaturet) { unsigned char tim = 0; unsigned char tem = 0; unsigned char buf = 0; if (!sign) { timeh1 = 0; timeh2 = 0; timem1 = 0; timem2 = 0; tempd1 = 0; tempd2 = 0; tempd3 = 0; tim = hour/10; tem = temperaturet/10; Display(tim, tem); timeh1 = 1; timeh2 = 0; timem1 = 0; timem2 = 0; tempd1 = 1; tempd2 = 0; tempd3 = 0; __delay_us(500); timeh1 = 0; timeh2 = 0; timem1 = 0; timem2 = 0; tempd1 = 0; tempd2 = 0; tempd3 = 0; buf = tim*10; tim = hour - buf; tem = temperaturet - tem*10; Displaypoint(tim, tem); timeh1 = 0; timeh2 = 1; timem1 = 0; timem2 = 0; tempd1 = 0; tempd2 = 1; tempd3 = 0; __delay_us(500); timeh1 = 0; timeh2 = 0; timem1 = 0; timem2 = 0; tempd1 = 0; tempd2 = 0; tempd3 = 0; tim = min/10; tem = temp_drob; Display(tim, tem); timeh1 = 0; timeh2 = 0; timem1 = 1; timem2 = 0; tempd1 = 0; tempd2 = 0; tempd3 = 1; __delay_us(500); timeh1 = 0; timeh2 = 0; timem1 = 0; timem2 = 0; tempd1 = 0; tempd2 = 0; tempd3 = 0; buf = tim*10; tim = min-buf; Display(tim, tem); timeh1 = 0; timeh2 = 0; timem1 = 0; timem2 = 1; tempd1 = 0; tempd2 = 0; tempd3 = 1; __delay_us(500); timeh1 = 0; timeh2 = 0; timem1 = 0; timem2 = 0; tempd1 = 0; tempd2 = 0; tempd3 = 0; __delay_us(500); } else { timeh1 = 0; timeh2 = 0; timem1 = 0; timem2 = 0; tempd1 = 0; tempd2 = 0; tempd3 = 0; tim = hour/10; tem = 10; Display(tim, tem); timeh1 = 1; timeh2 = 0; timem1 = 0; timem2 = 0; tempd1 = 1; tempd2 = 0; tempd3 = 0; __delay_ms(1); timeh1 = 0; timeh2 = 0; timem1 = 0; timem2 = 0; tempd1 = 0; tempd2 = 0; tempd3 = 0; buf = tim*10; tim = hour - buf; tem = temperaturet/10; Displaypointminus(tim, tem); timeh1 = 0; timeh2 = 1; timem1 = 0; timem2 = 0; tempd1 = 0; tempd2 = 1; tempd3 = 0; __delay_ms(1); timeh1 = 0; timeh2 = 0; timem1 = 0; timem2 = 0; tempd1 = 0; tempd2 = 0; tempd3 = 0; tim = min/10; tem = temperaturet - tem*10; Display(tim, tem); timeh1 = 0; timeh2 = 0; timem1 = 1; timem2 = 0; tempd1 = 0; tempd2 = 0; tempd3 = 1; __delay_ms(1); timeh1 = 0; timeh2 = 0; timem1 = 0; timem2 = 0; tempd1 = 0; tempd2 = 0; tempd3 = 0; buf = tim*10; tim = min-buf; Display(tim, tem); timeh1 = 0; timeh2 = 0; timem1 = 0; timem2 = 1; tempd1 = 0; tempd2 = 0; tempd3 = 1; __delay_ms(1); timeh1 = 0; timeh2 = 0; timem1 = 0; timem2 = 0; tempd1 = 0; tempd2 = 0; tempd3 = 0; __delay_ms(1); } }
Ну и видео работы часов:
Исходники и PCB лежат на репе в разделе проекты.
У вас довольно часто встречаются команды типа printf
printf(“\fTime – %d :”, ReadHour());
printf(” %d :”, ReadMin());
printf(” %d “, ReadSeconds());
printf(“\r\ntemperatura — “);
printf(“\r\n*********************”);
printf(“\r\n Menu”);
printf(“\r\n 1 – Reload time”);
Где можно почитать более подробно про их применение. Конкретно не понятно применение значков “\r\n ” %d “,
Что они означают
Это стандартный синтаксис библиотекии stdio https://ru.wikipedia.org/wiki/Printf
Конкретно по вашему вопросу:
%d, отобразит в месте %d децимальное число, например printf(“%d”, 10) отобразит 10.
\r\n – вообще все просто маркер конца строки (ASCII table)
Здравствуйте!
Пытаюсь приспособить Ваш проект под 12ф629 в части показания температуры.
В temperature сохраняется целая часть значения, так?
Хочу вывести на одноиндикаторный семисегментный диод через сдвиговый регистр его значение по одному символу. Как вывести двухзначное значение temperature?
Односимвольную переменную для примера вывожу, проблем нет. Для двухзначных, наверное, нужно использовать строковые функции, но у меня не получилось.
Добрый день.
Не понимаю где вы затык поймали:
напримерь temperature = 25.
1. display tempereature/10
2. display temperature-temperature/10
Все так просто 🙂
А второй пункт разве не даст 25-2=23?
да, виноват, надо:
display temperature-(temperature/10)*10
Не показывает, точнее ноль.
Выводы определил так:
#define STATE TRISIO4
#define PIN GPIO4
Точнее в начале показывает 8, далее 2, а затем все время ноль.
почему-то вставка неправильно сработала, вот так надо:
write_byte(digits);
вместо
write_byte(digits1);
Опять не то, съедается квадратная скобка:
write_byte(digits квад.скобка “с” квад.скобка.закр.)
Проблема в том, что я не знаю внутренностей вашего кода и схемы, и более того, я крайне не хочу в это вникать.
Поэтому вы сначала разберитесь, точно ли у вас все правильно отображается.
digits[11] показывает 8, почему 8 то? У вас 11 элемент массива это 8?
Кажется я понял, у вас зачем то подряд идет две команды и нужная это
digits
Ок, что будет если вы расскоментируете строку temperature = 12 и не будете использовать функцию get_temp?
digits (11) очищает индикатор, т.е. гасит светодиоды (не использую линию сброса ради экономии ножек).
Если расскоментировать, то и будет показывать – 1 и 2, поэтому на нем сначала и проверял, т.е. функция вывода на индикатор работает верно. В остальном код Ваш.
Так с этого и надо было начинать, что не вывод не работает, а функция барахлит.
В протеусе пробовали проверять?
Так даже я бы предложил следующее:
1. Дальше обсуждать http://diymicro.ru/pic-mk-eksperiment-16-one-wire-na-primere-ds18b20.html тут, как в более подходящем месте
2. В протеусе соберите схемку и проверьте реагирует ли вообще ваш пик на изменение входа на этом пине, этот мк имеет малое количество пинов и там могут быть нюансы, о которых я к сожалению сходу вспомнить не могу