STM32 HAL I2C读取HMC5883L磁偏角的实践
- 源由
- 成果
- 代码
- 头文件 G85HAL.h
- 子文件 G85HAL.C
- 主程序调用
- 配置I2C引脚
- 参考链接
源由
用传统的方式编写I2C总线数据读取,程序代码细碎,不好维护,移植性不好。CUBE MX配置方便灵活,程序架构好,有现成的hal I2C函数可调用,仅用HAL_I2C_Mem_Write( … )和 HAL_I2C_Mem_Read(… )就实现了功能,
有车轮就不要自己再做车轮啦!
成果
两条语句就实现了HMC5883L磁偏角的读取,程序代码简洁、可靠。
重点说明:
语句1:
HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
语句2:
HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
参数:
1、I2C指针,即用I2C1 还是 I2C2…,查看CUBE MX配置
2、器件地址uint16_t DevAddress,与所读写的I2C芯片有关,查看芯片资料
3、要写入的内存地址 uint16_t MemAddress,与所读写的I2C芯片有关,查看芯片资料
4、内存地址类型,是一个地址存8bit ,还是16bit数据 , uint16_t MemAddSize,与所读写的I2C芯片有关,查看芯片资料,I2C_MEMADD_SIZE_8BIT和I2C_MEMADD_SIZE_16BIT二选一
5、对于写,是要写入的数组指针uint8_t *pData ;对于读取,是存数据的数组指针uint8_t *pData ;
6、数据 大小(要写入或读取几个字节)
7、多少时间没完成定义为超时,该语句退出
代码
头文件 G85HAL.h
#ifndef __GY85HAL_H
#define __GY85HAL_H #include "stm32f1xx_hal.h"
#include "i2c.h"#define ITG3205_Addr 0x68 //定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改
#define HMC5883L_Addr 0x3C //磁场传感器器件地址//定义HMC5883L配置寄存器地址
#define HMC5883l_CONFIG_A 0x00
#define HMC5883l_CONFIG_B 0x01
#define HMC5883l_MODECONFIG 0x02struct HMC5883L_Data {unsigned char vtemp[12];int x_h; //x方向磁强int y_h; //y方向磁强int z_h; //z方向磁强float angle;
};//***************************************
int g85_makeuint16(int msb, int lsb) ;
void Init_HMC5883L_HAL(I2C_HandleTypeDef *hi2c1);
/**** 读取磁场角度 */
float read_hmc5883l_HAL(I2C_HandleTypeDef *hi2c1,struct HMC5883L_Data *VL_temp);#endif
子文件 G85HAL.C
#include "gy85hal.h"
#include <math.h> //***************************************
//合并两个字节函数int g85_makeuint16(int msb, int lsb)
{return ((msb & 0xFF) << 8) | (lsb & 0xFF);
}//初始化和设置HMC5883L
void Init_HMC5883L_HAL(I2C_HandleTypeDef *hi2c1)
{unsigned char cdata[3]={0x70,0x20,0X00};HAL_I2C_Mem_Write(hi2c1,HMC5883L_Addr,HMC5883l_CONFIG_A, I2C_MEMADD_SIZE_8BIT,cdata, 1, 1000); //HAL_I2C_Mem_Write(hi2c1,HMC5883L_Addr,HMC5883l_CONFIG_B, I2C_MEMADD_SIZE_8BIT, cdata+1, 1, 1000); //设置增益, HAL_I2C_Mem_Write(hi2c1,HMC5883L_Addr,HMC5883l_MODECONFIG, I2C_MEMADD_SIZE_8BIT, cdata+2, 1, 1000); //设置测量模式,连续测量模式
}/**** 读取HMC5883L的磁场角度 */
float read_hmc5883l_HAL(I2C_HandleTypeDef *hi2c1,struct HMC5883L_Data *VL_temp)
{float fangle;int x,y; //用这个库函数,一次读6个字节少,了许多指令的调用 HAL_I2C_Mem_Read(hi2c1, HMC5883L_Addr, 0x03, I2C_MEMADD_SIZE_8BIT, VL_temp->vtemp, 6, 1000); VL_temp->x_h = g85_makeuint16(VL_temp->vtemp[0], VL_temp->vtemp[1]); VL_temp->y_h = g85_makeuint16(VL_temp->vtemp[4], VL_temp->vtemp[5]);VL_temp->z_h = g85_makeuint16(VL_temp->vtemp[2], VL_temp->vtemp[3]);if(VL_temp->x_h>0x7fff) VL_temp->x_h -= 0xffff; //做下预备处理if(VL_temp->y_h>0x7fff) VL_temp->y_h -= 0xffff; y= VL_temp->y_h; x= VL_temp->x_h;if(x == 0) {fangle =180; if(y>0) fangle =0;}if( x < 0) fangle =90+atan((y+0.001)/x)*57.3; //加0.001是为了强制进行浮点数运算,且对精度影响很小if( x > 0) fangle =270+atan((y+0.001)/x)*57.3;VL_temp->angle =fangle;return fangle;}
主程序调用
int main(void)
{/* USER CODE BEGIN 1 */Count1ms=0;CanInteruptFlag=0;int icount=0;int x,y;double fangle,gtan; int i =0;struct HMC5883L_Data HMC_temp;/* 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_TIM1_Init();MX_USART1_UART_Init();MX_CRC_Init();MX_IWDG_Init();MX_I2C1_Init();Init_HMC5883L_HAL(&hi2c1);/* USER CODE BEGIN 2 */ /* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */ while (1){HAL_IWDG_Refresh(&hiwdg); //复位看门狗 //在1ms中断中,每过1ms,Count1ms加1if(Count1ms > 500){Count1ms = 0; HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13); //指示程序在运行fangle = read_hmc5883l_HAL(&hi2c1,&HMC_temp); //调用子程序printf("%d %d ",HMC_temp.y_h,HMC_temp.x_h); //从串口送出读到的数据,供调试测试用printf("%0.2f \n\r ",fangle);}// for(icount=0;icount<6;icount++) printf("%d ",HMC_temp.vtemp[icount]);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
配置I2C引脚
串口收到的数据,比较稳定,每列为Y值,第二列为X值,第三列为折算出来磁偏角(度)
参考链接
[链接]https://www.freesion.com/article/57631089788/ [VL53L0X TOF激光测距的 STM32 HAL库驱动代码] (感谢作者的分享))