STM32单片机+DS1302时钟模块+OLED屏幕+源代码

目录

一、DS1302时钟模块介绍

二、DS1302时钟模块接线说明

三、测试说明、DS1302时钟模块驱动代码

四、串口调试助手软件下载 

五、源代码

六、DS1302时钟模块原理图资料


一、DS1302时钟模块介绍

一、 DS1302时钟芯片介绍
        DS1302是DALLAS公司推出的涓流充电时钟芯片,内部含有一个实时时钟/日历和31字节静态RAM,通过简单的串行接口与单片机进行通信。该芯片是3线SPI接口。实时时钟/日历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可以自动调整。时钟操作通过AM/PM只是决定采用24或12小时格式。DS1302与单片机之间能简单地采用同步串行的方式进行通信,仅需要用到三根通信线:
① RES复位;② I/O数据线;③ SCLK串行时钟。

        时钟/RAM的读/写数据以一个字节或多达31个字节的字符组方式通信。DS1302工作时功耗很低,保持数据个时钟信息时功率小于1mW。DS1302的双电源管脚用于主电源和备份电源供应,Vcc1为可编程涓流充电电源,附加七个字节存储器。它广泛应用与电话、传真、便携式仪器以及电池供电的仪器仪表等产品领域下面。

        DS1302主要的性能指标:实时时钟具有能计算2100年之前的秒、分、时、日、周、月、年的能力,还有闰年调整能力。31个8位暂存数据存储RAM。串行I/O口方式使得管脚数量最少。宽范围工作电压3.0~5.5V。工作在2.0V时,电流小于300nA。读/写时钟或RAM数据时有两种传送方式:单字节传送和多字节传送方式。5脚DIP封装或可选的8脚SOIC封装根据表面装配。
简单3线接口。与TTL兼容Vcc=5V。可选工业级温度范围-40~+85。具有涓流充电能力。
采用主电源和备份电源双电源供应,备份电源可用电池或大容量电容实现。

二、DS1302时钟模块接线说明

VCC(+):电源正极接口,外接电源3 ~ 5V电源正极,接单片机的5v或者3v引脚

GND(-):电源负极接口,外接电源负极或地线GND,接单片机的GND

 CLK        :时钟线,接单片机的PB10引脚

 DAT        :数据线,接单片机的PB1引脚

 RST        :接单片机的PB11引脚        

三、测试说明、DS1302时钟模块驱动代码

编译环境:keil5

测试单片机: STM32F103C8T6

功能:功能1:按键1设置时间、按键2选择功能、按键3加功能、按键4减功能、按键5取消功能

DS1302.c文件编写雨滴传感器驱动代码如下:

#include "DS1302.h"
#include "delay.h"
#include "OLED.h"
#include "Key.h"
extern uint8_t KeyNum,MODE,TimeSetSelect,TimeSetFlashFlag;				//按键情况、模式选择、时间修改位、修改位闪烁标志
extern uint8_t AlarmSetSelect,AlarmSetFlashFlag,AlarmNum;
extern uint16_t Tempo;
uint16_t datetime[7] = {24, 6, 1, 12, 0, 0, 1};//默认时间

void ds1302_gpio_init()//使用前用这个函数初始化
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //RST
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_ResetBits(GPIOB,GPIO_Pin_11); 

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//CLK
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_ResetBits(GPIOB,GPIO_Pin_10); 
}

void ds1032_DATAOUT_init()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//DAT
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_ResetBits(GPIOB,GPIO_Pin_1);
}

void ds1032_DATAINPUT_init()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}


void ds1302_write_onebyte(u8 data)
{
	ds1032_DATAOUT_init();
	u8 count=0;
	SCLK_L;
	for(count=0;count<8;count++)
		{	SCLK_L;
			if(data&0x01)
			{DATA_H;}
			else{DATA_L;}
			SCLK_H;
			data>>=1;
		}
}

void ds1302_wirte_rig(u8 address,u8 data)
{
	u8 temp1=address;
	u8 temp2=data;
	CE_L;SCLK_L;Delay_us(1);
	CE_H;Delay_us(2);
	ds1302_write_onebyte(temp1);
	ds1302_write_onebyte(temp2);
	CE_L;SCLK_L;Delay_us(2);
}

