[STM32F4] 使用STM32 HAL库读取RTC时间芯片SD3088

[复制链接]
634|11
 楼主| 欢乐家园 发表于 2022-9-26 23:27 | 显示全部楼层 |阅读模式
ST, sd, tc
美信的RTC芯片看起来不错,但是贵。

威帆的SD3088这个不错,而且还可以给电池充电,便宜很多,淘宝上价格6元一片。我这项目对时间要求严格,就不使用1元多的芯片了。


网传STM32F1的I2C有Bug,模拟通信最为保险。

威帆网站上的例子是模拟的,看起来也蛮简单。官方说0.5秒内读值就行,要求不高。


我这里是使用HAL库,先前使用I2C读过PCF8563,看起来也正常。


环境:

IAR7.40

STM32CUBEMX 4.10.0

STM32F1 V1.20


 楼主| 欢乐家园 发表于 2022-9-26 23:29 | 显示全部楼层
1、STM32CUBEMX配置I2C

按默认值。

不启用中断。

不使用DMA。
 楼主| 欢乐家园 发表于 2022-9-26 23:30 | 显示全部楼层
 楼主| 欢乐家园 发表于 2022-9-26 23:41 | 显示全部楼层
Pin配置
109826331c5e9800bc.png
 楼主| 欢乐家园 发表于 2022-9-26 23:53 | 显示全部楼层
2、启用Freertos
 楼主| 欢乐家园 发表于 2022-9-26 23:54 | 显示全部楼层
3、sd3088.h
  1. /*
  2. *文件 sd3088.h
  3. */
  4. #ifndef SD3088_H
  5. #define SD3088_H
  6. #include "i2c.h"
  7. #define DEBUG

  8. #ifdef DEBUG
  9. #include "stdio.h"
  10. #endif

  11. #define RTC_Addr 0x64  //RTC器件地址
  12. #define IDcode 0x72  //8字节ID号起始地址
  13. #define        Bat_High_Addr 0x1A  //电量最高位寄存器地址
  14. #define        Bat_Low_Addr 0x1B  //电量低八位寄存器地址

  15. #define BCD2DEC(x) (((x) >> 4) * 10 + ((x) & 0x0f))

  16. typedef struct
  17. {
  18.   uint8_t second;
  19.   uint8_t minute;
  20.   uint8_t hour;
  21.   uint8_t week;
  22.   uint8_t day;
  23.   uint8_t month;
  24.   uint8_t year;
  25.   uint8_t quantity;  // 电量
  26. }Time;

  27. extern Time Time_sd3088;        //初始化时间结构体变量(设置时间:2014年11月12日 14:59:55  星期一)

  28. void read_rtc(void);

  29. #endif
 楼主| 欢乐家园 发表于 2022-9-26 23:55 | 显示全部楼层
4、sd3088.c
/*
*SD3088时钟芯片 读写
*文件 sd3088.h
*作者 于
*麦知 www.mazclub.com
*版本 v1.0
*/
#include "sd3088.h"

extern I2C_HandleTypeDef hi2c1;

Time Time_sd3088 = {0x55, 0x59, 0x14, 0x01, 0x12, 0x11, 0x14};        //初始化时间结构体变量(设置时间:2014年11月12日 14:59:55  星期一)

uint8_t  rtc_data[8];                  //通用数据缓存器
uint8_t        sram[8];                //通用数据缓存器
uint8_t pdata;

void read_rtc(void)
{  
  // 读取时间
  pdata = 0;
  if(HAL_I2C_Master_Transmit(&hi2c1, 0x64, &pdata, 1, 1) == HAL_OK)
    if(HAL_I2C_Master_Receive(&hi2c1, 0x65, &rtc_data[0], 7, 1) == HAL_OK) {
      
      Time_sd3088.second = BCD2DEC(rtc_data[0] & 0x7f);
      Time_sd3088.minute = BCD2DEC(rtc_data[1] & 0x7f);
      Time_sd3088.hour = BCD2DEC(rtc_data[2] & 0x1f);
      Time_sd3088.week = BCD2DEC(rtc_data[3] & 0x07);
      Time_sd3088.day = BCD2DEC(rtc_data[4] & 0x3f);
      Time_sd3088.month = BCD2DEC(rtc_data[5] & 0x1f);
      Time_sd3088.year = BCD2DEC(rtc_data[6]);

    }
   
  // 电量
  pdata = 0x1b;
  if(HAL_I2C_Master_Transmit(&hi2c1, 0x64, &pdata, 1, 1) == HAL_OK)
    if(HAL_I2C_Master_Receive(&hi2c1, 0x65, &rtc_data[7], 1, 1) == HAL_OK) {
   
    Time_sd3088.quantity = BCD2DEC(rtc_data[7]);
  }
  
        
  #ifdef DEBUG
  printf("%d-%d-%d,week %d, %d:%d:%d, qualit:%d\r\n",Time_sd3088.year,Time_sd3088.month,Time_sd3088.day, \
       Time_sd3088.week,Time_sd3088.hour,Time_sd3088.minute,Time_sd3088.second, Time_sd3088.quantity);         
  #endif
  
}
 楼主| 欢乐家园 发表于 2022-9-26 23:57 | 显示全部楼层
存在的错误,读取 星期和电量不对。
563936331cb72b87a4.png
 楼主| 欢乐家园 发表于 2022-9-26 23:58 | 显示全部楼层
另在串口窗口看打印信息,这里照着老外抄了个简单的:

我是在生成的usart.c中
 楼主| 欢乐家园 发表于 2022-9-26 23:59 | 显示全部楼层
1)添加 变量定义,FILE已经定义,这里只需引用
  1. /* USER CODE BEGIN 0 */
  2. FILE __stdout;
  3. /* USER CODE END 0 */
 楼主| 欢乐家园 发表于 2022-9-26 23:59 | 显示全部楼层
2)添加 函数


在需要打印的位置使用printf函数即可, 头文件要保含 stdio.h。

IAR的工程配置为默认。
  1. /* USER CODE BEGIN 1 */
  2. int fputc(int ch, FILE *f)
  3. {
  4.     /* Send your custom byte */
  5.     /* Send byte to USART */
  6.   uint8_t ch_t[1] = {ch};
  7.     HAL_UART_Transmit(&huart1, ch_t, 1, 1);
  8.    
  9.     /* If everything is OK, you have to return character written */
  10.     return ch;
  11.     /* If character is not correct, you can return EOF (-1) to stop writing */
  12.     //return -1;
  13. }
  14. /* USER CODE END 1 */
caoenq 发表于 2022-9-27 09:40 | 显示全部楼层
想说明什么问题?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

114

主题

1067

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部