STM32模拟I2C协议获取HMC5883L电子罗盘磁角度数据 (HAL)

这篇具有很好参考价值的文章主要介绍了STM32模拟I2C协议获取HMC5883L电子罗盘磁角度数据 (HAL)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

STM32模拟I2C协议获取HMC5883L电子罗盘磁角度数据(HAL)

HMC5883L 传感器采用霍尼韦尔各向异性磁阻(AMR)技术,应用于罗盘和三轴磁场角度检测领域,常用于水平物体转动的角度识别。HMC5883L 采用I2C总线接口,2.16~3.6V供电范围,带有校准测试功能。

HMC5883L的硬件连接

hmc5883寄存器,STM32,stm32,HMC5883,HMC5883L,电子罗盘,磁角度
HMC5883L的硬件连接有5个管脚,除了VCC和GND,以及I2C的SCK和SDA,还有一根INT中断线,用于向MCU报告数据可读取。

HMC5883L的寄存器说明

HMC5883L有如下的一些寄存器,按作用分为4种:
hmc5883寄存器,STM32,stm32,HMC5883,HMC5883L,电子罗盘,磁角度

地址00~02用于配置测试过程中的采样平均次数,数据输出率,测量配置(对应正常或自检测试),增益配置,测量模式(正常或自检测试)。
地址03~08存放测试结果数据,每轴16位,用两个字节存放,注意这6个地址对应的顺序是 X轴–Z轴–Y轴,而不是 X轴–Y轴–Z轴。
地址09是状态的读寄存器,可以通过读取状态获得结果数据是否可读取,替代的方式使用HMC5883L输出的上升沿硬件中断线。
地址10~12存放一些识别码,一般用于读出比较,验证I2C总线访问是否成功。

STM32工程基本配置

这里以STM32G030F6P6以及STM32CUBEIDE开发平台为例,通过模拟I2C访问HMC5883L的方式,实现地磁角度的识别,实现的功能有:

  1. 写读HMC5883L内部寄存器
  2. 配置HMC5883L为正常工作模式,并获取地磁角度数据
  3. 配置HMC5883L为自检工作模式,实现自检校准系数的应用
  4. 实现HMC5883L的温度校准系数的生成和应用

