|
本帖最后由 凌净清河 于 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;
- }
- }
复制代码
测试时的截图:
测试中,对比室内的酒精温度计,该转换值偏大了约1.75℃
相关文件如下:
【测试工程】:工程中的延时函数形参编写时出了一个小纰漏,应该改成ulong型,并更改相应实参值
DS3231温度读取 凌净清河.zip
(99.37 KB, 下载次数: 115)
【DS3231英文手册】:英文手册比中文的在某些细节描述更详尽
DS3231.pdf
(361.01 KB, 下载次数: 36)
【DS3231中文手册】
DS3231中文手册.pdf
(449.27 KB, 下载次数: 85)
下载注明:可以回复本帖得到黑币补贴(评分),本人现在最高能给15黑币/帖,多次回复亦有补贴。
|
评分
-
查看全部评分
|