STM32基于HAL库实现DS3231硬件I2C读写

一、芯片介绍

二、模块与接线

笔者使用的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_Set_Pointer(DS3231_REG addr)
{
	HAL_I2C_Mem_Write(&hi2c2,0xD0,addr,1,NULL,0,0xffff);
}

/*一次性读取所有的寄存器*/
void DS3231_Read_All()
{
	DS3231_Set_Pointer(SECONDS);
	
	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_Set_Pointer(DS3231_REG addr)
{
	HAL_I2C_Mem_Write(&hi2c2,0xD0,addr,1,NULL,0,0xffff);
}

/*一次性读取所有的寄存器*/
void DS3231_Read_All()
{
	DS3231_Set_Pointer(SECONDS);
	
	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

作者:田甲

物联沃分享整理
物联沃-IOTWORD物联网 » STM32基于HAL库实现DS3231硬件I2C读写

发表评论