求助关于用模拟I2C读取HMC5883L磁罗盘数据的问题?

2019-10-15 23:32发布

[mw_shl_code=c,true]求哪位高手帮我看看哪里的问题,读取数据用的I2C时序全是原子哥例程里照搬的,读取HMC5883L数据部分也是根据一位吧友的改的(改动很小),现在读取数据返回的全是65535,检测引脚电压一直为3.3V,不确定是不是硬件问题。硬件用的是GY-87的模块,包含MPU6050,BMP180,HMC5883L三个传感器,我现在只用这一个,对另外两个也没处理,不知道有没有影响?[/mw_shl_code] [mw_shl_code=c,true][/mw_shl_code] IIC.h文件
[mw_shl_code=c,true]#ifndef __IIC_H #define __IIC_H #include "sys.h" #include "delay.h" #include "USART3.h" //IO方向设置 #define SDA_IN() {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=8<<12;} //PA11 通用推挽输出模式,最大速度50MHZ #define SDA_OUT() {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=3<<12;} //PA11 上拉/下拉输入模式 //IO操作函数 #define IIC_SCL PAout(10) //SCL #define IIC_SDA PAout(11) //SDA #define READ_SDA PAin(11) //输入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读取一个字节 //读一个字节,ack = 1时, 发送ACK, ack = 0,发送nACK u8 IIC_Wait_Ack(void); //IIC等待ACK信号 void IIC_Ack(void); //IIC发送ACK信号 void IIC_NAck(void); //IIC不发送ACK信号 void IIC(void); #endif [/mw_shl_code] IIC.c文件 [mw_shl_code=c,true]#include "IIC.h" #include "USART3.h" void IIC_Init(void) { // RCC->APB2ENR |= 1 << 4; // GPIOC->CRH &= 0xfff00fff; //PC11 PC12推挽输出 // GPIOC->CRH |= 0x00033000; // GPIOC->ODR |= 3 << 11; //PC11 PC12输出高 // // RCC->APB2ENR |= 1 << 3;//先使能外设IO PORTB时钟 // GPIOB->CRL &= 0X00FFFFFF;//PB6-SCL PB7-SDA 推挽输出 // GPIOB->CRL |= 0X33000000; // GPIOB->ODR |= 0X03 << 6; // 拉高 GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_SetBits(GPIOA,GPIO_Pin_10|GPIO_Pin_11); //PA10,PA11 输出高 printf("i'm iic init "); } //void IIC(void) //此函数功能是点亮开发板上PC13所连小灯,验证PCout()位带操作是否可用 //{ // GPIO_InitTypeDef GPIO_InitStructure; // RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE ); // // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出 // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // GPIO_Init(GPIOC, &GPIO_InitStructure); // PCout(13)=0; //SCL //} //产生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; if((txd&0x80)>>7) IIC_SDA=1; else IIC_SDA=0; 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; } [/mw_shl_code] HMC5883L.h 文件 [mw_shl_code=c,true]#ifndef __HMC5883L_H #define __HMC5883L_H #include "sys.h" #include "IIC.h" #include "USART3.h" #define SlaveAddress 0x3C void Init_HMC5883(void); void Write_HMC5883(u8 add, u8 da); u8 Read_HMC5883(u8 REG_Address); void Multiple_read_HMC5883(u8*BUF); #endif [/mw_shl_code] hmc5883l.c文件
[mw_shl_code=c,true]#include "HMC5883L.h" #include "IIC.h" #define SlaveAddress 0x3C void Init_HMC5883(void) { // //IIC_Init(); // Write_HMC5883(0x00, 0x78); //每次测量输出中选择采样平均数8; 在连续测量模式下的所有可选的输出速率75hz // Write_HMC5883(0x01, 0x00); //增益设置 // Write_HMC5883(0x02, 0x00); //连续测量模式 Write_HMC5883(0x00, 0x70); //每次测量输出中选择采样平均数8; 在连续测量模式下的所有可选的输出速率75hz Write_HMC5883(0x01, 0xA0); //增益设置 Write_HMC5883(0x02, 0x00); //连续测量模式 } void Write_HMC5883(u8 add, u8 da) { IIC_Start(); //起始信号 IIC_Send_Byte(SlaveAddress); //发送设备地址+写信号 IIC_Wait_Ack(); IIC_Send_Byte(add); //内部寄存器地址,请参考中文pdf IIC_Wait_Ack(); IIC_Send_Byte(da); //内部寄存器数据,请参考中文pdf IIC_Wait_Ack(); IIC_Stop(); //发送停止信号 delay_ms(10);//后加 } u8 Read_HMC5883(u8 REG_Address) { u8 REG_data; IIC_Start(); //起始信号 IIC_Send_Byte(SlaveAddress); //发送设备地址+写信号 IIC_Wait_Ack(); IIC_Send_Byte(REG_Address); //发送存储单元地址,从0开始 IIC_Wait_Ack(); IIC_Start(); //起始信号 IIC_Send_Byte(SlaveAddress+1); //发送设备地址+读信号 IIC_Wait_Ack(); REG_data=IIC_Read_Byte(0); //读出寄存器数据 IIC_Stop(); //停止信号 delay_ms(5);//后加 return REG_data; } //****************************************************** // //连续读出HMC5883内部角度数据,地址范围0x3~0x5 // //****************************************************** void Multiple_read_HMC5883(u8* BUF) { u8 i; IIC_Start(); //起始信号 IIC_Send_Byte(SlaveAddress); //发送设备地址+写信号 IIC_Wait_Ack(); IIC_Send_Byte(0x03); //发送存储单元地址,从0x3开始 IIC_Wait_Ack(); IIC_Start(); //起始信号 IIC_Send_Byte(SlaveAddress+1); //发送设备地址+读信号 IIC_Wait_Ack(); for (i=0; i<6; i++) //连续读取6个地址数据,存储中BUF { if (i == 5) { BUF = IIC_Read_Byte(0); //最后一个数据需要回NOACK } else { BUF = IIC_Read_Byte(1); //返回ACK } } IIC_Stop(); //停止信号 printf("i'm hmcmulread "); } //***************************************************[/mw_shl_code]
主函数
[mw_shl_code=c,true]#include "delay.h" #include "sys.h" #include "USART3.h" #include "gps.h" #include "string.h" #include "Distance.h" #include "stdio.h" #include <stm32f10x.h> #include "hmc5883l.h" #include "math.h" u8 BUF[6]; double angle; int main(void) { int x,y,z; // double x,y,z; SystemInit(); delay_init(); //延时函数初始化 NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 USART3_Init(9600); //初始化串口1 // IIC(); IIC_Init(); delay_ms(50); Init_HMC5883(); delay_ms(10); while(1) { delay_ms(20); Init_HMC5883(); Multiple_read_HMC5883(BUF); x=BUF[0] << 8 | BUF[1]; //Combine MSB and LSB of X Data output register z=BUF[2] << 8 | BUF[3]; //Combine MSB and LSB of Z Data output register y=BUF[4] << 8 | BUF[5]; //Combine MSB and LSB of Y Data output register /* if(x>32768) x = -(0xFFFF - x + 1); if(z>32768) z = -(0xFFFF - z + 1); if(y>32768) y = -(0xFFFF - y + 1); angle= (atan2((double)y,(double)x) * (180 / 3.14159265) + 180); // angle in degrees delay_ms(10); */ printf("x:%d ",x); printf("y:%d ",y); printf("z:%d ",z); printf("angle:%.2f ",angle); } }[/mw_shl_code] [mw_shl_code=c,true]  [/mw_shl_code]
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
21条回答
opennedver
1楼-- · 2019-10-16 18:09
回复【7楼】流浪者转世:
---------------------------------
就是这个程序,楼主的代码已经贴出来了
Fliger
2楼-- · 2019-10-16 22:47
 精彩回答 2  元偷偷看……
