GD32驱动DS3231显示时钟踩坑记录

   近日调试GD32驱动ds3231的程序,程序从STM 32移植过来的,所以就没想太多。当时STM32有HAL库开发,运行在内部晶振经PLL后的64MHZ频率。具体驱动程序网上一大堆,我这里就不在赘述了。只写一点我的感受。

   在STM32上运行良好,延时程序采用单独书写的delay.c。移植过来后由于刚开始时钟方面配置的问题,导致GD32运行在默认8MHZ情况下,这时候DS3231的读写一切正常。直到我将时钟提高到108MHZ后,数据始终读不出来,用示波器观察波形,发现根本就没有所谓IIC 波形。这就很郁闷了。我试着将单片机运行频率降低,结果依然不行。通过研究示波器波形发现,在108MHZ情况下,iic的波形根本就存在,好像软件延时根本就没起作用。于是乎在网上查找相关记录,然并卵。于是从头开始研究IIC,最后还是看到koukou_1538725213在本站写的“模拟IIC的实现”一文,猜测是不是将延时函数写到和DS3231一个文件里,不使用调用头文件的形式会有作用。果不其然,IIC波形立刻就出来了,还可以调速。感谢koukou_1538725213。哪位大侠知道是何原因,请一定指教一下,谢谢啦!

具体部分程序如下:可以看到里面有延时函数的头文件调用。
#include "main.h"
#include "DS3231.h"
#include "gd32f10x.h"
//#include "delay.h"
#include "usart.h"


TIMER_TYPE Timer={0};

//uint8_t mid_flag;  居中标志,暂时没有使用

extern uint16_t sec;
//uint32_t DS3231_Now_Time=0;

const unsigned char rtc_address[7]={0x00,0x01,0x02,0x03,0x04,0x05,0x06};//秒分时日月周年 最低位读写位

/*设置SDA引脚为输入模式*/
void DS3231_SET_SDA_IN(void)
{
 gpio_init(DS3231_SDA_GPIO_PORT,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,DS3231_SDA_GPIO_PIN);
}
/*设置SDA引脚为输出模式*/
void DS3231_SET_SDA_OUT(void)
{  gpio_init(DS3231_SDA_GPIO_PORT,GPIO_MODE_OUT_OD,GPIO_OSPEED_50MHZ,DS3231_SDA_GPIO_PIN);
}
/*设置SCL引脚为输入模式*/
void DS3231_SET_SCL_IN(void)
{  gpio_init(DS3231_SCL_GPIO_PORT,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,DS3231_SCL_GPIO_PIN);
}
/*设置SCL引脚为输出模式*/
void DS3231_SET_SCL_OUT(void)
{   gpio_init(DS3231_SCL_GPIO_PORT,GPIO_MODE_OUT_OD,GPIO_OSPEED_50MHZ,DS3231_SCL_GPIO_PIN);

}


//定义一个软件延时函数,用于对IIC 调速
static void I2C_delay(void)
{
volatile int i=8;
while(i--);
}

//使用软件模拟IIC //
//初始化
void IIC_init(void)
{
    DS3231_SET_SDA_OUT();        //设置SDA引脚为通用开漏输出模式
    DS3231_SET_SCL_OUT();        //设置SCL引脚为通用开漏输出模式
    IIC_SDA_H;      //SDA置高
    IIC_SCL_H;      //SCL置高
//    Read_RTC();    

}

//读取数据
unsigned char SDA_READ(void)
{
        return gpio_input_bit_get(DS3231_SDA_GPIO_PORT, DS3231_SDA_GPIO_PIN);    /* 读SDA口线状态 */  
}

//产生起始信号
void IIC_Start(void)
{
    DS3231_SET_SDA_OUT();
    IIC_SCL_H;//set SDA pin as output high
    I2C_delay();

    IIC_SDA_H;//set SCL pin as output high
    I2C_delay();

    IIC_SDA_L;//set SDA pin as output low
    I2C_delay();
    IIC_SCL_L;//set SCL pin as output low
    I2C_delay();
}

//产生停止信号
void IIC_Stop(void)
{
    DS3231_SET_SDA_OUT();
    IIC_SCL_L;//set SDA pin as output low
    I2C_delay();
    IIC_SDA_L;//set SCL pin as output high
    I2C_delay();
    IIC_SCL_H;//set SDA pin as output high
    I2C_delay();
    IIC_SDA_H;
    I2C_delay();
}

