[TH] ESP8266+PCF8583

บทความนี้เป็นการเขียนโปรแกรมภาษา Python ของ MicroPython เพื่อตั้งค่า/อ่านค่าวันที่และเวลาของ pcf8583 ซึ่งเป็น RTC ที่พวกเราชอบใช้ ซึ่งพวกเราพบว่ามีตัวอย่างที่เป็นภาษาไพธอนค่อนข้างน้อยจึงนำโค้ดตัวอย่างที่ทำไว้ออกมาให้ได้ลองศึกษากัน

ภาพที่ 1 บอร์ด ET-mini PCF8583

อุปกรณ์

อุปกรณ์สำหรับการทดลองในครั้งนี้ประกอบด้วย

  1. NodeMCU V2/V3
  2. ET-mini PCF8583
  3. บอร์ด ET-BASE NodeMCU

pcf8583

ไอซี PCF8583 เป็นไอซีประเภทฐานนาฬิกาเวลาจริง (RTC: Real Time Clock) ที่ทำงานกับบัส I2C สามารถกำหนดค่าตำแหน่งของตัวเองได้ (บนบอร์ด ET-mini PCF8583 มีจัมเปอร์สำหรับเลือกค่าตำแหน่งของบอร์ด) รองรับการจัดเก็บวันที่และเวลา โดยวันที่นั้นเก็บค่าปีได้ 4 ปี (เก็บค่า 0,1,2 หรือ 3) ทำให้การเขียนโปรแกรมต้องตั้งใจเอาไว้ว่าปี 0 คือปีใด ซึ่งในตัวอย่างโปรแกรมที่เขียนนั้นตั้งเอาไว้ที่ปี 2020 ซึ่งรายละเอียดของการทำงานอ่านได้จากเอกสารของ PCF8583 นอกจากนี้สามารถตั้งเวลาให้บอร์ดแจ้งเตือนในช่วงเวลาที่กำหนดได้ คุณสมบัติของ pcf8583 คือ

  1. สื่อสารผ่านบัสแบบ I2C ต้องการแรงดันไฟฟ้ากระแสตรงในช่วง 2.5 V ถึง 6 V ในการทำงาน
  2. นาฬิกาทำงานที่แรงดัน 1.0 V ถึง 6.0 V ที่อุณหภูมิในช่วง 0 °C ถึง +70 °C
  3. มีหน่วยความจำแรม (RAM) ขนาด 8 บิต จำนวน 240 ตำแหน่ง ทำให้สามารถเก็บข้อมูลขณะที่ยังมีไฟเลี้ยงได้อีก 240 ไบต์
  4. ต้องการแรงดัน 1.0 Vถึง 6.0 V ในการเก็บข้อมูล
  5. ใช้กระแสสูงสุด 50 μA
  6. นาฬิกาทำงานได้ในช่วงเวลา 4 ปี
  7. รองรับรูปแบบเวลา 24 ชม. หรือ 12 ชม.
  8. รองรับสัญญาณนาฬิกา 32.768 kHz หรือ 50 Hz
  9. ตั้งค่าการเตือน ตัวตั้งเวลา และการสร้างสัญญาณการขัดจังหวะได้ (interrupt)
  10. ค่าตำแหน่งของการอ่านเป็น 0xA1 หรือ 0xA3 และตำแหน่งของการเขียนเป็น 0xA0 หรือ 0xA2
ภาพที่ 2 การเชื่อมต่อสายจากขั้วเชื่อมต่อของบอร์ด ET-mini PCF8583

การเชื่อมต่อ

การเชื่อมต่อระหว่าง ESP8266 กับ PCF8583 เป็นดังนี้

PCF8583ESP8266
Vcc5VDC (Vin)
GNDGND
SDAD2 (GPIO4)
SCLD1 (GPIO5)
INTไม่ได้ใช้
ภาพที่ 3 การเชื่อมต่อที่บอร์ด ET-BASE NodeMCU ที่ติดตั้ง NodeMCU

ตัวอย่างโปรแกรม

ตัวอย่างโปรแกรมต่อไปนี้เป็นการสั่งเริ่มต้นให้กับการทำงานของ PCF8583 หลังจากนั้นตั้งค่าันที่ผ่านทางฟังก์ชัน adjust() และทำการอ่านค่าวันที่และเวลาจากฟังก์ชัน now() เป็นจำนวน 10ครั้ง โดยวิธีการสั่งงานสามารถอ่านได้จากเอกสารของ PCF8583

