zoukankan      html  css  js  c++  java
  • 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
Copyright © 2011-2022 走看看