当前位置: 首页 > news >正文

pcf8563时钟驱动编写记录

驱动层代码

头文件

/********************************************************************************* @file           : i2c_clock_pcf8563.h* @author         : shchl* @brief          : None* @version        : 1.0* @attention      : None* @date           : 25-5-3******************************************************************************
*/#ifndef I2C_CLOCK_PCF8563_H
#define I2C_CLOCK_PCF8563_H
#include <time.h>
#include <stdbool.h>
struct pcf8563_driver;
struct pcf8563_driver_op;
typedef struct pcf8563_driver pcf8563_driver_t;
typedef struct pcf8563_driver_op pcf8563_driver_op_t;
struct pcf8563_driver_op
{bool (*write_reg)(pcf8563_driver_t* drv,uint8_t reg, const uint8_t* data, uint8_t data_size);bool (*read_reg)(pcf8563_driver_t* drv,uint8_t reg, uint8_t* data, uint8_t data_size);
};
struct pcf8563_driver
{uint8_t addr;pcf8563_driver_op_t op;
};
bool pcf8563_driver_init(pcf8563_driver_t* driver);
bool pcf8563_set_time(const time_t time);
bool pcf8563_get_time(time_t* time);
#endif //I2C_CLOCK_PCF8563_H

源文件

/********************************************************************************* @file           : i2c_clock_pcf8563.c* @author         : shchl* @brief          : None* @version        : 1.0* @attention      : None* @date           : 25-5-3******************************************************************************
*/#include "i2c_clock_pcf8563.h"#define 	SHIELD_PCF8563_STATE1   (unsigned char)0xa8
#define 	SHIELD_PCF8563_STATE2   (unsigned char)0x1f
#define 	SHIELD_PCF8563_SEC      (unsigned char)0x7f
#define 	SHIELD_PCF8563_MIN      (unsigned char)0x7f
#define 	SHIELD_PCF8563_HOUR     (unsigned char)0x3f
#define 	SHIELD_PCF8563_DAY      (unsigned char)0x3f
#define 	SHIELD_PCF8563_WEEK     (unsigned char)0x07
#define 	SHIELD_PCF8563_MON      (unsigned char)0x1f
#define 	SHIELD_PCF8563_YEAR     (unsigned char)0xff
/* register */
#define		REG_PCF8563_STATE1		0x00
#define		REG_PCF8563_STATE2		0x01
#define		REG_PCF8563_SEC			  0x02
#define		REG_PCF8563_MIN			  0x03
#define		REG_PCF8563_HOUR		  0x04
#define		REG_PCF8563_DAY			  0x05
#define		REG_PCF8563_WEEK		  0x06
#define		REG_PCF8563_MON			  0x07
#define		REG_PCF8563_YEAR		  0x08
#define		REG_PCF8563_CLKOUT		  0x0dstatic pcf8563_driver_t* pcf8563_drv = NULL;
/* bcd to hex */
static unsigned char bcd_to_hex(unsigned char data)
{const unsigned char temp = ((data >> 4) * 10 + (data & 0x0f));return temp;
}/* hex_to_bcd */
static unsigned char hex_to_bcd(unsigned char data)
{const unsigned char temp = (((data / 10) << 4) + (data % 10));return temp;
}bool pcf8563_driver_init(pcf8563_driver_t* driver)
{uint8_t buff[1] = {0};pcf8563_drv = driver;/* close clock out */buff[0] = 0x7F; // 清除时钟暂停位return pcf8563_drv->op.write_reg(pcf8563_drv,REG_PCF8563_CLKOUT, buff, 1);
}bool pcf8563_set_time(const time_t *timestamp)
{// 定义一个7字节的缓冲区,用于存放BCD码格式的时间数据uint8_t buff[7] = {0};// 将time_t类型的时间转换为tm结构体,便于处理const struct tm* time_new = NULL;time_new = localtime(timestamp);// 将各个时间字段转换为BCD码,并存入缓冲区buff[6] = hex_to_bcd(time_new->tm_year + 1900 - 2000);buff[5] = hex_to_bcd(time_new->tm_mon + 1);buff[3] = hex_to_bcd(time_new->tm_mday);buff[4] = hex_to_bcd(time_new->tm_wday + 1);buff[2] = hex_to_bcd(time_new->tm_hour);buff[1] = hex_to_bcd(time_new->tm_min);buff[0] = hex_to_bcd(time_new->tm_sec);if (!pcf8563_drv->op.write_reg(pcf8563_drv, REG_PCF8563_SEC, buff, 7))return false;return true;
}bool pcf8563_get_time(time_t* time)
{uint8_t buffer[7] = {0};pcf8563_drv->op.read_reg(pcf8563_drv, 2, buffer, 7);struct tm time_temp;time_temp.tm_year = bcd_to_hex(buffer[6] & SHIELD_PCF8563_YEAR) + 2000 - 1900;// 将读取到的BCD码转换为十进制,并赋值给time_temp结构体的月份字段time_temp.tm_mon = bcd_to_hex(buffer[5] & SHIELD_PCF8563_MON) - 1;// 将读取到的BCD码转换为十进制,并赋值给time_temp结构体的日期字段time_temp.tm_mday = bcd_to_hex(buffer[3] & SHIELD_PCF8563_DAY);// 将读取到的BCD码转换为十进制,并赋值给time_temp结构体的小时字段time_temp.tm_hour = bcd_to_hex(buffer[2] & SHIELD_PCF8563_HOUR);// 将读取到的BCD码转换为十进制,并赋值给time_temp结构体的分钟字段time_temp.tm_min = bcd_to_hex(buffer[1] & SHIELD_PCF8563_MIN);// 将读取到的BCD码转换为十进制,并赋值给time_temp结构体的秒数字段time_temp.tm_sec = bcd_to_hex(buffer[0] & SHIELD_PCF8563_SEC);if (!time) return false;*time = mktime(&time_temp);return true;
}

