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

【Proteus8.17仿真】 STM32仿真 0.96OLED 屏幕显示ds1302实时时间

前言

在嵌入式系统开发中,实时时钟(RTC)和显示模块是常见的功能需求。今天我们来分享如何使用STM32F103C8T6(蓝桥杯常用芯片)驱动DS1302实时时钟芯片,并在OLED屏幕上显示时间信息。本文包含完整的代码实现和详细的原理讲解,适合嵌入式初学者和爱好者参考学习。

DS1302 概述

DS1302是美国Dallas公司(后被Maxim Integrated,现为ADI公司一部分)推出的一款低成本、低功耗的实时时钟芯片。它能够提供秒、分、时、日、月、年等日历信息,并且具有闰年自动调整功能(有效至2100年)。

由于其接口简单、成本低廉,在早期的电子设计、学习套件(如Arduino)、以及一些对时间精度要求不高的消费类产品中得到了非常广泛的应用。

ds1302实物图

主要特点

  1. 实时时钟功能

    • 提供秒、分、时、日、月、年和星期信息。
    • 月末日期自动调整,包括闰年补偿(有效至2100年)。
    • 可选择12小时制或24小时制。
  2. 低功耗

    • 在备用电源(如纽扣电池)模式下,功耗极低,典型值小于300nA,能保证在主电源断开后时钟长时间持续运行。
  3. 内置RAM

    • 提供31字节的额外静态RAM,可用于存储用户自定义的配置参数或数据。
  4. 串行接口

    • 采用简单的三线串行接口(CEI/OSCLK),与微控制器(如51单片机、AVR、Arduino等)连接非常方便,占用I/O口少。
  5. 双电源供电

    • 支持主电源和备用电源(如3V锂电池)双电源输入,具有电源切换和控制电路,在主电源失效时自动切换到备用电源。
  6. 宽电压工作

    • 主电源工作电压范围宽:2.0V 至 5.5V。

引脚定义与功能

DS1302通常有8引脚DIP或SOIC封装。

引脚编号引脚名称功能描述
1Vcc2主电源输入引脚。
2X132.768kHz晶振输入引脚1。
3X232.768kHz晶振输入引脚2。
4GND接地
5CE片选使能引脚(有时也标记为RST)。高电平有效,在开始读写数据前必须将其置为高电平。
6I/O双向数据线引脚,用于数据的串行输入和输出。
7SCLK串行时钟输入引脚。数据在时钟的上升沿或下降沿被读写。
8Vcc1备用电源输入引脚(如接3V纽扣电池)。

注意:Vcc1和Vcc2的供电关系是,当Vcc2 > Vcc1 + 0.2V时,芯片由Vcc2供电;当Vcc2 < Vcc1时,芯片自动切换到由Vcc1供电。


内部结构与核心部件

  1. 移位寄存器: 负责与微控制器进行串行通信。
  2. 控制逻辑: 解析微控制器发送的命令字节,决定是读操作还是写操作,以及目标是时钟寄存器还是RAM。
  3. 时钟/日历寄存器组: 存储秒、分、时等时间日期信息的BCD码。
  4. 静态RAM: 31字节的用户数据存储区。
  5. 振荡器与分频器: 外接32.768kHz晶振,经过内部分频链,产生1Hz的秒信号。
  6. 电源控制电路: 管理主电源和备用电源的自动切换。

通信协议(时序)

DS1302使用一种简单的同步串行协议,所有数据传输都发生在CE引脚为高电平期间。

  • 命令字节: 每次数据传输都必须以一个8位的命令字节开始。

    • Bit 7: 必须为1。
    • Bit 6: 1表示对RAM进行操作,0表示对时钟/日历寄存器进行操作。
    • Bit 5 - Bit 1: 指定要读写的寄存器/RAM地址。
    • Bit 0: 1表示读操作,0表示写操作。
  • 数据传输

    • 数据在SCLK上升沿被写入DS1302。
    • 数据在SCLK下降沿从DS1302读出。
    • 每个时钟周期传输1位数据,最低有效位(LSB)先行

    DS1302时序图

