目录
一、工程链接
STM32DS3231硬件I2C读写,基于HAL库资源-CSDN文库
二、芯片介绍
三、模块与接线
笔者使用的DS3231是淘宝买的模块,除了I2C通信引脚和电源引脚,剩余引脚并未引出,如下图所示。
笔者的单片机为STM32F103CBT6,使用I2C2
因此接线如下
VCC-->3V3
SCL-->PB10
SDA-->PB11
GND-->GND
四、cubemx配置
开启I2C2和串口1
开启时钟
五、驱动编写
阅读手册,下图为DS3231内的寄存器和定义
对于基础使用,只要前面几个年月日,时分秒寄存器的读写即可。
不妨定义一个DS3231的寄存器结构体和枚举类型
/*DS3231寄存器结构体*/
typedef struct
{
uint8_t Seconds;
uint8_t Minutes;
uint8_t Hours;
uint8_t Day;
uint8_t Date;
uint8_t Month_Century;
uint8_t Year;
uint8_t Alarm_1_Seconds;
uint8_t Alarm_1_Minutes;
uint8_t Alarm_1_Hours;
uint8_t Alarm_1_Day_Date;
uint8_t Alarm_2_Minutes;
uint8_t Alarm_2_Hours;
uint8_t Alarm_2_Day_Date;
uint8_t Control;
uint8_t Control_Status;
uint8_t Aging_Offset;
uint8_t Temp_MSB;
uint8_t Temp_LSB;
}DS3231_RegisterType;
typedef enum
{
SECONDS=0,
MINUTES,
HOURS,
DAY,
DATE,
MONTH_CENTURY,
YEAR,
ALARM_1_SECONDS,
ALARM_1_MINUTES,
ALARM_1_HOURS,
ALARM_1_DAY,
ALARM_1_DATE,
ALARM_2_MINUTES,
ALARM_2_HOURS,
ALARM_2_DAY_DATE,
CONTROL,
CONTROL_STATUS,
AGING_OFFSET,
TEMP_MSB,
TEMP_LSB
}DS3231_REG;
读数据
芯片采用的是I2C通信协议
需要注意的是,如果贸然读取,这里寄存器指针所指向的位置其实是不明确的,因此我们先发送一个地址进行定位
代码如下
/*一次性读取所有的寄存器*/
void DS3231_Read_All()
{
uint8_t temp[1] = {0};
/*设置寄存器指针位置*/
HAL_I2C_Master_Transmit(&hi2c2, 0xD0, temp, 1, 0xffff);
HAL_I2C_Master_Receive(&hi2c2, 0xD1, &(DS3231_Register), sizeof(DS3231_Register), 0xffff);
}
波形如下
写数据
代码如下
void DS3231_Update()
{
HAL_I2C_Mem_Write(&hi2c2,0xD0,0x00,1,&DS3231_Register,sizeof(DS3231_Register),0xffff);
}
波形如下
时间转换
需要注意的是DS3231内寄存器存放的格式是8421BCD码,与平时的十进制不同,因此引入两个函数进行互相转换
uint8_t bcd2dec(uint8_t bcd)
{
return ( (bcd) >> 4 ) * 10 + ( (bcd) & 0x0f );
}
uint8_t dec2bcd(uint8_t dec)
{
return (( (dec)/10 ) << 4) + ( (dec) % 10 );
}
时间解析
通过转换时间来解析芯片内的实时时间
void DS3231_Read_Time()
{
DS3231_Time.sec = bcd2dec(DS3231_Register.Seconds);
DS3231_Time.min = bcd2dec(DS3231_Register.Minutes);
if((DS3231_Register.Hours & 0x40) == 0x40)
{
DS3231_Time.hour_form = HOUR_FORM_12;
DS3231_Time.AM_PM = (DS3231_Register.Hours) & 0x20;
DS3231_Time.hour = bcd2dec(DS3231_Register.Hours & 0x1F);
}
else
{
DS3231_Time.hour_form = HOUR_FORM_24;
DS3231_Time.hour = bcd2dec(DS3231_Register.Hours);
}
DS3231_Time.year = bcd2dec(DS3231_Register.Year);
DS3231_Time.mon = bcd2dec(DS3231_Register.Month_Century);
DS3231_Time.date = bcd2dec(DS3231_Register.Date);
DS3231_Time.day = DS3231_Register.Day;
}
设置时间
设置DS3231结构体内的值,设置好后通过写寄存器函数将设置的时间写入芯片
void DS3231_Set_Time(DS3231_TimeType* time)
{
DS3231_Register.Seconds = dec2bcd(time->sec);
DS3231_Register.Minutes = dec2bcd(time->min);
if(time->hour_form == HOUR_FORM_12)
{
DS3231_Register.Hours = (0x40 | (time->AM_PM<<5))|(dec2bcd(time->hour));
}
else
{
DS3231_Register.Hours = dec2bcd(time->hour);
}
DS3231_Register.Year = dec2bcd(time->year);
DS3231_Register.Month_Century = dec2bcd(time->mon);
DS3231_Register.Date = dec2bcd(time->date);
DS3231_Register.Day = time->day;
}
读取温度
DS3231提供了内置的温度,这里编写一个函数进行读取
float DS3231_Read_Temp()
{
uint8_t sign = (DS3231_Register.Temp_MSB >> 7);
float ret;
ret = (float)DS3231_Register.Temp_MSB + (float)(DS3231_Register.Temp_LSB >> 6)*0.25f;
if(sign)
{
ret = 0 - ret;
}
else
{
}
return ret;
}
六、代码编写
添加串口重定向和头文件包含#include "stdio.h"
/**
* 函数功能: 重定向c库函数printf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
main.c文件包含一下ds3231.h和stdio.h
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C2_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
DS3231_Read_All();
DS3231_Read_Time();
printf("20%d/%d/%d %d:%d:%d\r\n",DS3231_Time.year,DS3231_Time.mon,DS3231_Time.date,DS3231_Time.hour,DS3231_Time.min,DS3231_Time.sec);
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
七、效果展示
八、驱动附录
ds3231.c
#include "ds3231.h"
volatile uint8_t DS3231_buffer[19];
DS3231_RegisterType DS3231_Register;
DS3231_TimeType DS3231_Time;
uint8_t bcd2dec(uint8_t bcd)
{
return ( (bcd) >> 4 ) * 10 + ( (bcd) & 0x0f );
}
uint8_t dec2bcd(uint8_t dec)
{
return (( (dec)/10 ) << 4) + ( (dec) % 10 );
}
/*一次性读取所有的寄存器*/
void DS3231_Read_All()
{
uint8_t temp[1] = {0};
/*设置寄存器指针位置*/
HAL_I2C_Master_Transmit(&hi2c2, 0xD0, temp, 1, 0xffff);
HAL_I2C_Master_Receive(&hi2c2, 0xD1, &(DS3231_Register), sizeof(DS3231_Register), 0xffff);
}
float DS3231_Read_Temp()
{
uint8_t sign = (DS3231_Register.Temp_MSB >> 7);
float ret;
ret = (float)DS3231_Register.Temp_MSB + (float)(DS3231_Register.Temp_LSB >> 6)*0.25f;
if(sign)
{
ret = 0 - ret;
}
else
{
}
return ret;
}
void DS3231_Read_Time()
{
DS3231_Time.sec = bcd2dec(DS3231_Register.Seconds);
DS3231_Time.min = bcd2dec(DS3231_Register.Minutes);
if((DS3231_Register.Hours & 0x40) == 0x40)
{
DS3231_Time.hour_form = HOUR_FORM_12;
DS3231_Time.AM_PM = (DS3231_Register.Hours) & 0x20;
DS3231_Time.hour = bcd2dec(DS3231_Register.Hours & 0x1F);
}
else
{
DS3231_Time.hour_form = HOUR_FORM_24;
DS3231_Time.hour = bcd2dec(DS3231_Register.Hours);
}
DS3231_Time.year = bcd2dec(DS3231_Register.Year);
DS3231_Time.mon = bcd2dec(DS3231_Register.Month_Century);
DS3231_Time.date = bcd2dec(DS3231_Register.Date);
DS3231_Time.day = DS3231_Register.Day;
}
void DS3231_Set_Time(DS3231_TimeType* time)
{
DS3231_Register.Seconds = dec2bcd(time->sec);
DS3231_Register.Minutes = dec2bcd(time->min);
if(time->hour_form == HOUR_FORM_12)
{
DS3231_Register.Hours = (0x40 | (time->AM_PM<<5))|(dec2bcd(time->hour));
}
else
{
DS3231_Register.Hours = dec2bcd(time->hour);
}
DS3231_Register.Year = dec2bcd(time->year);
DS3231_Register.Month_Century = dec2bcd(time->mon);
DS3231_Register.Date = dec2bcd(time->date);
DS3231_Register.Day = time->day;
}
void DS3231_Update()
{
HAL_I2C_Mem_Write(&hi2c2,0xD0,0x00,1,&DS3231_Register,sizeof(DS3231_Register),0xffff);
}
ds3231.h
#ifndef DS3231_H
#define DS3231_H
#include "main.h"
#include "i2c.h"
typedef enum
{
SECONDS=0,
MINUTES,
HOURS,
DAY,
DATE,
MONTH_CENTURY,
YEAR,
ALARM_1_SECONDS,
ALARM_1_MINUTES,
ALARM_1_HOURS,
ALARM_1_DAY_DATE,
ALARM_2_MINUTES,
ALARM_2_HOURS,
ALARM_2_DAY_DATE,
CONTROL,
CONTROL_STATUS,
AGING_OFFSET,
TEMP_MSB,
TEMP_LSB
}DS3231_REG;
/*小时制*/
typedef enum
{
HOUR_FORM_24,
HOUR_FORM_12
}DS3231_HOUR_FORM;
/*上午下午*/
typedef enum
{
AM,
PM
}AM_PM;
/*DS3231寄存器结构体*/
typedef struct
{
uint8_t Seconds;
uint8_t Minutes;
uint8_t Hours;
uint8_t Day;
uint8_t Date;
uint8_t Month_Century;
uint8_t Year;
uint8_t Alarm_1_Seconds;
uint8_t Alarm_1_Minutes;
uint8_t Alarm_1_Hours;
uint8_t Alarm_1_Day_Date;
uint8_t Alarm_2_Minutes;
uint8_t Alarm_2_Hours;
uint8_t Alarm_2_Day_Date;
uint8_t Control;
uint8_t Control_Status;
uint8_t Aging_Offset;
uint8_t Temp_MSB;
uint8_t Temp_LSB;
}DS3231_RegisterType;
/*时间结构体*/
typedef struct
{
uint8_t hour;
uint8_t AM_PM;
DS3231_HOUR_FORM hour_form;
uint8_t min;
uint8_t sec;
uint8_t year;
uint8_t mon;
uint8_t date;
uint8_t day;
}DS3231_TimeType;
/*DS3231结构体缓存*/
extern volatile uint8_t DS3231_buffer[19];
/*DS3231全局变量*/
extern DS3231_RegisterType DS3231_Register;
/*时间全局变量*/
extern DS3231_TimeType DS3231_Time;
void DS3231_Read_All();
void DS3231_Read_Time();
float DS3231_Read_Temp();
void DS3231_Set_Time(DS3231_TimeType* time);
void DS3231_Update();
#endif