u8 ds1302_read_rig(u8 address)
{
	u8 temp3=address;
	u8 count=0;
	u8 return_data=0x00;
	CE_L;SCLK_L;Delay_us(3);
	CE_H;Delay_us(3);
	ds1302_write_onebyte(temp3);
	ds1032_DATAINPUT_init();
	Delay_us(2);
	for(count=0;count<8;count++)
		{
		Delay_us(2);
		return_data>>=1;
		SCLK_H;Delay_us(4);
		SCLK_L;Delay_us(14);
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1))
		{return_data=return_data|0x80;}
		
		}
	Delay_us(2);
	CE_L;DATA_L;
	return return_data;
}

void ds1032_set_time()//将datetime数据写入DS1302(在初始化后应该用该函数写入一次时间数据)
{
	ds1302_wirte_rig(0x8e,0x00);//关闭写保护
	ds1302_wirte_rig(0x80,datetime[5]/10*16+datetime[5]%10);//seconds
	ds1302_wirte_rig(0x82,datetime[4]/10*16+datetime[4]%10);//minutes
	ds1302_wirte_rig(0x84,datetime[3]/10*16+datetime[3]%10);//hours
	ds1302_wirte_rig(0x86,datetime[2]/10*16+datetime[2]%10);//date
	ds1302_wirte_rig(0x88,datetime[1]/10*16+datetime[1]%10);//months
	ds1302_wirte_rig(0x8a,datetime[6]/10*16+datetime[6]%10);//days
	ds1302_wirte_rig(0x8c,datetime[0]/10*16+datetime[0]%10);//year
	ds1302_wirte_rig(0x8e,0x80);//开启写保护
}

void ds1032_read_time()//从DS1302读出时间数据并写入datetime,可以在主函数对datetime进行读取和修改操作
{
	uint16_t Temp;
	Temp=ds1302_read_rig(0x81);	
	datetime[5]=Temp/16*10+Temp%16;
	Temp=ds1302_read_rig(0x83);	
	datetime[4]=Temp/16*10+Temp%16;
	Temp=ds1302_read_rig(0x85);	
	datetime[3]=Temp/16*10+Temp%16;
	Temp=ds1302_read_rig(0x87);	
	datetime[2]=Temp/16*10+Temp%16;
	Temp=ds1302_read_rig(0x89);	
	datetime[1]=Temp/16*10+Temp%16;
	Temp=ds1302_read_rig(0x8B);	
	datetime[6]=Temp/16*10+Temp%16;
	Temp=ds1302_read_rig(0x8D);	
	datetime[0]=Temp/16*10+Temp%16;
}

//struct Alarm_Set{
//uint8_t num;
//uint8_t enable;
//uint8_t mode;
//uint8_t flag;	
//uint8_t hour;
//uint8_t minute;
//};

//struct Alarm_Set Alarm[5]={
//{0,1,0,0,0,0},
//{1,1,1,0,0,1},
//{2,1,2,0,0,2},
//{3,1,3,0,0,3},
//{4,0,0,0,0,4}
//};

uint8_t GetDay(void)
{
	uint8_t week;
	uint16_t temp[3];
	temp[0]=datetime[0];
	temp[1]=datetime[1];
	temp[2]=datetime[2];
	if (temp[1] == 1 || temp[1] == 2) 
	{
        temp[1] += 12;
        temp[0]--;
    }
	week = (temp[0] + temp[0] / 4 + (13*(temp[1]+1)/5) + temp[2] - 36) % 7;
	return week;
}
	
void ShowDay(void)
 {
	switch(GetDay())
	{
		case 0:
            OLED_ShowString(4,8,"7");
            break;
        case 1:
            OLED_ShowString(4,8,"1");
            break;
        case 2:
            OLED_ShowString(4,8,"2");
            break;
        case 3:
            OLED_ShowString(4,8,"3");
            break;
        case 4:
            OLED_ShowString(4,8,"4");
            break;
        case 5:
            OLED_ShowString(4,8,"5");
            break;
        case 6:
            OLED_ShowString(4,8,"6");
            break;
	}
}

void ShowTime(void)
{
	ds1032_read_time();
	ShowDay();
	OLED_ShowNum(2,4,2000+datetime[0],4);
	OLED_ShowNum(2,9,datetime[1],2);
	OLED_ShowNum(2,12,datetime[2],2);
	OLED_ShowNum(3,5,datetime[3],2);
	OLED_ShowNum(3,8,datetime[4],2);
	OLED_ShowNum(3,11,datetime[5],2);
}

