友情提示:380元/半年,儿童学编程,就上码丁实验室。
我是潘,曾经是个工程师。这是 “Arduino 公开课” 系列的入门教程。前面课程介绍了 DS1302 模块,本课将介绍其 I2C 协议版的 DS1307,并利用它输出方波。有任何疑问请在评论区提出,我会逐一回答。
常见的 DS1307 模块,使用了可充电的 LIR2032 扣钮电池,保证在掉电情况下,可维持一年的时间,而且通电后,电池可以再次充满,反复利用:
主要参数:
电源电压范围:4.5V ~ 5.5V
工作温度范围:-40°C ~ 85°C
SRAM:56 bytes
时钟频率:32.768kHz
保证准确日期:2100年
这个模块还具备了24C32 32K EEPROM存储器,同样使用 I2C 协议连接。由于模块集成了SRAM 所以电路看起来很复杂,但是自己DIY的话,DS1307 芯片的外部电路十分简单,只要一个石英晶振就可以工作,为了掉电保存时间,还需要一颗扣钮电池:
SQW 对应模块的SQ,为方波输出端口,可作为Arduino 外部中断触发源。方波频率可设置为:1Hz、4.096 kHz、8.192 kHz 和 32.768 kHz,该端口必须接上拉电阻。
我们看看它的 Datasheet:
从表格看到,时间参数(秒、分、时、星期、日、月年)由前面 7 个寄存器(00H~06H)来存储,第8个(07H)则用于方波控制,剩下的则是 RAM 的信息。怎么使用这些信息呢?
记住一点很重要,寄存器中,所有信息都是 0 和 1 构成的二进制信息,我们必须将其转换为10 进制。
比如,13:24:56(13点14分56秒),小时在寄存器地址是02H。bit 7 不用,取0;bit 6 是否为12小时制,取0;如果bit6 取0 ,bit5、bit4 就是小时最左边的倍数,如果是23小时分别去 1、0,我们是13小时,分别取 0、1;bit3 ~ bit0 代表小时的个位数,13点就是 0011。对整个小时寄存器来说,13点就是00010011,其他时间单位如此类推。
要读取这些信息前面已经介绍过了,留意注释:
1
2
3
4
5
6
7
8
9
10
11
|
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS,7);//从DS1307返回7个寄存器的数据
*second =bcdToDec(Wire.read();//将二进制信息转换为十进制
*minute =bcdToDec(Wire.read();
*hour =bcdToDec(Wire.read();
*dayOfWeek =bcdToDec(Wire.read());
*dayOfMonth=bcdToDec(Wire.read());
*month =bcdToDec(Wire.read());
*year =bcdToDec(Wire.read());
|
由于DS1307 返回的数字 bcdToDec() 方法是将二进制转换成十进制。接下来,我们要为DS1307 设置时间,需要向其7个寄存器写入数据,如果要输出方波,还需要向其第8个寄存器写入数据:
1
2
3
4
5
6
7
8
9
10
11
|
Wire.beginTransmission(0×68);
Wire.write(0);
Wire.write(decToBcd(second));
Wire.write(decToBcd(minute));
Wire.write(decToBcd(hour));
Wire.write(decToBcd(dayOfWeek));
Wire.write(decToBcd(dayOfMonth));
Wire.write(decToBcd(month));
Wire.write(decToBcd(year));
Wire.write(00010000);
Wire.endTransmission();
|
另外,顺便提一下,使用库 DS1307RTC.h 可以免去数学转换和读取 I2C 信息的麻烦,但这里就不做介绍了。
现在我们要输出方波,根据DataSheet:
第8个寄存器中,bit7 设置不输出方波时,SQW引脚电平,一般设为0。bit4设置输出是否可用,设置为1,bit1 和 bit0 设置输出频率,00 为 1Hz,01 为 4.096kHz,10 为 8.192kHz,11 为 32.786kHz。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
/*
作者:Ardui.Co
效果:DS1307 输出方波
版本:1.0
更新时间:2017年4月28日
*/
#include “Wire.h”
#define DS1307_I2C_ADDRESS 0×68
voidsetup()
{
Wire.begin();
}
voidsqw1()// 输出 1Hz 方波
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0×07);// 将指针指向SQW寄存器的地址
Wire.write(0×10);// 相当于二进制 00010000
Wire.endTransmission();
}
voidsqw2()// 输出 4.096 kHz 方波
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0×07);
Wire.write(0×11);// 相当于二进制00010001
Wire.endTransmission();
}
voidsqw3()// 输出 8.192 kHz 方波
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0×07);//
Wire.write(0×12);// 相当于二进制 00010010
Wire.endTransmission();
}
voidsqw4()// 输出 32.768 kHz 方波 (晶振频率)
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0×07);//
Wire.write(0×13);// 相当于二进制 00010011
Wire.endTransmission();
}
voidsqwOff()
// 关闭方波输出
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0×07);
Wire.write(0×00);// 关闭方波输出
Wire.endTransmission();
}
voidloop()
{
sqw1();
delay(5000);
sqw2();
delay(5000);
sqw3();
delay(5000);
sqw4();
delay(5000);
sqwOff();
delay(5000);
}
|
这里有个技巧:
1
|
Wire.write(0×07);// 将指针指向SQW寄存器的地址
|
之前的课程提到,读写 I2C 设备寄存器时都要写入一个字节数据。实际上,其作用是将指针指向寄存器,“0” 是开始位置,0×07 是方波输出寄存器的位置。