【STM32】DS3231硬件I2C读写,基于HAL库

目录

一、工程链接

二、芯片介绍

三、模块与接线

四、cubemx配置

五、驱动编写

读数据

写数据

时间转换

时间解析

设置时间

读取温度

六、代码编写

七、效果展示

八、驱动附录

ds3231.c

ds3231.h


一、工程链接

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
好的,关于STM32 HAL硬件I2C通信,我可以给你一些基本的信息和代码示例。 首先需要在CubeMX中配置I2C外设,并且生成HAL初始化代码。以下是一个示例代码,可以用于初始化I2C1外设: ``` /* I2C1 init function */ static void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.Timing = 0x00707CBB; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } } ``` 然后,就可以使用HAL提供的函数进行I2C通信了。以下是一个示例代码,可以用于向I2C设备发送数据: ``` uint8_t i2c_tx_buf[2]; i2c_tx_buf[0] = 0x00; // 选择寄存器地址 i2c_tx_buf[1] = 0x12; // 写入的数据 HAL_I2C_Master_Transmit(&hi2c1, I2C_DEVICE_ADDRESS, i2c_tx_buf, 2, HAL_MAX_DELAY); ``` 其中,`I2C_DEVICE_ADDRESS`是I2C设备的地址,可以在设备的数据手册中查找。 接下来是一个示例代码,可以用于从I2C设备读取数据: ``` uint8_t i2c_rx_buf[2]; i2c_rx_buf[0] = 0x00; // 选择寄存器地址 HAL_I2C_Master_Transmit(&hi2c1, I2C_DEVICE_ADDRESS, i2c_rx_buf, 1, HAL_MAX_DELAY); HAL_I2C_Master_Receive(&hi2c1, I2C_DEVICE_ADDRESS, i2c_rx_buf, 2, HAL_MAX_DELAY); ``` 其中,先使用`HAL_I2C_Master_Transmit`函数向I2C设备发送寄存器地址,然后使用`HAL_I2C_Master_Receive`函数从I2C设备接收数据。 以上是一个简单的硬件I2C通信的示例,希望可以帮助到你!
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值