SPI接口DS1302时钟芯片操作

  今天,又花了差不多一天时间,从手册看起,到写完代码,最后仿真。期间出现了一个细小的差错,折腾了约1个钟头才解决掉(所以,最怕底层细小之处出现错误)。

DS1302是达拉斯公司出品的一款实时时钟芯片。具体且详细的资料介绍在其芯片手册上面都有写着。说起来自己读DS1302芯片手册,也花了不少精力,主要是对一个问题一直没理解。

下图是DS1302时钟寄存器的结构。(注意左边READ与WRITE两列)

                       

下图是DS1302的命令字节(就是跟它通信的格式)

 

  其中A4到A0可以代表寄存器的地址。我想,5bit表示的地址,翻遍了手册,在上面也没有说明5bit的地址是怎么表示的(手册上只有读写地址,8bit)。就这样,我纳闷了,就去问问搜索引擎。网上挂出来最多的尽是些代码(说实话,驱动代码不难写,难的是对芯片的理解),最终还是找到了一篇博文(写了对DS1302的理解),而且我才焕然大悟,原来READ与WRITE两列是什么的。

  举个例子:写秒寄存器的地址是0x80,展开成8bit的就是1000,0000(结合命令字节看看),你会发现其实就是命令字节。

  现在来说说DS1302的SPI接口(其实比标准的SPI接口少了一根线),它包含RST线、SCLK线、IO线(双向传送数据用,标准的SPI则将其分成两根MISO与MOSI)3条接线。

 

  上面这张图片就是其时序图,单字节读取和单字节写。相比1条线的单总线、2条线的IIC,这个SPI貌似是最简单的。每次传送时,需要先发送8bit命令字节,再发送/接收8bit数据。

  再细小的看,CE(也就是RST)先拉至高电平,在IO线上事先要准备好数据,然后将SCLK拉高,一个上升沿,发完了1bit。如此往复,发完接下来的几位。如果是发送数据的话,注意每次都是上升沿发送1bit。如果是接收数据的话,注意,在传完最后命令字节的1(高电平)之后的第一个下降沿后DS1302发送数据。当然DS1302能够每次传送多个字节。

  说完了通信机制,通信内容,基本上差不多了。值得提醒的是,DS1302内部有31字节RAM,可以用来保存数据。

  今天写的有点少。下面贴上调好的代码:

头文件部分:

#ifndef __hal_ds1302_h__
#define __hal_ds1302_h__

#include<reg52.h>
#include"datatype.h"
#include"delay.h"
#include"hal.h"

sbit rst=P3^2;
sbit sclk=P3^3;
sbit sda_ds1302=P1^7;

#define RST rst
#define SCLK sclk
#define SIO sda_ds1302

#define WRITE_SECONDS    0x80//
#define READ_SECONDS    0x81
#define WRITE_MINUTES    0x82//
#define READ_MINUTES    0x83
#define WRITE_HOUR        0x84//
#define READ_HOUR        0x85
#define WRITE_DATE        0x86//
#define READ_DATE        0x87
#define WRITE_MONTH        0x88//
#define READ_MONTH        0x89
#define WRITE_DAY        0x8a//星期
#define READ_DAY        0x8b
#define WRITE_YEAR        0x8c//
#define READ_YEAR        0x8d
#define WRITE_WP        0x8e//写保护bit7为高时,不允许写
#define READ_WP            0x8f//所以写之前需将其设为0


//ds1302时间结构体类型
struct ds1302_time
{
    //秒0-59
    uchar seconds;
    //分0-59
    uchar minutes;
    //时0-23(24小时模式)
    //如果需要12小时模式,跟寄存器格式需要一致
    uchar hour;
    //星期1-7
    enum{Sunday=1,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday} day;
    //日1-31
    uchar date;
    //月1-12
    uchar month;
    //年0-99
    uchar year;
};

//参数1:写保护;参数0:取消写保护
#define HAL_DS1302_WRITE_PROTECT(wp) hal_ds1302_single_byte_write(WRITE_WP,wp?0x80:0x00)

void hal_ds1302_init();
void hal_ds1302_single_byte_write(uchar comm,uchar val);
uchar hal_ds1302_single_byte_read(uchar comm);

void hal_ds1302_init_time(struct ds1302_time time);
void hal_ds1302_get_time(struct ds1302_time * time);

#endif

