基于STM32的智慧宿舍系统(DAY4)_DS1307

在本系统里使用了一个RTC模块DS1307,并且通过STM32来控制,显示标准时间,日历、计时等功能,这个芯片使用i2c接口,同多对对应寄存器的读取就能获取当前时间,当然这个时间是需要我们先设置一下的,具体内容感兴趣可以参考芯片手册,我这里值展示我们能用到的相关内容。

#define DS1307_I2C_ADDR     0x68
#define DS1307_REG_SECOND   0x00
#define DS1307_REG_MINUTE   0x01
#define DS1307_REG_HOUR     0x02
#define DS1307_REG_DOW      0x03
#define DS1307_REG_DATE     0x04
#define DS1307_REG_MONTH    0x05
#define DS1307_REG_YEAR     0x06
#define DS1307_REG_CONTROL  0x07
#define DS1307_REG_UTC_HR   0x08
#define DS1307_REG_UTC_MIN  0x09
#define DS1307_REG_CENT     0x10
#define DS1307_REG_RAM      0x11
#define DS1307_TIMEOUT      1000

我把比较关键的函数接口写在下面,供参考,我们首先从硬件层面来说是初始化操作,启动计时

/**
 * @brief 初始化 DS1307 模块。设置时钟停止位为 0,开始计时。
 * @param hi2c 用户提供的 I2C 句柄指针。
 */
void DS1307_Init(I2C_HandleTypeDef *hi2c) {
    _ds1307_ui2c = hi2c; // 将传入的 I2C 句柄保存到全局变量
    DS1307_SetClockHalt(0); // 设置时钟停止位为 0,启动计时
}

/**
 * @brief 设置时钟停止位。
 * @param halt 时钟停止位,0 或 1。0 用于开始计时,1 用于停止计时。
 */
void DS1307_SetClockHalt(uint8_t halt) {
    uint8_t ch = (halt ? 1 << 7 : 0); // 根据传入的 halt 值决定设置时钟停止位
    // 设置 DS1307 的秒钟寄存器(SECOND),将停止位修改为所需值
    DS1307_SetRegByte(DS1307_REG_SECOND, ch | (DS1307_GetRegByte(DS1307_REG_SECOND) & 0x7f));
}

/**
 * @brief 获取当前时钟停止位。
 * @return 时钟停止位,0 或 1。
 */
uint8_t DS1307_GetClockHalt(void) {
    // 获取秒钟寄存器中的停止位(第 7 位)
    return (DS1307_GetRegByte(DS1307_REG_SECOND) & 0x80) >> 7;
}

/**
 * @brief 设置指定 DS1307 寄存器的字节值。
 * @param regAddr 寄存器地址。
 * @param val 要设置的值,范围是 0 到 255。
 */
void DS1307_SetRegByte(uint8_t regAddr, uint8_t val) {
    uint8_t bytes[2] = { regAddr, val }; // 创建一个包含寄存器地址和数据的字节数组
    // 通过 I2C 总线向 DS1307 发送数据
    HAL_I2C_Master_Transmit(_ds1307_ui2c, DS1307_I2C_ADDR << 1, bytes, 2, DS1307_TIMEOUT);
}

/**
 * @brief 获取指定 DS1307 寄存器的字节值。
 * @param regAddr 寄存器地址。
 * @return 寄存器中存储的值,范围是 0 到 255。
 */
uint8_t DS1307_GetRegByte(uint8_t regAddr) {
    uint8_t val;
    // 通过 I2C 总线发送寄存器地址,并接收寄存器中的数据
    HAL_I2C_Master_Transmit(_ds1307_ui2c, DS1307_I2C_ADDR << 1, &regAddr, 1, DS1307_TIMEOUT);
    HAL_I2C_Master_Receive(_ds1307_ui2c, DS1307_I2C_ADDR << 1, &val, 1, DS1307_TIMEOUT);
    return val;
}

DS1307_SetRegByte和DS1307_GetRegByte是封装的两个函数接口,下面是获取当前时间的一些函数,我们通过调用即可获取

/**
 * @brief 获取当前星期几。
 * @return 距离上一个星期天的天数,范围是 0 到 6。
 */
uint8_t DS1307_GetDayOfWeek(void) {
    return DS1307_DecodeBCD(DS1307_GetRegByte(DS1307_REG_DOW)); // 获取星期几的值并解码
}

/**
 * @brief 获取当前日期(月份中的第几天)。
 * @return 日期,范围是 1 到 31。
 */
uint8_t DS1307_GetDate(void) {
    return DS1307_DecodeBCD(DS1307_GetRegByte(DS1307_REG_DATE)); // 获取日期并解码
}

/**
 * @brief 获取当前月份。
 * @return 月份,范围是 1 到 12。
 */
uint8_t DS1307_GetMonth(void) {
    return DS1307_DecodeBCD(DS1307_GetRegByte(DS1307_REG_MONTH)); // 获取月份并解码
}

/**
 * @brief 获取当前年份。
 * @return 年份,范围是 2000 到 2099。
 */