void SetTime(void)
{

	if(KeyNum==4)//取消修改
	{
		MODE=0;
	}
	if(KeyNum==2)//保存修改
	{
		MODE=0;
		ds1032_set_time();
	}
	if(KeyNum==3)//移位
	{	
		TimeSetSelect++;
		if(TimeSetSelect>5)TimeSetSelect=0;
//		TimeSetSelect%=6;//TimeSetSelect = TimeSetSelect % 6;
	}
	if(KeyNum==5)//数值+1
	{
		datetime[TimeSetSelect]++;//时间设置位数值加1
		if(datetime[0]>99){datetime[0]=0;}//年越界判断
		if(datetime[1]>12){datetime[1]=1;}//月越界判断
		if( datetime[1]==1 || datetime[1]==3 || datetime[1]==5 || datetime[1]==7 || 
			datetime[1]==8 || datetime[1]==10 || datetime[1]==12)//日越界判断
		{
			if(datetime[2]>31){datetime[2]=1;}//大月
		}
		else if(datetime[1]==4 || datetime[1]==6 || datetime[1]==9 || datetime[1]==11)
		{
			if(datetime[2]>30){datetime[2]=1;}//小月
		}
		else if(datetime[1]==2)
		{
			if(datetime[0]%4==0)
			{
				if(datetime[2]>29){datetime[2]=1;}//闰年2月
			}
			else
			{
				if(datetime[2]>28){datetime[2]=1;}//平年2月
			}
		}
		if(datetime[3]>23){datetime[3]=0;}//时越界判断
		if(datetime[4]>59){datetime[4]=0;}//分越界判断
		if(datetime[5]>59){datetime[5]=0;}//秒越界判断
	}
	if(KeyNum==1)//数值-1
	{
		datetime[TimeSetSelect]--;//时间设置位数值减1
		if(datetime[0]>100){datetime[0]=99;}//年越界判断
		if(datetime[1]<1){datetime[1]=12;}//月越界判断
		if( datetime[1]==1 || datetime[1]==3 || datetime[1]==5 || datetime[1]==7 || 
			datetime[1]==8 || datetime[1]==10 || datetime[1]==12)//日越界判断
		{
			if(datetime[2]<1){datetime[2]=31;}//大月
			if(datetime[2]>31){datetime[2]=1;}
		}
		else if(datetime[1]==4 || datetime[1]==6 || datetime[1]==9 || datetime[1]==11)
		{
			if(datetime[2]<1){datetime[2]=30;}//小月
			if(datetime[2]>30){datetime[2]=1;}
		}
		else if(datetime[1]==2)
		{
			if(datetime[0]%4==0)
			{
				if(datetime[2]<1){datetime[2]=29;}//闰年2月
				if(datetime[2]>29){datetime[2]=1;}
			}
			else
			{
				if(datetime[2]<1){datetime[2]=28;}//平年2月
				if(datetime[2]>28){datetime[2]=1;}
			}
		}
		if(datetime[3]>100){datetime[3]=23;}//时越界判断
		if(datetime[4]>100){datetime[4]=59;}//分越界判断
		if(datetime[5]>100){datetime[5]=59;}//秒越界判断
	}
	//以下是实现被选中位闪烁效果
	if(TimeSetSelect==0 && TimeSetFlashFlag==1){OLED_ShowString(2,4,"    ");}
	else {OLED_ShowNum(2,4,2000+datetime[0],4);}
	if(TimeSetSelect==1 && TimeSetFlashFlag==1){OLED_ShowString(2,9,"  ");}
	else {OLED_ShowNum(2,9,datetime[1],2);}
	if(TimeSetSelect==2 && TimeSetFlashFlag==1){OLED_ShowString(2,12,"  ");}
	else {OLED_ShowNum(2,12,datetime[2],2);}
	if(TimeSetSelect==3 && TimeSetFlashFlag==1){OLED_ShowString(3,5,"  ");}
	else {OLED_ShowNum(3,5,datetime[3],2);}
	if(TimeSetSelect==4 && TimeSetFlashFlag==1){OLED_ShowString(3,8,"  ");}
	else {OLED_ShowNum(3,8,datetime[4],2);}
	if(TimeSetSelect==5 && TimeSetFlashFlag==1){OLED_ShowString(3,11,"  ");}
	else {OLED_ShowNum(3,11,datetime[5],2);}
	ShowDay();
}

