Załączam działający kod:
/******************************************************************
Created with PROGRAMINO IDE for Arduino - 06.08.2018 15:23:03
Project : Atari ST IKBD clock injector with DS3231 RTC
Libraries : SoftwareSerial, Wire
Author : tzok
Description : ARD_RX0 from KB_5, ARD_TX1 to ST_5, ARD_D10 from/to KB/ST_6
******************************************************************/
#include <SoftwareSerial.h>
#include <Wire.h>
#define DS3231_ADDRESS (0x68)
#define DS3231_REG_TIME (0x00)
SoftwareSerial Control(10, 11);
byte cmd;
int inject = -1;
byte date[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC};
// ss, mm, hh, DD, MM, YY
byte ds3231[7];
void setup()
{
Serial.begin(7812);
Control.begin(7812);
Control.listen();
Wire.begin();
}
void loop()
{
if (Control.available())
{
cmd = Control.read();
if (cmd == 0x1C)
{
Wire.beginTransmission(DS3231_ADDRESS);
Wire.write(DS3231_REG_TIME);
Wire.endTransmission();
Wire.requestFrom(DS3231_ADDRESS, 7);
while(!Wire.available()) {};
for (int i = 6; i >= 0; i--)
{
ds3231[i] = Wire.read();
}
date[5] = ds3231[0] + 0xA0; // YY
date[4] = ds3231[1] & 0x1F; // MM
date[3] = ds3231[2]; // DD
date[2] = ds3231[4] & 0x1F; // hh
date[1] = ds3231[5]; // mm
date[0] = ds3231[6]; // ss
inject = 6;
}
else if (cmd == 0x1B)
{
for (int i = 5; i >=0; i--)
{
while(!Control.available()) {};
date[i] = Control.read();
}
ds3231[0] = date[5] - 0xA0; // YY
ds3231[1] = date[4]; // MM
ds3231[2] = date[3]; // DD
ds3231[4] = date[2]; // hh
ds3231[5] = date[1]; // mm
ds3231[6] = date[0]; // ss
Wire.beginTransmission(DS3231_ADDRESS);
Wire.write(DS3231_REG_TIME);
for (int i = 6; i >= 0; i--)
{
Wire.write(ds3231[i]);
}
Wire.write(DS3231_REG_TIME);
Wire.endTransmission();
}
}
if (Serial.available())
{
if (inject == -1)
Serial.write(Serial.read());
else
{
Serial.read();
Serial.write(date[inject--]);
}
}
}Kod działa i umożliwia zarówno "podstawianie" daty z dodatkowego, podtrzymywanego bateryjnie RTC, jak i jego ustawianie przy pomocy standardowego oprogramowania, np. CONTROL.ACC. Mankamentem rozwiązania jest wprowadzenie opóźnienie ok 1,5ms (czas transmisji 1 bajtu z prędkością 7812bps) oraz brak jakiejkolwiek obsługi błędów. Czas opóźnienia można skrócić do czasu transmisji 1 bitu, czyli ok 0,2ms. Opóźnienie dotyczy niestety nie tylko klawiatury ale również myszy i joysticków.
TOS przechowuje rok na 7 bitach, jako liczba lat po roku 1980. Zatem maksymalny rok jaki można obsłużyć to 2107. Zarówno DS3231 jak i IKBD używają formatu BCD, ale szczęśliwie TOS ma bardzo prostą formułę konwersji BCD do BIN, dzięki czemu akceptuje i poprawnie interpretuje wartości większe niż 0x99. Dla przykładu miesiąc grudzień powinien być zapisany jako 0x12, ale równie dobrze można wysłać 0x0C i też zadziała ;) Dzięki temu można przesłać np. rok 115-ty czyli 0xB5 co zostanie prawidłowo przeliczone jako rok 2015 (roku 2018 już tak nie zapiszemy, bo F to najwyższa wartość półbajtu). Na upartego ten sam rok można też zapisać jako 0xAF i też powinno zadziałać (ale nie sprawdzałem). Od tej wartości jest odejmowane 0x50 (80) i jest to przechowywane jako bajt roku w TOSie. Jak widać obliczenia nadal działają 115 - 80 = 35. Żeby odczytać rok TOS dodaje do wartości z rejestru datę początkową, tj 1980, mamy zatem 1980 + 35 = 2015.
Co jeszcze ciekawsze CONTROL.ACC domyślnie wysyła wartość 0xB8 po wpisaniu roku 18 (mimo, że oryginalny IKBD nie byłby w stanie tego obsłużyć).