C文件部分:

  1 #include"hal_ds1302.h"
  2 
  3 void hal_ds1302_init()
  4 {
  5     RST=0;
  6     SCLK=0;
  7     SIO=1;
  8 }
  9 
 10 //实质上传送了16bit
 11 void hal_ds1302_single_byte_write(uchar comm,uchar val)
 12 {
 13     //RST低电平    SCLK低电平
 14     uchar i;
 15     RST=1;
 16     for(i=0;i<8;i++)//从低位开始传送
 17     {
 18         if(comm&(0x01<<i))
 19             SIO=1;
 20         else
 21             SIO=0;
 22         SCLK=1;//SCLK一个上升沿,读取了SDA上的电平
 23         //单片机时钟周期1us情况下,几乎不用考虑延时
 24         SCLK=0;
 25     }
 26     for(i=0;i<8;i++)
 27     {
 28         if(val&(0x01<<i))
 29             SIO=1;
 30         else
 31             SIO=0;
 32         SCLK=1;//上升沿读取
 33         SCLK=0;
 34     }
 35     RST=0;
 36     //RST低电平    SCLK低电平    SDA电平未知
 37 }
 38 
 39 //实质上传送了16bit
 40 uchar hal_ds1302_single_byte_read(uchar comm)
 41 {
 42      //RST低电平  SCLK低电平
 43      uchar i,tmp=0;  
 44      RST=1;
 45      for(i=0;i<8;i++)
 46      {
 47          SCLK=0;//放在这儿是为了第8次SCLK依旧是高电平
 48          if(comm&(0x01<<i))
 49             SIO=1;
 50         else
 51             SIO=0;
 52         SCLK=1;//上升沿,DS1302读取值    
 53      }
 54      //现在SCLK依旧是高电平
 55      //而且达拉斯考虑到了总线释放问题,所以传送的最后一位都为1
 56      for(i=0;i<8;i++)
 57      {
 58          SCLK=1;//放在此处是为了i=7时候,SCLK仍为低电平
 59          SCLK=0;//下降沿,DS1302输出数据
 60         if(SIO)
 61             tmp=tmp|(0x01<<i);    
 62      }    
 63      RST=0;
 64      return tmp;
 65      //RST低电平  SCLK低电平  SDA电平状态未知
 66 }
 67 
 68 //参数char类型16进制
 69 //传出2个4位BCD码组成的8bit数据
 70 uchar hal_ds1302_uchar2BCD(uchar val)
 71 {
 72     uchar shi=0,ge=0;
 73     shi=val/10%10;
 74     ge=val%10;
 75     return (shi<<4)|ge;
 76 }
 77 
 78 uchar hal_ds1302_BCD2uchar(uchar val)
 79 {
 80     uchar shi=0,ge=0;
 81     shi=val>>4;
 82     ge=val&0x0f;//小心,就是这儿0x0f写错了,不是0xf0
 83     return shi*10+ge;
 84 }
 85 
 86 //1.设置写保护位为0
 87 //2.设置秒字节,同时将bit7置1(暂停计时)
 88 //3.设置年、月、日、星期、时、分
 89 //4设置秒字节,晶振起震
 90 //5.设置写保护字节bit7为1
 91 //6.之后可以读取时间了
 92 void hal_ds1302_init_time(struct ds1302_time time)
 93 {
 94     HAL_DS1302_WRITE_PROTECT(0);
 95     delay_ms(1);
 96     hal_ds1302_single_byte_write(WRITE_SECONDS,0x80);
 97     delay_ms(1);
 98     hal_ds1302_single_byte_write(WRITE_YEAR,hal_ds1302_uchar2BCD(time.year));
 99     delay_ms(1);
100     hal_ds1302_single_byte_write(WRITE_MONTH,hal_ds1302_uchar2BCD(time.month));
101     delay_ms(1);
102     hal_ds1302_single_byte_write(WRITE_DATE,hal_ds1302_uchar2BCD(time.date));
103     delay_ms(1);
104     hal_ds1302_single_byte_write(WRITE_DAY,hal_ds1302_uchar2BCD(time.day));
105     delay_ms(1);
106     hal_ds1302_single_byte_write(WRITE_HOUR,hal_ds1302_uchar2BCD(time.hour));
107     delay_ms(1);
108     hal_ds1302_single_byte_write(WRITE_MINUTES,hal_ds1302_uchar2BCD(time.minutes));
109     delay_ms(1);
110       hal_ds1302_single_byte_write(WRITE_SECONDS,hal_ds1302_uchar2BCD(time.seconds));
111     delay_ms(1);
112     HAL_DS1302_WRITE_PROTECT(1);
113 }
114 
115 //注意对12小时模式没有进行编写,如有需要,需要额外修改
116 void hal_ds1302_get_time(struct ds1302_time * time)
117 {
118     time->year=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_YEAR));
119     delay_ms(1);
120     time->month=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_MONTH));
121     delay_ms(1);
122     time->date=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_DATE));
123     delay_ms(1);
124     time->day=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_DAY));
125     delay_ms(1);
126     time->hour=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_HOUR));
127     delay_ms(1);
128     time->minutes=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_MINUTES));
129     delay_ms(1);
130     time->seconds= hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_SECONDS));    
131 }
原文地址:https://www.cnblogs.com/yulongchen/p/2890148.html