//等待响应信号
//0--接收应答成功 1-接收应答失败
unsigned char IIC_Wait_Ack(void)
{
   int ucErrTime = 0;

    IIC_SDA_H;//set SCL pin as output high
    IIC_SCL_H; //set sda as input with pull up
    
    DS3231_SET_SDA_IN();  //设置SDA引脚为浮空输入模式
    
    while(SDA_READ())
    {
                ucErrTime++;
                if(ucErrTime > 1024)
                {
                     DS3231_SET_SDA_OUT();      //设置SDA引脚为通用开漏输出模式
                        IIC_Stop();
                        return 1;
            }
    }
    DS3231_SET_SDA_OUT();   //设置SDA引脚为通用开漏输出模式
    IIC_SCL_L; //set SCL pin as output low
    return 0;
}

//产生ACK信号
void IIC_Ack(void)
{

    IIC_SCL_L;//set SCL pin as output low
   I2C_delay();
    IIC_SDA_L;//set SDA pin as output low
   I2C_delay();
    IIC_SCL_H;//set SDA pin as output high
   I2C_delay();
    IIC_SCL_L; //set SCL pin as output low
    I2C_delay();
}

//No ACK
void IIC_NAck(void)
{
    IIC_SCL_L; //set SCL pin as output low
    I2C_delay();
    IIC_SDA_H;//set SDA pin as output high
    I2C_delay();
    IIC_SCL_H;//set SCL pin as output high
   I2C_delay();//延时
    IIC_SCL_L;//set SCL pin as output low
    I2C_delay();
}

//IIC发送一个字节
void IIC_Send_Byte(unsigned char txd)
{
    unsigned char i;

    IIC_SCL_L; //set SCL pin as output low
    for(i = 0; i < 8; i++)
    {
            if((txd & 0x80)>>7)
            {
                IIC_SDA_H;//set SDA pin as output high
            }
            else
            {
                IIC_SDA_L;//set SDA pin as output low
            }
            txd <<= 1;
            I2C_delay();
            IIC_SCL_H;//set SCL pin as output high
            I2C_delay();
 
            IIC_SCL_L; //set SCL pin as output low
            I2C_delay();
    }
}

//读取一个字节
unsigned char IIC_Read_Byte(unsigned char ack)
{
    unsigned char i, res = 0;
    IIC_SDA_H; 
    DS3231_SET_SDA_IN(); //set sda as input with pull up

    for(i = 0; i < 8; i++ )
    {
            IIC_SCL_L;//set SCL pin as output high
          // delay_1us();
                 I2C_delay();

            IIC_SCL_H;//set SCL pin as output high
          // delay_1us();
                  I2C_delay();
            res <<= 1;
            if(SDA_READ())
            {
              res ++;
            }
    }
   DS3231_SET_SDA_OUT();
    if(!ack)
      IIC_NAck();
    else
      IIC_Ack();
    return res;
}
//-------------------------------------------------------------------
void IIC_single_byte_write(unsigned char Waddr,unsigned char Data)
{
  //指定位置写入一个字节数据函数
    IIC_Start();//产生起始信号
    IIC_Send_Byte(0xd0);//写入设备地址(写)
    IIC_Wait_Ack();//等待设备的应答
    IIC_Send_Byte(Waddr);//写入要操作的单元地址。
    IIC_Wait_Ack();//等待设备的应答。
    IIC_Send_Byte(Data);
    IIC_Wait_Ack();
    IIC_Stop();//产生停止符号。
}
//-------------------------------------------------------------------
unsigned char IIC_single_byte_read(unsigned char Waddr)
{
     //从任意地址读取一个字节数据函数
    unsigned char Data;//定义一个缓冲寄存器。
    IIC_Start();//产生起始信号
    IIC_Send_Byte(0xd0);//写入设备地址(写)
    IIC_Wait_Ack();//等待设备的应答
    IIC_Send_Byte(Waddr);//写入要操作的单元地址。
    IIC_Wait_Ack();//等待设备的应答。
    IIC_Stop();//产生停止符号。

    IIC_Start();//产生起始信号
    IIC_Send_Byte(0xd1);//写入设备地址(写)
    IIC_Wait_Ack();//等待设备的应答
    Data=IIC_Read_Byte(0);//写入数据。
   // i2c_Delay();
    IIC_Stop();//产生停止符号。
    //-------------------返回读取的数据--------------------
    return Data;//返回读取的一个字节数据。 
}

