Приветствую всех любителей самоделок! Сегодня хочу рассказать о своём проекте - часы в подарок. У однокурсника в сентябре день рождения, но подарок решил начать готовить пораньше, так как в учебное время этим некогда будет заниматься. Эти часы начинал собирать ещё года так 3-4 назад, но потом забросил их чего-то и недавно наводя порядок в своих закромах наткнулся на них. То есть для меня по сути эти часы нужно доработать, а именно сделать культурный корпус и добавить датчик комнатной температуры, в его роли будет выступать ds18b20. Начинаем!
Для этого нам понадобится:
- Светодиодная матрица на MAX7219.
- Плата Arduino Nano (можно и другую, например Pro Mini).
- Модуль часов реального времени DS1302.
- Датчик температуры ds18b20 и к нему резистор на 4,7 Ком.
- Тонкий провод (в моём случае это МГТФ-0,25).
- Стойки, винты и гайки к ним.
- Двухсторонний скотч.
- Термоклей и клеевой пистолет.
- Ненужный USB провод.
- Два разъёма типа "мама" (необязательно, можно припаять провод без них).
- Три тактовые кнопочки, кусочек макетной платы и 3 SMD резистора по 10 кОм.
- Паяльник, припой, канифоль и т.д.
1. Прошиваемся
Я постарался максимально понятно написать код с комментариями. Да, он не идеален и его можно упростить, но и так сойдёт. Функция dat работает с датчиком температуры и выводит всю информацию о нём в монитор порта, можно посмотреть. Стоит сразу отметить, что ds18b20 нужно подключать именно к аналоговому входу МК, сначала прицепил на цифровой и долго думал почему ничего не работает.
Сам код:
//недостающие библиотеки качаем из инета
#include <iarduino_RTC.h> // эта библиотека версии 1.3.4 от 09.01.2020
#include <Wire.h>
#include <SPI.h>
#include <OneWire.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
#include <DallasTemperature.h>
OneWire ds(A0); //(пин куда подключён датчик)
byte i; //всё для датчика
byte present = 0;
byte type_s;
byte data[9];
byte addr[8];
float celsius, fahrenheit;
uint8_t h,m,s; // переменные для хранения времени
Max72xxPanel matrix = Max72xxPanel(10, 1, 4); // пин CS, кол-во матриц по вертикали, кол-во матриц по горезонтали
iarduino_RTC watch(RTC_DS1302,2,3,4); //rst clk dat модуля часов
int spacer = 1; // расстояние между цифрами температуры
int width = 5 + spacer; // размер шрифта
void setup(void) {
Serial.begin(9600);
matrix.setIntensity(1); // Яркость от 0 до 15
matrix.setRotation(matrix.getRotation()+1); // положение матриц +1 - 90 +2 - 180 +3 - 270 градусов
watch.begin(); // запуск часов
watch.settime(0,0,12); // установка текущего времени (сек, мин, час), записывается один раз
pinMode(8, OUTPUT); // настройка пинов для кнопок
digitalWrite(8,1);
pinMode(7, INPUT);
pinMode(6, INPUT);
pinMode(5, INPUT);
}
void dat() { // подключение датчика и вся инфа о нём
if ( !ds.search(addr)) {
Serial.println("No more addresses.");
Serial.println();
ds.reset_search();
delay(10);
return;
}
Serial.print("ROM =");
for( i = 0; i < 8; i++) {
Serial.write(' ');
Serial.print(addr[i], HEX);
}
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return;
}
Serial.println();
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
Serial.println(" Chip = DS18S20"); // or old DS1820
type_s = 1;
break;
case 0x28:
Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
Serial.println(" Chip = DS1822");
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
//delay(750); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
Serial.print(" Data = ");
Serial.print(present, HEX);
Serial.print(" ");
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
Serial.print(data[i], HEX);
Serial.print(" ");
}
Serial.print(" CRC=");
Serial.print(OneWire::crc8(data, 8), HEX);
Serial.println();
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
}
celsius = (float)raw / 16.0; //расчёт температуры в градусах
// fahrenheit = celsius * 1.8 + 32.0;
Serial.print(" Temperature = ");
Serial.print(celsius);
Serial.print(" Celsius, ");
// Serial.print(fahrenheit);
// Serial.println(" Fahrenheit");
//delay(500);
}
void loop(void){
dat();
Display();
watch.gettime();
if(millis()%1000==0){ // если прошло 1 секунда
h = watch.Hours; // Получаем текущие часы
m = watch.minutes; // Получаем текущие минуты
s = watch.seconds; // Получаем текущие секунды
delay(2);
}
bool button_setup = digitalRead(7); // считываем состояние кнопок
bool button_plus = digitalRead(6);
bool button_minus = digitalRead(5);
//Проверка нажатий
int regim=1;
int flag=0;
if (regim==1 and button_minus==1){
temp();
}
if(button_setup==1&&flag==0)
{
regim++;
flag=1;
if(regim>3) regim=1;
}
if(button_setup==0&&flag==1) flag=0;
if(regim==1)//настройка часов
{
if(button_plus==1){ //настройка часов
h++;
if(h>23) h=0;
watch.settime(0,m,h);
delay(250);
}
}
if(regim==2)//настройка минут
{
if(button_plus==1){
m++;
if(m>59) m=0;
watch.settime(0,m,h);
delay(250);
}
}
}
void temp() { //вывод температуры
String tape = String(celsius, 1)+" ";
for ( int i = 0 ; i < width * tape.length() + matrix.width() - 1 - spacer; i++ ) {
matrix.fillScreen(LOW);
int letter = i / width;
int x = (matrix.width() - 1) - i % width;
int y = (matrix.height() - 8) / 2;
while ( x + width - spacer >= 0 && letter >= 0 ) {
if ( letter < tape.length() ) {
matrix.drawChar(x, y, tape[letter], HIGH, LOW, 1);
}
letter--;
x -= width;
}
matrix.write();
delay(50);
}
}
void Display(){ //вывод времени
matrix.fillScreen(0);
int y = (matrix.height() - 8) / 2; // центрирование по вертикали
if(watch.seconds & 1) // мигающее двоеточие
{
matrix.drawChar(14, y, (String(":"))[0], HIGH, LOW, 1);
}
else
{
matrix.drawChar(14, y, (String(" "))[0], HIGH, LOW, 1);
}
String hour1 = String (h/10); // преобразовываем числа для вывода
String hour2 = String (h%10);
String min1 = String (m/10);
String min2 = String (m%10);
String sec1 = String (s/10);
String sec2 = String (s%10);
int xh = 2;
int xm = 19;
matrix.drawChar(xh, y, hour1[0], HIGH, LOW, 1);
matrix.drawChar(xh+6, y, hour2[0], HIGH, LOW, 1);
matrix.drawChar(xm, y, min1[0], HIGH, LOW, 1);
matrix.drawChar(xm+6, y, min2[0], HIGH, LOW, 1);
matrix.write(); // Вывод на дисплей
}
2. Паяем, собираем
После успешной прошивки переходим к сборке часов. Прикручиваем стойки к матрице по краям для крепления в корпус. Крепим Arduino, модуль часов и кнопки на двухсторонний скотч к обратной стороне платы матрицы, провода на термоклей. Схема:
Датчик:
Клавиатура (вид снизу):
Провод питания можно сделать так. Берём ненужный USB-провод от зарядки и откусываем разъём микро-USB (в моём случае). Теперь зачищаем провода и аккуратно припаиваем разъёмы "мама". Места спайки изолируем термоусадкой. Соблюдая полярность питания подключаем провод к разъёму ISP для программатора.
Готово!
3. Корпус
Так как это подарок то корпус должен быть хороший, поэтому открываю программу Компас-3D, моделирую и отправляю для печати чудесной шайтан-машине под названием 3D-принтер. Только под кнопки вручную отверстия надо будет сделать. Вот как это будет выглядеть:
4. Настройка
Настройку немного переработал - осуществляется двумя кнопками + датчик.
При нажатии кнопки 2, увеличиваем час на 1.
При одновременном нажатии на кнопки 1 и 2, увеличиваем минуты на 1.
При нажатии на кнопку 3 отображаем температуру с датчика в виде бегущей строки. Вот как-то так:
На этом у меня всё, будет интересно узнать ваше мнение об этом проекте. Всем удачных самоделок!