STM32 IO口模拟I2C控制DS3231 一直调不通

2019-10-15 19:13发布

 一直 无法接收到ACK信号  从设备一直无反应  我单独给SDA拉高 置低 IDR是有反应的  我买了5个DS3231的时钟模块 那个模块式5V供电 经过一个稳压二极管 变成3.3v给芯片供电的  SDA SCL 上拉电阻都是10K 附件里有 DS3231的驱动程序 和 模块的原理图 从昨天到今天 在网上下了3个修改后都不行 昨天晚上 自己又重写了一个 从设备的ACK 信号一直没有响应  所以对时钟模块的读写操作 都是无效的 后来感觉是时钟芯片拽不动STM32的IO口 所以 就换了下上拉电阻  1K 4.7K 10K都换过 还是不好使 群里有朋友说 实在不行 就换成STM32的外设I2C   小弟实在是晕菜了 之前搞24c系列的模拟I2C也没这么困难过  求大家 给小弟支支招 
附件里 有 程序和模块原理图
我主程序里是这样写的
 GPIOA->CRL&=0x00ffffff;
 GPIOA->CRL|=0x22000000;//0x22000000; //SCK SDA
 delay_ms(100);
   I2cByteWrite(0xD0,0x0e,0); 
   I2cByteWrite(0xD0,0x0f,0);
后面就是读 时分秒


