找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 8577|回复: 18
打印 上一主题 下一主题
收起左侧

DS3231温度读取实验 附单片机源程序

  [复制链接]
跳转到指定楼层
楼主
本帖最后由 凌净清河 于 2019-2-13 19:46 编辑

DS3231作为一个走时精准的RTC芯片,内部带有温度补偿电路,此例将读取其中11H和12H寄存器,提取测得的温度值并传送到串口输出。

类似程序网上非常之多,不再赘述,在此重新提说几处需要注意的地方。
1.根据DS3231的芯片手册,其温度传感器的精度为±3℃,毕竟不是专用的温度传感器,在使用中可以作为一个参考,且仅此而已。
2.根据DS3231的芯片手册,其温度分辨率为±0.25℃,所以其小数部分读出的值只能是.00、.25、.50、.75这四种,如果读出的值不是这四种,则数据处理有误。
3.本实验使用一个float型数据直接接收了转换的温度值,没有对补码的符号位进行判断等。

注明:本程序没有使用CONV位进行强制转换,但是实际上温度值的刷新速度还是很令人满意(用手按住芯片,温度值更改速度很快,下面的测试图片是恒温下检测的,故无变化)。
测试程序:
  1. #include<STC15.H>
  2. #include"stdio.h"
  3. #include<intrins.h>
  4. //位定义
  5. sbit DS3231_SDA=P3^3;
  6. sbit DS3231_SCL=P3^2;

  7. //运行数组
  8. unsigned char DS3231_Time_Buffer[7]={0x00,0x48,0x11,0x02,0x12,0x02,0x19};
  9. unsigned char temp[2]={0,0};
  10. char buf[20]={0};
  11. //运行标志位
  12. bit busy=0;
  13. //运行变量
  14. float v;

  15. /*##############################################################################
  16. 编写/测试:凌净清河
  17. 日期:2019年2月12日
  18. 测试平台:IAP15W4K58S4

  19. 鸣谢:DS3231部分驱动函数借用了51黑论坛上某位的程序,但是时间太久忘记是谁的了。
  20. 并未修改原作者的写法,如果原作者认出,鄙人在此表示感谢,或可联系我提名。
  21. ##############################################################################*/

  22. /*###################以下为给DS3231定义的IIC通信函数################*/
  23. void DS3231_Delay()//使用空操作进行短暂的延时
  24. {
  25.         _nop_();
  26.         _nop_();
  27.         _nop_();
  28.         _nop_();
  29. }

  30. void DS3231_IIC_Start()//IIC总线的开始信号
  31. {
  32.         DS3231_SCL=1;
  33.         DS3231_SDA=1;
  34.         DS3231_Delay();
  35.         DS3231_SDA=0;
  36.         DS3231_Delay();
  37.         DS3231_SCL=0;
  38. }

  39. void DS3231_IIC_Stop()//IIC总线的停止信号
  40. {
  41.         DS3231_SCL=0;
  42.         DS3231_SDA=0;
  43.         DS3231_Delay();
  44.         DS3231_SCL=1;
  45.         DS3231_Delay();
  46.         DS3231_SDA=1;
  47.         DS3231_Delay();
  48. }

  49. bit DS3231_IIC_Send_Byte(unsigned char dat)//写操作
  50. {
  51.         unsigned char mask;//定义一个掩码用于进行按位发送数据的操作
  52.         bit ack;

  53.         for(mask=0x80;mask!=0;mask>>=1)
  54.         {
  55.                 if((mask&dat)==0)
  56.                         DS3231_SDA=0;
  57.                 else
  58.                         DS3231_SDA=1;
  59.                 DS3231_Delay();
  60.                 DS3231_SCL=1;
  61.                 DS3231_Delay();
  62.                 DS3231_SCL=0;
  63.         }
  64.         DS3231_SDA=1;
  65.         DS3231_Delay();
  66.         DS3231_SCL=1;
  67.         ack=DS3231_SDA;
  68.         DS3231_Delay();
  69.         DS3231_SCL=0;

  70.         return (~ack);
  71. }

  72. unsigned char DS3231_IIC_Read_Byte_NAK()//读操作+非应答
  73. {
  74.         unsigned char mask;//定义一个用于累加的位存储临时变量
  75.         unsigned char dat;

  76.         DS3231_SDA=1;
  77.         for(mask=0x80;mask!=0;mask>>=1)
  78.         {
  79.                 DS3231_Delay();
  80.                 DS3231_SCL=1;
  81.                 if(DS3231_SDA==0)
  82.                         dat&=~mask;
  83.                 else
  84.                         dat|=mask;
  85.                 DS3231_Delay();
  86.                 DS3231_SCL=0;
  87.         }
  88.         DS3231_SDA=1;
  89.         DS3231_Delay();
  90.         DS3231_SCL=1;
  91.         DS3231_Delay();
  92.         DS3231_SCL=0;

  93.         return dat;
  94. }

  95. unsigned char DS3231_IIC_Read_Byte_ACK()//读操作+应答
  96. {
  97.         unsigned char mask;//定义一个用于累加的位存储临时变量
  98.         unsigned char dat;

  99.         DS3231_SDA=1;
  100.         for(mask=0x80;mask!=0;mask>>=1)
  101.         {
  102.                 DS3231_Delay();
  103.                 DS3231_SCL=1;
  104.                 if(DS3231_SDA==0)
  105.                         dat&=~mask;
  106.                 else
  107.                         dat|=mask;
  108.                 DS3231_Delay();
  109.                 DS3231_SCL=0;
  110.         }
  111.         DS3231_SDA=0;
  112.         DS3231_Delay();
  113.         DS3231_SCL=1;
  114.         DS3231_Delay();
  115.         DS3231_SCL=0;

  116.         return dat;
  117. }
  118. /*#################以下为给DS3231封装的寄存器通信函数###############*/

  119. void DS3231_Read_Registers(unsigned char *buf,unsigned char addr,unsigned char len)//读EEPROM中多个字节
  120. {
  121.         do{
  122.                 DS3231_IIC_Start();
  123.                 if(DS3231_IIC_Send_Byte(0xD0))
  124.                 {
  125.                         break;
  126.                 }
  127.                 DS3231_IIC_Stop();
  128.           }while(1);
  129.         DS3231_IIC_Send_Byte(addr);
  130.         DS3231_IIC_Start();
  131.         DS3231_IIC_Send_Byte((0xD0)|0x01);//寻址,读操作
  132.         while(len>1)
  133.         {
  134.                 *buf++=DS3231_IIC_Read_Byte_ACK();
  135.                 len--;
  136.         }
  137.         *buf=DS3231_IIC_Read_Byte_NAK();//读一个字节
  138.         DS3231_IIC_Stop();
  139. }

  140. void DS3231_Write_Registers(unsigned char *buf,unsigned char addr,unsigned char len)//写寄存器,传入待写入数组
  141. {
  142.         while(len>0)
  143.         {        
  144.                 do{
  145.                         DS3231_IIC_Start();
  146.                         if(DS3231_IIC_Send_Byte(0xD0))
  147.                         {
  148.                                 break;
  149.                         }
  150.                         DS3231_IIC_Stop();
  151.                   }while(1);

  152.                 DS3231_IIC_Send_Byte(addr);
  153.                 while(len>0)
  154.                 {
  155.                         DS3231_IIC_Send_Byte(*buf++);
  156.                         len--;
  157.                         addr++;
  158.                         if((addr&0x07)==0)
  159.                         {
  160.                                 break;
  161.                         }
  162.                 }
  163.                 DS3231_IIC_Stop();
  164.         }
  165. }

  166. void SendData(unsigned char dat)//串口1发送一个字节数据
  167. {
  168.         while(busy);
  169.         busy=1;
  170.         SBUF=dat;
  171. }

  172. void SendString(char *p)//串口发送一个字符串
  173. {
  174.         while(*p!='\0')
  175.         {
  176.                 SendData(*p);
  177.                 p++;
  178.         }
  179. }

  180. void UartInit(void)                //9600bps@11.0592MHz
  181. {
  182.         SCON = 0x50;                //8位数据,可变波特率
  183.         AUXR |= 0x40;                //定时器1时钟为Fosc,即1T
  184.         AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
  185.         TMOD &= 0x0F;                //设定定时器1为16位自动重装方式
  186.         TL1 = 0xE0;                //设定定时初值
  187.         TH1 = 0xFE;                //设定定时初值
  188.         ET1 = 0;                //禁止定时器1中断
  189.         TR1 = 1;                //启动定时器1
  190. }

  191. void delay(unsigned long int i)//延时函数
  192. {
  193.         while(i--);
  194. }

  195. void main()
  196. {
  197.         P3M1=0x00;
  198.         P3M0=0x00;//IO初始化,这个准双向的初始化操作是为STC15W4K32S4系列单片机特别准备的
  199.         UartInit();//串口初始化
  200.         EA=1;//开总中断
  201.         ES=1;//开串口中断
  202.         DS3231_Write_Registers(DS3231_Time_Buffer,0x00,7);//向器件写入有效的IIC地址,以保证驱动振荡器起振,防止读出初始值0℃
  203.         while(1)
  204.         {
  205.                 DS3231_Read_Registers(temp,0x11,2);
  206.                 v=temp[0]*1.0+(temp[1]>>6)*0.25;//按照数据格式,将寄存器中的值放入一个有符号的float型数据,就不必纠结于补码的正负判别和转换了
  207.                 sprintf(buf,"温度值为:%6.2f",v);//字符串拼接输出,用于串口观察数据
  208.                 SendString(buf);//发送组合好的字符串
  209.                 delay(100000);//延时等待,以防止串口信息爆炸>v<
  210.         }
  211. }

  212. void UART() interrupt 4//串口中断服务函数
  213. {
  214.         if(RI)//接收标志位(未使用)
  215.         {
  216.                 RI=0;
  217.         }
  218.         
  219.         if(TI)//发送标志位
  220.         {
  221.                 TI=0;
  222.                 busy=0;
  223.         }
  224. }
