After I had enough time playing with a thermal sensor DS18b20 and the RTC DS1307 I decided to bundle them together into a single device. Another reason was the fact that the cheap Chinese clock called a day and let its electronic soul leave the nice enclosure. I considered this as an opportunity to put my stuff inside of it.
That is what I got in the end:

+1 reason is that I had a free sample of the “port expander” PCA9539, I mentioned this IC in experiment #13.
So, the first thing I want to describe is an indication system. I built it based on two 7-segment indicators (the red one is for the clock and the blue one for the temperature). The blue one was too bright, so I had to increase the resistor value to lower the brightness, since I was to lazy to add PWM here as well at the moment of time.
The schematic for the indication system is shown below:

The PCB:

After that, the main pcb has been assembled, where I placed the DS1307 clock and the thermal sensor DS18b20.
The schematic:

and the mainboard pcb:

The code:
#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; //hours
unsigned char tempmin = 0; //minutes
char temperature; //temp
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]={ //temp values with dot
0b11110111, //ноль
0b11000001, //один
0b01111101, //два
0b11101101, //три
0b11001011, //четыре
0b11101110, //пять
0b11111110, //шесть
0b11000101, //семь
0b11111111, //восемь
0b11101111 //девять
};
const unsigned char timedigit[10]={ //time values
0b11110101, //ноль
0b00100100, //один
0b10111001, //два
0b10101101, //три
0b01101100, //четыре
0b11001101, //пять
0b11011101, //шесть
0b10100100, //семь
0b11111101, //восемь
0b11101101 //девять
};
const unsigned char timedigitvspoint[10]={ //time values with dot
0b11110111, //ноль
0b00100110, //один
0b10111011, //два
0b10101111, //три
0b01101110, //четыре
0b11001111, //пять
0b11011111, //шесть
0b10100110, //семь
0b11111111, //восемь
0b11101111 //девять
};
/* functions calling */
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(); //getting temp values for the power on
InitIO(); //port io expander
/* setup timer and refresh period */
T1CKPS1 = 1;
T1CKPS0 = 1; // prescaler = 8
T1OSCEN = 0; //no intosc
TMR1CS = 0; // Fosc/4
GIE = 1; // global interrupt
PEIE = 1; // periferal interrups
TMR1IE = 1; // interrupt on TMR1 overflow
TMR1ON = 1; // enabling the timer
TMR1H = 0b10110000; TMR1L = 0x00; //init timer value 65024
INTE = 0;
temphour = ReadHour();
tempmin = ReadMin();
//get_temp();
for(;;){
DispAll(temphour, tempmin , temperature); //display everything
/* data refresh setup */
if (flag == 20) {
temphour = ReadHour();
tempmin = ReadMin();
i++;
flag = 0;
}
if (i == 100) { TMR1IE = 0;
get_temp();
i = 0;
TMR1IE = 1; }
/* button pressing handler */
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;
}
/*
/* uart menu */
input = getch();
switch (input) {
case 49 : ShowTime();
break;
case 50 : SetupTime();
break;
case 51 : get_temp();
ShowTime();
break;
}
if (input == 49) { SetupTime();}
*/
}
}
interrupt isr() { //interrupts handler
if (TMR1IF) {
flag++;
TMR1H = 0b10110000; TMR1L = 0x00;
TMR1IF = 0;
}
}
/* 1-wire functions */
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;
}
/* getting the temp value */
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;
}
/* clock functions */
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) { //write minutes value
i2c_start();
i2c_tx(0b11010000);
i2c_tx(0x01);
i2c_tx(DCBconv(minutes));
i2c_stop();
}
unsigned char ReadMin() {
unsigned char temp = 0;
i2c_start(); //read minutes
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) { //hour writing
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(); //read hours
i2c_tx(0b11010000);
i2c_tx(0x02);
i2c_start();
i2c_tx(0b11010001);
temp = i2c_rx(0);
i2c_stop();
return BCDconv(temp);
}
void SetSeconds(unsigned char seconds) { //write seconds
i2c_start();
i2c_tx(0b11010000);
i2c_tx(0x00);
i2c_tx(DCBconv(seconds));
i2c_stop();
}
unsigned char ReadSeconds() {
unsigned char temp = 0;
i2c_start(); //read seconds
i2c_tx(0b11010000);
i2c_tx(0x00);
i2c_start();
i2c_tx(0b11010001);
temp = i2c_rx(0);
i2c_stop();
return BCDconv(temp);
}
/* USART functions */
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();
}
/* io expander functions */
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);
}
}The video with the clock working:
The sources and the PCB are on my git repo