uint16_t DS1307_GetYear(void) {
    uint16_t cen = DS1307_GetRegByte(DS1307_REG_CENT) * 100; // 获取世纪部分
    return DS1307_DecodeBCD(DS1307_GetRegByte(DS1307_REG_YEAR)) + cen; // 获取年份并解码,合并世纪
}

/**
 * @brief 获取当前小时(24 小时制)。
 * @return 小时,范围是 0 到 23。
 */
uint8_t DS1307_GetHour(void) {
    return DS1307_DecodeBCD(DS1307_GetRegByte(DS1307_REG_HOUR) & 0x3f); // 获取小时并解码,去除 AM/PM 标志位
}

/**
 * @brief 获取当前分钟。
 * @return 分钟,范围是 0 到 59。
 */
uint8_t DS1307_GetMinute(void) {
    return DS1307_DecodeBCD(DS1307_GetRegByte(DS1307_REG_MINUTE)); // 获取分钟并解码
}

/**
 * @brief 获取当前秒钟(不包括时钟停止位)。
 * @return 秒钟,范围是 0 到 59。
 */
uint8_t DS1307_GetSecond(void) {
    return DS1307_DecodeBCD(DS1307_GetRegByte(DS1307_REG_SECOND) & 0x7f); // 获取秒钟并解码,去除停止位
}

下面是一些设置函数,通过使用这些函数后我们可以对当前时间进行设置

/**
 * @brief 设置当前星期几。
 * @param dayOfWeek 距离上一个星期天的天数,范围是 0 到 6。
 */
void DS1307_SetDayOfWeek(uint8_t dayOfWeek) {
    DS1307_SetRegByte(DS1307_REG_DOW, DS1307_EncodeBCD(dayOfWeek)); // 设置星期几,并编码为 BCD 格式
}

/**
 * @brief 设置当前日期(月份中的第几天)。
 * @param date 日期,范围是 1 到 31。
 */
void DS1307_SetDate(uint8_t date) {
    DS1307_SetRegByte(DS1307_REG_DATE, DS1307_EncodeBCD(date)); // 设置日期,并编码为 BCD 格式
}

/**
 * @brief 设置当前月份。
 * @param month 月份,范围是 1 到 12。
 */
void DS1307_SetMonth(uint8_t month) {
    DS1307_SetRegByte(DS1307_REG_MONTH, DS1307_EncodeBCD(month)); // 设置月份,并编码为 BCD 格式
}

/**
 * @brief 设置当前年份。
 * @param year 年份,范围是 2000 到 2099。
 */
void DS1307_SetYear(uint16_t year) {
    // 设置世纪部分(年份的前两位),存储在 CENT 寄存器中
    DS1307_SetRegByte(DS1307_REG_CENT, year / 100);
    // 设置年份的后两位(百位以下),存储在 YEAR 寄存器中
    DS1307_SetRegByte(DS1307_REG_YEAR, DS1307_EncodeBCD(year % 100));
}

/**
 * @brief 设置当前小时(24 小时制)。
 * @param hour_24mode 小时(24 小时制),范围是 0 到 23。
 */
void DS1307_SetHour(uint8_t hour_24mode) {
    // 将小时(0-23)编码为二进制编码十进制(BCD)格式,并设置到 HOUR 寄存器中
    DS1307_SetRegByte(DS1307_REG_HOUR, DS1307_EncodeBCD(hour_24mode & 0x3f));
    // 注意:使用与操作(& 0x3f)确保时钟数据的高位(AM/PM标志)为零,始终使用 24 小时制
}

/**
 * @brief 设置当前分钟。
 * @param minute 分钟,范围是 0 到 59。
 */
void DS1307_SetMinute(uint8_t minute) {
    // 将分钟编码为 BCD 格式并存储到 MINUTE 寄存器中
    DS1307_SetRegByte(DS1307_REG_MINUTE, DS1307_EncodeBCD(minute));
}

/**
 * @brief 设置当前秒钟。
 * @param second 秒钟,范围是 0 到 59。
 */
void DS1307_SetSecond(uint8_t second) {
    uint8_t ch = DS1307_GetClockHalt(); // 获取时钟停止位(如果是 1,则时钟停止)
    // 将秒钟编码为 BCD 格式,并设置到 SECOND 寄存器中,同时保留时钟停止位的状态
    DS1307_SetRegByte(DS1307_REG_SECOND, DS1307_EncodeBCD(second | ch));
}

/**
 * @brief 设置 UTC 偏移。
 * @note  UTC 偏移不会自动更新。
 * @param hr UTC 小时偏移,范围是 -12 到 12。
 * @param min UTC 分钟偏移,范围是 0 到 59。
 */
void DS1307_SetTimeZone(int8_t hr, uint8_t min) {
    // 设置 UTC 小时偏移,存储在 UTC_HR 寄存器中
    DS1307_SetRegByte(DS1307_REG_UTC_HR, hr);
    // 设置 UTC 分钟偏移,存储在 UTC_MIN 寄存器中
    DS1307_SetRegByte(DS1307_REG_UTC_MIN, min);
}

至此DS1307的驱动就算完成了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值