在这里插入图片描述

应用领域

  • Arduino/Raspberry Pi/51/32等开发板的时钟模块
  • 数字万用表、数字温度计等仪器仪表
  • 电话、传真机等办公设备
  • 便携式设备、电池供电的系统
  • 智能电表
  • 汽车电子(如行车记录仪)

实现准备

proteus 仿真图一份(如下)
在这里插入图片描述

实现代码(基于stm32f103c8t6 标准库 代码)

在这里插入图片描述

代码实现细节:

#include "stm32f10x.h"                  // Device header//#include "usart.h"
#include "delay.h"
#include "KEY.h"
#include "oled.h"
//#include "beep.h"
#include "bsp_dht11.h"
#include "adc0832.h" 
#include "stdio.h" //#include "ds1302.h"char time[7]={25, 4, 25, 12, 30, 0, 5};
char readtime[7]={25, 4, 25, 12, 30, 0, 5};
u8 war[32];
u8 time1[32];
//温度湿度阈值
//u8 dht11_data[4] = {20, 70, 20, 40};
u8 Tmin=20;
u8 Tmax=40;
u8 Hmin=30;
u8 Hmax=70;
u16 count=0;DHT11_Data_TypeDef DHT11_Data;#define Delay_us delay_usvoid Beep_Init()
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitStructure.GPIO_Pin =GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7 ;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_ResetBits(GPIOB,GPIO_Pin_5);
}void Beep_Run(unsigned char x)
{if(x==1){GPIO_SetBits(GPIOB,GPIO_Pin_5);}else{GPIO_ResetBits(GPIOB,GPIO_Pin_5);//GPIO_SetBits(GPIOB,GPIO_Pin_5);}}#define DS1302_SCLK_PIN    GPIO_Pin_7
#define DS1302_IO_PIN      GPIO_Pin_6
#define DS1302_CE_PIN      GPIO_Pin_5
#define DS1302_GPIO        GPIOAvoid DS1302_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// SCLK和CE配置为推挽输出GPIO_InitStructure.GPIO_Pin = DS1302_SCLK_PIN | DS1302_CE_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DS1302_GPIO, &GPIO_InitStructure);// IO配置为浮空输入(初始状态)GPIO_InitStructure.GPIO_Pin = DS1302_IO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(DS1302_GPIO, &GPIO_InitStructure);// 初始状态GPIO_ResetBits(DS1302_GPIO, DS1302_SCLK_PIN);GPIO_ResetBits(DS1302_GPIO, DS1302_CE_PIN);
}// 设置IO方向为输出
static void DS1302_IO_Output(void)
{GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = DS1302_IO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DS1302_GPIO, &GPIO_InitStructure);
}// 设置IO方向为输入
static void DS1302_IO_Input(void)
{GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = DS1302_IO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(DS1302_GPIO, &GPIO_InitStructure);
}// 向DS1302写入一个字节
static void DS1302_WriteByte(uint8_t dat)
{uint8_t i;DS1302_IO_Output();for(i=0; i<8; i++){if(dat & 0x01)GPIO_SetBits(DS1302_GPIO, DS1302_IO_PIN);elseGPIO_ResetBits(DS1302_GPIO, DS1302_IO_PIN);GPIO_SetBits(DS1302_GPIO, DS1302_SCLK_PIN);Delay_us(5);GPIO_ResetBits(DS1302_GPIO, DS1302_SCLK_PIN);Delay_us(5);dat >>= 1;}
}// 从DS1302读取一个字节
static uint8_t DS1302_ReadByte(void)
{uint8_t i, dat = 0;DS1302_IO_Input();for(i=0; i<8; i++){dat >>= 1;if(GPIO_ReadInputDataBit(DS1302_GPIO, DS1302_IO_PIN))dat |= 0x80;GPIO_SetBits(DS1302_GPIO, DS1302_SCLK_PIN);Delay_us(5);GPIO_ResetBits(DS1302_GPIO, DS1302_SCLK_PIN);Delay_us(5);}return dat;
}// DS1302命令定义
#define DS1302_SECOND       0x80
#define DS1302_MINUTE       0x82
#define DS1302_HOUR         0x84
#define DS1302_DAY          0x86
#define DS1302_MONTH        0x88
#define DS1302_WEEK         0x8A
#define DS1302_YEAR         0x8C
#define DS1302_WP           0x8E    // 写保护
#define DS1302_BURST        0xBE// 向DS1302寄存器写入数据
void DS1302_WriteReg(uint8_t reg, uint8_t dat)
{GPIO_SetBits(DS1302_GPIO, DS1302_CE_PIN);Delay_us(5);DS1302_WriteByte(reg);      // 写入寄存器地址DS1302_WriteByte(dat);      // 写入数据GPIO_ResetBits(DS1302_GPIO, DS1302_CE_PIN);Delay_us(5);
}// 从DS1302寄存器读取数据
uint8_t DS1302_ReadReg(uint8_t reg)
{uint8_t dat;GPIO_SetBits(DS1302_GPIO, DS1302_CE_PIN);Delay_us(5);DS1302_WriteByte(reg | 0x01);  // 读命令需要将地址最低位置1dat = DS1302_ReadByte();GPIO_ResetBits(DS1302_GPIO, DS1302_CE_PIN);Delay_us(5);return dat;
}// BCD码转十进制
static uint8_t BCD2DEC(uint8_t bcd)
{return (bcd>>4)*10 + (bcd&0x0F);
}// 十进制转BCD码
static uint8_t DEC2BCD(uint8_t dec)
{return ((dec/10)<<4) + (dec%10);
}// 设置时间
void DS1302_SetTime(uint8_t hour, uint8_t min, uint8_t sec)
{// 关闭写保护DS1302_WriteReg(DS1302_WP, 0x00);// 写入时间DS1302_WriteReg(DS1302_SECOND, DEC2BCD(sec));DS1302_WriteReg(DS1302_MINUTE, DEC2BCD(min));DS1302_WriteReg(DS1302_HOUR, DEC2BCD(hour));// 开启写保护DS1302_WriteReg(DS1302_WP, 0x80);
}// 读取时间
void DS1302_GetTime(uint8_t *hour, uint8_t *min, uint8_t *sec)
{*sec = BCD2DEC(DS1302_ReadReg(DS1302_SECOND) & 0x7F);*min = BCD2DEC(DS1302_ReadReg(DS1302_MINUTE));*hour = BCD2DEC(DS1302_ReadReg(DS1302_HOUR));
}typedef struct {uint8_t year;uint8_t month;uint8_t day;uint8_t week;uint8_t hour;uint8_t minute;uint8_t second;
} DS1302_DateTime;// 设置完整日期时间
void DS1302_SetDateTime(DS1302_DateTime *dt)
{// 关闭写保护DS1302_WriteReg(DS1302_WP, 0x00);// 写入时间日期DS1302_WriteReg(DS1302_SECOND, DEC2BCD(dt->second)& 0x7F);DS1302_WriteReg(DS1302_MINUTE, DEC2BCD(dt->minute));DS1302_WriteReg(DS1302_HOUR, DEC2BCD(dt->hour));DS1302_WriteReg(DS1302_DAY, DEC2BCD(dt->day));DS1302_WriteReg(DS1302_MONTH, DEC2BCD(dt->month));DS1302_WriteReg(DS1302_WEEK, DEC2BCD(dt->week));DS1302_WriteReg(DS1302_YEAR, DEC2BCD(dt->year));// 开启写保护DS1302_WriteReg(DS1302_WP, 0x80);
}// 读取完整日期时间
void DS1302_GetDateTime(DS1302_DateTime *dt)
{dt->second = BCD2DEC(DS1302_ReadReg(DS1302_SECOND) & 0x7F);dt->minute = BCD2DEC(DS1302_ReadReg(DS1302_MINUTE));dt->hour = BCD2DEC(DS1302_ReadReg(DS1302_HOUR));dt->day = BCD2DEC(DS1302_ReadReg(DS1302_DAY));dt->month = BCD2DEC(DS1302_ReadReg(DS1302_MONTH));dt->week = BCD2DEC(DS1302_ReadReg(DS1302_WEEK));dt->year = BCD2DEC(DS1302_ReadReg(DS1302_YEAR));
}int main(void)
{unsigned char  getkey=0,keymode=0;uint16_t tds=0;delay_init();	     //延时初始化//蜂鸣器初始化Beep_Init();//oled初始化OLED_Init();;Key_Init();DS1302_GPIO_Init();DS1302_DateTime dt;// 设置初始时间dt.year = 23;dt.month = 5;dt.day = 15;dt.week = 1;  // 周一dt.hour = 12;dt.minute = 0;dt.second = 0;OLED_Clear();delay_ms(20);OLED_ShowString(0, 0,"STM32-App time",16);//设置时间//DS1302_Init(); // 初始化DS1302// 写入初始时间//DS1302_WriteTime(time); // 2025年4月25日12点//TIME_Set();while(1){		 DS1302_GetDateTime(&dt);sprintf((char *)war, "%02d-%02d-%02d", dt.year,dt.month,dt.day);OLED_ShowString(0, 3,war,8);sprintf((char *)time1, "%02d-%02d-%02d",dt.hour,dt.minute,dt.second);OLED_ShowString(0, 4,time1,8);}//while line
}

