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编辑  收藏  举报

导航