OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 10366|回复: 4

有玩ds3231的吗,帮忙看看问题出在哪儿?

[复制链接]

7

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
194
金钱
194
注册时间
2012-2-28
在线时间
35 小时
发表于 2012-4-3 16:49:31 | 显示全部楼层 |阅读模式

 红色标记处及问题所在,反正ds3231驱动不了
#include <STC89.h>
#include <intrins.h>

#define uchar unsigned char
#define uint unsigned int
/********1602定义***********************/
#define LCD_DB P0
  sbit LCD_RS=P2^1;//0为指令,1为写数据
  sbit LCD_RW=P2^2;//0可写入,1为读
  sbit LCD_E=P2^5;//1允许

/*******ds3231相关定义*********/

/**************************** defines *******************************/
sbit    SCL = P1^7;             /* I2C pin definitions */
sbit    SDA = P1^6;
sbit    int0 = P3^2;
sbit    rest = P3^6;

#define ADDRTW  0xD0    //器件写地址
#define ADDRTD  0xD1 //器件读地址
//#define DS3231_WriteAddress 0xD0    //器件写地址
//#define DS3231_ReadAddress  0xD1    //器件读地址

#define DS3231_SEC 0x00    //秒
#define DS3231_MIN 0x01    //分
#define DS3231_HOUR 0x02    //时
#define DS3231_DAY 0x03    //星期
#define DS3231_DATE 0x04    //日
#define DS3231_MONTH    0x05    //月
#define DS3231_YEAR 0x06    //年
//闹铃1           
#define DS3231_Al1SEC 0x07    //秒
#define DS3231_AL1MIN 0x08    //分
#define DS3231_AL1HOUR 0x09    //时
#define DS3231_AL1DAY 0x0A    //星期/日
//闹铃2
#define DS3231_AL2MIN 0x0b    //分
#define DS3231_AL2HOUR 0x0c    //时
#define DS3231_AL2DAY 0x0d    //星期/日
#define DS3231_CONTROL 0x0e    //控制寄存器
#define DS3231_STATUS 0x0f    //状态寄存器


#define BSY             2       //忙
#define OSF             7       //振荡器停止标志
#define DS3231_XTAL     0x10    //晶体老化寄存器
#define DS3231_TEMP_H 0x11    //温度寄存器高字节(8位)
#define DS3231_TEMP_L 0x12    //温度寄存器低字节(高2位) 

//extern xdata uchar   sec, min, hour, day, date, month, year,Dtemp;
//extern xdata uchar al1_min,al1_hour,al1_day,al2_min,al2_hour,al2_day;
uchar year,month,date,day,hour,min,sec,Dtemp=0;
uchar al1_min,al1_hour,al1_day,al2_min,al2_hour,al2_day;

/*********************** Function Prototypes **************************/
uchar BCD2HEX(uchar val);
uchar B_BCD(uchar val);
void delayus(uchar i);
void    Start();
void    Stop();
void I2CACK(bit a);
void SendByte(uchar Dat);
uchar ReceiveByte(uchar b);
uchar I2CWrite(uchar addr,uchar bytedata);
uchar I2CRead();
uchar I2CReadAdd(uchar addr);
void    read_temp();
void    init_alrm();
void Readtime();
void ReadAlarm();
void SetTime(uchar yea,uchar mon,uchar da,uchar hou,uchar min,uchar sec);
void InitDS3231();
bit  runnian();
void autoweek();

bit ack;

uchar qushi;

/*******按键定义******/
sbit KEY  = P3^2;


void InitTimer0(void);
//要在哪行那位显示啥就修改a和b
 uchar idata c[]="ABCDEFGHIJKLMNOP";//显示字符串,一行最多16个字母
 uchar idata d[]="0123456789abcdef";
 uchar idata num[10]="0123456789";//数字表
 uchar a[16]="2000-00-00 Day 0";//显示字符串,一行最多16个字母
 uchar b[16]="00-00-00  00C   ";
   //////////"0123456789123456";

/******定义函数****************/


#define Busy 0x80 //DB7为1时表示忙,为0时表示闲
#define SomeNOP(); { _nop_(); }//空函数,用于微小延时,包含在intrins.h


