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

STM32模拟I2C驱动SD3078的程序

STM32模拟I2C驱动SD3078的程序。SD3078是一款内置晶振和温度补偿的高精度实时时钟芯片,采用I2C接口通信。

SD3078 基础要点

特性 描述
I2C地址 写地址:0x64,读地址:0x65
数据格式 时间寄存器数据为BCD码,读写需转换
写保护 写操作前需关闭写保护(寄存器操作),完成后建议重新开启
重要提示 I2C通信时,SCL和SDA线建议接10kΩ上拉电阻

软件驱动实现

基于STM32的HAL库进行模拟I2C,你可以根据实际使用的MCU调整GPIO操作。

1. 宏定义与结构体

#include "main.h"  // 包含你的MCU相关头文件// 根据你的硬件连接修改以下宏定义
#define SDA_PIN    GPIO_PIN_0
#define SDA_PORT   GPIOB
#define SCL_PIN    GPIO_PIN_1
#define SCL_PORT   GPIOB#define SD3078_WRITE_ADDR  0x64  // 写地址 
#define SD3078_READ_ADDR   0x65  // 读地址 // 时间寄存器结构体 
typedef struct {uint8_t second;uint8_t minute;uint8_t hour;uint8_t week;uint8_t date;uint8_t month;uint8_t year;
} SD3078_TimeTypeDef;// 模拟I2C延时函数,调整以实现合适的时序(如5us左右)
void I2C_Delay(void)
{for(uint32_t i = 0; i < 10; i++); // 具体延时需根据MCU主频调整
}

2. 模拟I2C基础时序

这些函数模拟了I2C总线的基本时序:

// 初始化I2C GPIO,设置为开漏输出模式并带上拉电阻
void I2C_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};// 使能GPIO时钟__HAL_RCC_GPIOB_CLK_ENABLE();// 配置SDA和SCL为开漏输出模式GPIO_InitStruct.Pin = SDA_PIN | SCL_PIN;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(SDA_PORT, &GPIO_InitStruct);// 初始状态拉高HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_SET);HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_SET);
}// 产生I2C起始信号:SCL高电平期间,SDA产生下降沿
void I2C_Start(void)
{HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_SET);HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_SET);I2C_Delay();HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_RESET);I2C_Delay();HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_RESET);I2C_Delay();
}// 产生I2C停止信号:SCL高电平期间,SDA产生上升沿
void I2C_Stop(void)
{HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_RESET);I2C_Delay();HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_SET);I2C_Delay();HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_SET);I2C_Delay();
}// 发送应答信号(ACK):SCL高电平期间,SDA为低电平
void I2C_Ack(void)
{HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_RESET);I2C_Delay();HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_SET);I2C_Delay();HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_RESET);I2C_Delay();HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_SET); // 释放SDA
}// 发送非应答信号(NACK):SCL高电平期间,SDA为高电平
void I2C_NAck(void)
{HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_SET);I2C_Delay();HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_SET);I2C_Delay();HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_RESET);I2C_Delay();
}// 等待应答信号,返回0表示收到ACK,1表示无ACK(超时)
uint8_t I2C_Wait_Ack(void)
{uint16_t timeout = 0;HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_SET); // 释放SDAI2C_Delay();HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_SET);I2C_Delay();// 检测SDA是否被从机拉低 while (HAL_GPIO_ReadPin(SDA_PORT, SDA_PIN) == GPIO_PIN_SET){timeout++;if(timeout > 1000) // 超时判断 {I2C_Stop();return 1;}}HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_RESET);I2C_Delay();return 0;
}// 模拟I2C发送一个字节
void I2C_SendByte(uint8_t data)
{for(uint8_t i = 0; i < 8; i++){HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, (data & 0x80) ? GPIO_PIN_SET : GPIO_PIN_RESET);data <<= 1;I2C_Delay();HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_SET);I2C_Delay();HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_RESET);I2C_Delay();}// 释放SDA,准备接收ACKHAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_SET);
}// 模拟I2C接收一个字节
uint8_t I2C_ReadByte(void)
{uint8_t data = 0;// 确保SDA为输入模式或在外部被上拉HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, GPIO_PIN_SET); // 释放SDAfor(uint8_t i = 0; i < 8; i++){data <<= 1;HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_SET);I2C_Delay();if(HAL_GPIO_ReadPin(SDA_PORT, SDA_PIN) == GPIO_PIN_SET){data |= 0x01;}HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_RESET);I2C_Delay();}return data;
}

3. SD3078专用驱动函数