实现效果

在这里插入图片描述
需要 源码工程的小伙伴在 评论区留言。

http://www.dtcms.com/a/426668.html

相关文章:

  • 佛山做营销型网站建设wordpress修改域名后无法登陆
  • mysql数据库学习之常用函数(五)
  • 避坑实战!京东商品详情接口开发指南:分页优化、多规格解析与数据完整性保障
  • win10(十二)Nuitka打包程序
  • 【Rust GUI开发入门】编写一个本地音乐播放器(11. 支持动态明暗主题切换)
  • 自己做网站帮公司出认证证书违法吗上海定制网站建设公司
  • [论文阅读] AI + 软件工程(Debug)| 告别 “猜 bug”:TreeMind 用 LLM+MCTS 破解 Android 不完整报告复现难题
  • ESP32 + MCP over MQTT:通过大模型控制智能硬件设备
  • 五大关系数据库(sqlserver、mysql、oracle、pgsql、sqlite)的对象名称和转义字符
  • 央企云原生PaaS建设方案及案例集锦
  • 使用Django从零开始构建一个个人博客系统
  • 工业互联网的云原生转型路径
  • 做网站需要哪些素材建筑工程 技术支持 东莞网站建设
  • Spring Boot 缓存技术
  • AI应用生成平台:数据库、缓存与存储
  • J2Cache 多级缓存配置与使用
  • 【JAVA】【BUG】经常出现的典型 bug 及解决办法
  • 做网站怎么存放视频哪个公司的室内设计公司
  • GitHub 热榜项目 - 日榜(2025-09-30)
  • Microsoft Fabric - 尝试一下Workspace中的Deployment pipeline
  • 区块链论文速读 CCF A--WWW 2025(6)
  • Bug——PaddleX人脸识别报错:Process finished with exit code -1073741819 (0xC0000005)
  • SSM基于的宠物领养管理系统ugssn(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
  • 四种对象型创建模式:抽象工厂、 build模式、原型ProtoType与单例模式
  • 即墨网站建设公司旅游网站建设电子商务的困惑
  • 央视优购物官方网站网页制作与网站管理
  • 本地多版本 Node.js 切换指南:解决 Vue nodejs 等项目版本冲突问题
  • 阿里云 AI 中间件重磅发布,打通 AI 应用落地“最后一公里”
  • 全面解析Umi-OCR手写体识别能力:开源OCR的新标杆
  • Spring Boot整合Kafka:解决消息挤压、丢失与重复消费