DS1302时钟模块(基于STM32F407Hal库)

一、介绍

        DS1302是一款实时时钟(RTC)芯片,它能够为微控制器提供年、月、日、星期、时、分、秒的时间信息,并且可以通过简单的串行接口进行通信。DS1302 具有低功耗、备用电池接口和 RAM 存储等功能,广泛应用于需要时间记录的电子设备中。

        以上是我们要使用的模块,芯片的详细介绍看一看之前在蓝桥杯里面的介绍。

二、程序

采用STM32F407来驱动,下列是引脚接口:

DS1302_RST

PC12

DS1302_DAT

PC11

DS1302_CLK

PC10

1、CubeMX配置

        将三个GPIO都初始化为推挽上拉输出,输出速度不必太高。

2、编写一个微秒延时函数(这个并不准确,如果需要更准确的延时,建议采用定时器)

// 添加微秒级延时函数
void Delay_us(uint32_t us)
{
    uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
    while (delay--)
    {
        __NOP();
    }
}

3、DS1302.c文件

uint8_t DS1302_Time[3] = {23, 59, 50}; //初始时间 23:59:50
uint8_t RTC_Write_Addr[3] = {0x84, 0x82, 0x80};
uint8_t RTC_Read_Addr[3] = {0x85, 0x83, 0x81};
void DS1302_DataPin_Input(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = DS1302_DAT_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(DS1302_DAT_GPIO_Port, &GPIO_InitStruct);
}

void DS1302_DataPin_Output(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = DS1302_DAT_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DS1302_DAT_GPIO_Port, &GPIO_InitStruct);
}
/*RST*/
#define CE_L HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_RESET)
#define CE_H HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_SET)
/*SCLK*/
#define SCLK_L HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_RESET)
#define SCLK_H HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_SET)
/*IO*/
#define IO_L HAL_GPIO_WritePin(DS1302_DAT_GPIO_Port, DS1302_DAT_Pin, GPIO_PIN_RESET)
#define IO_H HAL_GPIO_WritePin(DS1302_DAT_GPIO_Port, DS1302_DAT_Pin, GPIO_PIN_SET)

void Write_DS1302(uint8_t dat)
{
    DS1302_DataPin_Output();
    for(uint8_t i=0; i<8; i++)
    {  
		SCLK_L;
        if(dat & 0x01) IO_H;
        else IO_L;
		Delay_us(2);
        SCLK_H;
        Delay_us(2);
        
        dat >>= 1;
    }
}

void Write_DS1302_Byte(uint8_t addr, uint8_t dat)
{
    CE_L; 	
    SCLK_L; Delay_us(5);
    CE_H;   Delay_us(5);
    Write_DS1302(addr);
    Write_DS1302(dat);
    CE_L;
    SCLK_L; 
}

uint8_t Read_DS1302_Byte(uint8_t addr)
{
    uint8_t dat = 0;
    CE_L;	
    SCLK_L; Delay_us(5);
    CE_H;  	Delay_us(5);
    Write_DS1302(addr);
    DS1302_DataPin_Input();
    for(uint8_t i=0; i<8; i++)
    {
		SCLK_L; 
		Delay_us(2);
		dat >>= 1;
		if(HAL_GPIO_ReadPin(DS1302_DAT_GPIO_Port, DS1302_DAT_Pin) == GPIO_PIN_SET)
            dat |= 0x80;
        SCLK_H;     
		Delay_us(2);
		
		
    }
	CE_L;	Delay_us(2);
	SCLK_L;	Delay_us(2);
    
    return dat;
}

void DS1302_SetTime(void)
{
    uint8_t i=0;
    Write_DS1302_Byte(0x8E, 0x00); // Disable write protection
    for(i=0; i<3; i++)
    {
        Write_DS1302_Byte(RTC_Write_Addr[i], (DS1302_Time[i] / 10 * 16 + DS1302_Time[i] % 10));
    }
    Write_DS1302_Byte(0x8E, 0x80); // Enable write protection
}

void DS1302_GetTime(void)
{
    uint8_t i=0, temp=0;
    for(i=0; i<3; i++)
    {
        temp = Read_DS1302_Byte(RTC_Read_Addr[i]);
        DS1302_Time[i] = (temp / 16 * 10 + temp % 16);
    }
}

4、DS1302.h文件

#ifndef __DS1302_H
#define __DS1302_H

#include "main.h"
#include "gpio.h"
#include "oled.h"

extern uint8_t DS1302_Time[3];

void DS1302_SetTime(void);
void DS1302_GetTime(void);

#endif

5、可以调用自己的OLED函数显示数组中存储的时分秒时间,年月日也是同样道理,在数组中添加相应地址即可(注意先后与顺序)。