I2C硬件驱动(由CubeMx生成,使用的是I2C1)

头文件

/* USER CODE BEGIN Header */
/********************************************************************************* @file    i2c.h* @brief   This file contains all the function prototypes for*          the i2c.c file******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __I2C_H__
#define __I2C_H__#ifdef __cplusplus
extern "C" {
#endif/* Includes ------------------------------------------------------------------*/
#include "main.h"/* USER CODE BEGIN Includes */
#include "i2c_clock_pcf8563.h"
#define 	PCF8563_ADDRESS			0xA2
/* USER CODE END Includes */extern I2C_HandleTypeDef hi2c1;/* USER CODE BEGIN Private defines *//* USER CODE END Private defines */void MX_I2C1_Init(void);/* USER CODE BEGIN Prototypes *//* USER CODE END Prototypes */#ifdef __cplusplus
}
#endif#endif /* __I2C_H__ */

源文件

/* USER CODE BEGIN Header */
/********************************************************************************* @file    i2c.c* @brief   This file provides code for the configuration*          of the I2C instances.******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "i2c.h"/* USER CODE BEGIN 0 */bool pcf8563_read_reg(pcf8563_driver_t* drv, uint8_t reg, uint8_t* data, uint8_t data_size);
bool pcf8563_write_reg(pcf8563_driver_t* drv, uint8_t reg, const uint8_t* data, uint8_t data_size);
pcf8563_driver_t pcf8563_driver = {.addr = PCF8563_ADDRESS,.op = {.read_reg = pcf8563_read_reg,.write_reg = pcf8563_write_reg,},
};
/* USER CODE END 0 */I2C_HandleTypeDef hi2c1;/* I2C1 init function */
void MX_I2C1_Init(void)
{/* USER CODE BEGIN I2C1_Init 0 *//* USER CODE END I2C1_Init 0 *//* USER CODE BEGIN I2C1_Init 1 *//* USER CODE END I2C1_Init 1 */hi2c1.Instance = I2C1;hi2c1.Init.Timing = 0x10D19CE4;hi2c1.Init.OwnAddress1 = 0;hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;hi2c1.Init.OwnAddress2 = 0;hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;if (HAL_I2C_Init(&hi2c1) != HAL_OK){Error_Handler();}/** Configure Analogue filter*/if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK){Error_Handler();}/** Configure Digital filter*/if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK){Error_Handler();}/* USER CODE BEGIN I2C1_Init 2 */if (pcf8563_driver_init(&pcf8563_driver)){// printf("PCF8563 init success\r\n");
#define TIMESTAMP_START_VALUE 1746250282Utime_t rtc_time;pcf8563_get_time(&rtc_time);if(rtc_time<TIMESTAMP_START_VALUE){rtc_time = TIMESTAMP_START_VALUE;pcf8563_set_time(&rtc_time);}}/* USER CODE END I2C1_Init 2 */
}void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};if (i2cHandle->Instance == I2C1){/* USER CODE BEGIN I2C1_MspInit 0 *//* USER CODE END I2C1_MspInit 0 *//** Initializes the peripherals clock*/PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_I2C1;PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK){Error_Handler();}__HAL_RCC_GPIOA_CLK_ENABLE();/**I2C1 GPIO ConfigurationPA9     ------> I2C1_SCLPA10     ------> I2C1_SDA*/GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* I2C1 clock enable */__HAL_RCC_I2C1_CLK_ENABLE();/* USER CODE BEGIN I2C1_MspInit 1 *//* USER CODE END I2C1_MspInit 1 */}
}void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{if (i2cHandle->Instance == I2C1){/* USER CODE BEGIN I2C1_MspDeInit 0 *//* USER CODE END I2C1_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_I2C1_CLK_DISABLE();/**I2C1 GPIO ConfigurationPA9     ------> I2C1_SCLPA10     ------> I2C1_SDA*/HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9);HAL_GPIO_DeInit(GPIOA, GPIO_PIN_10);/* USER CODE BEGIN I2C1_MspDeInit 1 *//* USER CODE END I2C1_MspDeInit 1 */}
}/* USER CODE BEGIN 1 */bool pcf8563_read_reg(pcf8563_driver_t* drv, uint8_t reg, uint8_t* data, uint8_t data_size)
{HAL_StatusTypeDef status = HAL_I2C_Mem_Read(&hi2c1, drv->addr, reg,I2C_MEMADD_SIZE_8BIT, data, data_size, HAL_MAX_DELAY);if (status != HAL_OK){return false;}return true;
}bool pcf8563_write_reg(pcf8563_driver_t* drv, uint8_t reg, const uint8_t* data, uint8_t data_size)
{const HAL_StatusTypeDef status = HAL_I2C_Mem_Write(&hi2c1,drv->addr, reg, I2C_MEMADD_SIZE_8BIT,data, data_size,HAL_MAX_DELAY);if (status != HAL_OK){return false;}return true;
}/* USER CODE END 1 */