复制代码


测试时的截图:

测试中,对比室内的酒精温度计,该转换值偏大了约1.75℃

相关文件如下:
【测试工程】:工程中的延时函数形参编写时出了一个小纰漏,应该改成ulong型,并更改相应实参值
DS3231温度读取 凌净清河.zip (99.37 KB, 下载次数: 115)
【DS3231英文手册】:英文手册比中文的在某些细节描述更详尽
DS3231.pdf (361.01 KB, 下载次数: 36)
【DS3231中文手册】
DS3231中文手册.pdf (449.27 KB, 下载次数: 85)

下载注明:可以回复本帖得到黑币补贴(评分),本人现在最高能给15黑币/帖,多次回复亦有补贴。


评分

参与人数 3黑币 +70 收起 理由
NPC-1024 + 5 凌:由于站点对评分机制的修改,帖子不再给.
tieq1952 + 15 赞一个!
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏9 分享淘帖 顶2 踩
回复

使用道具 举报

沙发
ID:253767 发表于 2019-2-13 08:00 | 只看该作者
谢谢分享!!!

评分

参与人数 1黑币 +15 收起 理由
凌净清河 + 15 黑币补贴

查看全部评分

回复

使用道具 举报

板凳
ID:448212 发表于 2019-5-19 14:12 | 只看该作者
感谢!!学习了!
回复