/******************************************
名   称:Read_RTC();
功   能:循环读取当前时间;
参   数:i:计数;temp:时间缓存区;p:缓存区指针
rtc_address:时间地址存放缓存区

**********************************************/
void Read_RTC(void)
{
    unsigned char i;
    unsigned char temp[7]={0};
    const unsigned char *p;
      p=rtc_address;         //地址传递
    for(i=0;i<7;i++)            //分6次读取 秒分时日月年
    {
      temp[i]=IIC_single_byte_read(*p);
            
      p++;
    }
   //Timer.second=temp[0];
      sec=temp[0];
    Timer.minute=temp[1];
    Timer.hour=temp[2];
    Timer.week=temp[3];
      Timer.day=temp[4];
    Timer.month=temp[5]&0X1F;
    Timer.year=temp[6];
        
}

unsigned char BCD2HEX(unsigned char val)    //BCD转换为Byte
{
    unsigned char temp;
    temp=val&0x0f;
    val>>=4;
    val&=0x0f;
    val*=10;
    temp+=val;
   
    return temp;
}

unsigned char HEX2BCD(unsigned char val)    //B码转换为BCD码
{
    unsigned char i,j,k;
    i=val/10;
    j=val%10;
    k=j+(i<<4);
    return k;
}
/****************************************************************
函数功能:依据服务器GPRS传来时间信息 设置DS3231时间
输入参数:服务器传来信息
返回参数:无
备    注:无
*****************************************************************/
void Set_RTC(unsigned char *data)
{
    unsigned char i;
    for(i=0;i<7;i++)
    {  
     data[i+7]=HEX2BCD(data[i+7]);
    }
    IIC_single_byte_write(0x0e,0X8c);
    for(i=0;i<7;i++)        //6次写入 秒分时周日月年
    {
        IIC_single_byte_write(rtc_address[i],data[i+7]);
    }
    IIC_single_byte_write(0x0e,0x0c);
}

void DS1302_Initial(void)
{
      
    IIC_SDA_H;//释放IIC总线的数据线。
    IIC_SCL_H;
    IIC_single_byte_write(0x0e,0x0c);
}
/****************************************************************
函数功能:读取DS3231中当前时间 将时间存入TIMER_TYPE Timer结构体中
输入参数:无
返回参数:无
备    注:无  测试代码,稍后可删除
*****************************************************************/
void Clock_Run(void)
{
                Read_RTC();

                 //-----测试代码--------
                  usart2_send_byte(0x20);
                      usart2_send_byte(Timer.year);
                usart2_send_byte(Timer.month);
                usart2_send_byte(Timer.day);
                  usart2_send_byte(Timer.week);
    
                usart2_send_byte(Timer.hour);
                usart2_send_byte(Timer.minute);
                usart2_send_byte(sec);
                //---------------------
           }
                
 /*******************************************
名   称:void DS3231_Set(uint8_t yea,uint8_t mon,uint8_t da,uint8_t we,uint8_t hou,uint8_t min,uint8_t sec)
功   能:设置DS3231的时间,
参   数:yea:年  mon:月   da:日   we:周   hou:时  min:分  se:秒
说   明:数据格式采用16进制,例如22时56分应写成 hou:0x16;min:0x38
**********************************************/
void DS3231_Set(uint8_t yea,uint8_t mon,uint8_t da,uint8_t we,uint8_t hou,uint8_t min,uint8_t se)
{
    uint8_t temp=0;

    temp=HEX2BCD(yea);
     IIC_single_byte_write(DS3231_YEAR,temp);

    temp=HEX2BCD(mon);
    temp=temp|0x80;
     IIC_single_byte_write(DS3231_MONTH,temp);

    temp=HEX2BCD(da);
     IIC_single_byte_write(DS3231_DAY,temp);
    
    temp=HEX2BCD(we);
     IIC_single_byte_write(DS3231_WEEK,temp);

    temp=HEX2BCD(hou);
     IIC_single_byte_write(DS3231_HOUR,temp);

    temp=HEX2BCD(min);
     IIC_single_byte_write(DS3231_MINUTE,temp);

    temp=HEX2BCD(se);
     IIC_single_byte_write(DS3231_SECOND,temp);
}


 

原文如下:模拟IIC的实现_koukou_1538725213的博客-CSDN博客_模拟iic

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值