FreeRTOS测试

void StartDefaultTask(void* argument)
{/* USER CODE BEGIN StartDefaultTask *//* Infinite loop */time_t time;for (;;){// printf("hello\n");if (pcf8563_get_time(&time)){printf("time: %ld\n", (uint32_t)time);}osDelay(1000);}/* USER CODE END StartDefaultTask */
}

测试结果

在这里插入图片描述

相关文章:

  • C++/SDL 进阶游戏开发 —— 双人塔防(代号:村庄保卫战 20)
  • Java响应式编程
  • 【C++篇】类和对象(上)
  • 第6章 Python 基本数据类型详解(int, float, bool, str)细节补充
  • 探索Grok-3的高级用法:功能与应用详解
  • SeataAT模式
  • 【傻呱呱】BIOS里的某个启动引导项丢失如何找回?
  • AtCoder AT_abc404_g [ABC404G] Specified Range Sums
  • Windows下编译WebRTC源码
  • 第1章 Python 解释器安装(Anaconda/Pyenv 推荐)
  • STM32基础教程——软件I2C
  • 域名与官网的迷思:数字身份认证的全球困境与实践解方-优雅草卓伊凡
  • RT-Thread studio的驱动5.1.0报错修改
  • Mybatisplus:一些常用功能
  • 【Linux】Linux应用开发小经验
  • vmware diffy配置ollama 本机ip无法访问
  • SMT贴片检验标准核心要点与实施规范
  • Learning vtkjs之WindowedSincPolyDataFilter
  • Spring 命名空间注入:p、c 与 .util 的深度解析
  • 54、【OS】【Nuttx】编码规范解读(二)
  • 给3亿老人爆改房子,是门好生意吗?
  • 五一假期首日,上海外滩客流超55万人次
  • 2024年境内酒店住宿行业指标同比下滑:酒店行业传统增长模式面临挑战
  • 4月人民币对美元即期汇率微跌,今年以来升值0.48%
  • 海量数据处于“原矿”状态,数据价值释放如何破局?
  • 秦洪看盘|上市公司业绩“排雷”近尾声,A股下行压力趋缓