使用道具 举报

地板
ID:184096 发表于 2019-5-20 12:12 | 只看该作者
感谢了楼主 学到了
回复

使用道具 举报

5#
ID:581125 发表于 2019-7-9 18:40 | 只看该作者
很强很强很强学到了感谢楼主
回复

使用道具 举报

6#
ID:483407 发表于 2019-7-9 21:45 | 只看该作者
串口助手用得不错,学习了。
回复

使用道具 举报

7#
ID:585103 发表于 2019-7-16 14:42 | 只看该作者
谢谢分享。
回复

使用道具 举报

8#
ID:585374 发表于 2019-7-16 20:55 | 只看该作者
谢谢分享
回复

使用道具 举报

9#
ID:371527 发表于 2019-7-19 09:25 | 只看该作者
多字节操作子程序清晰,读取温度运算的方式比其它判符号程序简洁
回复

使用道具 举报

10#
ID:111376 发表于 2019-8-13 11:02 | 只看该作者
感谢楼主的无私奉献精神
回复

使用道具 举报

11#
ID:91162 发表于 2019-12-22 16:01 | 只看该作者
正想做一个精准时钟,谢谢楼主分享
回复

使用道具 举报

12#
ID:4306 发表于 2020-1-18 20:47 | 只看该作者
正在学习中,谢谢
回复

使用道具 举报

13#
ID:138937 发表于 2020-6-19 14:45 | 只看该作者

谢谢分享。
回复

使用道具 举报

14#
ID:702127 发表于 2020-8-4 07:36 | 只看该作者
刚弄好DS3231的时间,最近在弄温度,总是出错,看了你的贴子,嗯,找到错误原因了,感谢
回复

使用道具 举报

15#
ID:491923 发表于 2021-1-3 11:37 | 只看该作者
刚刚买了1个模块,正在学习使用中,这个资料太有用了 谢谢楼主分享
回复

使用道具 举报

16#
ID:90970 发表于 2021-4-15 13:26 | 只看该作者
看看这个温度是不是能用
回复

使用道具 举报

17#
ID:884042 发表于 2021-7-16 14:24 | 只看该作者
楼主,我是直接读取11H和12H这两个寄存器的值然后显示到屏幕上,在显示小数点的,照样用,应该不要建变量吧?
回复

使用道具 举报

18#
ID:884042 发表于 2021-7-16 14:26 | 只看该作者
我是这样写的:
OLED_P8x16(0,6,DS3231Time[7]/10);
          OLED_P8x16(8,6,DS3231Time[7]%10);
我通过温度读取函数直接将温度值显示在OLED屏幕上的
回复

使用道具 举报

19#
ID:972563 发表于 2021-11-19 11:18 | 只看该作者
ds3231的温度可是有点不靠谱,毕竟手册上也是正负3度的误差,3度的误差不小了,没办法只能改用DS18B20
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表