//////////////驱动程序
#include <stm32f10x_lib.h>
#include "delay.h"
#include "DS3231new.h"  #define SCL_H  GPIOA->ODR|=1<<7
#define SCL_L  GPIOA->ODR&=~(1<<7) #define SDA_H  GPIOA->ODR|=(1<<6)
#define SDA_L  GPIOA->ODR&=~(1<<6) #define SDA   (GPIOA->IDR & 1<<6) extern u8 year,month,date,hour,minute,second;   u8 BCD2HEX(u8 val)   //BCD转换为Byte
{
    u8 i;
    i= val&0x0f;
    val >>= 4;
    val &= 0x0f;
    val *= 10;
    i += val;
   
    return i;
} u8 B_BCD(u8 val)//B码转换为BCD码
{
  u8 i,j,k;
  i=val/10;
  j=val%10;
  k=j+(i<<4);
  return k;
} void delay(u16 us)
{
   delay_us(us*7);
}
/************************START***************************/
void Start(void)
{
  SDA_H;
  delay(5);
  SCL_H;
  delay(5);
  SDA_L;
  delay(5);
}
/********************************************************/
/************************STOP****************************/
void Stop(void)
{
  SDA_L;
  delay(5);
  SCL_H;
  delay(5);
  SDA_H;
  delay(5);
}
/********************************************************/
/***********向I2C总线发送一个字节+接收一个ACK************/
void SendByte(u8 Dat)
{
  u8 i=0;
  u8 T_Data=0;
 
  setsda();//DDRD|=(1<<1);//输出
  SCL_L;
  delay(10);
  T_Data=Dat;
  for(i=0;i<8;i++)
    {          
 
          if(T_Data&0x80)
            SDA_H;
          else
            SDA_L;
          delay(5);
         SCL_L;
          delay(5);
          SCL_H;
          delay(5);
          T_Data=T_Data<<1;
          SCL_L;
          delay(5);
   }
  SDA_H;//释放总线
  delay(5);
  SCL_L;     /*********************/
  delay(5);//接收一个ACK,不做处理
  SCL_H;     /*********************/
  delay(5);   SCL_L;
}
/********************************************************/
/**********从I2C总线上读取一个字节+发送一个ACK***********/
u8 ReceiveByte(u8 b)
{
  u8 i;
  u8 temp;
  u8 Dat=0;
/*
  SDA_H;
  delay(5);
  SCL_L;
  delay(5);
*/
  clrsda();//DDRD&=~(1<<1);//输入
  for(i=0;i<8;i++)
    {
          SCL_H;
      delay(5);           Dat=Dat<<1;
          delay(5);
    if(SDA){temp=1;}
    else{temp=0;}
          if(temp)
            Dat|=0x01;
          else
            Dat|=0x00;
         delay(5);
         SCL_L;
          delay(5);
    }
  setsda();//DDRD|=(1<<1);//输出
 
  if(b)//每收一个数后发送ACK或nACK
    SDA_H;
  else
    SDA_L;
       
  delay(5);
  SCL_H;
  delay(5);
  SCL_L;
  delay(5);
  SDA_H;        //释放总线
  delay(100);
  return Dat;
}
/****************************************************/
/***********将一个字节写入DS3231指定的地址***********/
void I2cByteWrite(u8 device,u8 addr,u8 bytedata)
{
  Start();
  delay(5);
  SendByte(device);
  delay(5);
  SendByte(addr);
  delay(5);
  SendByte(bytedata);
  delay(5);
  Stop();
}
/****************************************************/
/************从DS3231指定的地址读一个字节************/
u8 I2cByteRead(u8 device,u8 addr)
{
  u8 Dat=0;
 
  Start();
  SendByte(device);
  delay(5);
  SendByte(addr);
  delay(5);
  Start();//Restart
  SendByte(0xd1);//读数
  delay(5);
  Dat=ReceiveByte(1);//只接收一个字节,所以发nACK
  Stop();
  return Dat;
}
/***************************************************/
/*********************读取时间**********************/
void Readtime(void)
{
  year=I2cByteRead(0xd0,0x06);  //年
  month=I2cByteRead(0xd0,0x05); //月
  date=I2cByteRead(0xd0,0x04);  //日
  hour=I2cByteRead(0xd0,0x02);  //时
  minute=I2cByteRead(0xd0,0x01);//分
  second=I2cByteRead(0xd0,0x00);//秒
}
/***************************************************/
/****************修改时间,BCD码输入*****************/
void ModifyTime(u8 yea,u8 mon,u8 da,u8 hou,u8 min,u8 sec)
{
  u8 temp=0;
 
  temp=B_BCD(yea);
  I2cByteWrite(0xD0,0x06,temp);//修改年
 
  temp=B_BCD(mon);
  I2cByteWrite(0xD0,0x05,temp);//修改月
  
  temp=B_BCD(da);
  I2cByteWrite(0xD0,0x04,temp);//修改日
 
  temp=B_BCD(hou);
  I2cByteWrite(0xD0,0x02,temp);//修改时
 
  temp=B_BCD(min);
  I2cByteWrite(0xD0,0x01,temp);//修改分
 
  temp=B_BCD(sec);
  I2cByteWrite(0xD0,0x00,temp);//修改秒
} /****************************************************/
/****************读取时间 计算 并显示****************/
void get_show_time(void)
{
//year,month,date,hour,minute,second; year=I2cByteRead(0xd0,0x06);  //年
year=BCD2HEX(year);
month=I2cByteRead(0xd0,0x05);  //月
month=BCD2HEX(month);
date=I2cByteRead(0xd0,0x04);  //日
date=BCD2HEX(date);
  hour=I2cByteRead(0xd0,0x02);  //时 24小时制
hour&=0x3f;                  
hour=BCD2HEX(hour);
minute=I2cByteRead(0xd0,0x01);  //分
minute=BCD2HEX(minute);
 
 
second=I2cByteRead(0xd0,0x00);  //秒
second=BCD2HEX(second);
} void setsda(void)
{
GPIOA->CRL&=0xf0ffffff;
GPIOA->CRL|=0x02000000;
}
void clrsda(void)
{
GPIOA->CRL&=0xf0ffffff;
GPIOA->CRL|=0x04000000 ; }

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
13条回答
狼烟四起
1楼-- · 2019-10-16 01:07
一般是模拟I2C的时序不符合要求,用示波器钳一下看看波形。前段时间在自己的板子上调试24C04,程序用的是原子的代码 ,调了好几天调不出来,能读但不能写。后来在原程序上的某些延时点调整了一下,就正常了。
狼烟四起
2楼-- · 2019-10-16 02:57
我的板子上24C04与DS3231是同挂在一条I2C模拟总线上,24C04程序改好了,DS3231没有调。现在主要是在做界面,7吋800X480,等界面做得差不多了,再来搞实时时钟。STM32支持的RAM太小了,大屏无法实现流畅的滑屏特效。
qingtian305
3楼-- · 2019-10-16 08:28
 精彩回答 2  元偷偷看……
huang137
4楼-- · 2019-10-16 12:53
楼主你好,小弟刚好要用STM32 驱动DS3231,把你的代码移植过来,怎么弄都读不到数据,只读秒,全部是高电平,完全无数据,看波形也是一样,请问楼主你公布的代码是调试成功了的代码吗?
jinfahua
5楼-- · 2019-10-16 13:22
楼主的问题解决了吗?我用STM32F103模拟IIC操作DS3231成功了,采用秒中断方式,需要的话我就把程序传上来。
灰太狼小灰兔
6楼-- · 2019-10-16 17:03
回复【6楼】jinfahua:
---------------------------------
5楼您哈,用硬件很难么?

一周热门 更多>