void LCD_init(void);//初始化函数
void WaitForEnable( void );
void LCD_write_command(uchar dat,uchar AttribC);//写指令函数
void LCD_write_data(uchar dat);//写数据函数
void LCD_disp_addw(uchar x,uchar y,uchar dat);//在某个屏幕位置上显示一个字符,X(0-16),y(1-2)
void LCD_disp_lin(uchar x,uchar y,uchar dat[],uchar s);

void Delay5Ms(void);//延时函数
//********************************
//*******初始化函数***************
void LCD_init(void)
{
LCD_write_command(0x38,0);//设置8位格式,2行,5x7
Delay5Ms();
LCD_write_command(0x38,0);//设置8位格式,2行,5x7
Delay5Ms();
LCD_write_command(0x38,0);//设置8位格式,2行,5x7
Delay5Ms();
LCD_write_command(0x38,1);//设置8位格式,2行,5x7
LCD_write_command(0x08,1);// 显示关闭
LCD_write_command(0x01,1);//清除屏幕显示
LCD_write_command(0x06,1);//设定输入方式,增量不移位
LCD_write_command(0x0c,1);//整体显示,无光标,闪烁,0x0c
Delay5Ms();
}


/*=======================================================
正常读写操作之前必须检测LCD控制器状态: CS=1 RS=0 RW=1
DB7: 0 LCD控制器空闲; 1 LCD控制器忙---忙信号检测函数
========================================================*/
void WaitForEnable( void )//测忙函数
{
LCD_DB=0xff;
LCD_RS=0;
LCD_RW=1;
SomeNOP();
LCD_E=1;
SomeNOP();
SomeNOP();
while(LCD_DB&Busy);
LCD_E=0;
}

//********************************
//********写指令函数************
void LCD_write_command(uchar dat,uchar AttribC)
{
if (AttribC) WaitForEnable(); // 检测忙信号
LCD_DB=dat;
LCD_RS=0;//指令
LCD_RW=0;//写入
LCD_E=1;//允许
SomeNOP();
LCD_E=0;
Delay5Ms();
}
//*******************************
//********写数据函数*************
void LCD_write_data(uchar dat)
{
LCD_DB=dat;
LCD_RS=1;//数据
LCD_RW=0;//写入
LCD_E=1;//允许
SomeNOP();
LCD_E=0;
Delay5Ms();
}
//********************************
//**指定显示位置******************
void LCD_disp_addw(uchar x,uchar y,uchar dat)
{
uchar address;
if(y==1)
  address=0x80+x;//第一行
if(y==2)
  address=0xc0+x;//第二行
LCD_write_command(address,0);
LCD_write_data(dat);
}

//********************************
//*******显示多个字符函数或向任意行的任意位置写任意个字符,但位置不能超过16个*********
//x表示开始位置,第一位为1;y表示行数;dat[]是要显示的内容;s表示内容的长度,最大16
void LCD_disp_lin(uchar x,uchar y,uchar dat[],uchar s)
{
 uchar ss;            
 if(s>16||x>16)return;//各种情况下保证不超过16位
 x=x-1;//为了符合自然习惯,在调用本函数是1代表末一行的第一位
 if(s+x>16)return;//各种情况下保证不超过16位
 
 for(ss=0;ss<s;ss++)
  {
   LCD_disp_addw(x++,y,dat[ss]);//指向每个字符,一个一个的写,x轴自动加1,y表示行
  }
}

// 短延时
void Delay5Ms(void)
{uchar w,i,j;  
  for(w=5;w>0;w--)
  for(i=2;i>0;i--)
  for(j=255;j>0;j--);
}

 

/************************************************************/

/**********开始3231***********/
uchar BCD2HEX(uchar val)   //BCD转换为Byte
{
uchar i;
    i= val&0x0f;
    val >>= 4;
    val &= 0x0f;
    val *= 10;
    i += val;
   
    return i;
}

uchar B_BCD(uchar val)//B码转换为BCD码
{
uchar i,j,k;

  i=val/10;
  j=val%10;
  k=j+(i<<4);
  return k;
}