蜕变
3楼-- · 2019-10-17 04:14
回复【9楼】Fliger:
---------------------------------
对的,是要把BYPASS模式打开的,要设置一下就可以了。我这个程序是适合只有HMC5883模块的(直接接单片机的IIC),想把那个图删掉没发现操作的地方,后来忙就忘了,误导你了不好意思。不过我当时在GY87上也调通了,就是对着手册设置个寄存器就行了。你先试一下,不行的话改天我有空把程序再改一下
Fliger
4楼-- · 2019-10-17 07:01
回复【10楼】蜕变:
---------------------------------
麻烦你给个gy87的程序吧,我觉得这个也不难,之前怀疑模块坏了(因为看到有人是买到坏的模块)  然后我又买了2个模块,还是没弄好,我在想要不要换一家买个试下呢~~~~~55555~~~~~
雪噬剑
5楼-- · 2019-10-17 09:02
楼主是在做四轴吗?我虽然不是用的模块,不过也是mpu6050+hmc5883+bmp085的方案,可否加个QQ交流下?
xumvp5577
6楼-- · 2019-10-17 10:27
蜕变 发表于 2015-5-7 21:39
GY-87模块原理图

我的模块和你的一样,磁力计也是挂载在MPU6050上的,可是我看网上说需要把MPU6050的I2C改成直通模式才能直接的访问HMC5883L。但是我看你代码没有啊。

一周热门 更多>