จากบทความการเขียนโปรแกรมภาษาไพธอนบน Micropython เพื่อใช้งาน RTC เบอร์ DS1302 ในคราวนี้เปลี่ยนภาษาการเขียนโปรแกรมเป็น C++ สำหรับ Arduino โดยใช้ไมโครคอนโทรลเลอร์ Cortex-M0 เบอร์ STM32F030F4P6 / esp8266 และ Arduino Mega เป็นตัวทำงานแทน ESP32 ดังภาพที่ 1, 2 และ 6 โดยรายงานการทำงานออกทางพอร์ต RS232 เพื่อแสดงวันและเวลาตามตัวอย่างผลลัพธ์ในภาพที่ 4
โปรแกรม
โค้ดโปรแกรมสำหรับการอ่านและเขียนวันที่/เวลากับโมดูล RTC ของไอซี ds1302 เป็นดังนี้ โดยเชื่อมต่อกับไมโครคอนโทรลเลอร์ผ่านทางขา PA2, PA3 และ PA4 เข้ากับขา SCLK, IO และ CE ตามลำดับ ดังภาพที่ 3
// ds1302
// (C) 2021, by JarutEx (https://ww.jarutex.com)
#include <miniSerial.h>
#define PIN_CE PA4
#define PIN_SCLK PA2
#define PIN_IO PA3
#define REG_SECOND 0x80
#define REG_MINUTE 0x82
#define REG_HOUR 0x84
#define REG_DAY 0x86
#define REG_MONTH 0x88
#define REG_WEEKDAY 0x8A
#define REG_YEAR 0x8C
#define REG_WP 0x8E
#define REG_CTRL 0x90
#define REG_RAM 0xC0
uint8_t rtc[] = {0, 0, 0, 0, 0, 0, 0}; // y/m/d/dw/h/mi/s
inline void disCe() {
digitalWrite( PIN_CE, LOW );
}
inline void enaCe() {
digitalWrite( PIN_CE, HIGH );
}
inline void pulse() {
digitalWrite( PIN_SCLK, HIGH );
digitalWrite( PIN_SCLK, LOW );
}
uint8_t dec2bcd(uint8_t n) {
return ((int)(n / 10) * 16 + (n % 10));
}
uint8_t bcd2dec( uint8_t n ) {
return ((int)(n / 16 * 10) + (n % 16));
}
void write( uint8_t data ) {
uint8_t dataBit;
pinMode( PIN_IO, OUTPUT );
for (int i = 0; i < 8; i++) {
dataBit = (data & 0x01);
data >>= 1;
digitalWrite( PIN_IO, dataBit );
pulse();
}
}
uint8_t read() {
uint8_t byteData = 0x00;
uint8_t bitData;
pinMode( PIN_IO, INPUT );
for (int i = 0; i < 8; i++) {
bitData = digitalRead( PIN_IO ) & 0x01;
bitData <<= i;
byteData |= bitData;
pulse();
}
return byteData;
}
void set(uint8_t reg, uint8_t value) {
enaCe();
write(reg);
write(value);
disCe();
}
uint8_t get(uint8_t reg) {
uint8_t value = 0;
enaCe();
write(reg + 1);
value = read();
disCe();
return value;
}
void now() {
rtc[0] = bcd2dec( get(REG_YEAR) );
rtc[1] = bcd2dec( get(REG_MONTH) );
rtc[2] = bcd2dec( get(REG_DAY) );
rtc[3] = bcd2dec( get(REG_WEEKDAY) );
rtc[4] = bcd2dec( get(REG_HOUR) );
rtc[5] = bcd2dec( get(REG_MINUTE) );
rtc[6] = bcd2dec( get(REG_SECOND) );
}
void adjust(uint8_t day, uint8_t month, uint16_t year,
uint8_t dow, uint8_t hour, uint8_t minute, uint8_t second) {
// convert
year -= 2000;
year &= 0xff;
year = dec2bcd((uint8_t)year);
month = dec2bcd(month);
day = dec2bcd(day);
dow = dec2bcd(dow);
minute = dec2bcd(minute);
hour = hour & 0x1F;
hour = dec2bcd(hour);
second = dec2bcd(second);
// adjust
set(REG_YEAR, year);
set(REG_MONTH, month);
set(REG_DAY, day);
set(REG_WEEKDAY, dow);
set(REG_HOUR, hour);
set(REG_MINUTE, minute);
set(REG_SECOND, second);
}
void show() {
Serial.print( rtc[3] );
Serial.print(" ");
Serial.print( rtc[0]+2000 );
Serial.print("-");
Serial.print( rtc[1] );
Serial.print("-");
Serial.print( rtc[2] );
Serial.print(" ");
Serial.print( rtc[4] );
Serial.print(":");
Serial.print( rtc[5] );
Serial.print(":");
Serial.print( rtc[6] );
Serial.println("");
}
void setup(void)
{
Serial.begin(9600);
// Serial.begin(19200, PA2, PA3);
// Setting
pinMode( PIN_IO, OUTPUT );
pinMode( PIN_SCLK, OUTPUT );
pinMode( PIN_CE, OUTPUT );
disCe();
digitalWrite( PIN_SCLK, LOW );
adjust( 8, 7, 2021, 4, 13, 53, 0);
}
void loop()
{
Serial.run();
now();
show();
delay(1000);
}
ผลการทำงานเป็นดังภาพที่ 4
ตัวอย่างสำหรับ esp8266
กรณีที่ใช้กับ esp8266 ทางทีมงานเราเลือกขาหมายเลข D1, D2 และ D4 หรือ GPIO5, GPIO4 และ GPIO2 เชื่อมต่อกับขา SCLK, IO และ CE เพื่อใช้งาน DS1302 ซึ่งโค้ดโปรแกรมเป็นดังนี้
// ds1302/esp8266
// (C) 2021, by JarutEx (https://ww.jarutex.com)
#define PIN_CE 2 // D4
#define PIN_SCLK 5 // D1
#define PIN_IO 4 // D2
#define REG_SECOND 0x80
#define REG_MINUTE 0x82
#define REG_HOUR 0x84
#define REG_DAY 0x86
#define REG_MONTH 0x88
#define REG_WEEKDAY 0x8A
#define REG_YEAR 0x8C
#define REG_WP 0x8E
#define REG_CTRL 0x90
#define REG_RAM 0xC0
uint8_t rtc[] = {0, 0, 0, 0, 0, 0, 0}; // y/m/d/dw/h/mi/s
inline void disCe() {
digitalWrite( PIN_CE, LOW );
}
inline void enaCe() {
digitalWrite( PIN_CE, HIGH );
}
inline void pulse() {
digitalWrite( PIN_SCLK, HIGH );
digitalWrite( PIN_SCLK, LOW );
}
uint8_t dec2bcd(uint8_t n) {
return ((int)(n / 10) * 16 + (n % 10));
}
uint8_t bcd2dec( uint8_t n ) {
return ((int)(n / 16 * 10) + (n % 16));
}
void write( uint8_t data ) {
uint8_t dataBit;
pinMode( PIN_IO, OUTPUT );
for (int i = 0; i < 8; i++) {
dataBit = (data & 0x01);
data >>= 1;
digitalWrite( PIN_IO, dataBit );
pulse();
}
}
uint8_t read() {
uint8_t byteData = 0x00;
uint8_t bitData;
pinMode( PIN_IO, INPUT );
for (int i = 0; i < 8; i++) {
bitData = digitalRead( PIN_IO ) & 0x01;
bitData <<= i;
byteData |= bitData;
pulse();
}
return byteData;
}
void set(uint8_t reg, uint8_t value) {
enaCe();
write(reg);
write(value);
disCe();
}
uint8_t get(uint8_t reg) {
uint8_t value = 0;
enaCe();
write(reg + 1);
value = read();
disCe();
return value;
}
void now() {
rtc[0] = bcd2dec( get(REG_YEAR) );
rtc[1] = bcd2dec( get(REG_MONTH) );
rtc[2] = bcd2dec( get(REG_DAY) );
rtc[3] = bcd2dec( get(REG_WEEKDAY) );
rtc[4] = bcd2dec( get(REG_HOUR) );
rtc[5] = bcd2dec( get(REG_MINUTE) );
rtc[6] = bcd2dec( get(REG_SECOND) );
}
void adjust(uint8_t day, uint8_t month, uint16_t year,
uint8_t dow, uint8_t hour, uint8_t minute, uint8_t second) {
// convert
year -= 2000;
year &= 0xff;
year = dec2bcd((uint8_t)year);
month = dec2bcd(month);
day = dec2bcd(day);
dow = dec2bcd(dow);
minute = dec2bcd(minute);
hour = hour & 0x1F;
hour = dec2bcd(hour);
second = dec2bcd(second);
// adjust
set(REG_YEAR, year);
set(REG_MONTH, month);
set(REG_DAY, day);
set(REG_WEEKDAY, dow);
set(REG_HOUR, hour);
set(REG_MINUTE, minute);
set(REG_SECOND, second);
}
void show() {
Serial.print( rtc[3] );
Serial.print(" ");
Serial.print( rtc[0]+2000 );
Serial.print("-");
Serial.print( rtc[1] );
Serial.print("-");
Serial.print( rtc[2] );
Serial.print(" ");
Serial.print( rtc[4] );
Serial.print(":");
Serial.print( rtc[5] );
Serial.print(":");
Serial.print( rtc[6] );
Serial.println("");
}
void setup(void)
{
Serial.begin(9600);
pinMode( PIN_IO, OUTPUT );
pinMode( PIN_SCLK, OUTPUT );
pinMode( PIN_CE, OUTPUT );
disCe();
digitalWrite( PIN_SCLK, LOW );
adjust( 8, 7, 2021, 4, 13, 53, 0);
}
void loop()
{
now();
show();
delay(1000);
}
โดยตั้งค่าของ Arduino IDE ดังภาพที่ 5
ตัวอย่างสำหรับ Arduino Mega
เมื่อลองเปลี่ยนค่าของขาสำหรับ SCLK, IO และ CE เป็น D2, D3 และ D4 ของบอร์ด Arduino Mega ดังภาพที่ 6 และตั้งค่าตามภาพที่ 7 จะได้โค้ดของโปรแกรมเป็นดังนี้
// ds1302/Arduino Mega
// (C) 2021, by JarutEx (https://ww.jarutex.com)
#define PIN_CE 4
#define PIN_SCLK 2
#define PIN_IO 3
#define REG_SECOND 0x80
#define REG_MINUTE 0x82
#define REG_HOUR 0x84
#define REG_DAY 0x86
#define REG_MONTH 0x88
#define REG_WEEKDAY 0x8A
#define REG_YEAR 0x8C
#define REG_WP 0x8E
#define REG_CTRL 0x90
#define REG_RAM 0xC0
uint8_t rtc[] = {0, 0, 0, 0, 0, 0, 0}; // y/m/d/dw/h/mi/s
inline void disCe() {
digitalWrite( PIN_CE, LOW );
}
inline void enaCe() {
digitalWrite( PIN_CE, HIGH );
}
inline void pulse() {
digitalWrite( PIN_SCLK, HIGH );
digitalWrite( PIN_SCLK, LOW );
}
uint8_t dec2bcd(uint8_t n) {
return ((int)(n / 10) * 16 + (n % 10));
}
uint8_t bcd2dec( uint8_t n ) {
return ((int)(n / 16 * 10) + (n % 16));
}
void write( uint8_t data ) {
uint8_t dataBit;
pinMode( PIN_IO, OUTPUT );
for (int i = 0; i < 8; i++) {
dataBit = (data & 0x01);
data >>= 1;
digitalWrite( PIN_IO, dataBit );
pulse();
}
}
uint8_t read() {
uint8_t byteData = 0x00;
uint8_t bitData;
pinMode( PIN_IO, INPUT );
for (int i = 0; i < 8; i++) {
bitData = digitalRead( PIN_IO ) & 0x01;
bitData <<= i;
byteData |= bitData;
pulse();
}
return byteData;
}
void set(uint8_t reg, uint8_t value) {
enaCe();
write(reg);
write(value);
disCe();
}
uint8_t get(uint8_t reg) {
uint8_t value = 0;
enaCe();
write(reg + 1);
value = read();
disCe();
return value;
}
void now() {
rtc[0] = bcd2dec( get(REG_YEAR) );
rtc[1] = bcd2dec( get(REG_MONTH) );
rtc[2] = bcd2dec( get(REG_DAY) );
rtc[3] = bcd2dec( get(REG_WEEKDAY) );
rtc[4] = bcd2dec( get(REG_HOUR) );
rtc[5] = bcd2dec( get(REG_MINUTE) );
rtc[6] = bcd2dec( get(REG_SECOND) );
}
void adjust(uint8_t day, uint8_t month, uint16_t year,
uint8_t dow, uint8_t hour, uint8_t minute, uint8_t second) {
// convert
year -= 2000;
year &= 0xff;
year = dec2bcd((uint8_t)year);
month = dec2bcd(month);
day = dec2bcd(day);
dow = dec2bcd(dow);
minute = dec2bcd(minute);
hour = hour & 0x1F;
hour = dec2bcd(hour);
second = dec2bcd(second);
// adjust
set(REG_YEAR, year);
set(REG_MONTH, month);
set(REG_DAY, day);
set(REG_WEEKDAY, dow);
set(REG_HOUR, hour);
set(REG_MINUTE, minute);
set(REG_SECOND, second);
}
void show() {
Serial.print( rtc[3] );
Serial.print(" ");
Serial.print( rtc[0]+2000 );
Serial.print("-");
Serial.print( rtc[1] );
Serial.print("-");
Serial.print( rtc[2] );
Serial.print(" ");
Serial.print( rtc[4] );
Serial.print(":");
Serial.print( rtc[5] );
Serial.print(":");
Serial.print( rtc[6] );
Serial.println("");
}
void setup(void)
{
Serial.begin(9600);
pinMode( PIN_IO, OUTPUT );
pinMode( PIN_SCLK, OUTPUT );
pinMode( PIN_CE, OUTPUT );
disCe();
digitalWrite( PIN_SCLK, LOW );
adjust( 8, 7, 2021, 4, 13, 53, 0);
}
void loop()
{
now();
show();
delay(1000);
}
สรุป
จากบทความนี้จะพบว่าเมื่อเข้าใจหลักของการทำงาน และสามารถเขียนด้วยภาษาใดภาษาหนึ่งได้ การแปลงโค้ดโปรแกรมข้ามภาษาเป็นสิ่งที่กระทำได้ไม่ยุ่งยากนัก และเป็นการฝึกปรือการเขียนโค้ดที่ดี นอกจากนี้จะพบว่า การย้ายโค้ดเพื่อใช้กับไมโครคอนโทรลเลอร์ที่แตกต่างกันด้วยการใช้เฟรมเวิร์ก Arduino นั้นจะต้องระวังเรื่องของสถาปัตยกรรมและหมายเลขขาให้ดีก่อนการเขียนโปรแกรม สุดท้าย พวกเราหวังว่าตัวอย่างโปรแกรมการใช้งานโมูล RTC ของไอซี DS1302 คงเป็นประโยชน์บ้างไม่มากก็น้อย และขอให้สนุกกับการเขียนโปรแกรมครับ
ท่านใดอยากพูดคุยสามารถคอมเมนท์ไว้ได้เลยครับ
(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-07-08, 2021-07-09, 2021-10-18