void delayus(uchar i)
{
   while(--i) ;
}
/************************START***************************/
void Start()
{
    SDA=1;                  //发送起始条件的数据信号
    delayus(1);
    SCL=1;
    delayus(5);             //起始条件建立时间大于4.7us,延时
  
    SDA=0;                  //发送起始信号
    delayus(5);             // 起始条件锁定时间大于4μs
      
    SCL=0;                  //钳住I2C总线,准备发送或接收数据
    delayus(2);
}
/********************************************************/
/************************STOP****************************/
void Stop()
{
    SDA=0;                  //发送结束条件的数据信号
    delayus(1);             //发送结束条件的时钟信号
    SCL=1;                  //结束条件建立时间大于4us
    delayus(5);
  
    SDA=1;                  //发送I2C总线结束信号
    delayus(4);
}
/********************************************************/
/*******************************************************************
                  字节数据发送函数              
函数原型:     void   SendByte(uchar Dat);
功能:      将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
           此状态位进行操作.(不应答或非应答都使ack=0)
           ack=1        发送数据正常,
           ack=0        被控器无应答或损坏。
********************************************************************/
void SendByte(uchar Dat)
{
uchar BitCnt;
  
    for(BitCnt=0;BitCnt<8;BitCnt++)         //要传送的数据长度为8位
    {
        if((Dat<<BitCnt)&0x80)
            SDA=1;                          //判断发送位
        else
            SDA=0;              
          delayus(1);
          SCL=1;                            //置时钟线为高,通知被控器开始接收数据位
          delayus(5);                       //保证时钟高电平周期大于4μs  
          SCL=0;
    }
  
    delayus(2);
    SDA=1;                                  //8位发送完后释放数据线,准备接收应答位
    delayus(2); 
    SCL=1;
    delayus(3);
    if(SDA==1)
        ack=0;   
    else
        ack=1;                              //判断是否接收到应答信号
    SCL=0;
    delayus(2);
}
/********************************************************/
/*******************************************************************
                  字节数据接收函数              
函数原型:     uchar   RcvByte();
功能:      用来接收从器件传来的数据,并判断总线错误(不发应答信号),
           发完后请用应答函数应答从机。 
********************************************************************/
uchar RcvByte()
{
uchar retc;
uchar BitCnt;
 
   retc=0;
   SDA=1;                           //置数据线为输入方式
   for(BitCnt=0;BitCnt<8;BitCnt++)
   {
        delayus(1); 
        SCL=0;                      //置时钟线为低,准备接收数据位
      
        delayus(5);                 //时钟低电平周期大于4.7μs
     
        SCL=1;                      //置时钟线为高使数据线上数据有效
        delayus(3);
        retc=retc<<1;
        if(SDA==1)
            retc=retc+1;            //读数据位,接收的数据位放入retc中
        delayus(2);
   }
   SCL=0;
   delayus(2);
   return(retc);
}
/********************************************************************
                      应答子函数
函数原型:   void I2CACK(bit a);
功能:       主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
********************************************************************/
void I2CACK(bit a)
{
 
    if(a==0)
        SDA=0;              //在此发出应答或非应答信号
    else
        SDA=1;
    delayus(3);    
    SCL=1;
  
    delayus(5);             //时钟低电平周期大于4μs
  
    SCL=0;                  //清时钟线,钳住I2C总线以便继续接收
    delayus(2);  
}
/****************************************************/
/***********将一个字节写入DS3231指定的地址***********/
uchar I2CWrite(uchar addr,uchar bytedata)
{
 Start();
    SendByte(ADDRTW);
    if (ack == 0)
        return 0;
  
    SendByte(addr);  
    if (ack == 0)
        return 0;
  
    SendByte(bytedata);
    if (ack == 0)
        return 0;
  
    Stop();
    delayus(10);     
    return 1;
}
/****************************************************/
/************从DS3231当前地址读一个字节************/
uchar I2CRead()
{
uchar read_data;

    Start();
    SendByte(ADDRTD);
    if(ack==0)
    {
  LCD_disp_addw(11,1,'t');  /////
  return(0);
    } 
    read_data = RcvByte();
    I2CACK(1);
    Stop();
    return read_data;
}

