STM32F1与STM32CubeIDE编程实例-HMC5883电子罗盘驱动

HMC5883电子罗盘驱动

1、HMC5883介绍

Honeywell的HMC5883L 是一款表面贴装多芯片模块,专为低场磁场感应而设计,具有数字接口,适用于低成本罗盘和磁力测量等应用。 HMC5883L 包括先进的高分辨率 HMC118X 系列磁阻传感器和一个 ASIC,其中包含放大、自动消磁带驱动器、偏移消除和一个 12 位 ADC,可实现 1° 至 2° 罗盘航向 准确性。 I2C 串行总线允许简单的接口。 HMC5883L 是一款 3.0x3.0x0.9mm 表面贴装 16 引脚无引线芯片载体 (LCC)。 HMC5883L 的应用包括移动电话、上网本、消费电子产品、自动导航系统和个人导航设备。

HMC5883L 采用霍尼韦尔的各向异性磁阻 (AMR) 技术,与其他磁传感器技术相比具有优势。 这些各向异性方向传感器具有精确的轴内灵敏度和线性度。 这些传感器的固态结构具有极低的交叉轴灵敏度,旨在测量从毫高斯到 8 高斯的地球磁场的方向和大小。 霍尼韦尔的磁传感器是业内最灵敏、最可靠的低场传感器之一。

在这里插入图片描述

2、HMC5883配置

关于STM32CubeIDE工程创建、配置请参考前面文章:

本次HMC5883的配置如下:

在这里插入图片描述

3、HMC5883驱动实现

1)HMC5883基本定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/\*
\* hmc2883.h
\*
\* Created on: Jul 3, 2022
\* Author: jenson
\*/

#ifndef HMC5883\_HMC5883\_H\_
#define HMC5883\_HMC5883\_H\_

#include <stm32f1xx\_hal.h>
#include <stdbool.h>

#define HMC5883\_DEVICE\_ADDR (0x1E)

typedef struct {
uint16\_t id;
uint8\_t addr;
I2C_HandleTypeDef\* i2c;
int32\_t x,y,z;
float angle_xy; // XY平面角度
float angle_xz; // XZ平面角度
float angle_yz; // YZ平面角度
bool inited;
}hmc5883\_t;

// 判断HMC5883设备是否就绪
bool hmc5883\_is\_ready(hmc5883\_t\* hmc5883);
// HMC5883初始化
bool hmc5883\_init(hmc5883\_t\* hmc5883);
// HMC5883数据采集及刷新
void hmc5883\_update(hmc5883\_t\* hmc5883);

#endif /\* HMC5883\_HMC5883\_H\_ \*/


2)驱动基本定义实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/\*
\* hmc5883.c
\*
\* Created on: Jul 3, 2022
\* Author: jenson
\*/

#include "hmc5883.h"
#include <stdio.h>
#include <math.h>

bool hmc5883\_is\_ready(hmc5883\_t \*hmc5883) {
return HAL\_I2C\_IsDeviceReady(hmc5883->i2c, hmc5883->addr, 2, 10);
}

bool \_\_hmc5883\_write(hmc5883\_t \*hmc5883, uint8\_t mem_addr, uint8\_t \*pData,
uint32\_t size) {
if (HAL\_I2C\_Mem\_Write(hmc5883->i2c, hmc5883->addr << 1, mem_addr, 1, pData,
size, 1000) == HAL_OK) {
return true;
}
printf("write failed\r\n");
return false;
}

bool \_\_hmc5883\_read(hmc5883\_t \*hmc5883, uint8\_t mem_addr, uint8\_t \*pData,
uint32\_t size) {
if (HAL\_I2C\_Mem\_Read(hmc5883->i2c, hmc5883->addr << 1, mem_addr, 1, pData,
size, 1000) == HAL_OK) {
return true;
}
printf("read failed\r\n");
return false;
}

bool hmc5883\_init(hmc5883\_t \*hmc5883) {
if (!hmc5883\_is\_ready(hmc5883)) {
printf("hmc5883\_init:device not found\r\n");
return false;
}

// 设置传感器采样模式
uint8\_t mem_addr = 0x02;
uint8\_t write_data = 0x00; // 连续采样模式
bool res = \_\_hmc5883\_write(hmc5883, mem_addr, &write_data, 1);
hmc5883->inited = res;
return res;

}

void hmc5883\_update(hmc5883\_t \*hmc5883) {
uint8\_t mem_addr = 0x03; // X MSB 寄存器
uint8\_t data[6] = { 0 };

\_\_hmc5883\_read(hmc5883, mem_addr, data, 6);

hmc5883->x = data[0] << 8 | data[1];
hmc5883->y = data[2] << 8 | data[3];
hmc5883->z = data[4] << 8 | data[5];

// 计算XY,XZ,YZ平面角度

//计算XY平面角度
hmc5883->angle_xy = atan2((double) hmc5883->y, (double) hmc5883->x)
\* (180 / 3.14159265) + 180.0;

//计算XZ平面角度
hmc5883->angle_xz = atan2((double) hmc5883->z, (double) hmc5883->x)
\* (180 / 3.14159265) + 180.0;

//计算YZ平面角度
hmc5883->angle_yz = atan2((double) hmc5883->z, (double) hmc5883->y)
\* (180 / 3.14159265) + 180.0;
}

3、驱动测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/
#include <stdio.h>
#include <hmc5883/hmc5883.h>
/\* USER CODE END Includes \*/

/\* Private variables ---------------------------------------------------------\*/

/\* USER CODE BEGIN PV \*/
hmc5883\_t hmc5883;
/\* USER CODE END PV \*/

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\_USART1\_UART\_Init();
MX\_I2C1\_Init();
/\* USER CODE BEGIN 2 \*/

hmc5883.id = 0x01;
hmc5883.addr = HMC5883_DEVICE_ADDR;
hmc5883.i2c = &hi2c1;

if (!hmc5883\_init(&hmc5883)) {
printf("hmc5883 init failed\r\n");
while (1)
;
}

/\* USER CODE END 2 \*/

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

/\* USER CODE BEGIN 3 \*/
hmc5883\_update(&hmc5883);
printf("x = %d,y = %d,z = %d\r\n", hmc5883.x, hmc5883.y, hmc5883.z);
printf("xy = %.2f,xz = %.2f,yz = %.2f\r\n", hmc5883.angle_xy,
hmc5883.angle_xz, hmc5883.angle_yz);
HAL\_Delay(100);
}
/\* USER CODE END 3 \*/
}

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

/\*\* Initializes the RCC Oscillators according to the specified parameters
\* in the RCC\_OscInitTypeDef structure.
\*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
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_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

if (HAL\_RCC\_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
Error\_Handler();
}
}

文章来源: https://iotsmart.blog.csdn.net/article/details/125868203