首先建立基本工程并配置时钟:
hmc5883寄存器,STM32,stm32,HMC5883,HMC5883L,电子罗盘,磁角度
配置UART2串口用于打印输出:
hmc5883寄存器,STM32,stm32,HMC5883,HMC5883L,电子罗盘,磁角度
任选三个GPIO用于接口HMC5883L,这里用:
PA0: INT
PA4: SCK
PA5: SDA
PA0配置为上升沿触发中断管脚并使能中断:
hmc5883寄存器,STM32,stm32,HMC5883,HMC5883L,电子罗盘,磁角度
hmc5883寄存器,STM32,stm32,HMC5883,HMC5883L,电子罗盘,磁角度
hmc5883寄存器,STM32,stm32,HMC5883,HMC5883L,电子罗盘,磁角度
I2C配置为Open-drain模式:
hmc5883寄存器,STM32,stm32,HMC5883,HMC5883L,电子罗盘,磁角度
hmc5883寄存器,STM32,stm32,HMC5883,HMC5883L,电子罗盘,磁角度
保存并生成初始工程代码:
hmc5883寄存器,STM32,stm32,HMC5883,HMC5883L,电子罗盘,磁角度
注意如果代码编译后空间不够,参考 STM32 region `FLASH‘ overflowed by xxx bytes 问题解决

STM32工程组件代码

  1. 工程里会使用printf打印输出,相关的代码部分说明参考 STM32 UART串口printf函数应用及浮点打印代码空间节省 (HAL)

  2. 模拟I2C的实现部分要用到微秒级延时函数,相关的代码部分说明参考 STM32 HAL us delay(微秒延时)的指令延时实现方式及优化
    I2C基本访问的代码如下:

void I2C_Init(void)
{

	SCL_OUT_H;
	SDA_OUT_H;
	PY_Delay_us_t(2000000); //Provide device stability time

}

void I2C_Start(void)
{
	PY_Delay_us_t(us_num) ;
	SDA_OUT_H;
	SCL_OUT_H;
	PY_Delay_us_t(us_num/2) ;
	SDA_OUT_L;
	PY_Delay_us_t(us_num/2) ;
	SCL_OUT_L;
}

void I2C_Stop(void)
{
	SCL_OUT_L;
	PY_Delay_us_t(us_num) ;
	SDA_OUT_L;
	PY_Delay_us_t(us_num) ;
	SCL_OUT_H;
	PY_Delay_us_t(us_num) ;
	SDA_OUT_H;
	PY_Delay_us_t(us_num) ;
}

void I2C_Write_Ack(void)
{

    PY_Delay_us_t(us_num/2) ;
	SDA_OUT_L;
	PY_Delay_us_t(us_num/2) ;
	SCL_OUT_H;
	PY_Delay_us_t(us_num) ;
	SCL_OUT_L;
	SDA_OUT_H;

}

uint8_t I2C_Read_Ack(void)
{
	uint8_t status=0;

	SCL_OUT_L;
	PY_Delay_us_t(us_num/2) ;
	SDA_OUT_H;
	PY_Delay_us_t(us_num/2) ;
	status = SDA_IN;
	SCL_OUT_H;
	PY_Delay_us_t(us_num) ;
	SCL_OUT_L;
	SDA_OUT_L;

	return status;

}


void I2C_Send_Byte(uint8_t txd){


    for(uint8_t i=0;i<8;i++)
    {
    	PY_Delay_us_t(us_num/2) ;
        if((txd&0x80)>>7) SDA_OUT_H;
        else SDA_OUT_L;
        txd<<=1;
        PY_Delay_us_t(us_num/2) ;
        SCL_OUT_H;
        PY_Delay_us_t(us_num) ;
		SCL_OUT_L;
    }

    SDA_OUT_L;
}

uint8_t I2C_Read_Byte(unsigned char rdack)
{
	uint8_t rxd=0;


    for(uint8_t i=0;i<8;i++ )
	{
    	SCL_OUT_L;
    	PY_Delay_us_t(us_num/2) ;
    	SDA_OUT_H;
    	PY_Delay_us_t(us_num/2) ;
    	SCL_OUT_H;
        rxd<<=1;
        if(SDA_IN) rxd++;
        PY_Delay_us_t(us_num) ;
    }

    SCL_OUT_L;
    SDA_OUT_H;

    if (rdack) I2C_Write_Ack();

    return rxd;
}

3. HMC5883L的访问操作代码:

#define CRA 0x00
#define CRB 0x01
#define MR 0x02
#define DOXMR 0x03
#define DOXLR 0x04
#define DOZMR 0x05
#define DOZLR 0x06
#define DOYMR 0x07
#define DOYLR 0x08
#define SR 0x09
#define IRA 0x0A
#define IRB 0x0B
#define IRC 0x0C

#define SelfTest_EN 1
uint8_t SF=0;  //Self Test Flag

void PY_HMC5883L_WriteReg(uint8_t WrAddr, uint8_t data)
{
	  uint8_t daddr;
	  daddr = 0x3c; //HMC5883L device address (0x1E<<1)

	  I2C_Start();
	  I2C_Send_Byte(daddr);
	  I2C_Read_Ack();
  	  I2C_Send_Byte(WrAddr);
  	  I2C_Read_Ack();
  	  I2C_Send_Byte(data);
  	  I2C_Read_Ack();
  	  I2C_Stop();

}

uint8_t PY_HMC5883L_ReadReg(uint8_t RdAddr)
{

	  uint8_t RegValue = 0;
	  uint8_t daddr;
	  daddr = 0x3c; //HMC5883L device address (0x1E<<1)

	  I2C_Start();
	  I2C_Send_Byte(daddr);
	  I2C_Read_Ack();
  	  I2C_Send_Byte(RdAddr);
  	  I2C_Read_Ack();

  	  I2C_Start();
	  I2C_Send_Byte(daddr+1);
	  I2C_Read_Ack();
	  RegValue=I2C_Read_Byte(0);
  	  I2C_Stop();

	  return RegValue;
}

/*Note:
To minimize the communication between the master and this device, the address pointer updated automatically without master intervention.
This automatic address pointer update has two additional features. First when address 12 or higher is accessed the pointer updates to address 00 and secondly when address 08 is reached, the pointer rolls back to address 03. Logically, the address pointer operation functions as shown below.
If (address pointer = 08) then address pointer = 03
Else if (address pointer >= 12) then address pointer = 0
Else (address pointer) = (address pointer) + 1
*/
int XD, YD, ZD;
uint16_t Angle;
double XFactor = 1.0,  YFactor = 1.0,  ZFactor = 1.0; //Correction factor coming for self test process
double XFactor_T = 1.0,  YFactor_T = 1.0,  ZFactor_T = 1.0; //Correction factor coming for self test process for temperature impact
void PY_HMC5883L_ReadData(void)
{
      uint8_t data[6];
      uint16_t x, y, z;
	  double angle;

	  uint8_t daddr;
	  daddr = 0x3c; //HMC5883L device address (0x1E<<1)

	  I2C_Start();
	  I2C_Send_Byte(daddr);
	  I2C_Read_Ack();
  	  I2C_Send_Byte(0x03);
  	  I2C_Read_Ack();

  	  I2C_Start();
	  I2C_Send_Byte(daddr+1);
	  I2C_Read_Ack();
	  data[0]=I2C_Read_Byte(1);
	  data[1]=I2C_Read_Byte(1);
	  data[2]=I2C_Read_Byte(1);
	  data[3]=I2C_Read_Byte(1);
	  data[4]=I2C_Read_Byte(1);
	  data[5]=I2C_Read_Byte(0);
  	  I2C_Stop();

  	  x = (((uint16_t)data[0])<<8)|((uint16_t)data[1]);
  	  z = (((uint16_t)data[2])<<8)|((uint16_t)data[3]);
  	  y = (((uint16_t)data[4])<<8)|((uint16_t)data[5]);

  	  if((x>>15)!=0) XD = -(0x10000-x);
  	  else XD = x;

  	  if((y>>15)!=0) YD = -(0x10000-y);
  	  else YD = y;

  	  if((z>>15)!=0) ZD = -(0x10000-z);
  	  else ZD = z;

  	  angle = atan2((double)YD*YFactor*YFactor_T,(double)XD*XFactor*XFactor_T);

  	  if(angle<0) angle += 6.28318530718 ; //Converted to range: 0 ~ 2π
  	  Angle = angle*(360/6.2831853071);    //Converted to °
}

/*
SELF TEST OPERATION
To check the HMC5883L for proper operation, a self test feature in incorporated in which the sensor offset straps are excited to create a nominal field strength (bias field) to be measured. To implement this self test, the least significant bits (MS1 and MS0) of configuration register A are changed from 00 to 01.
Then, by placing the mode register into single-measurement mode (0x01), two data acquisition cycles will be made on each magnetic vector. The first acquisition will be a set pulse followed shortly by measurement data of the external field. The second acquisition will have the offset strap excited (about 10 mA) in the positive bias mode for X, Y, and Z axes to create about a ±1.1 gauss self test field plus the external field. The first acquisition values will be subtracted from the second acquisition, and the net measurement will be placed into the data output registers.
If the configuration register B is left at the factory default value of 0x40, values around +951 ADC LSB (1.16 Ga * 820 LSB/Ga) will be placed in the X and Y data output registers and around +886 (1.08 Ga * 1820 LSB/Ga) in Z data output register. To leave the self test mode, change MS1 and MS0 bit of the configuration register A back to 00. Also change the mode register if single-measurement mode is not the intended mode of operation.
*/
void PY_HMC5883L_SELF_TEST(void)
{
    SF=1;
    XFactor = 1.0; YFactor = 1.0; ZFactor = 1.0;
	PY_HMC5883L_WriteReg(CRA, 0X71);//samples average: 8; data output rate: 15Hz; measure mode: self test of positive bias
	PY_HMC5883L_WriteReg(CRB, 0X20);//gain: ± 1.3 Ga
	PY_HMC5883L_WriteReg(MR, 0X01); //Single-Measurement Mode
	HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);
}

/*
Alternatively, the built-in self test can be used to periodically compensate the scaling errors due to temperature variations.
A compensation factor can be found by comparing the self test outputs with the ones obtained at a known temperature.
For example, if the self test output is 1130 at room temperature and 1150 at the current temperature then a scale factor of
(1130/1150) should be applied to all current magnetic readings. A temperature sensor is not required using this method.
 */
int XD_T0, YD_T0, ZD_T0;
int XD_T1, YD_T1, ZD_T1;
void PY_HMC5883L_T0Param(void)
{
    SF=2;
    XFactor_T = 1.0; YFactor_T = 1.0; ZFactor_T = 1.0;
	PY_HMC5883L_WriteReg(CRA, 0X71);//samples average: 8; data output rate: 15Hz; measure mode: self test of positive bias
	PY_HMC5883L_WriteReg(CRB, 0X20);//gain: ± 1.3 Ga
	PY_HMC5883L_WriteReg(MR, 0X01); //Single-Measurement Mode
	HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);

	while(SF!=0) PY_Delay_us_t(1000);

	PY_HMC5883L_WriteReg(CRA, 0X70);//samples average: 8; data output rate: 15Hz; measure mode: normal
	PY_HMC5883L_WriteReg(CRB, 0X20);//gain: ± 1.3 Ga
	PY_HMC5883L_WriteReg(MR, 0X00);//continuous-measurement mode
	HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);
}

void PY_HMC5883L_T1Param(void)
{
    SF=3;
    XFactor_T = 1.0; YFactor_T = 1.0; ZFactor_T = 1.0;
	PY_HMC5883L_WriteReg(CRA, 0X71);//samples average: 8; data output rate: 15Hz; measure mode: self test of positive bias
	PY_HMC5883L_WriteReg(CRB, 0X20);//gain: ± 1.3 Ga
	PY_HMC5883L_WriteReg(MR, 0X01); //Single-Measurement Mode
	HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);

	while(SF!=0) PY_Delay_us_t(1000);

	PY_HMC5883L_WriteReg(CRA, 0X70);//samples average: 8; data output rate: 15Hz; measure mode: normal
	PY_HMC5883L_WriteReg(CRB, 0X20);//gain: ± 1.3 Ga
	PY_HMC5883L_WriteReg(MR, 0X00);//continuous-measurement mode
	HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);
}


void PY_HMC5883L_Init(void)
{
	uint8_t Reg[13];

	Reg[0] = PY_HMC5883L_ReadReg(CRA);
	Reg[1] = PY_HMC5883L_ReadReg(CRB);
	Reg[2] = PY_HMC5883L_ReadReg(MR);
	Reg[3] = PY_HMC5883L_ReadReg(DOXMR);
	Reg[4] = PY_HMC5883L_ReadReg(DOXLR);
	Reg[5] = PY_HMC5883L_ReadReg(DOZMR);
	Reg[6] = PY_HMC5883L_ReadReg(DOZLR);
	Reg[7] = PY_HMC5883L_ReadReg(DOYMR);
	Reg[8] = PY_HMC5883L_ReadReg(DOYLR);
	Reg[9] = PY_HMC5883L_ReadReg(SR);
	Reg[10] = PY_HMC5883L_ReadReg(IRA); //data = 0x48
	Reg[11] = PY_HMC5883L_ReadReg(IRB); //data = 0x34
	Reg[12] = PY_HMC5883L_ReadReg(IRC); //data = 0x33

      if(!((Reg[10]==0x48)&&(Reg[11]==0x34)&&(Reg[12]==0x33)))
      {
    	  printf("HMC5883 I2C access failure!\r\n");
    	  printf("HMC5883 regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\r\n", Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], Reg[5], Reg[6], Reg[7], Reg[8], Reg[9], Reg[10], Reg[11], Reg[12]);
    	  return PY_HMC5883L_Init();
      }
      else
      {
    	  printf("HMC5883 I2C access OK!\r\n");
    	  printf("HMC5883 regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\r\n", Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], Reg[5], Reg[6], Reg[7], Reg[8], Reg[9], Reg[10], Reg[11], Reg[12]);

    	  if(SelfTest_EN)
    	  {
    		  PY_HMC5883L_SELF_TEST();
    		  while(SF!=0) PY_Delay_us_t(1000);
    	  }

    	  PY_HMC5883L_WriteReg(CRA, 0X70);//samples average: 8; data output rate: 15Hz; measure mode: normal
    	  PY_HMC5883L_WriteReg(CRB, 0X20);//gain: ± 1.3 Ga
    	  PY_HMC5883L_WriteReg(MR, 0X00);//continuous-measurement mode
    	  HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);
      }
}

而在GPIO的中断函数里做读取和处理:

void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
	const float cr = 1.1*1090;  //1.1Gauss * 1090LSB/Gauss

	if (GPIO_Pin==GPIO_PIN_0)
	{
		PY_HMC5883L_ReadData();
		HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);

		if(SF==1)
		{
			printf("\r\n\r\nSelf-Test X: %d ; Y: %d ; Z: %d\r\n\r\n", XD, YD, ZD);
            XFactor = cr/XD;
            YFactor = cr/YD;
            ZFactor = cr/ZD;

			SF = 0;
		}
		else if(SF==2)
		{
            XD_T0 = XD;
            YD_T0 = YD;
            ZD_T0 = ZD;
            printf("\r\n\r\nT0 parameter test and set done!\r\n\r\n", XD, YD, ZD);

            SF = 0;
		}
		else if(SF==3)
		{
            XD_T1 = XD;
            YD_T1 = YD;
            ZD_T1 = ZD;
            printf("\r\n\r\nT1 parameter test and set done!\r\n\r\n", XD, YD, ZD);

            XFactor_T = XD_T0/XD_T1;
            YFactor_T = YD_T0/YD_T1;
            ZFactor_T = ZD_T0/ZD_T1;

            SF = 0;
		}
		else
		{
			printf("Normal-Test X: %d ; Y: %d ; Z: %d ==> Angle(0~359): %d\r\n", XD, YD, ZD, Angle);
		}

	}
}

STM32工程完整代码

完整的工程代码如下:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/*Written by Pegasus Yu in 2022*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <math.h>
#include "usart.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
__IO float usDelayBase;
void PY_usDelayTest(void)
{
  __IO uint32_t firstms, secondms;
  __IO uint32_t counter = 0;

  firstms = HAL_GetTick()+1;
  secondms = firstms+1;

  while(uwTick!=firstms) ;

  while(uwTick!=secondms) counter++;

  usDelayBase = ((float)counter)/1000;
}

void PY_Delay_us_t(uint32_t Delay)
{
  __IO uint32_t delayReg;
  __IO uint32_t usNum = (uint32_t)(Delay*usDelayBase);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}

void PY_usDelayOptimize(void)
{
  __IO uint32_t firstms, secondms;
  __IO float coe = 1.0;

  firstms = HAL_GetTick();
  PY_Delay_us_t(1000000) ;
  secondms = HAL_GetTick();

  coe = ((float)1000)/(secondms-firstms);
  usDelayBase = coe*usDelayBase;
}


void PY_Delay_us(uint32_t Delay)
{
  __IO uint32_t delayReg;

  __IO uint32_t msNum = Delay/1000;
  __IO uint32_t usNum = (uint32_t)((Delay%1000)*usDelayBase);

  if(msNum>0) HAL_Delay(msNum);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define us_num 10

#define SCL_OUT_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)
#define SCL_OUT_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
#define SDA_OUT_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET)
#define SDA_OUT_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET)
#define SDA_IN HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)

#define INT_IN HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)

void I2C_Init(void)
{

	SCL_OUT_H;
	SDA_OUT_H;
	PY_Delay_us_t(2000000); //Provide device stability time

}

void I2C_Start(void)
{
	PY_Delay_us_t(us_num) ;
	SDA_OUT_H;
	SCL_OUT_H;
	PY_Delay_us_t(us_num/2) ;
	SDA_OUT_L;
	PY_Delay_us_t(us_num/2) ;
	SCL_OUT_L;
}

void I2C_Stop(void)
{
	SCL_OUT_L;
	PY_Delay_us_t(us_num) ;
	SDA_OUT_L;
	PY_Delay_us_t(us_num) ;
	SCL_OUT_H;
	PY_Delay_us_t(us_num) ;
	SDA_OUT_H;
	PY_Delay_us_t(us_num) ;
}

void I2C_Write_Ack(void)
{

    PY_Delay_us_t(us_num/2) ;
	SDA_OUT_L;
	PY_Delay_us_t(us_num/2) ;
	SCL_OUT_H;
	PY_Delay_us_t(us_num) ;
	SCL_OUT_L;
	SDA_OUT_H;

}

uint8_t I2C_Read_Ack(void)
{
	uint8_t status=0;

	SCL_OUT_L;
	PY_Delay_us_t(us_num/2) ;
	SDA_OUT_H;
	PY_Delay_us_t(us_num/2) ;
	status = SDA_IN;
	SCL_OUT_H;
	PY_Delay_us_t(us_num) ;
	SCL_OUT_L;
	SDA_OUT_L;

	return status;

}


void I2C_Send_Byte(uint8_t txd){


    for(uint8_t i=0;i<8;i++)
    {
    	PY_Delay_us_t(us_num/2) ;
        if((txd&0x80)>>7) SDA_OUT_H;
        else SDA_OUT_L;
        txd<<=1;
        PY_Delay_us_t(us_num/2) ;
        SCL_OUT_H;
        PY_Delay_us_t(us_num) ;
		SCL_OUT_L;
    }

    SDA_OUT_L;
}

uint8_t I2C_Read_Byte(unsigned char rdack)
{
	uint8_t rxd=0;


    for(uint8_t i=0;i<8;i++ )
	{
    	SCL_OUT_L;
    	PY_Delay_us_t(us_num/2) ;
    	SDA_OUT_H;
    	PY_Delay_us_t(us_num/2) ;
    	SCL_OUT_H;
        rxd<<=1;
        if(SDA_IN) rxd++;
        PY_Delay_us_t(us_num) ;
    }

    SCL_OUT_L;
    SDA_OUT_H;

    if (rdack) I2C_Write_Ack();

    return rxd;
}

#define CRA 0x00
#define CRB 0x01
#define MR 0x02
#define DOXMR 0x03
#define DOXLR 0x04
#define DOZMR 0x05
#define DOZLR 0x06
#define DOYMR 0x07
#define DOYLR 0x08
#define SR 0x09
#define IRA 0x0A
#define IRB 0x0B
#define IRC 0x0C

#define SelfTest_EN 1
uint8_t SF=0;  //Self Test Flag

void PY_HMC5883L_WriteReg(uint8_t WrAddr, uint8_t data)
{
	  uint8_t daddr;
	  daddr = 0x3c; //HMC5883L device address (0x1E<<1)

	  I2C_Start();
	  I2C_Send_Byte(daddr);
	  I2C_Read_Ack();
  	  I2C_Send_Byte(WrAddr);
  	  I2C_Read_Ack();
  	  I2C_Send_Byte(data);
  	  I2C_Read_Ack();
  	  I2C_Stop();

}

uint8_t PY_HMC5883L_ReadReg(uint8_t RdAddr)
{

	  uint8_t RegValue = 0;
	  uint8_t daddr;
	  daddr = 0x3c; //HMC5883L device address (0x1E<<1)

	  I2C_Start();
	  I2C_Send_Byte(daddr);
	  I2C_Read_Ack();
  	  I2C_Send_Byte(RdAddr);
  	  I2C_Read_Ack();

  	  I2C_Start();
	  I2C_Send_Byte(daddr+1);
	  I2C_Read_Ack();
	  RegValue=I2C_Read_Byte(0);
  	  I2C_Stop();

	  return RegValue;
}

/*Note:
To minimize the communication between the master and this device, the address pointer updated automatically without master intervention.
This automatic address pointer update has two additional features. First when address 12 or higher is accessed the pointer updates to address 00 and secondly when address 08 is reached, the pointer rolls back to address 03. Logically, the address pointer operation functions as shown below.
If (address pointer = 08) then address pointer = 03
Else if (address pointer >= 12) then address pointer = 0
Else (address pointer) = (address pointer) + 1
*/
int XD, YD, ZD;
uint16_t Angle;
double XFactor = 1.0,  YFactor = 1.0,  ZFactor = 1.0; //Correction factor coming for self test process
double XFactor_T = 1.0,  YFactor_T = 1.0,  ZFactor_T = 1.0; //Correction factor coming for self test process for temperature impact
void PY_HMC5883L_ReadData(void)
{
      uint8_t data[6];
      uint16_t x, y, z;
	  double angle;

	  uint8_t daddr;
	  daddr = 0x3c; //HMC5883L device address (0x1E<<1)

	  I2C_Start();
	  I2C_Send_Byte(daddr);
	  I2C_Read_Ack();
  	  I2C_Send_Byte(0x03);
  	  I2C_Read_Ack();

  	  I2C_Start();
	  I2C_Send_Byte(daddr+1);
	  I2C_Read_Ack();
	  data[0]=I2C_Read_Byte(1);
	  data[1]=I2C_Read_Byte(1);
	  data[2]=I2C_Read_Byte(1);
	  data[3]=I2C_Read_Byte(1);
	  data[4]=I2C_Read_Byte(1);
	  data[5]=I2C_Read_Byte(0);
  	  I2C_Stop();

  	  x = (((uint16_t)data[0])<<8)|((uint16_t)data[1]);
  	  z = (((uint16_t)data[2])<<8)|((uint16_t)data[3]);
  	  y = (((uint16_t)data[4])<<8)|((uint16_t)data[5]);

  	  if((x>>15)!=0) XD = -(0x10000-x);
  	  else XD = x;

  	  if((y>>15)!=0) YD = -(0x10000-y);
  	  else YD = y;

  	  if((z>>15)!=0) ZD = -(0x10000-z);
  	  else ZD = z;

  	  angle = atan2((double)YD*YFactor*YFactor_T,(double)XD*XFactor*XFactor_T);

  	  if(angle<0) angle += 6.28318530718 ; //Converted to range: 0 ~ 2π
  	  Angle = angle*(360/6.2831853071);    //Converted to °
}

/*
SELF TEST OPERATION
To check the HMC5883L for proper operation, a self test feature in incorporated in which the sensor offset straps are excited to create a nominal field strength (bias field) to be measured. To implement this self test, the least significant bits (MS1 and MS0) of configuration register A are changed from 00 to 01.
Then, by placing the mode register into single-measurement mode (0x01), two data acquisition cycles will be made on each magnetic vector. The first acquisition will be a set pulse followed shortly by measurement data of the external field. The second acquisition will have the offset strap excited (about 10 mA) in the positive bias mode for X, Y, and Z axes to create about a ±1.1 gauss self test field plus the external field. The first acquisition values will be subtracted from the second acquisition, and the net measurement will be placed into the data output registers.
If the configuration register B is left at the factory default value of 0x40, values around +951 ADC LSB (1.16 Ga * 820 LSB/Ga) will be placed in the X and Y data output registers and around +886 (1.08 Ga * 1820 LSB/Ga) in Z data output register. To leave the self test mode, change MS1 and MS0 bit of the configuration register A back to 00. Also change the mode register if single-measurement mode is not the intended mode of operation.
*/
void PY_HMC5883L_SELF_TEST(void)
{
    SF=1;
    XFactor = 1.0; YFactor = 1.0; ZFactor = 1.0;
	PY_HMC5883L_WriteReg(CRA, 0X71);//samples average: 8; data output rate: 15Hz; measure mode: self test of positive bias
	PY_HMC5883L_WriteReg(CRB, 0X20);//gain: ± 1.3 Ga
	PY_HMC5883L_WriteReg(MR, 0X01); //Single-Measurement Mode
	HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);
}

/*
Alternatively, the built-in self test can be used to periodically compensate the scaling errors due to temperature variations.
A compensation factor can be found by comparing the self test outputs with the ones obtained at a known temperature.
For example, if the self test output is 1130 at room temperature and 1150 at the current temperature then a scale factor of
(1130/1150) should be applied to all current magnetic readings. A temperature sensor is not required using this method.
 */
int XD_T0, YD_T0, ZD_T0;
int XD_T1, YD_T1, ZD_T1;
void PY_HMC5883L_T0Param(void)
{
    SF=2;
    XFactor_T = 1.0; YFactor_T = 1.0; ZFactor_T = 1.0;
	PY_HMC5883L_WriteReg(CRA, 0X71);//samples average: 8; data output rate: 15Hz; measure mode: self test of positive bias
	PY_HMC5883L_WriteReg(CRB, 0X20);//gain: ± 1.3 Ga
	PY_HMC5883L_WriteReg(MR, 0X01); //Single-Measurement Mode
	HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);

	while(SF!=0) PY_Delay_us_t(1000);

	PY_HMC5883L_WriteReg(CRA, 0X70);//samples average: 8; data output rate: 15Hz; measure mode: normal
	PY_HMC5883L_WriteReg(CRB, 0X20);//gain: ± 1.3 Ga
	PY_HMC5883L_WriteReg(MR, 0X00);//continuous-measurement mode
	HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);
}

void PY_HMC5883L_T1Param(void)
{
    SF=3;
    XFactor_T = 1.0; YFactor_T = 1.0; ZFactor_T = 1.0;
	PY_HMC5883L_WriteReg(CRA, 0X71);//samples average: 8; data output rate: 15Hz; measure mode: self test of positive bias
	PY_HMC5883L_WriteReg(CRB, 0X20);//gain: ± 1.3 Ga
	PY_HMC5883L_WriteReg(MR, 0X01); //Single-Measurement Mode
	HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);

	while(SF!=0) PY_Delay_us_t(1000);

	PY_HMC5883L_WriteReg(CRA, 0X70);//samples average: 8; data output rate: 15Hz; measure mode: normal
	PY_HMC5883L_WriteReg(CRB, 0X20);//gain: ± 1.3 Ga
	PY_HMC5883L_WriteReg(MR, 0X00);//continuous-measurement mode
	HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);
}


void PY_HMC5883L_Init(void)
{
	uint8_t Reg[13];

	Reg[0] = PY_HMC5883L_ReadReg(CRA);
	Reg[1] = PY_HMC5883L_ReadReg(CRB);
	Reg[2] = PY_HMC5883L_ReadReg(MR);
	Reg[3] = PY_HMC5883L_ReadReg(DOXMR);
	Reg[4] = PY_HMC5883L_ReadReg(DOXLR);
	Reg[5] = PY_HMC5883L_ReadReg(DOZMR);
	Reg[6] = PY_HMC5883L_ReadReg(DOZLR);
	Reg[7] = PY_HMC5883L_ReadReg(DOYMR);
	Reg[8] = PY_HMC5883L_ReadReg(DOYLR);
	Reg[9] = PY_HMC5883L_ReadReg(SR);
	Reg[10] = PY_HMC5883L_ReadReg(IRA); //data = 0x48
	Reg[11] = PY_HMC5883L_ReadReg(IRB); //data = 0x34
	Reg[12] = PY_HMC5883L_ReadReg(IRC); //data = 0x33

      if(!((Reg[10]==0x48)&&(Reg[11]==0x34)&&(Reg[12]==0x33)))
      {
    	  printf("HMC5883 I2C access failure!\r\n");
    	  printf("HMC5883 regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\r\n", Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], Reg[5], Reg[6], Reg[7], Reg[8], Reg[9], Reg[10], Reg[11], Reg[12]);
    	  return PY_HMC5883L_Init();
      }
      else
      {
    	  printf("HMC5883 I2C access OK!\r\n");
    	  printf("HMC5883 regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\r\n", Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], Reg[5], Reg[6], Reg[7], Reg[8], Reg[9], Reg[10], Reg[11], Reg[12]);

    	  if(SelfTest_EN)
    	  {
    		  PY_HMC5883L_SELF_TEST();
    		  while(SF!=0) PY_Delay_us_t(1000);
    	  }

    	  PY_HMC5883L_WriteReg(CRA, 0X70);//samples average: 8; data output rate: 15Hz; measure mode: normal
    	  PY_HMC5883L_WriteReg(CRB, 0X20);//gain: ± 1.3 Ga
    	  PY_HMC5883L_WriteReg(MR, 0X00);//continuous-measurement mode
    	  HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);
      }
}
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */
uint8_t TStatsu = 0;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @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_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  PY_usDelayTest();
  PY_usDelayOptimize();

  I2C_Init();

  PY_HMC5883L_Init();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  PY_Delay_us_t(1);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(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.HSIDiv = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
  RCC_OscInitStruct.PLL.PLLN = 8;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  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_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
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_4|GPIO_PIN_5, GPIO_PIN_SET);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PA4 PA5 */
  GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI0_1_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);

}

/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
	const float cr = 1.1*1090;  //1.1Gauss * 1090LSB/Gauss

	if (GPIO_Pin==GPIO_PIN_0)
	{
		PY_HMC5883L_ReadData();
		HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);

		if(SF==1)
		{
			printf("\r\n\r\nSelf-Test X: %d ; Y: %d ; Z: %d\r\n\r\n", XD, YD, ZD);
            XFactor = cr/XD;
            YFactor = cr/YD;
            ZFactor = cr/ZD;

			SF = 0;
		}
		else if(SF==2)
		{
            XD_T0 = XD;
            YD_T0 = YD;
            ZD_T0 = ZD;
            printf("\r\n\r\nT0 parameter test and set done!\r\n\r\n", XD, YD, ZD);

            SF = 0;
		}
		else if(SF==3)
		{
            XD_T1 = XD;
            YD_T1 = YD;
            ZD_T1 = ZD;
            printf("\r\n\r\nT1 parameter test and set done!\r\n\r\n", XD, YD, ZD);

            XFactor_T = XD_T0/XD_T1;
            YFactor_T = YD_T0/YD_T1;
            ZFactor_T = ZD_T0/ZD_T1;

            SF = 0;
		}
		else
		{
			printf("Normal-Test X: %d ; Y: %d ; Z: %d ==> Angle(0~359): %d\r\n", XD, YD, ZD, Angle);
		}

	}
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
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 */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

使用及校准说明

使用说明:
程序启动后,先读取HMC5883L的识别码,如果正确向后执行,不正确就循环打印报错信息。
根据自测使能标识,决定是否执行自检测试,如果不执行自检测试,则配置为正常模式,然后在INT管脚中断里读取数据并解析。解析的数据为360度内的角度值,报告为0到359度。如果执行自检测试,则通过计算获得校准系数用于以后的正常模式数据校准,自检后配置为正常模式。
可选进行温度一致性校准,将T1温度的值回归到基准T0温度的值。因此在传感器静止时,在T0温度时执行一次PY_HMC5883L_T0Param(), 然后在T1温度时执行一次 PY_HMC5883L_T1Param(),就实现了温度校准系数的生成和应用。

校准原理说明:
自测校准模式触发HMC5883L自动进行两次测试,第一次测试环境三轴的磁强度,然后在每轴上增加1.1高斯量,再测试三轴的磁强度,然后将结果相减得到绝对变化量,也就是对应1.1高斯的实际变量化,而1.1高斯量的理论变化量可以通过设定的增益等级对应的单位高斯变化量计算而得。从而可以得到每轴的校准系数=理论变化量/实际变化量。
hmc5883寄存器,STM32,stm32,HMC5883,HMC5883L,电子罗盘,磁角度
温度校准模式可以在温度变化产生影响时,将不同温度T1的测试值回归到特定温度T0的对应值。在T0温度做自检测试得到对应1.1高斯变化的检测数值变化量,而在T1温度做自检测试也得到对应1.1高斯变化的检测数值变化量,由于温度不同产生的影响,这两个数值变化量不同,因此可以产生温度校准系数=value(T0)/value(T1), 将T1温度的检测值乘以系数,就得到如果是在T0温度做测试会得到的结果值。

测试效果

串口打印输出的效果如下:

hmc5883寄存器,STM32,stm32,HMC5883,HMC5883L,电子罗盘,磁角度

校准扩展

可以基于实际环境和应用进行进一步的校准,如在设定的一些角度位如0度,45,90度,135度,180度,225度,270度,315度进行角度测试,将结果和理论值比较,从而再次产生分段校准系数。一般针对水平面运动精度就已足够。如果涉及三维运动,则要进行更复杂的转换和校准。

例程下载

STM32G030模拟I2C协议获取HMC5883L电子罗盘磁角度数据 (HAL)例程

–End–文章来源地址https://www.toymoban.com/news/detail-643656.html

到了这里,关于STM32模拟I2C协议获取HMC5883L电子罗盘磁角度数据 (HAL)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【【STM32----I2C通信协议】】

    我们会发现I2C有两根通信线: SCL和SDA 同步 半双工 带数据应答 支持总线挂载多设备(一主多从,多主多从) 硬件电路 所有I2C设备的SCL连在一起,SDA连在一起 设备的SCL和SDA均要配置成开漏输出模式 SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右 左边的CPU就是主机,他的权

    2024年02月12日
    浏览(16)
  • stm32中的i2c协议

    协议通讯图 I2C上一个总线能挂载多个设备共用信号线,可以连接多个从机 只用了两个总线,一条双向串行数据线(SDA),一条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。 每个连接到总线的设备都有独立的地址,主机可以通过该地址进行访问 I2C空闲

    2024年01月22日
    浏览(25)
  • 【STM32】STM32学习笔记-I2C通信协议(31)

    I2C(Inter-Integrated Circuit)总线 是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。 串行的 8 位双向数据传输位速率在标准模式下可

    2024年01月23日
    浏览(25)
  • STM32软件模拟I2C从机的实现方法

    在使用I2C通信时,一般会用到软件模拟I2C。目前网络上能搜索到的软件模拟I2C一般都是模拟I2C主机,很少有模拟I2C从机的例程。由于I2C主机在进行数据收发时,有明确的可预见性,也就是主机明确知道什么时候要进行数据的收发操作,而且I2C的同步时钟信号也是由主机产生的

    2024年02月01日
    浏览(15)
  • 【STM32学习】——I2C通信协议&MPU6050姿态传感器&软件I2C读写MPU6050

    ​   目录 前言 一、I2C通信协议 1.简介 2.硬件电路设计 3.I2C时序(软件)

    2024年02月16日
    浏览(22)
  • STM32 OLED显示汉字及屏幕滚动(I2C协议)

    理解OLED屏显和汉字点阵编码原理,使用STM32F103的SPI或IIC接口实现以下功能: 显示自己的学号和姓名; 显示AHT20的温度和湿度; 上下或左右的滑动显示长字符。 STM32F103C8T6最小板 AHT20温湿度传感器 ST-LINK 仿真器 4针脚使用I2C通信协议的OLED屏 面包板 杜邦线 KEIL 5 字模软件 可以看

    2024年02月03日
    浏览(23)
  • 电脑传输数据STM32模拟I2C显示实时画面到OLED

    写的不好,还望大家指正,有的地方引用了一下大佬的代码。 一、所需硬件: STM32F103C8T6 USB转串口模块 OLED 128*64显示屏 STLINK 二、代码部分 1.stm32串口部分代码 2.stm32OLED屏幕部分代码 3.主程序 4.电脑通过opencv库截取电脑当前1080p一帧画面,并对图片二值化处理,通过电脑端编写

    2024年02月13日
    浏览(18)
  • STM32使用模拟I2C读取AS5600(深入讲解:带波形图)

    首先我们要了解I2C的基本原理 当IIC处于空闲状态的时候,SDA和SCL都处于高电平状态, 当IIC通信开始信号,SCL保持高电平,SDA从高电平变成低电平(SCL=1,SDA=1-0), 当IIC通信结束信号,SCL保持高电平,SDA从低电平变成高电平(SCL=1,SDA=0-1)。 IIC通信开始后,发送8位数据信号

    2024年02月01日
    浏览(21)
  • HMC5883L电子罗盘原理及应用,全网最详细~

    HMC5883L模块具有两个配置寄存器,配置寄存器A 用来配置该装置设置的数据输出速率和测量配置;配置寄存器 B 设置装置的增益。 模式寄存器则是用来设定装置的操作模式,有连续测量模式,单一测量模式和闲置模式等。具体的情况可以查阅HMC5883L数据手册。  下面我们对HM

    2024年02月01日
    浏览(25)
  • 基于HAL库的stm32的OLED显示屏显示(模拟I2C,四脚,0.96寸)

    参考视频:江科大oled程序移植stm32hal库,freertos学习,cpu使用率_哔哩哔哩_bilibili ​ STM32入门教程-2023持续更新中_哔哩哔哩_bilibili 高速和低速晶振均选择为陶瓷晶振即可。 不需更改初始化配置,因为模拟I2C初始化时会设置这两个引脚的电平 step1、step2完成后生成工程即可。 代

    2024年02月06日
    浏览(24)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包