AD7739的SPI程序,DS1302的SPI程序,和24C02IIC程序字节读写总结

落爺英雄遲暮 提交于 2020-03-12 13:08:39

一、AD7739的SPI程序

空闲电平是高电平,所以字节读写程序最后时钟电平是高电平,必须是完整的时钟周期。

void Write7738(unsigned char ch)
{

    unsigned char idata, n=8;         // 向SDA上发送一位数据字节,共八位            //传输时钟频率117.260KHZ,T=8.528US和波形相符合2020.1.11
    CS=0;                                                                            //但是硬件的SPI计算频率140.625KHZ,实际波形234.625KHZ,T=4.26US不相符合2020.1.11
    SCK = 1 ;                        //时钟置高
    while(n--)
    {
        delay_us(3);
       //delay(3);
       SCK = 0 ;                     //时钟置低
       if((ch&0x80) == 0x80)         // 若要发送的数据最高位为1则发送位1
         {
           MOSI = 1;                 // 传送位1
         }
    else
          {
        MOSI = 0;                 // 否则传送位0
      }
          delay_us(3);
          //delay(3);
        SCK = 1 ;                    //时钟置高
           ch = ch<<1;                  // 数据左移一位
        
        }
        CS=1;      //在103行导致RDY引脚一直是高电平
}
//---------------------------------------------------------------------------------------------
// 函数名称: Read7738
// 入口参数: ch
// 函数功能: 从AD7738寄存器读出一个字节
//---------------------------------------------------------------------------------------------
void Read7738reg()
{

     unsigned char i;         // 向SDA上发送一位数据字节,共八位
     CS=0;
/*    unsigned char idata,i, n=8;         // 向SDA上发送一位数据字节,共八位
    CS=0;
    SCK = 1 ;                        //时钟置高
    while(n--)      */                //因为这几行没有去掉,所以导致读字节失败,相当于循环了8次读字节,读取最后一次数据,时序中每个字节
                                        //读前和读后都是高电平 ,模拟SPI时序成功2019.9.20
                                            //读出91 后循环读取后面7个字节是FF,读出70,后面7个 字节也是FF。也就是
                                          //DOUT空闲是后并不是保持最后一个位的数据不变,而是变为1。W25Q64空闲是DOUT是高阻态
      SCK=1;
      MOSI=0;
      for(i=0;i<8;i++)
      {
         delay_us(3);
         SCK=0;                                    //单片机写的时候,提供上升沿是为了SPI从设备有锁定时刻;
         delay_us(3);                             //单片机读的时候,单片机引脚自动锁定,提供高低变化是为了从设备提供下降沿,变化输出数据
         temp1=temp1<<1;
         if(MISO==1)
            temp1=temp1|0x01;
         else
            temp1=temp1&0xFE;
         SCK=1;

       }
         tempbuf=temp1; 
         CS=1;             //有没有此语句,都可以读出来,但是连续时必须有此语句,根据时序要求
                           //官方例程三个字节连读,也是CS一直是低
}

二、DS1302的SPI程序

空闲电平是低电平,所以字节读写程序最后时钟电平是低电平,必须是完整的时钟周期,并且是片选信号选择后,两个字节连写,写字节的最后下降沿移出读字节的第一位数据到IO引脚。再取消片选信号

void SPI_Write_Byte(uchar tdata)         
{
    uint i;
//    DS1302_CS = 1;
    DS1302_CLK = 0;
    delayNus(4);
    for(i = 0;i < 8;i++)
    {
//        DS1302_CLK = 0;                       //此行不修改单独写可以成功但是读字节不能成功,因为空闲状态是低电平,所以必须改到循环体下面才符合写字节时序,2020.2.28
        delayNus(3);
        if((tdata&0x01) == 0x01)
            DS1302_DATA = 1;
        else
            DS1302_DATA = 0;    
        DS1302_CLK = 1;
        delayNus(3);
        DS1302_CLK = 0;                   //写命令的最后一个下降沿会输出需要读数据的第一位,规格书特别强调注意了2020.3.12
        tdata >>=1;            //写数据,移位在下面                          
    }
//    DS1302_CS = 0;              //单字节写完,CS不能拉低,否则写不进去。必须是命令和数据写完再拉低还必须拉低,否则也写不进去.
}                              //必须和规格书时序一样2020.1.17实际测试

