跳转至

STM32 驱动 DS1302

项目开源链接

手机上可以点击下方的右上角复制,然后软件就可以自动打开了。

我用夸克网盘给你分享了「STM32ClockLab」,点击链接或复制整段内容,打开「夸克APP」即可获取。 /~33fc3bKR34~:/ 链接:https://pan.quark.cn/s/ba1c83849941
网页上可以点击链接:https://pan.quark.cn/s/ba1c83849941

有问题可以展开联系我

微信号:Qhua_Li7

DS1302的处理,这是我正在做的一个练习项目的一部分,如果只看关于DS1302的部分,查看 02_Firmware\01_DS1302_ReadWrite 的代码即可。

项目说明

这篇文章所讲内容,是我在看 DS1302 时候的一点记录,也是想把整个项目的学习过程做一个记录。所以可能后续会每完成一个项目点,做一点总结,感兴趣的朋友可以关注一下这个仓库的项目,但是这是学习项目,所以可能代码不那么严谨,如果有建议,欢迎交流。

DS1302 介绍

关于 DS1302 其实使用的比较多了,就是一个时钟芯片。可设置和读取年月日时分秒星期。

说一些我以前学习没有注意的地方。

  • 可操作寄存器除了年、月、日、时、分、秒、星期、控制,这8个寄存器,还有一个充电寄存器,但是我现在也还未作过多了解。
  • 还有31字节的非易失性 RAM。这个我以前不知道,这个RAM可以用来存一些变量,但是以前没有使用过。询问Ai用途,他说这个可以用来存储一些时钟设置,比如是否断过电。
  • 时钟那8个寄存器可以多字节读写,不带充电寄存器。31字节的 RAM 也可以多字节读写。(以前一直是单字节读写使用,好像单字节读写也不会耗太多时间,显得这个多字节读写好像没那么必要)

有人知道那个 非易失性 RAM 有什么实际上的作用吗?请教一下。不知道其他的时钟芯片是不是也有这种东西。

DS1302 软件设计

用户接口

对 DS1302 的操作,无非就是3个引脚IO的控制,CLK、DATA、RST。其中,DATA引脚需要具备可读可写的功能。我将用户接口放在了文件的最开始,需要自己替换代码中的内容。

1
2
3
4
5
6
7
static void ds1302_gpio_init(void);
static void ds1302_set_clk_output(uint8_t state);
static void ds1302_set_data_gpio_mode(uint8_t mode);
static void ds1302_set_data_output(uint8_t state);
static uint8_t ds1302_get_data_input(void);
static void ds1302_set_rst_output(uint8_t state);
static void ds1302_delay_us(u8 xus);

这些函数,需要用户替换成自己的操作,如果你和我一样是STM32F103的话,就只需要改我最上面的 define 定义了。

1
2
3
4
5
6
7
8
9
#define CLK_PORT_CLK  (RCC_APB2Periph_GPIOA)
#define CLK_PORT  GPIOA
#define CLK_PIN   GPIO_Pin_0
#define DATA_PORT_CLK  (RCC_APB2Periph_GPIOA)
#define DATA_PORT GPIOA
#define DATA_PIN  GPIO_Pin_1
#define RST_PORT_CLK  (RCC_APB2Periph_GPIOA)
#define RST_PORT  GPIOA
#define RST_PIN   GPIO_Pin_2

在这里我提一个自己之前遇到的问题,就是在切换引脚状态的时候,初始化引脚为输出模式,一定要把配置写全,我就是因为配置输出没有带上 SPEED 的配置,导致输出配置失败,但是却又看不出来,一开始还以为是自己读写时序写错了。

就是下面这个函数,最开始我没有写 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 这一行。

static void ds1302_set_data_gpio_mode(uint8_t mode)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    if (mode == 0)
    { 
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_InitStructure.GPIO_Pin = DATA_PIN;
        GPIO_Init(DATA_PORT, &GPIO_InitStructure);
    }
    else
    { 
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Pin   = DATA_PIN;
        GPIO_Init(DATA_PORT, &GPIO_InitStructure);
    }   
}

DS1302 读写单字节

读写单字节的方式比较简单,看时序图即可,大概可以总结几点。

  • RST 在置为有效后,需要等几 US 的数据稳定。
  • 需要写入数据的时候,DAT把数据准备好,然后CLK给一个上升沿
  • 需要读取 BIT 数据的时候,一个CLK下降沿,数据准备好一个,读出来后执行下一个下降沿。
  • 中间还有很多时刻需要延时,这个看时序图,但是很多时候的时间感觉都不是很长,我在代码中有做一点注释。

具体的实现方式可以看我的开源代码中的

static void ds1302_write_byte(uint8_t w_addr, uint8_t w_byte)
static void ds1302_read_byte(uint8_t r_addr, uint8_t *r_byte)

ds1302 的 时钟寄存器有 8 个,再配合一个充电寄存器,都是可以单独读写的。

alt text

寄存器比较特殊的地方有如下:

  • 秒里面有个 CH 起振位,它为 0 时钟才会启动
  • 控制寄存器里面有个写保护位,为 0 才能写入数据。
  • 数据存储方式是 BCD 码,如果要转10进制,需要转换。
  • 小时寄存器比较特殊,bit7 代表是12小时制还是24小时制,bit5 在 12 小时制的时候有上午下午之分。

具体的读写设置,可以看我的下面这两个函数:

int8_t ds1302_set_datetime(const ds1302_datetime_t *dt) 
int8_t ds1302_get_datetime(ds1302_datetime_t *dt)

DS1302 读写 RAM

之前讲到,DS1302 有31字节的非易失性 RAM。他们也是可以读写的,他们的起始地址是 0xC0。

alt text

注意最低位是读写位,地址都是从 Bit1 往上加的,我的读写函数中,在读的时候把地址 |0X01 所以就没有管读写位。

这个 RAM 我也测试通过了,但是暂时不知道有什么用。

使用函数如下:

uint8_t ds1302_read_ram(uint8_t addr, uint8_t *data) ;
uint8_t ds1302_write_ram(uint8_t addr, uint8_t data) ;

我这里给的 addr 你直接填 0 - 30 即可,在函数中做了地址转换。

DS1302 读写多字节

DS1302 是可以读写多字节的,读写方式就是,写了地址后,连续读或者写多个字节。具体的实现在以下API:

static void ds1302_write_bytes(uint8_t w_addr, const uint8_t w_byte[],uint8_t w_len)
static void ds1302_read_bytes(uint8_t r_addr, uint8_t *r_byte, uint8_t r_len)

读取设置时钟,最多可控制8个字节,写的地址是 0xBE,连续读写分别控制 秒、分、时、日、月、星期、年、控制寄存器。只能按照这个顺序。

alt text

读取设置RAM,最多可控制31个字节,写的地址是 0xEF,连续读写寄存器,只能按照顺序,比如你配置长度5,那就是读写的前5个RAM字节。

alt text

关于时钟设置的多字节读取,我在时钟设置函数中用 CLOCK_USE_MULTI_BYTE_READ_WRITE 这个宏定义来打开关闭。

总结

以上便是全部内容了,后续如果有更新,会在文章中注上更新说明。