标题:
DS3231温度读取实验 附单片机源程序
[打印本页]
作者:
凌净清河
时间:
2019-2-12 17:21
标题:
DS3231温度读取实验 附单片机源程序
本帖最后由 凌净清河 于 2019-2-13 19:46 编辑
DS3231作为一个走时精准的RTC芯片,内部带有温度补偿电路,此例将读取其中11H和12H寄存器,提取测得的温度值并传送到串口输出。
类似程序网上非常之多,不再赘述,在此重新提说几处需要注意的地方。
1.根据DS3231的芯片手册,其温度传感器的精度为±3℃,毕竟不是专用的温度传感器,在使用中可以作为一个参考,且仅此而已。
2.根据DS3231的芯片手册,其温度分辨率为±0.25℃,所以其小数部分读出的值只能是.00、.25、.50、.75这四种,如果读出的值不是这四种,则数据处理有误。
3.本实验使用一个float型数据直接接收了转换的温度值,没有对补码的符号位进行判断等。
注明:本程序没有使用CONV位进行强制转换,但是实际上温度值的刷新速度还是很令人满意(用手按住芯片,温度值更改速度很快,下面的测试图片是恒温下检测的,故无变化)。
测试程序:
#include<STC15.H>
#include"stdio.h"
#include<intrins.h>
//位定义
sbit DS3231_SDA=P3^3;
sbit DS3231_SCL=P3^2;
//运行数组
unsigned char DS3231_Time_Buffer[7]={0x00,0x48,0x11,0x02,0x12,0x02,0x19};
unsigned char temp[2]={0,0};
char buf[20]={0};
//运行标志位
bit busy=0;
//运行变量
float v;
/*##############################################################################
编写/测试:凌净清河
日期:2019年2月12日
测试平台:IAP15W4K58S4
鸣谢:DS3231部分驱动函数借用了51黑论坛上某位的程序,但是时间太久忘记是谁的了。
并未修改原作者的写法,如果原作者认出,鄙人在此表示感谢,或可联系我提名。
##############################################################################*/
/*###################以下为给DS3231定义的IIC通信函数################*/
void DS3231_Delay()//使用空操作进行短暂的延时
{
_nop_();
_nop_();
_nop_();
_nop_();
}
void DS3231_IIC_Start()//IIC总线的开始信号
{
DS3231_SCL=1;
DS3231_SDA=1;
DS3231_Delay();
DS3231_SDA=0;
DS3231_Delay();
DS3231_SCL=0;
}
void DS3231_IIC_Stop()//IIC总线的停止信号
{
DS3231_SCL=0;
DS3231_SDA=0;
DS3231_Delay();
DS3231_SCL=1;
DS3231_Delay();
DS3231_SDA=1;
DS3231_Delay();
}
bit DS3231_IIC_Send_Byte(unsigned char dat)//写操作
{
unsigned char mask;//定义一个掩码用于进行按位发送数据的操作
bit ack;
for(mask=0x80;mask!=0;mask>>=1)
{
if((mask&dat)==0)
DS3231_SDA=0;
else
DS3231_SDA=1;
DS3231_Delay();
DS3231_SCL=1;
DS3231_Delay();
DS3231_SCL=0;
}
DS3231_SDA=1;
DS3231_Delay();
DS3231_SCL=1;
ack=DS3231_SDA;
DS3231_Delay();
DS3231_SCL=0;
return (~ack);
}
unsigned char DS3231_IIC_Read_Byte_NAK()//读操作+非应答
{
unsigned char mask;//定义一个用于累加的位存储临时变量
unsigned char dat;
DS3231_SDA=1;
for(mask=0x80;mask!=0;mask>>=1)
{
DS3231_Delay();
DS3231_SCL=1;
if(DS3231_SDA==0)
dat&=~mask;
else
dat|=mask;
DS3231_Delay();
DS3231_SCL=0;
}
DS3231_SDA=1;
DS3231_Delay();
DS3231_SCL=1;
DS3231_Delay();
DS3231_SCL=0;
return dat;
}
unsigned char DS3231_IIC_Read_Byte_ACK()//读操作+应答
{
unsigned char mask;//定义一个用于累加的位存储临时变量
unsigned char dat;
DS3231_SDA=1;
for(mask=0x80;mask!=0;mask>>=1)
{
DS3231_Delay();
DS3231_SCL=1;
if(DS3231_SDA==0)
dat&=~mask;
else
dat|=mask;
DS3231_Delay();
DS3231_SCL=0;
}
DS3231_SDA=0;
DS3231_Delay();
DS3231_SCL=1;
DS3231_Delay();
DS3231_SCL=0;
return dat;
}
/*#################以下为给DS3231封装的寄存器通信函数###############*/
void DS3231_Read_Registers(unsigned char *buf,unsigned char addr,unsigned char len)//读EEPROM中多个字节
{
do{
DS3231_IIC_Start();
if(DS3231_IIC_Send_Byte(0xD0))
{
break;
}
DS3231_IIC_Stop();
}while(1);
DS3231_IIC_Send_Byte(addr);
DS3231_IIC_Start();
DS3231_IIC_Send_Byte((0xD0)|0x01);//寻址,读操作
while(len>1)
{
*buf++=DS3231_IIC_Read_Byte_ACK();
len--;
}
*buf=DS3231_IIC_Read_Byte_NAK();//读一个字节
DS3231_IIC_Stop();
}
void DS3231_Write_Registers(unsigned char *buf,unsigned char addr,unsigned char len)//写寄存器,传入待写入数组
{
while(len>0)
{
do{
DS3231_IIC_Start();
if(DS3231_IIC_Send_Byte(0xD0))
{
break;
}
DS3231_IIC_Stop();
}while(1);
DS3231_IIC_Send_Byte(addr);
while(len>0)
{
DS3231_IIC_Send_Byte(*buf++);
len--;
addr++;
if((addr&0x07)==0)
{
break;
}
}
DS3231_IIC_Stop();
}
}
void SendData(unsigned char dat)//串口1发送一个字节数据
{
while(busy);
busy=1;
SBUF=dat;
}
void SendString(char *p)//串口发送一个字符串
{
while(*p!='\0')
{
SendData(*p);
p++;
}
}
void UartInit(void) //9600bps@11.0592MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设定定时器1为16位自动重装方式
TL1 = 0xE0; //设定定时初值
TH1 = 0xFE; //设定定时初值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
void delay(unsigned long int i)//延时函数
{
while(i--);
}
void main()
{
P3M1=0x00;
P3M0=0x00;//IO初始化,这个准双向的初始化操作是为STC15W4K32S4系列单片机特别准备的
UartInit();//串口初始化
EA=1;//开总中断
ES=1;//开串口中断
DS3231_Write_Registers(DS3231_Time_Buffer,0x00,7);//向器件写入有效的IIC地址,以保证驱动振荡器起振,防止读出初始值0℃
while(1)
{
DS3231_Read_Registers(temp,0x11,2);
v=temp[0]*1.0+(temp[1]>>6)*0.25;//按照数据格式,将寄存器中的值放入一个有符号的float型数据,就不必纠结于补码的正负判别和转换了
sprintf(buf,"温度值为:%6.2f",v);//字符串拼接输出,用于串口观察数据
SendString(buf);//发送组合好的字符串
delay(100000);//延时等待,以防止串口信息爆炸>v<
}
}
void UART() interrupt 4//串口中断服务函数
{
if(RI)//接收标志位(未使用)
{
RI=0;
}
if(TI)//发送标志位
{
TI=0;
busy=0;
}
}
复制代码
测试时的截图:
测试截图.png
(71.07 KB, 下载次数: 113)
下载附件
2019-2-12 17:14 上传
测试中,对比室内的酒精温度计,该转换值偏大了约1.75℃
相关文件如下:
【测试工程】:工程中的延时函数形参编写时出了一个小纰漏,应该改成ulong型,并更改相应实参值
DS3231温度读取 凌净清河.zip
(99.37 KB, 下载次数: 116)
2019-2-12 17:18 上传
点击文件名下载附件
下载积分: 黑币 -5
【DS3231英文手册】:英文手册比中文的在某些细节描述更详尽
DS3231.pdf
(361.01 KB, 下载次数: 36)
2019-2-12 17:19 上传
点击文件名下载附件
下载积分: 黑币 -5
【DS3231中文手册】
DS3231中文手册.pdf
(449.27 KB, 下载次数: 85)
2019-2-12 17:19 上传
点击文件名下载附件
下载积分: 黑币 -5
下载注明:可以回复本帖得到黑币补贴(评分),本人现在最高能给15黑币/帖,多次回复亦有补贴。
作者:
tieq1952
时间:
2019-2-13 08:00
谢谢分享!!!
作者:
persistence
时间:
2019-5-19 14:12
感谢!!学习了!
作者:
big土坑
时间:
2019-5-20 12:12
感谢了楼主 学到了
作者:
大魔导师刘秀
时间:
2019-7-9 18:40
很强很强很强学到了感谢楼主
作者:
wangwing
时间:
2019-7-9 21:45
串口助手用得不错,学习了。
作者:
sdlovelife
时间:
2019-7-16 14:42
谢谢分享。
作者:
wangtttt
时间:
2019-7-16 20:55
谢谢分享
作者:
1113634577
时间:
2019-7-19 09:25
多字节操作子程序清晰,读取温度运算的方式比其它判符号程序简洁
作者:
stlong
时间:
2019-8-13 11:02
感谢楼主的无私奉献精神
作者:
流淌的歌声
时间:
2019-12-22 16:01
正想做一个精准时钟,谢谢楼主分享
作者:
wdh9203
时间:
2020-1-18 20:47
正在学习中,谢谢
作者:
逍遥宿元
时间:
2020-6-19 14:45
谢谢分享。
作者:
ii11nnocent
时间:
2020-8-4 07:36
刚弄好DS3231的时间,最近在弄温度,总是出错,看了你的贴子,嗯,找到错误原因了,感谢
作者:
benniu
时间:
2021-1-3 11:37
刚刚买了1个模块,正在学习使用中,这个资料太有用了 谢谢楼主分享
作者:
stone528
时间:
2021-4-15 13:26
看看这个温度是不是能用
作者:
xjx51
时间:
2021-7-16 14:24
楼主,我是直接读取11H和12H这两个寄存器的值然后显示到屏幕上,在显示小数点的,照样用,应该不要建变量吧?
作者:
xjx51
时间:
2021-7-16 14:26
我是这样写的:
OLED_P8x16(0,6,DS3231Time[7]/10);
OLED_P8x16(8,6,DS3231Time[7]%10);
我通过温度读取函数直接将温度值显示在OLED屏幕上的
作者:
土老冒527
时间:
2021-11-19 11:18
ds3231的温度可是有点不靠谱,毕竟手册上也是正负3度的误差,3度的误差不小了,没办法只能改用DS18B20
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1