Real time clock (RTC) trên STM32F103C8T6

Bài viết này sẽ giúp các bạn tìm hiểu về bộ RTC trên vi điều khiển STM32F103C8T6 và thực hành lập trình làm việc với ngoại vi này. TAPIT cũng có bài viết hướng dẫn giao tiếp vi điều khiển với IC RTC DS3231, các bạn có thể tham khảo thêm tại đây

A. Lý thuyết về RTC

  • Chắc hẳn các bạn đã nghe thuật ngữ RTC ở đâu đó rồi phải không. Vậy thì RTC là gì? RTC (Real time clock) là bộ thời gian thực được cung cấp cho chúng ta thời gian giống như một chiếc đồng hồ thông thường.
  • So với các loại module hiện có trên thị trường như DS3231, DS1307… chúng ta phải dùng thêm IC để đọc được dữ liệu thời gian về ngày, tháng, năm, giờ, phút, giây và đa số các loại IC này đều sử dụng giao thức I2C để đọc/ghi dữ liệu.
  • Còn đối với chip STM32F103C8 của chúng ta, ở bên trong nó đã tích hợp sẵn một bộ thời gian thực.

Ưu và nhược điểm khi sử dụng bộ RTC trong chip STM32F103C8:

Ưu điểm: Không phải tốn chi phí cho bất kì IC RTC nào vì đã được tích hợp sẵn, tiết kiểm diện tích thiết kế mạch. 

Nhược điểm: Bộ RTC trong chip STM32F103C8 sử dụng từ Clock từ các bộ LSI, LSE, HSE. Nếu sử dụng LSI làm bộ nguồn Clock thì đây là bộ clock nội và sai số tầm khoảng 1%, vì vậy trong quá trình hoạt động thì khi chúng ta đọc thời gian sẽ bị sai lệch (có thể lưu ý khắc phục được)

Việc của chúng ta chỉ cần tìm hiểu và sử dụng chứ không cần bận tâm đến phần cứng nữa. Một số ứng dụng chính mà bộ RTC mang lại là làm đồng hồ, mạch kiểm soát thời gian, báo thức, bộ đếm…Bộ RTC này sử dụng timer độc lập, tách biệt với các bộ timer khác. Việc cài đặt thời gian, đọc thời gian cũng trở nên dễ dàng bằng cách tác động trực tiếp vào thanh ghi.

[HỌC ONLINE: LẬP TRÌNH VI ĐIỀU KHIỂN STM32, VI XỬ LÝ ARM CORTEX – M]

Nguồn clock cấp cho bộ RTC hoạt động có thể được sử dụng 1 trong 3 nguồn sau:

  • HSE : sử dụng thạch anh ngoài tốc độ cao 62.5 Khz, từ 8MHZ sẽ được chia 128 lần để ra tần số 62.5Khz
  • LSI RC: sử dụng bộ giao động RC nội tốc độ 40Khz.
  • LSE : sử dụng thạc anh ngoài tốc độ thấp 32.768khz.
Thạch anh ngoài giúp bộ MCU hoạt động ổn định hơn so với bộ giao động RC nội (sai số 1%). Khi cần Backup data khi mất nguồn trên chân VDD thì cần có 2 điều kiện là sử dụng thạch anh ngoài và có điện áp trên chân VBAT.
Các chức năng cơ bản của bộ RTC:
  • Bộ chia clock lên đến 20 bit, giúp bộ RTC hoạt động chính xác.
  • Độ phân giải của timer RTC lên đến 32 bit – tức là 2^32 giây mới tràn và cần reset lại.
  • 3 nguồn clock source có thể được sử dụng.
  • 2 loại Reset RTC riêng biệt.
  • Có các ngắt hỗ trợ là : ngắt Alarm, ngắt mỗi giây, ngắt tràn bộ đếm.

Giản đồ block khối RTC: 

Hãy cùng phân tích giản đồ này để hiểu quá trình hoạt động của RTC trước khi chúng ta đi qua một số thanh ghi quan trọng trong RTC.

Bộ RTC ở đây sẽ gồm 2 phần chính:

  • Đầu tiên, APB1 Interface được sử dụng để giao tiếp với APB1 bus. APB1 Interface giúp cho Core có thể đọc ghi dữ liệu đến các thanh ghi trong bộ RTC thông qua APB1 bus. Ngoài ra, APB1 interface sẽ được APB1 bus clock trong quá trình giao tiếp dữ liệu.
  • Tiếp theo, các khối RTC được chia làm 2 phần chính:
    • Khối đầu tiên, RTC prescaler sau khi chúng ta cấp clock cho RTC thì ở đây nó sẽ qua bộ RTC_DIV để chia tần, và chúng ta có thể lập trình tạo ra tần số lên đến 1Hz (1s).
    • Sau đó xung TR_CLK sẽ được cấp vào khối 32 bit programmable counter, giá trị trong RTC_CNT theo với tần số TR_CLK cấp vào, RTC_CNT sẽ được so sánh với giá trị định sẵn trong RTC_ALR để tạo ra ngắt đánh thức hệ thống dậy ở chế động Standby mode(chế độ tiết kiệm năng lượng)