DS1302是一款实时时钟芯片,能为微控制器提供年、月、日、星期、时、分、秒的时间信息,可通过简单串行接口通信,具有低功耗、备用电池接口和RAM存储等功能,在需要时间记录的电子设备中应用广泛[^1]。 以下是一个使用STM32HAL编写的DS1302时钟模块程序示例,包含头文件和源文件: ### DS1302.h文件 ```c #ifndef __DS1302_H #define __DS1302_H #include "main.h" // 时间结构体 typedef struct { uint16_t year; uint8_t month; uint8_t day; uint8_t hour; uint8_t minute; uint8_t second; uint8_t week; } DS1302TimeStruct; typedef struct { void (* Init)(void); void (* SetTime)(uint8_t *writeTime); void (* GetTime)(DS1302TimeStruct *timeData); } DS1302ClassStruct; extern DS1302ClassStruct DS1302Class; #endif ``` ### DS1302.c文件 ```c #include "DS1302.h" #include "stm32f4xx_hal.h" // 定义DS1302引脚 #define DS1302_CLK_PIN GPIO_PIN_0 #define DS1302_CLK_PORT GPIOA #define DS1302_IO_PIN GPIO_PIN_1 #define DS1302_IO_PORT GPIOA #define DS1302_RST_PIN GPIO_PIN_2 #define DS1302_RST_PORT GPIOA // 函数声明 static void DS1302_Init(void); static void DS1302_SetTime(uint8_t *writeTime); static void DS1302_GetTime(DS1302TimeStruct *timeData); // 初始化DS1302ClassStruct DS1302ClassStruct DS1302Class = { .Init = DS1302_Init, .SetTime = DS1302_SetTime, .GetTime = DS1302_GetTime }; // 写入一个字节到DS1302 static void DS1302_WriteByte(uint8_t dat) { uint8_t i; for (i = 0; i < 8; i++) { HAL_GPIO_WritePin(DS1302_CLK_PORT, DS1302_CLK_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(DS1302_IO_PORT, DS1302_IO_PIN, (dat & 0x01)? GPIO_PIN_SET : GPIO_PIN_RESET); dat >>= 1; HAL_GPIO_WritePin(DS1302_CLK_PORT, DS1302_CLK_PIN, GPIO_PIN_SET); } } // 从DS1302读取一个字节 static uint8_t DS1302_ReadByte(void) { uint8_t i, dat = 0; for (i = 0; i < 8; i++) { HAL_GPIO_WritePin(DS1302_CLK_PORT, DS1302_CLK_PIN, GPIO_PIN_RESET); dat >>= 1; if (HAL_GPIO_ReadPin(DS1302_IO_PORT, DS1302_IO_PIN) == GPIO_PIN_SET) { dat |= 0x80; } HAL_GPIO_WritePin(DS1302_CLK_PORT, DS1302_CLK_PIN, GPIO_PIN_SET); } return dat; } // 初始化DS1302 static void DS1302_Init(void) { // 使能GPIO时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); // 配置CLK、IO、RST引脚为输出模式 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = DS1302_CLK_PIN | DS1302_IO_PIN | DS1302_RST_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_GPIO_WritePin(DS1302_RST_PORT, DS1302_RST_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(DS1302_CLK_PORT, DS1302_CLK_PIN, GPIO_PIN_RESET); } // 设置DS1302时间 static void DS1302_SetTime(uint8_t *writeTime) { uint8_t i; HAL_GPIO_WritePin(DS1302_RST_PORT, DS1302_RST_PIN, GPIO_PIN_SET); DS1302_WriteByte(0x8E); // 写保护寄存器地址 DS1302_WriteByte(0x00); // 关闭写保护 for (i = 0; i < 7; i++) { DS1302_WriteByte(0x80 + 2 * i); // 时间寄存器地址 DS1302_WriteByte(writeTime[i]); // 写入时间数据 } DS1302_WriteByte(0x8E); // 写保护寄存器地址 DS1302_WriteByte(0x80); // 打开写保护 HAL_GPIO_WritePin(DS1302_RST_PORT, DS1302_RST_PIN, GPIO_PIN_RESET); } // 获取DS1302时间 static void DS1302_GetTime(DS1302TimeStruct *timeData) { uint8_t i; uint8_t readData[7]; HAL_GPIO_WritePin(DS1302_RST_PORT, DS1302_RST_PIN, GPIO_PIN_SET); for (i = 0; i < 7; i++) { DS1302_WriteByte(0x81 + 2 * i); // 时间寄存器地址 readData[i] = DS1302_ReadByte(); // 读取时间数据 } HAL_GPIO_WritePin(DS1302_RST_PORT, DS1302_RST_PIN, GPIO_PIN_RESET); timeData->second = (readData[0] & 0x0F) + ((readData[0] >> 4) * 10); timeData->minute = (readData[1] & 0x0F) + ((readData[1] >> 4) * 10); timeData->hour = (readData[2] & 0x0F) + ((readData[2] >> 4) * 10); timeData->day = (readData[3] & 0x0F) + ((readData[3] >> 4) * 10); timeData->month = (readData[4] & 0x0F) + ((readData[4] >> 4) * 10); timeData->week = readData[5]; timeData->year = 2000 + (readData[6] & 0x0F) + ((readData[6] >> 4) * 10); } ``` ### main.c文件调用示例 ```c #include "main.h" #include "DS1302.h" void SystemClock_Config(void); static void MX_GPIO_Init(void); DS1302TimeStruct currentTime; int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); // 初始化DS1302 DS1302Class.Init(); // 设置时间示例 uint8_t setTime[7] = {0x00, 0x30, 0x12, 0x01, 0x01, 0x01, 0x23}; // 秒、分、时、日、月、周、年 DS1302Class.SetTime(setTime); while (1) { // 获取当前时间 DS1302Class.GetTime(&currentTime); // 可以在这里处理获取到的时间,例如打印到串口等 HAL_Delay(1000); } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2, GPIO_PIN_RESET); /*Configure GPIO pins : PA0 PA1 PA2 */ GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } ``` ### 代码说明 1. **DS1302.h**:定义了时间结构体和DS1302操作函数结构体,以及相关的外部变量声明。 2. **DS1302.c**:实现了DS1302的初始化、写入字节、读取字节、设置时间和获取时间等功能。 3. **main.c**:调用DS1302的初始化、设置时间和获取时间函数,并在循环中每秒获取一次当前时间。 ### 注意事项 - 请根据实际情况修改DS1302的引脚定义。 - 代码中的时间设置示例可以根据需要修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值