DS3231的使用(二) (附IIC源码)
本节主要讲述IIC的使用及源码实现。
IIC数据有效性:只有在SCL线为低时,SDA线才允许改变电平。
初始宏定义如下:
1 /**************宏定义***************/ 2 #define DS_SCL BIT6 //DS_SCL = P1.6 3 #define DS_SDA BIT5 //DS_SDA = P1.5 4 #define DS_SCL_IN P1DIR &= ~DS_SCL 5 #define DS_SCL_OUT P1DIR |= DS_SCL 6 #define DS_SCL_L P1OUT &= ~DS_SCL 7 #define DS_SCL_H P1OUT |= DS_SCL 8 #define DS_SDA_IN P1DIR &= ~DS_SDA 9 #define DS_SDA_OUT P1DIR |= DS_SDA 10 #define DS_SDA_L P1OUT &= ~DS_SDA 11 #define DS_SDA_H P1OUT |= DS_SDA 12 #define DS_SDA_BIT P1IN & DS_SDA 13 #define DS_SDA_IN_H P1REN |= DS_SDA
IIC时序图(取自DS3231数据手册):
先看前一部分(开始与结束):
从时序图可以看出来,开始信号为SCL为高时,SDA由高变低;结束信号为SCL为低时,SDA由低变高。
1 /******************************************* 2 函数名称:DS_Start 3 功 能:I2C起始数据 4 参 数:无 5 返回值 :无 6 ********************************************/ 7 void DS_Start(void) 8 { 9 DS_SDA_OUT; //设置IO口方向 10 DS_SCL_OUT; 11 DS_SCL_H; //SCL、SDA先拉高 12 Delay_us(5); //delay应该有个最小时间要求 13 DS_SDA_H; 14 Delay_us(5); 15 DS_SDA_L; //SDA拉低表明开始 16 Delay_us(5); 17 DS_SCL_L; //SCL拉低,数据传输准备就绪 18 Delay_us(5); 19 }
1 /******************************************* 2 函数名称:DS_Stop 3 功 能:I2C终止数据 4 参 数:无 5 返回值 :无 6 ********************************************/ 7 void DS_Stop(void) 8 { 9 DS_SDA_OUT; //设置IO口方向 10 DS_SCL_OUT; 11 DS_SCL_L; //先把SCL、SDA拉低,给结束信号做准备 12 Delay_us(5); 13 DS_SDA_L; 14 Delay_us(5); 15 DS_SCL_H; //SCL拉高 16 Delay_us(5); 17 DS_SDA_H; //当SCL为高,SDA由低变高为结束信号 18 Delay_us(1); 19 }
发送数据与读数据:
由图可知,开始信号后,应把SCL拉低,准备数据传输,SDA电平变化后,再拉高SCL,发送数据(最高位先发送),循环8次(一个字节)。
读取函数同理,只不过过程是反的,SDA是输入,主机做接收端。
1 /******************************************* 2 函数名称:DS_Send_Byte 3 功 能:I2C发送数据 4 参 数:data 5 返回值 :data 6 ********************************************/ 7 void DS_Send_Byte(u8 data) 8 { 9 DS_SDA_OUT; //设置IO口输出方向 10 DS_SCL_OUT; 11 DS_SCL_L; //SCL为低时,允许SDA改变电平 12 unsigned char temp; 13 for(temp=0x80;temp!=0;temp>>=1) 14 { 15 if(temp&data==0) //高位先发 16 { 17 DS_SDA_L; 18 } 19 else 20 { 21 DS_SDA_H; 22 } 23 Delay_us(5); 24 DS_SCL_H; //SCL拉高 发送数据 25 Delay_us(5); 26 DS_SCL_L; 27 } 28 }
1 /******************************************* 2 函数名称:DS_Read 3 功 能:I2C接收数据 4 参 数:data 5 返回值 :data 6 ********************************************/ 7 unsigned char DS_Read(void) 8 { 9 unsigned char temp; 10 unsigned char data; 11 12 DS_SDA_IN; //主机做接收,SDA线为输入 13 DS_SDA_IN_H ; 14 for(temp=0x80;temp!=0;temp>>=1) 15 { 16 DS_SCL_H; //SCL拉高,保证接收数据时SDA不改变 17 Delay_us(5); 18 if(DS_SDA_BIT==1) 19 { 20 data|=temp; //高电平保留 21 } 22 else 23 { 24 data&=~temp; 25 } 26 DS_SCL_L; //SCL拉低,数据准备 27 } 28 return data; 29 }
主机应答信号与非应答信号:
主机接收完从机数据后,要发送应答或者非应答信号。
1 /******************************************* 2 函数名称:DS_Ack 3 功 能:I2C发送应答信号 4 参 数:无 5 返回值 :无 6 ********************************************/ 7 void DS_Ack(void) 8 { 9 DS_SDA_OUT; //主机为接收端 发送应答信号 10 DS_SCL_L; //SCL拉低,允许SDA改变电平 11 DS_SDA_L; //SDA低电平为应答 12 DS_SCL_H; 13 Delay_us(5); 14 DS_SCL_L; 15 }
1 /******************************************* 2 函数名称:DS_NAck 3 功 能:I2C发送非应答信号 4 参 数:无 5 返回值 :无 6 ********************************************/ 7 void DS_NAck(void) 8 { 9 DS_SDA_OUT; //此时,相当于主机在接收数据,是被动方 10 DS_SCL_L; //SCL拉低,允许SDA改变电平 11 DS_SDA_H; //SDA高电平为非应答 12 DS_SCL_H; 13 Delay_us(5); 14 DS_SCL_L; 15 }
主机接收从机应答信号:
从机在接收主机数据后,从机要发送一个应答信号,主机判断此应答信号为应答信号或者非应答信号,做下一步处理。
/******************************************* 函数名称:DS_Get_Ack 功 能:I2C接收应答信号 参 数:无 返回值 :ack ********************************************/ uchar DS_Get_Ack(void) { unsigned char ack; DS_SDA_IN; //释放数据线,准备接收应答 DS_SDA_IN_H ; //SDA线输入上拉 DS_SCL_H; //SCL线拉高 if(DS_SDA_BIT==1) { ack=0;//无应答信号 } else { ack=1;//有应答信号 } DS_SCL_L; Delay_us(5); }
下面是DS3231传输时序图:
由图可知,在发送开始信号后,DS3231接收的第一个字节的前7位是从机地址,即DS3231地址,第八位为读/写操作。
从DS3231的数据手册中可以看出来,DS3231的地址为1101000,所以主机操作的写地址为0XD1,读地址为0XD0。(不要写反)读寄存器指针的方式是开始信号-写器件地址-写寄存器地址-开始信号-接收数据-停止。
1 /******************************************* 2 函数名称:DS3231_WriteByte 3 功 能:I2C总线给DS3231发送单字节 4 参 数:WriteAddr DataToWrite 5 返回值 :无 6 ********************************************/ 7 void DS3231_WriteByte(u8 WriteAddr,u8 DataToWrite) 8 { 9 DS_Start(); 10 DS_Send_Byte(0XD1); //发送器件地址 11 DS_Get_Ack(); 12 DS_Send_Byte(WriteAddr); //发送首地址 13 DS_Get_Ack(); 14 DS_Send_Byte(DataToWrite);//发送数据 15 DS_Get_Ack(); 16 DS_Stop(); 17 Delay_ms(1); 18 }
1 /******************************************* 2 函数名称:DS3231_ReadByte 3 功 能:I2C总线从DS3231接收单字节 4 参 数:ReadAddr DataToRead 5 返回值 :Data 6 ********************************************/ 7 uchar DS3231_ReadByte(u8 ReadAddr) 8 { 9 uchar R_Data=0; 10 DS_Start(); 11 DS_Send_Byte(0XD0);//读地址 12 DS_Ack(); 13 DS_Send_Byte(ReadAddr); 14 DS_Ack(); 15 DS_Start(); 16 DS_Send_Byte(0XD1); 17 R_Data=DS_Read(); 18 Delay_us(5); 19 DS_NAck(); 20 DS_Stop(); 21 return R_Data; 22 }
1 /******************************************* 2 函数名称:Readtime 3 功 能:读取DS3231时间 4 参 数:R_tmpdate 5 返回值 :无 6 ********************************************/ 7 void Read_RTC() 8 { unsigned char rtc_address[6]={0x00,0x01,0x02,0x04,0x05,0x06}; 9 unsigned char R_tmpdate[6]; 10 unsigned char i,*p; 11 p=rtc_address; //地址传递 12 for(i=0;i<6;i++) //分6次读取 秒分时日月年 13 { 14 R_tmpdate[i]=DS3231_ReadByte(*p); 15 p++; 16 } 17 }
1 void ModifyTime(uchar yea,uchar mon,uchar da,uchar hou,uchar min,uchar sec) 2 { 3 uchar temp=0; 4 5 DS3231_WriteByte(0x06,temp);//修改年 6 7 DS3231_WriteByte(0x05,temp);//修改月 8 9 DS3231_WriteByte(0x04,temp);//修改日 10 11 DS3231_WriteByte(0x02,temp);//修改时 12 13 DS3231_WriteByte(0x01,temp);//修改分 14 15 DS3231_WriteByte(0x00,temp);//修改秒 16 }
posted on 2018-01-30 21:08 Knight.Wxz 阅读(11431) 评论(1) 编辑 收藏 举报