这部分函数实现了SD3078的核心操作:

// 使能写操作(关闭写保护)
void SD3078_WriteEnable(void)
{I2C_Start();I2C_SendByte(SD3078_WRITE_ADDR);I2C_Wait_Ack();I2C_SendByte(0x10); // 写保护寄存器地址I2C_Wait_Ack();I2C_SendByte(0x00); // 写入0x00关闭写保护 I2C_Wait_Ack();I2C_Stop();// 额外操作确保写使效 I2C_Start();I2C_SendByte(SD3078_WRITE_ADDR);I2C_Wait_Ack();I2C_SendByte(0x0F); // 控制寄存器地址I2C_Wait_Ack();I2C_SendByte(0x00); // 确保控制寄存器配置正确 I2C_Wait_Ack();I2C_Stop();
}// 禁止写操作(开启写保护)
void SD3078_WriteDisable(void)
{I2C_Start();I2C_SendByte(SD3078_WRITE_ADDR);I2C_Wait_Ack();I2C_SendByte(0x10); // 写保护寄存器地址I2C_Wait_Ack();I2C_SendByte(0x80); // 写入0x80开启写保护 I2C_Wait_Ack();I2C_Stop();
}// 十进制转BCD码
uint8_t DEC_to_BCD(uint8_t dec)
{return ((dec / 10) << 4) | (dec % 10);
}// BCD码转十进制
uint8_t BCD_to_DEC(uint8_t bcd)
{return ((bcd >> 4) * 10) + (bcd & 0x0F);
}// 设置SD3078时间
void SD3078_SetTime(SD3078_TimeTypeDef *time)
{// 首先使能写操作SD3078_WriteEnable();I2C_Start();I2C_SendByte(SD3078_WRITE_ADDR);if(I2C_Wait_Ack()){I2C_Stop();return; // 器件无应答}I2C_SendByte(0x00); // 起始寄存器地址 I2C_Wait_Ack();// 依次发送秒、分、时、周、日、月、年,并转换为BCD码 I2C_SendByte(DEC_to_BCD(time->second));I2C_Wait_Ack();I2C_SendByte(DEC_to_BCD(time->minute));I2C_Wait_Ack();I2C_SendByte(DEC_to_BCD(time->hour) | 0x80); // 设置24小时制 I2C_Wait_Ack();I2C_SendByte(DEC_to_BCD(time->week));I2C_Wait_Ack();I2C_SendByte(DEC_to_BCD(time->date));I2C_Wait_Ack();I2C_SendByte(DEC_to_BCD(time->month));I2C_Wait_Ack();I2C_SendByte(DEC_to_BCD(time->year));I2C_Wait_Ack();I2C_Stop();// 可选:重新禁止写操作以保护时间设置// SD3078_WriteDisable();
}// 读取SD3078时间
void SD3078_GetTime(SD3078_TimeTypeDef *time)
{I2C_Start();I2C_SendByte(SD3078_WRITE_ADDR);if(I2C_Wait_Ack()){I2C_Stop();return; // 器件无应答}I2C_SendByte(0x00); // 起始寄存器地址 I2C_Wait_Ack();I2C_Start(); // 重新发送起始信号 I2C_SendByte(SD3078_READ_ADDR);I2C_Wait_Ack();// 依次读取秒、分、时、周、日、月、年,并转换为十进制 time->second = BCD_to_DEC(I2C_ReadByte() & 0x7F); // 忽略最高位I2C_Ack();time->minute = BCD_to_DEC(I2C_ReadByte() & 0x7F);I2C_Ack();time->hour = BCD_to_DEC(I2C_ReadByte() & 0x3F); // 24小时制处理 I2C_Ack();time->week = BCD_to_DEC(I2C_ReadByte() & 0x07); // 周只取低3位I2C_Ack();time->date = BCD_to_DEC(I2C_ReadByte() & 0x3F);I2C_Ack();time->month = BCD_to_DEC(I2C_ReadByte() & 0x1F);I2C_Ack();time->year = BCD_to_DEC(I2C_ReadByte());I2C_NAck(); // 最后一个字节发送NACK I2C_Stop();
}

4. 初始化与主函数示例

// SD3078初始化
void SD3078_Init(void)
{I2C_Init(); // 初始化模拟I2C GPIO// 可选:检查芯片是否正常工作SD3078_TimeTypeDef time;SD3078_GetTime(&time);// 如果读取到异常时间,可以设置默认时间if(time.year == 0 || time.month == 0 || time.date == 0){SD3078_TimeTypeDef defaultTime = {.second = 0,.minute = 0,.hour = 12,.week = 1,.date = 1,.month = 1,.year = 24};SD3078_SetTime(&defaultTime);}
}// 主函数使用示例
int main(void)
{// 系统初始化HAL_Init();SystemClock_Config();// SD3078初始化SD3078_Init();SD3078_TimeTypeDef currentTime;// 设置时间示例SD3078_TimeTypeDef setTime = {.second = 30,.minute = 15,.hour = 9,.week = 5,.date = 16,.month = 10,.year = 25};SD3078_SetTime(&setTime);while(1){// 读取并显示时间SD3078_GetTime(&currentTime);// 在这里添加你的时间显示逻辑// 例如:通过串口打印,或显示在LCD上HAL_Delay(1000); // 每秒更新一次}
}

参考代码 SD3078时钟芯片,模拟I2C读写程序 www.3dddown.com/cna/69816.html

关键问题与调试建议

  1. I2C通信失败

    • 检查硬件连接:确保SDA、SCL已接10kΩ上拉电阻到VCC,VCC通常为3.3V或5V。
    • 确认I2C地址:写地址0x64,读地址0x65
    • 调整时序延时:若通信不稳定,可尝试减小I2C速率(增加I2C_Delay)。
  2. 时间读写异常

    • 注意BCD码转换:直接读取的时间值为BCD码,需转换為十进制才能直观理解,设置时间前则需将十进制转换为BCD码。
    • 检查写保护:写时间前务必关闭写保护(调用SD3078_WriteEnable),写完后可根据需要重新开启。
  3. 其他注意事项

    • SD3078的控制寄存器(地址0x0F)在上电初期可能需要正确配置,具体配置值请参考数据手册。
    • 若使用STM32硬件I2C,可替换模拟时序部分为HAL库的硬件I2C函数,但需注意STM32硬件I2C自身可能存在的问题。
http://www.jsqmd.com/news/98118/

相关文章:

  • Umo Editor:Vue3文档编辑器的终极解决方案
  • 2026年浙江AI搜索营销优化公司权威盘点:十大知名机构深度解析 - 速递信息
  • 2025年评价高的单缸液压圆锥破碎机高口碑厂家推荐(评价高) - 行业平台推荐
  • 友达 G185HAN01.100 工业液晶显示屏:18.5 英寸宽温高色域场景的显示驱动技术解析
  • 半条鱼设计公司如何打造武汉商业空间效果图?
  • 友达 G185XW01 V1 工业液晶显示屏:18.5 英寸宽温高响应场景的显示驱动技术解析
  • 众包测试的组织与管理:数字化时代的质量保障新范式
  • A2A 架构里最容易被忽略的 3 个工程问题
  • 友达 G185XW01 V201 工业液晶显示屏:18.5 英寸宽温高响应场景的显示驱动技术解析
  • 中科院工程师分享:用Unsloth打造推理增强大模型|低显存、高推理、可复用
  • WinDirStat:彻底解决Windows磁盘空间管理难题的终极方案
  • DuckDB嵌入式数据库:5个实战技巧快速掌握高性能分析
  • 小白大模型课程30分钟:从认知到进阶之路
  • FlutterFire Remote Config用户细分实战:精准触达不同用户群体
  • 软件测试中的等价类划分与边界值分析法:原理、实践与演进
  • 26、深入探索Shell:功能、控制与兼容性
  • Langchain-Chatchat与MinIO结合存储文档的最佳实践
  • Rust UI框架选择指南:从需求出发的深度对比
  • 每月电费几十万?储能如何成为企业降本增效的隐形引擎
  • Gutenberg性能优化终极指南:从卡顿到流畅的全面解决方案
  • Jellyfin界面大改造:告别单调,打造专属媒体中心
  • 27、Shell编程基础:参数、变量与操作详解
  • 3C 电子连接器质检难?智能视觉方案实现 5μm 高精度管控,效率提升 3 倍!
  • 5个实战技巧轻松玩转AKShare:财经数据获取的终极指南
  • 2025论文季AI工具实测:避开代写陷阱,这款免费辅助工具太省心
  • 一站式虾分发平台在应用分发与内测分发领域表现出色
  • 25、深入探索Shell交互与非标准特性
  • Kali综合实验:网络渗透与防御技术实践
  • 10分钟搞定Kubernetes负载均衡:SLIM镜像优化实战
  • Apache Mesos运维实战:集群管理完整指南与故障处理方案