Một số thanh ghi quan trọng trong bài hôm nay:

1. RTC_CR – RTC control register.

Thanh ghi này bao gồm 2 thanh ghi high và low với các bit như sau:
  • OWIE: cờ báo ngắt tràn khi bộ đếm vượt qua giá trị 2^32.
  • ALRIE: cờ báo ngắt Alarm – giống như báo thời gian báo thức trong đồng hồ hẹn giờ.
  • SECIE : cờ báo ngắt 1s xảy ra.
  • RTOFF: cờ báo bộ RTC có đang chạy hay không.
  • CNF: Cờ báo có đang trong quá trình cấu hình hay đã cấu hình xong.
  • RSF: cờ báo các thanh ghi đã được đồng bộ, thống nhất với nhau hay chưa.
  • OWF : cờ báo tràn khi bộ đếm vượt qua giá trị 2^32.
  • ALRF: cờ báo Alarm – giống như báo thời gian báo thức trong đồng hồ hẹn giờ.
  • SECF: cờ báo mỗi 1s xảy ra.

2. RTC_DIV – RTC prescaler divider register.

3. RTC_CNT – RTC counter register.

Thanh ghi này 32bit chứa giá trị bộ đếm của couter. Muốn biết thời gian cần đọc giá trị từ thanh ghi này về.
B/Thực hành RTC trên kit STM32F103C8

Khi sử dụng CubeMX, phần mềm này đã hỗ trợ cho chúng ta cấu hình tất cả các thanh ghi ban đầu, trong bài này chúng ta sẽ thực hiện 2 việc đọc dữ liệu thời gian và cài đặt thời gian ban đầu.

Đầu tiên, tạo project với CubeMX và cấu hình như sau:

– SYS, phần debug chúng ta sẽ chọn Serial wire để nạp dữ liệu

– UART1, chúng ta sẽ sử dụng với mục đích in dữ liệu đọc được ra phần mềm Hercules

– Ở RTC, các bạn chọn Active Clock source

– Tiếp theo, click vào tab Clock Configuration chúng ta có thể thấy hiện tại bộ RTC đang sử dụng Clock LSI RC với tần số là 40Khz

– Tiếp theo, click vào tab configuration chúng ta mở RTC lên. Ở parameter settings, chúng ta sẽ set thời gian ban đầu cho bộ RTC, ở phần Calendat Date gồm ngày tháng năm, ở phần Calendar Time bao gồm giờ phút giây, phần General liên quan đến bộ chia tần để tạo ra khoảng thời gian đếm 1s, Output là tín hiệu đầu ra tại chân TAMPER pin khi có sự kiện. Ngoài ra còn có Alarm A, đây là thiết lập để hẹn giờ báo thức của bộ RTC.

– Sau khi cấu hình xong các bạn lưu cấu hình lại và qua bên project KeilC để lập trình

– Đầu tiên, chúng ta sẽ có 3 struct để chứa dữ liệu ngày tháng năm, giờ phút giây và alarm. Tiếp theo câu lệnh đọc thanh ghi backup xem thử có phải đúng giá trị 0x32f2 hay không, nếu không đúng giá trị đó thì chúng ta sẽ thực hiện việc cấu hình thời gian ban đầu cho bộ RTC.

– Sau khi cấu hình xong chúng ta sẽ ghi giá trị 0x32f2 vào thanh ghi backup để lần sau khi có khởi động lại chip thì chương trình sẽ chạy lại từ đầu và kiểm tra thanh ghi backup để không cần phải khởi tạo lại thời gian nữa vì nó đã được khởi tạo trước đó.

– Tiếp theo mình đã khởi tạo các biến đễ lưu trữ thời gian

– Tiếp theo, để đọc dữ liệu RTC mình sử dụng 2 hàm HAL_RTC_GetTime, và HAL_RTC_GetDate. Thông số thứ nhất là địa chỉ rtc chúng ta đang sử dụng, thông số thứ 2 là địa chỉ biến truct chúng ta nhận dữ liệu và thông số thứ 3 là format dữ liệu mà chúng ta đọc.

– Để in dữ liệu, mình sử dụng UART đã được cấu hình từ sẵn và dùng hàm printf để in dữ liệu lên Hercules. Để sử dụng printf các bạn tham khảo bài viết này. Hoặc các bạn có thể sử dụng tính năng debugs theo hướng dẫn tại bài viết này

Xem thêm: Tổng hợp các bài hướng dẫn Lập trình vi điều khiển STM32 tại đây.

Chúc các bạn thành công!

Nhóm TAPIT ARM R&D