/****************************************************/
/************从DS3231指定地址读一个字节************/
uchar I2CReadAdd(uchar addr)
{
    Start();
    SendByte(ADDRTD);
    if(ack==0)
    {
  LCD_disp_addw(12,1,'x');/////读不出来
  return(0);
    } 
    SendByte(addr);
    if(ack==0)
    {
  LCD_disp_addw(13,1,'y');
  return(0);
    } 
    return(I2CRead());
}
/***************************************************/
/*********************读取时间**********************/
void Readtime()
{
uchar temp;
 
  temp=I2CReadAdd(DS3231_SEC);//秒
  sec=BCD2HEX(temp);
  temp=I2CReadAdd(DS3231_MIN);//分
  min=BCD2HEX(temp);
  temp=I2CReadAdd(DS3231_HOUR);  //时
  //temp&=0x3F;
  hour=BCD2HEX(temp);
  day=I2CReadAdd(DS3231_DAY);//星期
  temp=I2CReadAdd(DS3231_DATE);  //日
  date=BCD2HEX(temp);
  temp=I2CReadAdd(DS3231_MONTH); //月
  month=BCD2HEX(temp);
  temp=I2CReadAdd(DS3231_YEAR);  //年
  year=BCD2HEX(temp);
  Dtemp=I2CReadAdd(DS3231_TEMP_H);//温度
}
/***************************************************/
/*******************读取闹铃时间********************/
void ReadAlarm()
{
uchar temp;
 
  temp=I2CReadAdd(DS3231_AL1MIN);//分
  al1_min=BCD2HEX(temp);
  temp=I2CReadAdd(DS3231_AL1HOUR);  //时
  al1_hour=BCD2HEX(temp);
  temp=I2CReadAdd(DS3231_AL1DAY);  //星期or日
  al1_day=BCD2HEX(temp);
  temp=I2CReadAdd(DS3231_AL2MIN);//分
  al2_min=BCD2HEX(temp);
  temp=I2CReadAdd(DS3231_AL2HOUR);  //时
  al2_hour=BCD2HEX(temp);
  temp=I2CReadAdd(DS3231_AL2DAY);  //星期or日
  al2_day=BCD2HEX(temp);
}


bit runnian()//闰年判断
{
 if((year%4==0&&year%100!=0)||(year%100==0&&year%400==0))
 {
  return 1;
 }
 else
 {
  return 0;
 }


}

void autoweek()
{
 Readtime();
 if( month == 1 || month == 2 ) 
    {
        month += 12;
        if( year> 0 )
            year--;
        else
            year = 4;
    }
 day = (1+(( date + 2*month + 3*(month+1)/5 + year + year/4 ) %7));
 I2CWrite(DS3231_DAY,day);
}

void InitDS3231()
{
 SCL=1;
 delayus(5);
 SDA=1;
 delayus(5);
 I2CWrite(DS3231_AL1DAY,0x81); //A1M4置位,时分秒匹配时闹钟响应
 I2CWrite(DS3231_AL2DAY,0x81); //A2M4置位,时分匹配时闹钟响应
 I2CWrite(DS3231_CONTROL,0x04); //中断允许,闹钟1和2关闭
 I2CWrite(DS3231_STATUS,0x00); //32KHZ输出禁止,闹钟标志位清零
 //SetTime(11,1,14,8,10,0);
}

 

/**********3231函数结束******/

void TimeDisplay(uchar Dhour,uchar Dmin,uchar Dsec)
{
    b[0]=num[Dhour / 10];        // 时十位
    b[1]=num[Dhour % 10];        // 时个位
    b[3]=num[Dmin / 10];         // 分十位
    b[4]=num[Dmin % 10];         // 分个位
    b[6]=num[Dsec / 10];         // 秒十位
    b[7]=num[Dsec % 10];         // 秒个位
  
}

 //uchar a[]="2000-00-00 Day 0";//显示字符串,一行最多16个字母
 //uchar b[]="00-00-00  00C   ";
 ////////////"0123456789123456";

 