uchar SPI_Read_Byte()
{
    uchar i;
    uchar temp = 0;
    DS1302_DATA = 1;//输入模式    //此语句有无都可以读成功2020.2.29
//    DS1302_CS = 1;
//    DS1302_CLK = 1;           //此A语句导致读字节失败,注释掉和BC配合才读自己成功2020.2.28
    delayNus(4);
    for(i = 0;i < 8;i++)
    {
        temp >>= 1;         //读数据,移位在上面,如果在最后一行,可能导致多一次移位2020.3.7
//        DS1302_CLK = 0;         //此B语句导致读字节失败2020.2.28
        delayNus(3);
        if(DS1302_DATA == 1)
            temp |= 0x80;    
        DS1302_CLK = 1;
        delayNus(3);
        DS1302_CLK = 0;    //此C语句加到此行读字节才成功,也就是B句应改在此行,空闲状态低电平2020.2.28
    }
    return (temp);
}

小结,这两个芯片都是上升沿采集位数据,下降沿移出下一个位数据到IO引脚。和高低电平的先后没关系。

三、24C02IIC程序

空闲状态是SCK,SDA高电平但是SCK高电平期间采集SDA信号,SDA必须稳定,SCK高电平期间SDA的变化是开始或者停止信号,所以SCL每个时钟周期最后要落到低电平,低电平允许SDA改变。起始和停止信号等信号要先写SDA,再写SCK。

bit AT24C04_Write_Byte(uchar tdata)
{
    uchar i;
    bit x;
    for(i = 0;i < 8;i++)
    {
    //    AT24C04_SCL = 1;                       //先高电平,可以假设上个周期SDA是0,则,高电平后SDA变为1,
    //    delayNus(2);                           //则GAO高电平期间SDA变化,是开始或这停止信号。应该保证高电平期间数据稳定采集2020.3.11
        AT24C04_SDA = (bit)(tdata&0x80);      //所以应该先让数据稳定再提供高电平信号,采集才能稳定
        delayNus(2);
        AT24C04_SCL = 1;
        delayNus(2);
        AT24C04_SCL = 0;
        delayNus(4);
        tdata <<= 1;

    }
    AT24C04_SDA = 1;             //模拟IIC写字节时候,不等待应答信号,失败。硬件IIC更需要读应答。读的时候不发送非应答信号是可以成功读取的(网上说模拟IIC可以不用)
    delayNus(2);                 //但是硬件IIC必须发送非应答否则读取失败2020.3.11
    AT24C04_SCL = 1;
    delayNus(2);
    x = AT24C04_SDA;
    AT24C04_SCL = 0;
    return x;
}
uchar AT24C04_Read_Byte()
{
    uchar i,temp;
    temp = 0;
    AT24C04_SDA = 1;         //输入模式先写12020.3.11
    for(i = 0;i < 8;i++)
    {
        temp <<= 1;
    //    AT24C04_SCL = 0;
        delayNus(2);
        AT24C04_SCL = 1; //高电平读数据,需要注意先提供高电平信号再去读引脚数据。读取的是高电平器件的数据
        delayNus(4);
        temp |= (unsigned char)AT24C04_SDA;    //虽然写反也能读取,但是不推荐2020.3.12
//        if(AT24C04_SDA = 1)     //    这个方式波形对,但是数码管显示不对2020.3.11
//            temp = temp|0x01;     //     但是在AD7739-STM32单片机模拟SPI中,这种方式刷程序到电路板上也是可以实现读字节的
//        else                 //ADI官方例程也是这模式,单片机是8位的类似51的单片机
//            //temp |= 0;           //
//            temp = temp& 0xfe;
        delayNus(2);
        AT24C04_SCL = 0;
    //    temp <<= 1;
    }
    return (temp);
}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!