Do tego potrzebne nam bedą:
- Wyświetlacz LCD
- Atmega (w moim przypadku była to 328, jednak 88/128 też powinny dać radę )
- ESP8266 ( ja użyłem wersję 1 1MB)
- Przejściówka USB <-> RS232
Schemat podłączenia:
Na początek instalujemy środowisko ArduinoIDE ( stąd: https://www.arduino.cc/en/main/software ) .
Uruchamiamy ArduinoIDE i wybieramy z górnego menu PLIK -> preferencje w polu „Dodatkowe adresy URL do menadżera płytek” wpisujemy: http://arduino.esp8266.com/stable/package_esp8266com_index.json i klikamy OK
Następnie przechodzimy do „Narzędzia” -> „Płytka …” -> „Menadżer płytek” , w polu wyszukiwania wpisujemy esp8266 i naciskamy enter. Pojawia nam się „esp8266 by ESP8266 Community” i klikamy instaluj. Czekamy aż się poprawnie się pobierze i zainstaluje płytka.
Gdy to zostanie zrobione instalujemy potrzebne biblioteki, a więc wchodzimy w „Narzędzia” -> „Zarządzaj bibliotekami” i instalujemy:
- NTPClient
- Time
- Timezone
Następnie wybieramy Narzędzia -> Płytka -> ESP8266 Generic .
Wpisujemy taki kod:
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <Time.h>
#include <TimeLib.h>
#include <Timezone.h>
// Właściwości NTP
#define NTP_OFFSET 0
#define NTP_INTERVAL 60 * 1000
#define NTP_ADDRESS "time.coi.pw.edu.pl" //adres serwera NTP, adresy innych serwerów można znaleźć w internecie
char ssid[] = "********"; // ssid
char pass[] = "********"; // hasło
///bufor ramki rs232
byte frame[10];
byte frCnt = 0;
//flaga czekania na odbiór ntp
boolean waitForReply = 0;
byte attempt = 0;
//obiekty UDP i protokołu NTP
WiFiUDP udp;
NTPClient timeClient(udp, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);
void setup()
{
Serial.begin(9600);
//Serial.println();
//Serial.println();
// Łączenie
//Serial.print("Connecting to ");
//Serial.println(ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
//Serial.print(".");
}
//Serial.println("");
//Serial.println("WiFi connected");
//Serial.println("IP address: ");
//Serial.println(WiFi.localIP());
//Serial.println("Starting NTP Client");
timeClient.begin();
//komunikat o poprawnym połączeniu
Serial.print("ic!\n");
}
void loop()
{
//odbierz dane
if (Serial.available() > 0) {
frame[frCnt] = Serial.read();
if (frame[frCnt] == '\n') {
//odebrano komplerną ramkę
if(frame[2] == '?') {
//odebrano zapytanie
if (frame[0] == 't' && frame[1] == 'i') {
//odebrano zapytanie o NTP
//aktualizuj dane
timeClient.update();
//pobierz dane w formacie unix (liczba sekund od 1.01.1970, UTC)
unsigned long unix = timeClient.getEpochTime();
// biblitoeka time.h wymaga używania formatu zmiennej time_t, dlatego tworzymy dwie zmienne (czas UTC i lokalny)...
time_t utc, ti;
//..i rzutujemy czas z serwera do zmiennej
utc = unix;
//Dane strefy czasowej wraz z regułami zmiany czasu. W naszym przypadku będzie to CET (zimowy) oraz CEST (letni).
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; //Central European Summer Time
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; //Central European Standard Time
Timezone LocalTime(CEST, CET);
//konwersja czasu
ti = LocalTime.toLocal(utc);
//wysyłamy dane
Serial.print("ti=");
Serial.print(year(ti));
Serial.print("-");
if (month(ti) < 10) Serial.print("0");
Serial.print(month(ti));
Serial.print("-");
if (day(ti) < 10) Serial.print("0");
Serial.print(day(ti));
Serial.print("-");
if (hour(ti) < 10) Serial.print("0");
Serial.print(hour(ti));
Serial.print("-");
if (minute(ti) < 10) Serial.print("0");
Serial.print(minute(ti));
Serial.print("-");
if (second(ti) < 10) Serial.print("0");
Serial.print(second(ti));
Serial.print("\n");
}
}
//zeruj
frCnt = 0;
} else {
frCnt++;
}
}
}
(kod skopiowany z zegara nixie z majsterkowo https://majsterkowo.pl/zegar-nixie-synchronizowany-z-ntp-cz-1/ trzeba uzupełnić o nazwę sieci i hasło własnej sieci Wi-Fi)
Klikamy zweryfikuj, podłączamy GPIO0 do GND na esp8266 resetujemy go i klikamy wgraj.
I to tyle od strony ESP8266 :).
Teraz przechodzimy do Eclipse i programujemy naszą atmegę 🙂
tworzymy nowy projekt do którego kopiujemy już bibliotekę UART (np. z Peter Fleury), oraz do obsługi LCD (ja używam bibliotekę z niebieskiej książki Mirosława Kardasia ), jednak ta od Peter Fleury też powinna działać poprawnie.
Tworzymy main.c, wpisujemy:
// Standard library:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <string.h>
// Own library
#include "uart/uart.h"
#include "lcd/lcd44780.h"
// Global variables
signed char h;
signed char m;
signed char s;
signed char day;
signed char month;
signed char year;
signed char date[15];
volatile uint16_t time;
unsigned int get_data;
char buffor[26];
uint16_t counter = 0;
#define UART_BAUD_RATE 9600
// Define functions:
void initialize_screen();
void initialize_wifi();
void initialize_clock();
void initialize_timer0();
void print_time();
void clock(char jumpDays);
void get_uart_message();
unsigned char computeDayNum(unsigned char y,unsigned char m);
//***************************** Main function: *******************************/
int main(void)
{
// Initialize functions
initialize_screen();
initialize_wifi();
initialize_clock();
initialize_timer0();
_delay_ms(3000);
// enable sei
sei();
// main loop
while(1)
{
get_uart_message();
}
}
/*************** Functions *******************/
void print_time(){
lcd_cls();
lcd_int(h);
lcd_str(":");
lcd_int(m);
lcd_str(":");
lcd_int(s);
lcd_locate(1,0);
lcd_int(day);
lcd_str("-");
lcd_int(month);
lcd_str("-20");
lcd_int(year);
}
void initialize_screen(){
lcd_init();
lcd_str("Uruchamiam");
}
void initialize_wifi(){
uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU));
uart_puts("ti?\r\n");
}
void initialize_clock(){
h = 0;
m = 0;
s = 0;
year = 19;
day = 1;
month = 1;
}
void initialize_timer0(){
/*
* Init Timer0
*/
TCCR0A |= (1<<WGM01);
OCR0A = 77;
TIMSK0 |= (1 << OCIE0A);
TCCR0B |= (1<<CS02) | (1<<CS00);
}
void clock(char jumpDays) {
if (s >= 60) {
s = 0;
m++;
}
if (m >= 60) {
m = 0;
h++;
}
if (h >= 24) {
h = 0;
if (jumpDays) day++;
}
if (day > computeDayNum(year,month)) {
day = 1;
month++;
}
if (month > 12) {
month = 1;
if(jumpDays) year++;
}
if(year > 99) year = 0;
if (s < 0) {
s = 59;
m--;
}
if (m < 0) {
m = 59;
h--;
}
if (h < 0) h = 23;
if (day < 1) {
month--;
day = computeDayNum(year,month);
}
if (month < 1) month = 12;
if (year < 0) year = 99;
}
unsigned char computeDayNum(unsigned char y,unsigned char m) {
if (m==4 || m==6 || m==9 || m==11) return 30;
else if (m==2) {
if (y % 4) {
return 28;
} else {
return 29;
}
} else return 31;
}
void get_uart_message(){
do{
get_data = uart_getc();
if ( get_data & UART_NO_DATA ) return;
else
{
if ( get_data & UART_FRAME_ERROR ) return;
if ( get_data & UART_OVERRUN_ERROR ) return;
if ( get_data & UART_BUFFER_OVERFLOW ) return;
}
buffor[counter] = get_data;
counter++;
}while(get_data != '\n');
counter = 0;
year = (buffor[5] - '0') * 10;
year += buffor[6] - '0';
month = (buffor[8] - '0') * 10;
month += buffor[9] - '0';
day = (buffor[11] - '0') * 10;
day += buffor[12] - '0';
h = (buffor[14] - '0') * 10;
h += buffor[15] - '0';
m = (buffor[17] - '0') * 10;
m += buffor[18] - '0';
s = (buffor[20] - '0') * 10;
s += buffor[21] - '0';
}
// ISR:
ISR(TIMER0_COMPA_vect){
time++;
if((time%100)==0){
// add seconds after 1 seconds
s+=1;
clock(1);
print_time();
}
if(time >=1000){
// get new date after 10 seconds
uart_puts("ti?\r\n");
// set time=0
time=0;
}
}
Kompilujemy i wgrywamy program do atmegi328 i na ekranie LCD powinien ukazać się aktualna data i godzina.
w razie jakichkolwiek pytań, proszę o komentarz.