###########################################
## (C) 2021, JarutEx
## https://www.jarutex.com
## https://docs.micropython.org/en/latest/library/machine.I2C.html
###########################################
import machine as mc
import time
SCL_PIN = mc.Pin(5)
SDA_PIN = mc.Pin(4)
i2c = mc.I2C(freq=2000000, scl=SCL_PIN, sda=SDA_PIN)
devices = i2c.scan()

PCF8583_ADDR = 0xA2 >> 1
RTC_CTRL = 0x00;
RTC_SEC_100 = 0x01
RTC_SEC = 0x02
ALM_CTRL = 0x08
RTC_YEAR_MEM_ADDR = 0x20

def int2bytes(x):
    return x.to_bytes(2, 'big')

def bytes2int(x):
    return int.from_bytes(x, 'big')

def dec2bcd(n):
    return ((n // 10 * 16) + (n % 10))

def bcd2dec(n):
    return ((n // 16 * 10) + (n % 16))

RTC_BEGIN_YEAR = 2020

rtc = [0,0,0,0,0,0,0]
dayOfWeek = ["sun","mon","tue","wed","thu","fri","sat"]

def begin():
    i2c.writeto_mem(PCF8583_ADDR,RTC_CTRL, b'\x00')
    i2c.writeto_mem(PCF8583_ADDR,ALM_CTRL, b'\x00')
    beginYear = int2bytes(RTC_BEGIN_YEAR)
    i2c.writeto_mem(PCF8583_ADDR,RTC_YEAR_MEM_ADDR,
                    bytearray([beginYear[0],beginYear[1]]))    


def now():
    buffer = i2c.readfrom_mem(PCF8583_ADDR,RTC_SEC,5)
    i2c.writeto(PCF8583_ADDR,b'\x20') #RTC_YEAR_MEM_ADDR);
    year = i2c.readfrom(PCF8583_ADDR, 2)
    rtc[0] = bcd2dec(buffer[0]) # second
    rtc[1] = bcd2dec(buffer[1]) # minute
    rtc[2] = bcd2dec(buffer[2]) # hour
    rtc[3] = bcd2dec(buffer[3]&0x3f) # day
    rtc[4] = bcd2dec(buffer[4]&0x1f) # month
    rtc[5] = bytes2int(year)+(buffer[3]>>6) # year
    rtc[6] = buffer[4]>>5 # day of week
    
def show():    
    print("{}. {}/{}/{} {}:{}:{}".format(
        dayOfWeek[rtc[6]],
        rtc[3],
        rtc[4],
        rtc[5],
        rtc[2],
        rtc[1],
        rtc[0]
        ))
    
def adjust(day,month,year,dow,hour,minute,second):
    y = (year-RTC_BEGIN_YEAR)<<6
    d = dow << 5
    buffer = bytearray([0,0,0,0,0])
    buffer[0] = dec2bcd(second)
    buffer[1] = dec2bcd(minute)
    buffer[2] = dec2bcd(hour)
    buffer[3] = dec2bcd(day)+y
    buffer[4] = dec2bcd(month)+d
    i2c.writeto_mem(PCF8583_ADDR,RTC_SEC,buffer)

####################### main program ############################
if __name__=="__main__":
    if not (PCF8583_ADDR in devices):
        print("not found PCF8583!!!")
    else:
        begin()
        adjust(9,6,2021,3,13,35,0)
        cnt = 0
        while cnt<10:
            now()
            show()
            time.sleep_ms(1000)
            cnt = cnt+1

จากโค้ดโปรแกรมจะพบว่า เนื่องจาก PCF8583 เก็บปีได้เพียง 4 ปี คือ ค่า 0,1,2 หรือ 3 ดังนั้น ผู้เขียนจึงจัดเก็บค่าปีเอาไว้ในหน่วยความจำ RAM ของ PCF8583 ในตำแหน่ง 0x20 เพื่อใช้สำหรับอ่านค่าปีมาบวกกับค่า 0 ถึง 3 ด้วยเหตุนี้เพมื่อเก็บปีเริ่มต้นเป็น 2020 เมื่อรวมกับค่า 1 จึงได้ผลลัพธ์เป็น 2021 และผลของการทำงานเป็นดังภาพที่ 4

ภาพที่ 4 ผลลัพธ์ของการทำงานจากการตั้งค่าและอ่านค่าจาก ET-mini PCF8583

สรุป

จากบทความนี้หวังว่าคงเป็นประโยชน์กับผู้ใช้งานบอร์ด ET-mini PCF8583 หรือผู้ที่เลือกใช้ rtc เป็นไอซี pcf8583 บ้างไม่มากก็น้อย สุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-06-09, 2021-06-10, 2021-09-26