stm32f407驱动BMX055记录
First Post:
Last Update:
Word Count:
Read Time:
Last Update:
Word Count:
2.5k
Read Time:
12 min
stm32f407驱动BMX055记录
前两天BOSS交给我一个BMX055芯片让我试试能不能用
长下面这样
刚好学习一下如何使用没有模块化的芯片
首先是接线问题,在网络上找不到现成的BMX055芯片连线连到stm32的接线图,在询问多个学长后得知有以下几种途径
- 查技术手册
- 在各个平台上搜索有用到这个芯片的模块
技术手册
首先可以在半导小芯等多个平台搜索这个芯片找到这个芯片的技术手册,中英文都可以,尽量看英文手册。
为了方便可以直接在此下载 BMX055 技术手册
然后找到你需要的接线,比如我需要用iic与之通讯,则找到iic的接线图如下:
同时可以参考引脚定义来辅助接线
在刚接线时别急着一次性就把他用好,而是先把基本的接线连好(可以先不连中断),然后先读chip id,确定基本的硬件连线没有问题,芯片上电之后可以工作,再去连中断线
是的,我这个芯片连线就连了,拔了,连了,拔了重复了好几次,所以不要放弃,多试试吧
接线完成了
然后就是配置stm32f407的iic了
网上搜到的大部分都是stm32f1的,所以我稍作修改,并添加了一些我自己写的函数,附在下面供大家取用
//myiic.c
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//myiic.c
#include "myiic.h"
#include "delay.h"
//初始化IIC
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
//GPIOB8,B9初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
IIC_SCL=1;
IIC_SDA=1;
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
void WriteData(u8 DevID,u8 Addr,u8 Dat)
{
IIC_Start();
IIC_Send_Byte(DevID << 1| 0); //发送设备地址和写信号
IIC_Wait_Ack();
IIC_Send_Byte(Addr);
IIC_Wait_Ack();
IIC_Send_Byte(Dat);
IIC_Wait_Ack();
IIC_Stop();
delay_ms(10);
}
void ReadData(u8 DevID,u8 Addr,u8 *Pbuf,u8 Num)
{
u8 i;
IIC_Start();
IIC_Send_Byte(DevID << 1 | 0); //发送设备地址和写信号
IIC_Wait_Ack();
IIC_Send_Byte(Addr);
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(DevID << 1 | 1); //发送设备地址和读信号
IIC_Wait_Ack();
for(i = 0;i < (Num - 1);i ++)
{
Pbuf[i] = IIC_Read_Byte(1);
}
Pbuf[i] = IIC_Read_Byte(0);
IIC_Stop();
delay_ms(5);
}
//myiic.h
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
//myiic.h
#ifndef __MYIIC_H
#define __MYIIC_H
#include "sys.h"
//IO方向设置
#define SDA_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;} //PB9输入模式
#define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //PB9输出模式
//IO操作函数
#define IIC_SCL PBout(8) //SCL
#define IIC_SDA PBout(9) //SDA
#define READ_SDA PBin(9) //输入SDA
//IIC所有操作函数
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //发送IIC开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(u8 txd); //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); //IIC等待ACK信号
void IIC_Ack(void); //IIC发送ACK信号
void IIC_NAck(void); //IIC不发送ACK信号
void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);
void WriteData(u8 DevID,u8 Addr,u8 Dat);
void ReadData(u8 DevID,u8 Addr,u8 *Pbuf,u8 Num);
#endif
接下来就是参考芯片技术手册,编写初始化函数等,通过iic与之通讯
//BMX055.c
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//BMX055.c
#include "usart.h"
#include "BMX055.h"
#include "myiic.h"
void IMU_Init(void)
{
WriteData(Acc_addr,0x0F, 0x03);//reset 复位acc
WriteData(Acc_addr,0x10, 0x08);//+/- 16g 设置acc的测量范围
WriteData(Acc_addr,0x11, 0x00);
delay_us(100);
WriteData(Gyro_addr,0x0F, 0x04);
WriteData(Gyro_addr,0x10, 0x07);// 500
WriteData(Gyro_addr,0x11, 0x00);
delay_us(100);
WriteData(Mag_addr,0x4B, 0x83);
delay_us(100);
WriteData(Mag_addr,0x4B, 0x01);
delay_us(100);
WriteData(Mag_addr, 0x4c, 0x00); //00000000 将mag由sleep mode切换到normal mode(active)
WriteData(Mag_addr, 0x4E, 0x84);
WriteData(Mag_addr, 0x51, 0x04);
WriteData(Mag_addr, 0x52, 0x16);
delay_us(100);
}
// 初始化BMX055加速度计
void BMX055_Init_Accelerometer() {
WriteData(Acc_addr, 0x0F, 0x03); // 设置范围为±2g
WriteData(Acc_addr, 0x10, 0x08); // 设置带宽为7.81 Hz
WriteData(Acc_addr, 0x11, 0x00); // 正常模式,睡眠时长0.5ms
delay_us(100000); // 延迟等待配置生效
}
// 初始化BMX055陀螺仪
void BMX055_Init_Gyroscope() {
WriteData(Gyro_addr, 0x0F, 0x04); // 设置范围为±125度/秒
WriteData(Gyro_addr, 0x10, 0x07); // 设置输出数据速率为100 Hz
WriteData(Gyro_addr, 0x11, 0x00); // 正常模式,睡眠时长2ms
delay_us(100000); // 延迟等待配置生效
}
// 初始化BMX055磁力计
void BMX055_Init_Magnetometer() {
WriteData(Mag_addr, 0x4B, 0x83); // 软复位
WriteData(Mag_addr, 0x4C, 0x00); // 正常模式,输出数据速率为10 Hz
WriteData(Mag_addr, 0x4E, 0x84); // 启用X、Y、Z轴
WriteData(Mag_addr, 0x51, 0x04); // 设置X-Y轴重复次数为9
WriteData(Mag_addr, 0x52, 0x0F); // 设置Z轴重复次数为15
delay_us(100000); // 延迟等待配置生效
}
// 读取加速度计数据
void BMX055_Read_Accelerometer(int16_t *x, int16_t *y, int16_t *z) {
uint8_t data[6];
ReadData(Acc_addr, 0x02, data, 6);
*x = (int16_t)((data[1] << 8) | (data[0] & 0xF0)) >> 4; // X轴数据
*y = (int16_t)((data[3] << 8) | (data[2] & 0xF0)) >> 4; // Y轴数据
*z = (int16_t)((data[5] << 8) | (data[4] & 0xF0)) >> 4; // Z轴数据
if (*x > 2047) *x -= 4096; // 负值处理
if (*y > 2047) *y -= 4096;
if (*z > 2047) *z -= 4096;
}
// 读取陀螺仪数据
void BMX055_Read_Gyroscope(int16_t *x, int16_t *y, int16_t *z) {
uint8_t data[6];
ReadData(Gyro_addr, 0x02, data, 6);
*x = (int16_t)((data[1] << 8) | data[0]); // X轴数据
*y = (int16_t)((data[3] << 8) | data[2]); // Y轴数据
*z = (int16_t)((data[5] << 8) | data[4]); // Z轴数据
if (*x > 32767) *x -= 65536; // 负值处理
if (*y > 32767) *y -= 65536;
if (*z > 32767) *z -= 65536;
}
// 读取磁力计数据
void BMX055_Read_Magnetometer(int16_t *x, int16_t *y, int16_t *z) {
uint8_t data[6];
ReadData(Mag_addr, 0x42, data, 6);
*x = (int16_t)((data[1] << 5) | (data[0] >> 3)); // X轴数据
*y = (int16_t)((data[3] << 5) | (data[2] >> 3)); // Y轴数据
*z = (int16_t)((data[5] << 7) | (data[4] >> 1)); // Z轴数据
if (*x > 4095) *x -= 8192; // 负值处理
if (*y > 4095) *y -= 8192;
if (*z > 16383) *z -= 32768;
}
// 读取所有传感器数据的示例
void BMX055_Read_All() {
int16_t xAccl, yAccl, zAccl;
int16_t xGyro, yGyro, zGyro;
int16_t xMag, yMag, zMag;
BMX055_Read_Accelerometer(&xAccl, &yAccl, &zAccl); // 读取加速度计数据
BMX055_Read_Gyroscope(&xGyro, &yGyro, &zGyro); // 读取陀螺仪数据
BMX055_Read_Magnetometer(&xMag, &yMag, &zMag); // 读取磁力计数据
printf("加速度 X: %d, Y: %d, Z: %d\n", xAccl, yAccl, zAccl);
printf("陀螺仪 X: %d, Y: %d, Z: %d\n", xGyro, yGyro, zGyro);
printf("磁场 X: %d, Y: %d, Z: %d\n", xMag, yMag, zMag);
}
// 读取chip id
void BMX055_Read_Chip_Id() {
uint8_t data;
ReadData(Acc_addr, 0x00, &data, 1); // 使用指针传递data
printf("Acc_addr chip_id:%d\n", data);
ReadData(Gyro_addr, 0x00, &data, 1);
printf("Gyro_addr chip_id:%d\n", data);
ReadData(Mag_addr, 0x40, &data, 1);
printf("Mag_addr chip_id:%d\n", data);
}
//BMX055.h
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
//BMX055.h
#ifndef __BMX055_H
#define __BMX055_H
#include "stm32f4xx.h"
#include "sys.h"
#define AccSen 0.0078125 //g/lsb @ +/- 16g
#define GyroSen 0.01524 //°/s/lsb @ 500
#define TempSen 0.5 //K/LSB center temperature is 23℃
#define MagxySen 0.3 //uT/lsb
#define MagzSen 0.15 //uT/lsb
//SDO1 SDO2 CSB3 pulled to GND
#define Acc_addr 0x18
#define Gyro_addr 0x68
#define Mag_addr 0x10
/* BMX055 Register Map */
//ACC define
#define ACC_ID 0x00 //OXFA
#define ACC_XL 0x02
#define ACC_XM 0x03
#define ACC_YL 0x04
#define ACC_YM 0x05
#define ACC_ZL 0x06
#define ACC_ZM 0x07
#define Temp 0x08
#define ACC_range 0x0f //1100b --> +/- 16g
#define Shasow_dis 0x13
#define ACC_ret 0x14 //write 0xb6
//Gyro define
#define GYRO_ID 0x00 //OXOF
#define GYRO_XL 0x02
#define GYRO_XM 0x03
#define GYRO_YL 0x04
#define GYRO_YM 0x05
#define GYRO_ZL 0x06
#define GYRO_ZM 0x07
#define GYRO_range 0x0f //010b --> +/- 500°/s
#define GYRO_ret 0x14 //write 0xb6
#define GYRO_OFFSET_reset 0x21 //writing 1 to the (0x21) offset_reset bit, all dynamic offset compensation register are reset to zero
#define GYRO_SLOW_OFFSET_EN 0x31 //EN: <0:2> x/y/z Adjustable rate: <7:6> Time_period <5:3>
#define GYRO_SLOW_OFFSET_UNFILT 0x1A //<5>
#define GYRO_FAST_OFFSET_EN 0x32 //EN: <0:2> x/y/z Cancellation Start: <3> (if the algorithm finished, <3>will reset to 0) Time_period <5:3>
#define GYRO_FAST_OFFSET_UNFILT 0x1A //<5>
#define GYRO_X_OFFSET 0x36
#define GYRO_Y_OFFSET 0x37
#define GYRO_Z_OFFSET 0x38
//MAG define 8bits register 0x40 - 0x71
// 0X40 - 0X4A read only
#define MAG_ID 0x40 //OX32
#define MAG_XL 0x42 //read only: data x[4:0] lsb
#define MAG_XM 0x43 //read only: data x[12:5] msb x-self-test
#define MAG_YL 0x44 //read only: data x[4:0] lsb
#define MAG_YM 0x45 //read only: data x[12:5] msb Y-self-test
#define MAG_ZL 0x46 //read only: data x[4:0] lsb
#define MAG_ZM 0x47 //read only: data x[12:5] msb Z-self-test
#define MAG_RHAL 0x48
#define MAG_RHAM 0x49
#define MAG_ret 0x4b //1000 0001b bring the device into sleep mode, 操作完成后,自动变为00
#define MAG_OPC 0x4C
void IMU_Init(void);
void BMX055_Init_Accelerometer();
void BMX055_Init_Gyroscope();
void BMX055_Init_Magnetometer();
void BMX055_Read_Accelerometer(int16_t *x, int16_t *y, int16_t *z);
void BMX055_Read_Gyroscope(int16_t *x, int16_t *y, int16_t *z);
void BMX055_Read_Magnetometer(int16_t *x, int16_t *y, int16_t *z);
void BMX055_Read_All();
void BMX055_Read_Chip_Id();
#endif
然后就可以通过stm32f407与bmx055进行iic通讯了
先试试chip id能不能读出来,能读出来再去读取其他的数据
用到芯片的模块
如果实在不会接线或者希望更快的使用这个芯片,可以找找有用到这个芯片的模块
例如下面这个模块
可以直接参考这个模块的接线方式进行
然后先把程序在这个模块上跑跑能不能成功运行
可以的话再在自己接好线的芯片上试试