void Scan_Key()
{
	KeyNum = Key_GetNum();		
		switch(KeyNum)
		{
		case 2:						//按2进入时间设置
			MODE=1;
			TimeSetSelect=0;
			OLED_Clear();
			OLED_ShowString(1,1,"SetTime");
			OLED_ShowString(2,8,"-  -");
			OLED_ShowString(3,7,":  :");
		  OLED_ShowString(4,1,"week:");
			while(MODE==1)
			{
				KeyNum = Key_GetNum();
				SetTime();
			}
			OLED_Clear();
			OLED_ShowString(2,8,"-  -");
			OLED_ShowString(3,7,":  :");
			OLED_ShowString(4,1,"week:");
			break;
		case 3:						//按3进入闹钟设置
//			MODE=2;
//			AlarmSetSelect=0;
//			AlarmNum=0;
//			OLED_Clear();
//			OLED_ShowString(4,13,":");
//			while(MODE==2)
//			{
//				KeyNum = Key_GetNum();
//				//SetAlarm();
//			}
//			OLED_Clear();
//			OLED_ShowString(2,8,"-  -");
//			OLED_ShowString(3,7,":  :");
			break;
		default:break;
		}
		ShowTime();
		//CheckAlarm();					//检查闹钟
}

DS1302.h文件,对驱动函数经行了声明: 

#ifndef __DS1302_H_ 
#define __DS1302_H_ 

//#include "sys.h" 
#include "stm32f10x.h"

#define CE_L GPIO_ResetBits(GPIOB,GPIO_Pin_11)	//	CE口接在PB11,若更改,.c文件中也要更改,下同
#define CE_H GPIO_SetBits(GPIOB,GPIO_Pin_11)
#define SCLK_L GPIO_ResetBits(GPIOB,GPIO_Pin_10)//	SCLK口接在PB10
#define SCLK_H  GPIO_SetBits(GPIOB,GPIO_Pin_10)
#define DATA_L  GPIO_ResetBits(GPIOB,GPIO_Pin_1)//	IO/data数据口接在PB1
#define DATA_H  GPIO_SetBits(GPIOB,GPIO_Pin_1)


extern uint16_t datetime[7];
void ds1302_gpio_init(void);
void ds1302_write_onebyte(u8 data);
void ds1302_wirte_rig(u8 address,u8 data);
u8 ds1302_read_rig(u8 address);
void ds1032_set_time(void);
void ds1032_DATAOUT_init(void);
void ds1032_DATAINPUT_init(void);
void ds1032_read_time(void);

uint8_t GetDay(void);
void ShowDay(void);
void ShowTime(void);
void SetTime(void);
void Scan_Key(void);
#endif

四、串口调试助手软件下载 

串口调试助手-keil5调试工具资源-CSDN文库

五、源代码

《STM32单片机+DS1302时钟模块+OLED屏幕》源代码资源-CSDN文库

六、DS1302时钟模块原理图资料

DS1302时钟模块原理图、模块资料资源-CSDN文库

  • 27
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
STM32是一款由意法半导体(STMicroelectronics)推出的32位微控制器,DS1302是一种实时时钟芯片,OLED是一种有机发光二极管显示屏。通过使用STM32微控制器、DS1302实时时钟芯片和OLED显示屏,我们可以实现一个电子时钟系统。 首先,我们需要将STM32DS1302OLED连接起来。将DS1302的引脚连接到STM32的相应引脚,这样,STM32就可以读取DS1302中的时间信息。然后,将OLED的引脚连接到STM32的相应引脚,以便将时间信息显示在OLED屏幕上。 接下来,我们需要编程来实现电子时钟的功能。使用STM32的开发环境,我们可以编写程序来读取DS1302中的时间信息,并将其显示在OLED屏幕上。同时,我们可以使用STM32的GPIO引脚配置按键,以便我们可以通过按键来进行时间的调整和设置。 在程序中,我们可以使用DS1302库来读取和设置时间信息,以及进行时间的计算和调整。然后,通过OLED库,将时间信息实时显示在屏幕上。我们还可以在程序中实现按键检测和按键事件处理的功能,以便通过按键来设置时间、调整时间等操作。 总结一下,通过使用STM32微控制器、DS1302实时时钟芯片和OLED显示屏,我们可以实现一个功能完善的电子时钟系统。这个系统可以通过按键进行时间的设置和调整,并将时间信息实时显示在OLED屏幕上。这样的电子时钟系统可以用于家庭、办公室等各种场合,提供精准的时间显示和方便的时间调整功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

STM32单片机定制

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值