void DateDisplay(uchar Dyear,uchar Dmonth,uchar Dday)
{
    a[2]=num[Dyear / 10];        // 年十位
    a[3]=num[Dyear % 10];        // 年个位
    a[5]=num[Dmonth / 10];       // 月十位
    a[6]=num[Dmonth % 10];       // 月个位
    a[8]=num[Dday / 10];         // 天十位
    a[9]=num[Dday % 10];         // 天个位
  
}


/*******定时器0*****/
void InitTimer0(void)//定时器0开,模式1,时长50ms
{
    EA = 1;
    TMOD = 0x01; 
    ET0 = 1;
    TH0 = 0x3C;
    TL0 = 0xB0;   
    TR0 = 1;
}


void Timer0Interrupt(void) interrupt 1
{
  qushi=qushi+1;
  if(qushi==8)//ds3231取时间隔400ms
   {
    qushi=0;
 Readtime();  //显示时间

 Delay5Ms();
 Delay5Ms();
 Delay5Ms();
 DateDisplay(year,month,date);
 TimeDisplay(hour,min,sec);
 //字符串显示
 //函数原型void LCD_disp_lin(uchar x,uchar y,uchar dat[],uchar s)
 //x表示开始位置,第一位为1;y表示行数;dat[]是要显示的内容;s表示内容的长度,最大16
    LCD_disp_lin(1,1,a,16);//从指定显示位置显示多个字符,这里指第1行第1位开始
    LCD_disp_lin(1,2,b,16);//从指定显示位置显示多个字符,这里指第2行第1位开始
    Delay5Ms();
   }
 //在任意行的任意位置单个字母显示,原始函数,直接调用LCD_disp_addw,可以不用啦
 //LCD_disp_addw(0,1,'V');//从指定显示位置显示一个字符,这里指第1行第1位,每行最多16个字符
 //LCD_disp_addw(0,2,'Q');//从指定显示位置显示一个字符,这里指第2行第1位
   
 
  TR0 = 0;//重新装定定时器0
  TH0 = 0x3C;
     TL0 = 0xB0;
  TR0 = 1;
}

//*********主函数*****************
void main(void)
{
 
 LCD_init();//初始化
 LCD_disp_lin(1,1,c,16);//从指定显示位置显示多个字符,这里指第1行第1位开始
 LCD_disp_lin(1,2,d,16);//从指定显示位置显示多个字符,这里指第2行第1位开始
 Delay5Ms();
 Delay5Ms();
 Delay5Ms();
 rest=0;
 InitDS3231(); //初始化DS3231
 autoweek(); //开机自动星期转换

 Delay5Ms();
 Delay5Ms();
 Delay5Ms();
 
 qushi=0;                                     
 InitTimer0();//定时器0开,模式1,时长50ms

 while(1);
}

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2012-4-3 20:03:19 | 显示全部楼层
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2012-5-26
在线时间
19 小时
发表于 2012-5-26 02:57:59 | 显示全部楼层
 /************从DS3231指定地址读一个字节************/
uchar I2CReadAdd(uchar addr)
{
    Start();
    SendByte(ADDRTD);//-----应改为 SendByte(ADDRTW);
    if(ack==0)
    {
  LCD_disp_addw(12,1,'x');/////读不出来

  return(0);
    } 
    SendByte(addr);
    if(ack==0)
    {
  LCD_disp_addw(13,1,'y');
  return(0);
    } 
    return(I2CRead());
}
一起来DIY啊
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2012-5-26
在线时间
19 小时
发表于 2012-5-26 02:59:45 | 显示全部楼层
两个代码的正确含义:
#define ADDRTW  0xD0  //令DS3231芯片进入被写状态
#define ADDRTD  0xD1   //另DS3231芯片进入被读状态
一起来DIY啊
回复 支持 反对

使用道具 举报

2

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
88
金钱
88
注册时间
2012-9-12
在线时间
13 小时
发表于 2015-5-21 10:09:17 | 显示全部楼层
回复【3楼】x机器:
---------------------------------
为什么读写地址都是0XD0???
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 09:01

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表