您是否想过您的计算机和智能小工具如何显示时间?这是使用RTC(实时时钟)完成的。本教程介绍了使用I2C与8051连接的DS3231 RTC。
在学习完本教程之后,您将知道如何使用I2C协议为DS3231 RTC编写嵌入式c代码。
为了显示日期和时间,我同时连接了PC和LCD。在本文中,我将解释如何使用DS3231在LCD上显示日期和时间。
DS3231 RTC硬件连接
我选择了8051微控制器作为主机,而DS3231作为从设备。
上拉电阻连接到微控制器的RTC的SDA和SCL引脚。
建议使用10K欧姆上拉电阻,以使RTC正常工作。
所述INT_RTC悬空并且可以用于产生用于外部或内部事件报警中断。
连接图
要开始使用实时时钟,需要了解DS3231的工作原理。这是对RTC进行编程所需的步骤。
对DS3231编程的步骤
#1通过设置控制寄存器来初始化RTC
void Initialize_RTC (void )<字体> < / font >
Write_To__RTC (control_Register,0x00 ); <字体> < / font >
Write_To__RTC (Status_Register,0x08 ); <字体> < / font >
当控制寄存器中的所有位都设置为零时,振荡器将运行其时钟,直到应用VBAT。
但是,日期和时间不是必需的。由于不需要温度转换来显示时间和日期,因此请设置CONV = 0。
少量 |
姓名 |
环境 |
0 |
A1IE |
0 |
1个 |
A2IE |
0 |
2个 |
情报网 |
0 |
3 |
RS1 |
0 |
4 |
RS2 |
0 |
5 |
转换 |
0 |
6 |
BBSQW |
0 |
7 |
EOSC |
0 |
#2通过设置状态寄存器初始化RTC
状态寄存器字节:
该寄存器监视计时寄存器的状态,例如日期,月份,年份,分钟,小时和秒。
要启用该寄存器,请将EN32kHz位设置为“ 1”。
少量 |
姓名 |
环境 |
0 |
A1F |
0 |
1个 |
A2F |
0 |
2个 |
BSY |
0 |
3 |
EN32kHz的 |
1个 |
4 |
0 |
0 |
5 |
0 |
0 |
6 |
0 |
0 |
7 |
OSF |
0 |
#3使用计时寄存器设置日期和时间
DS3231中的RTC寄存器
RTC地址 |
0x68 |
读取地址 |
D1 |
写地址 |
D0 |
日期 |
0x04 |
月 |
0x05 |
年 |
0x06 |
第二 |
0x00 |
分钟 |
0x01 |
小时 |
0x02 |
现在,您可以使用setTime和setDate函数设置日期和时间参数。
RTC有设定0x60的,0x40的启用小时的格式和AM / PM。
void setTime (unsigned char sethour,unsigned char setminute,unsigned char setsecond,short am_pm,short hour_twelve_twentyfour )<字体> < / font >
无符号char temp = 0 ; <字体> < / font >
Write_To__RTC (秒,Convert_DECIMAL_BCD (setsecond )); <字体> < / font >
Write_To__RTC (分钟,Convert_DECIMAL_BCD (setminute )); <字体> < / font >
开关(hour_twelve_twentyfour )<字体> < / font >
开关(am_pm )<字体> < / font >
temp = 0x60 ; <字体> < / font >
temp = 0x40 ; <字体> < / font >
Write_To__RTC (小时,(((temp | (0x1F &(Convert_DECIMAL_BCD (sethour )))))); <字体> < / font >
Write_To__RTC (小时,(0x3F &(Convert_DECIMAL_BCD (sethour )))); <字体> < / font >
要设置日期,日期和月份,请使用04、05、06地址。时间和日历寄存器以BCD格式预定义。因此,我们必须将Decimal格式转换为BCD表示法以将数据写入RTC。
void setDate (unsigned char setday,unsigned char setdate,unsigned char setmonth,unsigned char setyear )<字体> < / font >
Write_To__RTC (天,(Convert_DECIMAL_BCD (设置日期))); <字体> < / font >
Write_To__RTC (日期,(Convert_DECIMAL_BCD (setdate ))); <字体> < / font >
Write_To__RTC (月,(Convert_DECIMAL_BCD (setmonth ))); <字体> < / font >
Write_To__RTC (年,(Convert_DECIMAL_BCD (setyear ))); <字体> < / font >
写入数据后,我们可以使用以下功能读取计时寄存器。
#4读取日期和时间
RTC中的日历寄存器和计时寄存器为BCD格式。因此,要读取RTC日期和时间,请将BCD格式转换为十进制表示法。
void Readtime (void )<字体> < / font >
无符号char temp = 0 ,hour_twelve_twentyfour,t; <字体> < / font >
RTCsec = Read_From_RTC (秒); <字体> < / font >
RTCsec = Convert_BCD_DECIMAL (RTCsec ); <字体> < / font >
RTCmin = Read_From_RTC (分钟); <字体> < / font >
RTCmin = Convert_BCD_DECIMAL (RTCmin ); <字体> < / font >
hour_twelve_twentyfour = 0 ; //输入24小时<font> </ font>
开关(hour_twelve_twentyfour )<字体> < / font >
temp = Read_From_RTC (小时); <字体> < / font >
temp&= 0x20 ; <字体> < / font >
t = (短)(temp >> 5 ); <字体> < / font >
RTC_hour = (0x1F &Read_From_RTC (小时)); <字体> < / font >
RTC_hour = Convert_BCD_DECIMAL (RTC_hour ); <字体> < / font >
RTC_hour = (0x3F &Read_From_RTC (小时)); <字体> < / font >
RTC_hour = Convert_BCD_DECIMAL (RTC_hour ); <字体> < / font >
void ReadDate (void )<字体> < / font >
RTCyear = Read_From_RTC (年); <字体> < / font >
RTCyear = Convert_BCD_DECIMAL (RTCyear ); <字体> < / font >
RTCmonth = (0x1F &Read_From_RTC (month )); <字体> < / font >
RTCmonth = Convert_BCD_DECIMAL (RTCmonth ); <字体> < / font >
RTCdate = (0x3F &Read_From_RTC (date )); <字体> < / font >
RTCdate = Convert_BCD_DECIMAL (RTCdate ); <字体> < / font >
RTCday = (0x07 &Read_From_RTC (天)); <字体> < / font >
RTCday = Convert_BCD_DECIMAL (RTCday ); <字体> < / font >
RTC DS3231的LCD功能
如果使用LCD显示日期和时间,则可能会遇到困难。因为RTC的时间和日期格式为整数格式。问题是LCD仅显示ASCII字符。因此,我为LCD的ASCII函数写了一个整数。
将整数转换为ASCII格式的函数
-
提取整数。
-
添加0x30以转换为ASCII。
-
将ASCII字符存储在数组中。
-
将整数除以直到零。
-
反转数组以转换为原始形式。
void Show_Integer_Ascii (unsigned char lineno,unsigned char cursor_position,unsigned long value )<字体> < / font >
无符号字符a [ 11 ] ,b [ 11 ] ,i,m,n; <字体> < / font >
if (value == 0 && cursor_position == 4 )<字体> < / font >
否则if (value == 0 )<字体> < / font >
b [ 0 ] = '0' ; <字体> < / font >
b [ 1 ] = '\ 0' ; <字体> < / font >
loop1:for (i = 0 ; i < 11 ; i ++ )<字体> < / font >
a [ i ] = (值%10 )+ 0x30 ; <字体> < / font >
价值=价值/ 10 ; <字体> < / font >
if (value == 0 )<字体> < / font >
a [ i + 1 ] = '\ 0' ; <字体> < / font >
为(M = 1; M > = 0 ; M-- ){<字体> < / FONT >
b [ n ] = a [ m ] ;<字体> < / font >
如果(m == 0 )<字体> < / font >
b [ n ] = '\ 0' ; <字体> < / font >
循环:if (lineno == 1 )<字体> < / font >
Disp_Data (lineno,cursor_position,b ); <字体> < / font >
if (lineno == 2 )<字体> < / font >
Disp_Data (lineno,cursor_position,b ); <字体> < / font >
memset (b,0 ,sizeof (b )); <字体> < / font >
在液晶显示屏上显示日期
void Display_Date_LCD (void )<字体> < / font >
ReadDate (); <字体> < / font >
Disp_Data (1 ,7 ,“/” ); <字体> < / font >
if (RTCdate > = 0 && RTCdate < = 9 )<字体> < / font >
Disp_Data (1 ,5 ,“0” ); <字体> < / font >
Show_Integer_Ascii (1 ,6 ,RTCdate ); <字体> < / font >
Show_Integer_Ascii (1 ,5 ,RTCdate ); <字体> < / font >
Disp_Data (1 ,10 ,“/” ); <字体> < / font >
if (RTCmonth > = 0 && RTCmonth < = 9 )<字体> < / font >
Disp_Data (1 ,8 ,“0” ); <字体> < / font >
Show_Integer_Ascii (1 ,9 ,RTCmonth ); <字体> < / font >
Show_Integer_Ascii (1 ,8 ,RTCmonth ); <字体> < / font >
if (RTCyear > = 0 && RTCyear < = 9 )<字体> < / font >
Disp_Data (1 ,11 ,“0” ); <字体> < / font >
Show_Integer_Ascii (1 ,12 ,RTCyear ); <字体> < / font >
Show_Integer_Ascii (1 ,11 ,RTCyear ); <字体> < / font >
在LCD上显示时间
void Readtime (void )<字体> < / font >
无符号char temp = 0 ,hour_twelve_twentyfour,t; <字体> < / font >
RTCsec = Read_From_RTC (秒); <字体> < / font >
RTCsec = Convert_BCD_DECIMAL (RTCsec ); <字体> < / font >
RTCmin = Read_From_RTC (分钟); <字体> < / font >
RTCmin = Convert_BCD_DECIMAL (RTCmin ); <字体> < / font >
hour_twelve_twentyfour = 0 ; //输入24小时<font> </ font>
开关(hour_twelve_twentyfour )<字体> < / font >
temp = Read_From_RTC (小时); <字体> < / font >
temp&= 0x20 ; <字体> < / font >
t = (短)(temp >> 5 ); <字体> < / font >
RTC_hour = (0x1F &Read_From_RTC (小时)); <字体> < / font >
RTC_hour = Convert_BCD_DECIMAL (RTC_hour ); <字体> < / font >
RTC_hour = (0x3F &Read_From_RTC (小时)); <字体> < / font >
RTC_hour = Convert_BCD_DECIMAL (RTC_hour ); <字体> < / font >
RTC DS3231的C代码
这是读取RTC日期和时间的完整C代码。我已经使用8051微控制器的两个引脚通过I2C与实时时钟进行通信。
#include <reg51.h> <font> </ font>
#include“ header.h” <font> </ font>
void main ()<字体> < / font >
lcd_init (); <字体> < / font >
lcd_delay (2 ); <字体> < / font >
Disp_Data (1 ,0 ,“DS3231接口” ); <字体> < / font >
Disp_Data (2 ,0 ,“通过Codrey.com” ); <字体> < / font >
lcd_delay (10 ); <字体> < / font >
Disp_Data (1 ,0 ,“” ); <字体> < / font >
Disp_Data (2 ,0 ,“” ); <字体> < / font >
Initialize_RTC (); / *初始化RTC DS3231 * / <字体> < / font >
lcd_delay (2 ); <字体> < / font >
时刻设定(10 ,20 ,25 ,0 ,0 ); / *设置小时,分钟,秒* / <字体> < / font >
的setDate (2 ,16 ,05 ,18 ); / *设置日期,日期,月份,年份* / <字体> < /字体>
/ *无限WHILE循环,用于读取RTC的日期和时间* / <字体> < / font >
Disp_Data (1 ,0 ,“DATE” ); <字体> < / font >
Disp_Data (2 ,0 ,“TIME” ); <字体> < / font >
ReadDate (); //获取日,月和年<font> </ font>
Display_Date_LCD (); <字体> < / font >
ReadTime (); / *从DS3231获取时间* / <字体> < / font >
Display_Time_LCD (); <字体> < / font >
RTC的I2c功能
以下是使用I2c与RTC进行通信的步骤。
-
使用开始条件开始I2C通信。
-
写入RTC地址。
-
阅读确认。
-
写寄存器写地址。
-
从RTC读取数据。
-
阅读确认书
-
不写任何确认。
-
停止i2c通信。
void Start_I2C (void )<字体> < / font >
SCL_DISABLE; <字体> < / font >
SDA_ENABLE; <字体> < / font >
SCL_ENABLE; <字体> < / font >
SDA_DISABLE; <字体> < / font >
void Slave_Write (unsigned char byte )<字体> < / font >
无符号字符j,k; <字体> < / font >
对于(j = 0 ; j < 8 ; j ++ )<字体> < / font >
SCL_DISABLE; <字体> < / font >
SDA = (k&(0x80 >> j ))?1 :0 ; / *写bit_by_bit * / <字体> < / font >
SCL_ENABLE; <字体> < / font >
void Read_Ack (void )<字体> < / font >
SCL_DISABLE; <字体> < / font >
SDA_ENABLE; <字体> < / font >
SCL_ENABLE; <字体> < / font >
void Read_Ack (void )<字体> < / font >
SCL_DISABLE; <字体> < / font >
SDA_ENABLE; <字体> < / font >
SCL_ENABLE; <字体> < / font >
void No_Acknowledgement (void )<字体> < / font >
SCL_DISABLE; <字体> < / font >
SDA_ENABLE; <字体> < / font >
SCL_ENABLE; <字体> < / font >
unsigned char Read_I2C_Data (void )<字体> < / font >
无符号字符m,data_byte = 0 ; <字体> < / font >
对于(m = 0 ; m < 8 ; m ++ )<字体> < / font >
SCL_DISABLE; <字体> < / font >
SCL_ENABLE; <字体> < / font >
data_byte | = 0x80 >> m; <字体> < / font >
返回data_byte; <字体> < / font >
unsigned char Read_From_RTC (unsigned char地址)< font > < / font >
无符号char val = 0 ; <字体> < / font >
Start_I2C (); <字体> < / font >
Slave_Write (DS3231_Write ); <字体> < / font >
Read_Ack (); <字体> < / font >
Slave_Write (地址); <字体> < / font >
Read_Ack (); <字体> < / font >
Start_I2C (); <字体> < / font >
Slave_Write (DS3231_Read ); <字体> < / font >
Read_Ack (); <字体> < / font >
val = Read_I2C_Data (); <字体> < / font >
No_Acknowledgement (); <字体> < / font >
Stop_I2C (); <字体> < / font >
void Write_To__RTC (unsigned char regaddress,unsigned char val )<字体> < / font >
unsigned char loop_time; <字体> < / font >
Start_I2C (); <字体> < / font >
Slave_Write (DS3231_Write ); <字体> < / font >
Read_Ack (); <字体> < / font >
Slave_Write (regaddress ); <字体> < / font >
Read_Ack (); <字体> < / font >
Slave_Write (val ); <字体> < / font >
Read_Ack (); <字体> < / font >
Stop_I2C (); <字体> < / font >
for (loop_time = 0 ; loop_time < 255 ; loop_time ++ ); <字体> < / font >
for (loop_time = 0 ; loop_time < 255 ; loop_time ++ ); <字体> < / font >
变形模拟
DS3231的应用
-
用于GPS中以获取日期,时间,纬度,经度,位置,高度
-
用于服务器中以实现网络定时协议
-
在智能功率计中用于跟踪当前账单的日期和时间。
-
用于电信和网络应用。
最后的想法
RTC DS3231精确地保持低漂移的精确时间。这使其非常适合计时应用。
DS3231高度准确,可以管理日期,时间,年,月,日和秒。
此外,RTC具有±2ppm的精度,适合实时功能。
希望您了解如何使用I2C将DS3231 RTC与8051连接。由于8051没有内部i2c,因此我使用位冲击方法来生成时钟和数据以进行串行通信。
整个代码已经通过8051微控制器进行了测试,并且可以在任何稍作改动的情况下与任何微控制器一起使用。