求助关于用模拟I2C读取hmc5883l中文资料磁罗盘数据的问题

  搞过嵌入式开发的程序员一定知道有I2C总线,手机和电视中的主要串行技术,通过两条线SDA,SCL解决总线传输,地址区分和热插拔问题的技术。
  可是就是这么一个简单的东西,让我这个自认为有些经验的单片机开发者浪费了整整五个月!这还是我有比较充分的经验,在一年半前就已经非常了解I2C协议的情况下!这段时间我花了无数的时间在调试,思考,解决问题而没有一丝进展。反复的检查问题,想要的结果死活不出来!昨晚的反思让我今天早上我一大早起来第一件事就是调代码,结果正确出来的时候,眼泪都快出来了。这篇文章,总结下这五个月来的问题,这五个月给我好好的上了一课。
&&&&& 五个月前,初步规划方案阶段:
&&& &我做的体感项目发展到了第四代,为了尽可能的减少尺寸和功耗,将原来的64脚IPM封装的MSP430F149换成了更小,功耗更低的MSP430F2132。选择该型号有显然的好处:32QFN封装,硬件I2C,自带上拉电阻,16MHz的功耗更低。我们使用了原来所用的ADXL345加速计,MPU3050陀螺仪和HMC5883L的磁场计解决方案。在前一版的MSP430F149上是采用模拟I2C总线,而上述传感器挂在这条总线上跑起来都毫无问题,只要焊接无问题,就一定能保证正确结果。而事实证明,这种自信确实是最后的罪魁祸首。
  四个月前,第一版制作失败:
&&&& 换方案后,板子确实做得非常小,只有硬币那么厚,小拇指那样的细条。我们在设计上花费了很多精力,保证尽可能小的体积和封装。PCB制版,焊接,上电,加速度计工作非常正常,而其他传感器返回都为错误。我们一看这个情况,I2C出来啦!单片机没问题!推断只能是传感器焊接问题。重新焊接,不行?那可能是布线和焊接问题。之所以考虑是焊接,是因为那种芯片非常难焊,所有管脚都在芯片屁股下面。如果技巧不够,很容易出现焊接不良的情况,以前的多数问题都是焊接问题。
  解决了一些小的布局问题以后,准备做第二次板。&
&&&&&两个月前:第二版制作失败:
  第二版做出来之后,出现了更严重的问题,每次上电调试,第一次程序还能写进去,第二次就不行了。再用万用表测,电源短路。上面的所有传感器都烧掉了!后来才知道,用的助焊剂非常好用,但导电!如果不洗干净,就会出现短路的问题! 后来我们都把板子直接泡到酒精里。&
&&&&& 新的问题又出现了,单片机工作很不稳定。经常出现调试写入不正常,程序跑飞的情况,板子也会变得特别烫。用示波器一看,电源纹波相当大,在电源芯片旁边的电容烫的不能用手碰。仔细分析,原来是我们使用的电容值没有达到正常标准。这句话就在电源芯片PDF中的某一个非常不起眼的地方...更换以后,这部分没问题了。
&&&&& 可是,I2C还是出不来!加速度计的0X00寄存器返回0XEF值,原本以为是对的,但实际上应该是0xE5;加上驱动程序一跑,发现加速度计根本没正常工作!其他寄存器有的值读出来是错误的,比如写入0x3E,读出来却是0X5F.有些根本就不能读!但磁场计却能出来~陀螺仪永远出不来! 这是为什么呢?既然磁场计能正确读值,说明单片机和I2C总线软硬件都没问题,难道加速度计和陀螺仪芯片是假的??    
  我们骂了一遍那些&万恶的&淘宝卖家,重新买了一批传感器回来。因为硬件制作确实严格按照要求做了。我们高兴的以为,这不是我们的问题,开心的等待着顺丰把芯片送回来。同时,继续改进电路,完成了第三版。
  一个半月前:第三版的I2C依旧有问题:
&&&& 芯片买回来了,新PCB到货了,兴冲冲的上电,发现问题依旧,磁场计能出来,加速度计问题依旧,万恶的0xEF。陀螺仪还和往日一样,完全没反应。这下尴尬了!
&&&& 焊接问题?!我们找了手机维修的大牛,仔细的给我们焊了一遍。同组的同学也认真的焊接好多板子,出现的还是一样的问题。
  软件I2C问题?但为什么磁场计能出来?所以没问题
  电路问题?仔细查过,没问题。所有的布线都OK,测试都联通。
  单片机?工作的挺正常啊,JTAG调试都没问题啊,让它输出高电平就是高,输出低就是低,上拉电阻乖乖的焊上了。我不认为它有什么问题。
  所有的选项都排除了,我只能把它归结到自身:你平时太堕落了,老天看不下去,故意让你遇到这种最恶心的问题。那段时候,我极度迷信。事实上,这套系统我在PC端上开发了足够强大的服务器端,采用了最新的技术和设计方法,几乎硬件一调好,系统就能工作啊!各种应用接口,通信流量监测,识别算法,插件系统,自然交互界面,无所不用其极。这个项目不属于我正常的工作范畴,算是&周末项目&,做着玩玩赚点小钱花,但并不表示我对它不重视。它让我很有动力的学了很多的东西。有点意思的是,如果不是这套体感系统,我也不会这么钻研.NET程序开发,也不会在博客园开博客。哈哈。
  半个月前:绝望
  就像前一段,按照我的逻辑把所有的问题都考虑了一遍(后来想,真的是这样吗?)依旧无果。我已经不知道怎么做了,我变的迷信癫狂不知所措。可能是这个项目本身给我带来了太多的好处,老天已经觉得它应该退出我的人生舞台了。
&  可是我真的能放弃么?花了那么多钱,当然钱是次要的,那么多时间和精力才是关键。如果现在放弃,原有的那些东西都没有了任何价值,最多证明我学过某门技术。我的无数思考和结论都没有了意义。&&& 最主要的是,我困扰在了我原本认为最简单的问题上,它不可能解决不了呀?!怎么回事!
&&&&&好多次我11点多从实验室回来,一晚上的时间继续白费,还是出不来.....
  我翻了好多技术资料,发了好多询问帖,有人会帮我回答,但那些问题我都挨个排查过了,没有问题啊、
  我甚至不相信逻辑,觉得数学书上的证明都是扯淡,谁也没告诉你1+1一定等于2。我生活在一个不可知的世界。
  我会经常做梦,梦到传感器都出来了,然后兴奋的一塌糊涂,早上起来插上板子,发现问题依旧,还是"0XEF",还是错误的I2C!
&&&& 最近:契机
&&&&&我逐渐的将注意力集中在了单片机上面,是它的问题么?我虽然了解I2C协议,看过了各种可能的问题,并严格按照I2C协议写了代码。但我开始怀疑它在通信的时候到底做了什么。我为什么不用示波器看看波形呢?它输出高低电平无误就证明你该相信它么?&
&&&&波形捕获证明:它出现了中间电平。 数字电路只有0和1,不可能有中间电平这种东西!如果出现,只能是电阻分压!& 在与ADXL345通信时,这个问题表现得尤为明显,MHC5883L通信时,中间电平变低了,正好落在了单片机能正确检测的范围之内。
&&& 那么,出现了不该出现的电阻,它在不合时宜的地方出现,分解了本该正确的电平值导致了单片机端口电压检测错误!电阻从哪来呢?我明明已经关掉了单片机的上拉电阻使能,按照PDF的说明,这应该也是没有问题的。但肯定就是单片机问题!
&&&&&昨天:心血来潮
&&&& 正好是圣诞节,疯玩了一天,晚上回来,还是决定去实验室看看。将板子的I2C总线引出来,去掉CPU,接到了原来的MSP430F149软件I2C引脚,上电,三个传感器都毫无压力的出来了。非常流畅和清晰!就是单片机问题!
&  换单片机?代价太大,如果换掉,那么所有的板子都要重做。而且原来的尺寸太大,所以原来的外观设计都要推倒重来。如果这一步迈出去,我们五个月来的辛苦基本上都白费了。真的要这样么?原来的程序没问题啊!或许只能这样了。
&&&&& 我不信,MSP430提供了硬件I2C,为什么不用硬件I2C试试看呢?原来尝试过,但很奇怪所以没有继续深入。那我就要和你死磕。从晚上9点钟开始到12点宿舍熄灯。找到了一份完整的关于硬件I2C的代码模板,不过有些问题,明天继续。
&&&&& 今天:成功!
&&&& 6点钟睡不着了,想着那些事情,我赶紧坐起来,趁着自己有些精神,赶紧看那些代码。昨天晚上太累,好些地方写错了。修修改改,哦?有点意思啊。再改掉了中断的代码和其他的一些问题之后,加上驱动函数,加速度计正常工作!陀螺仪正常工作!磁场计正常工作!
&&&& 究其原因,是MSP430F2132和MSP430F149的端口结构不一致导致的,2系列的单片机存在上拉电阻和一些额外的配置,导致一般的模拟I2C代码移植到该单片机时,检测高低电平的时候无法正确判断。但硬件I2C不存在这个问题,只要外部加上拉电阻,就能正常工作,具体细节我还没有仔细论证分析,等待几天之后的分析结果。
  那一刻,我有点晕,有点不想说话。反倒是很平静。这种事情,从来都不会有那种&放着不动就能成功&的情形。但还是赶紧跑出去给队友打了电话。兴奋之情完全不用形容~原本这一刻,是准备在做好板子焊接完成后的五分钟搞定的,我花了五个月时间。经历了各种痛苦和无语,它今天总算出来了。项目因为这个问题卡的死死的没有半点进展,如果早出来的话,现在几乎已经做完了.....%&_&%&
  对这个成功,我真的无颜大肆渲染,这可能是一个本科生的简单小实验而已,把我足足干掉了五个月的时光。它不是什么历史性时刻,它仅仅是一个普普通通项目的简单开始而已,仅仅如此。
&&&&& 总结:&
&&&& 这部分可能是最本文关键的部分。我的盲目自信和粗心让我在如此简单的问题上困扰了整整五个月。这些问题让我快崩溃。写在下面的:
&&&&&任何事情首先建立反馈,能让我们真实的知道内部发生了什么,串口,调试JTAG,液晶屏,或者是示波器,逻辑分析仪,这些都是非常得力的助手。
&&&& 不怕一个问题出错,怕就怕在它是半对半错性质的,对的那方面很容易让你排除本身应该存在的问题,掩饰错误的真正原因,HMC5883L我恨你。
&&&& 仔细看手册说明!我什么时候学的坏毛病:喜欢跳读,大致明白什么意思就行了。可是,那些问题就藏在原本跳过去的地方(不过对我这个问题,单片机手册上还真没说明,否则我真能看出来,但电源芯片配置不正确烧板子的事情,却绝对有关联)。
&&&& 这个世界是有逻辑的,如果它出错,那么肯定是有内在问题,上帝非常公平。
  认真严谨的工作态度,详细分析问题的能力&&这两句是我写实验报告时经常写的,但我实际按照要求做了么?没有!别人给你传授经验为什么很多情况没用?来自真正努力地实践,而这却是好多人挂在嘴上而又特别缺乏的,包括我。多数问题真的都是个态度问题。
&&&&& 这个问题让我险些放弃了整个项目,因为越来越大的实验室压力和考试压力,让我不知道该怎么走下去。实际上再过几天调不出来,我就很可能放弃它了,它往后的故事也不会再有了,也更不会有这篇文章了。文章虽长,可我写它的时间不超过调试上面那个问题的五十分之一。
&&&& 这个问题虽然不大,但确实是自我出生以来让我最无语的问题,仿佛死死的卡着脖子不能说话,痛却说不出来。&
&&&& 我很感激陪伴我度过这五个月的队友,我妹妹,还有好多关心我的人。我还相信一件事情,我虽然是党员,但我也是&二元论&者,这个世界有物理规律支撑,同时,天在看,地也在看,努力工作,好好待人待己,这个世界都不会亏待你的。
阅读(...) 评论()
$(function(){ $("input[name=article_support]").click(function(){ $("textarea[class=comment_textarea]").val("文章不错,支持一下!"); ; }); $("input[name=article_pass]").click(function(){ $("textarea[class=comment_textarea]").val("飘过~~"); ; }); </script查看: 1433|回复: 15
【求助】MPU9150读磁力计数据问题
本帖最后由 zhongjiequan 于
00:19 编辑
我对mpu9150开了I2C pass-by模式,能读出AK8976的ID,但写测量命令后,还是无法读出磁力计数据
写自检命令,却能读到磁力的自检。。。
以下我mpu9150的代码
& & & & mpu6050_reset(mpu9150_device.i2c_bus);
& & & & mpu9150_delay_ms(100);
& & & & mpu6050_set_sleep_enabled(mpu9150_device.i2c_bus,RT_FALSE);// Activate MPU6050
& & & & mpu6050_set_temp_sensor_enabled(mpu9150_device.i2c_bus,RT_TRUE);// Enable temp sensor
& & & & mpu6050_set_int_enabled(mpu9150_device.i2c_bus,RT_FALSE);// Disable interrupts
& & & &
& & & & mpu6050_set_rate(mpu9150_device.i2c_bus,1);
& & & & mpu6050_set_DLFP_mode(mpu9150_device.i2c_bus,MPU6050_DLPF_BW_188);// Set digital low-pass bandwidth
& & & & mpu6050_set_clock_source(mpu9150_device.i2c_bus,MPU6050_CLOCK_PLL_XGYRO);// Set x-axis gyro as clock source
& & & & mpu6050_set_full_scale_gyro_range(mpu9150_device.i2c_bus,MPU6050_GYRO_FS_2000);// Set gyro full scale range
& & & & mpu6050_set_full_scale_accel_range(mpu9150_device.i2c_bus,MPU6050_ACCEL_FS_16);// Set accelerometer full scale range
& & & &
& & & & mpu6050_set_I2C_bypass_enabled(mpu9150_device.i2c_bus,RT_TRUE);
& & & &
& & & & rt_kprintf(&ak8975_get_device_ID = 0x%2x\n&,ak8975_get_device_ID(mpu9150_device.i2c_bus));
& & & & ak8975_set_operation_mode(mpu9150_device.i2c_bus,AK8975_CNTL_MODE_SINGLE);
& & & & rt_int16_t gx,gy,gz,ax,ay,az,mx,my,
& & & & rt_uint8_
& & & & while(1)
& & & & {
& & & & & & & & flag = ak8975_get_data_ready(mpu9150_device.i2c_bus);
& & & & & & & & rt_kprintf(&ak8975_get_data_ready = 0x%2x\n&,flag);
& & & & & & & & mpu6050_set_I2C_bypass_enabled(mpu9150_device.i2c_bus,RT_FALSE);
& & & & & & & & if(flag == 0x01)
& & & & & & & & {
& & & & & & & & & & & & ak8975_get_magnetometer(mpu9150_device.i2c_bus,&mx,&my,&mz);
& & & & & & & & & & & & rt_kprintf(&mx=%d,my=%d,mz=%d\n&,mx,my,mz);
& & & & & & & & & & & & ak8975_set_operation_mode(mpu9150_device.i2c_bus,AK8975_CNTL_MODE_SINGLE);
& & & & & & & &
& & & & & & & & }
& & & & & & & & rt_thread_delay(100);
& & & & }复制代码
自己顶一下,就没人懂???
&&你可以看看这贴怎样
楼主你好,这几天我也在弄mpu915的磁力计部分,差不多也遇到跟你相似的问题。我9150里关于6050的数据是能读出来的,但是按照网上说的去读取磁力计,就只有2个值,要么是0要么是-256.这是我的代码,希望能有大神来给我们这种菜鸟指点一二,在这里万分感谢void MPU6050_Init()
{
& & & & IIC_Init();
& & & &
& & & & //device init
& & & & IIC_Write_Data(MPU6050_Addr,PWR_MGMT_1,0x00);& & & &
& & & & IIC_DelayMs(20);
& & & & IIC_Write_Data(MPU6050_Addr,PWR_MGMT_1,0x03);& & & &
& & & & IIC_Write_Data(MPU6050_Addr,CONFIG_MPU);
& & & & IIC_Write_Data(MPU6050_Addr,SMPLRT_DIV,0x00);
& & & & IIC_Write_Data(MPU6050_Addr,GYRO_CONFIG,0x18);
& & & & IIC_Write_Data(MPU6050_Addr,ACCEL_CONFIG,0x08);
& & & &
& & & & //IIC_Write_Data(MPU6050_Addr,PWR_MGMT_1,0x00);
& & & & //IIC_Write_Data(MPU6050_Addr,SMPLRT_DIV,0x07);
& & & & //IIC_Write_Data(MPU6050_Addr,CONFIG, 0x06);
& & & & IIC_Write_Data(MPU6050_Addr,INT_PIN_CFG,0x02);
& & & & IIC_Write_Data(MPU6050_Addr,USER_CTRL,0x00);
& & & & IIC_Write_Data(MAGADD,CNTL, 0x00);
& & & & IIC_DelayMs(2);
& & & & IIC_Write_Data(MAGADD,CNTL, 0x01);
& & & &
& & & & //IIC_Read_Data_N(MAGADD,0X10,3,mag_sens_adj);
& & & &
}
uint16_t MPU6050_Read(unsigned char REG_Address)
{
& & & & uint8_t H,L;
& & & & uint16_
& & & & H=IIC_Read_Data(MPU6050_Addr,REG_Address);
& & & & L=IIC_Read_Data(MPU6050_Addr,REG_Address+1);
& & & & temp= (H&&8)|L ;& &
& & & &
}
uint16_t COMPASS_Read(unsigned char REG_Address)
{
& & & & uint8_t H,L;
& & & & uint16_
& & & &
& & & & H=IIC_Read_Data(MAGADD,REG_Address);& & & &
& & & & IIC_Write_Data(MAGADD,CNTL, 0x01);& & & &
& & & & L=IIC_Read_Data(MAGADD,REG_Address-1);& & & &
& & & & IIC_Write_Data(MAGADD,CNTL, 0x01);
& & & &
& & & & temp= (H&&8)|L ;& &
& & & &
void MPU6050_CONVENT()
{
& & & & ACC.X=MPU6050_Read(ACCEL_XOUT_H)-ACC_OFFSET.X;
& & & & ACC.Y=MPU6050_Read(ACCEL_YOUT_H)-ACC_OFFSET.Y;
& & & & ACC.Z=MPU6050_Read(ACCEL_ZOUT_H)-ACC_OFFSET.Z;
& & & &
& & & & GYR_RATE.X=MPU6050_Read(GYRO_XOUT_H);
& & & & GYR_RATE.Y= MPU6050_Read(GYRO_YOUT_H);
& & & & GYR_RATE.Z=MPU6050_Read(GYRO_ZOUT_H);
& & & &
& & & & COMPASS.X=COMPASS_Read(HXH);
& & & & COMPASS.Y=COMPASS_Read(HYH);
& & & & COMPASS.Z=COMPASS_Read(HZH);
& & & &
& & & & //COMPASS.X=((long)COMPASS.X * mag_sens_adj[0]) && 8;
& & & & //COMPASS.Y=((long)COMPASS.X * mag_sens_adj[1]) && 8;
& & & & //COMPASS.Z=((long)COMPASS.X * mag_sens_adj[2]) && 8;
& & & &
& & & & GYR.X= GYR_RATE.X-GYR_OFFSET.X;
& & & & GYR.Y= GYR_RATE.Y-GYR_OFFSET.Y;
& & & & GYR.Z= GYR_RATE.Z-GYR_OFFSET.Z;
& & & &
#define& & & & SMPLRT_DIV& & & & & & & & 0x19& & & & //?????????ù????u????u??0x07(125Hz)
#define& & & & CONFIG_MPU6050& & & & & & & & & & & && &0x1A& & & & //u??¨???¨AEu????u????u??0x06(5Hz)
#define& & & & GYRO_CONFIG& & & & & & & & 0x1B& & & & //??????×? 1/4 ì 1/4 °????·??§??u????u??0x18(?>>×? 1/4 ì??2000deg/s)
#define& & & & ACCEL_CONFIG& & & & 0x1C& & & & // 1/4 ??? 1/4 AE×? 1/4 ì??????·??§ 1/4 °,ss?¨???¨AEu????u????u??0x01(?>>×? 1/4 ì??2G??5Hz)
#define& & & & ACCEL_XOUT_H& & & & 0x3B
#define& & & & ACCEL_XOUT_L& & & & 0x3C
#define& & & & ACCEL_YOUT_H& & & & 0x3D
#define& & & & ACCEL_YOUT_L& & & & 0x3E
#define& & & & ACCEL_ZOUT_H& & & & 0x3F
#define& & & & ACCEL_ZOUT_L& & & & 0x40
#define& & & & TEMP_OUT_H& & & & & & & & 0x41
#define& & & & TEMP_OUT_L& & & & & & & & 0x42
#define& & & & GYRO_XOUT_H& & & & & & & & 0x43
#define& & & & GYRO_XOUT_L& & & & & & & & 0x44& & & &
#define& & & & GYRO_YOUT_H& & & & & & & & 0x45
#define& & & & GYRO_YOUT_L& & & & & & & & 0x46
#define& & & & GYRO_ZOUT_H& & & & & & & & 0x47
#define& & & & GYRO_ZOUT_L& & & & & & & & 0x48
#define& & & & PWR_MGMT_1& & & & & & & & 0x6B& & & & //u??????í??u????u??0x00(????AE???)
#define& & & & WHO_AM_I& & & & & & & & 0x75& & & & //IICu??· 1/4 ??aeAE÷(???????u0x68???>>??)
//#define& & & & SMPLRT_DIV& & & & & & & & 0x19& & & & //??????,???:0x07(125Hz)
#define& & & & CONFIG& & & & & & & & & & & & 0x1A& & & & //??????,???:0x06(5Hz)
#define HXL& && && && & 0X03
#define HXH& && && && & 0X04
#define HYL& && && && & 0X05
#define HYH& && && && & 0X06
#define HZL& && && && & 0X07
#define HZH& && && && & 0X08
#define CNTL& && && && &0X0A
#define INT_PIN_CFG& & & & & & & & 0X37
#define USER_CTRL& && & 0X6A
#define MPU9150SLAADD& &0XD0
#define MAGADD& & & & & & & & & & & & 0X18
//#define& & & & PWR_MGMT_1& & & & & & & & 0x6B& & & & //????,???:0x00(????)
#define& & & & WHO_AM_I& & & & & & & & & & & & 0x75& & & & //IIC?????(????0x68,??)
//****************************
#define& & & & MPU6050_Addr& &0xD0& & & && &//?¨??AE÷ 1/4 ???IIC×??ss??u???u??·,,ù 3/4 ?ALT&&ADDRESSu??·?? 1/2 ??>>????,?复制代码
/icview--1.html&&你可以看看这贴怎样
看过,不能解决我的问题
看过,不能解决我的问题
看过,没啥用,找了几个程序安照他们的配置,compass.x输出的值要么是0要么是-256,没啥用。严重怀疑我芯片是不是出问题了,或者接线不对(只接了SCL& &SDA&&VCC GND)。真心感觉没啥问题& & & & IIC_Write_Data(MPU6050_Addr,PWR_MGMT_1,0x01);& & & &
& & & & IIC_Write_Data(MPU6050_Addr,CONFIG_MPU);
& & & & IIC_Write_Data(MPU6050_Addr,GYRO_CONFIG,0x18);
& & & & IIC_Write_Data(MPU6050_Addr,ACCEL_CONFIG,0x08);
& & & & IIC_Write_Data(MPU6050_Addr,INT_PIN_CFG,0x32);
& & & & IIC_Write_Data(MPU6050_Addr,USER_CTRL,0x00);
& & & & IIC_DelayMs(10);
& & & &
& & & & IIC_Write_Data(MAGADD,CNTL, 0x01);
& & & & IIC_DelayMs(10);复制代码
每读一次地磁三个轴数据,都得写一次CNTL为0x01,不知楼主写了没?
还有,地磁传感器的数据读取周期不能小于7ms。亲测8毫秒是可以的
每读一次地磁三个轴数据,都得写一次CNTL为0x01,不知楼主写了没?
有写,也等了10ms。可是。。。哎
我发了一个开源帖子,看能解决你的问题不
CC2541软件模拟i2c读取没问题,但是硬件i2c读取加速计和陀螺仪没有问题,磁力计数据有问题,
要么不对要么读不出来!
问题已经解决,噢耶!
问题已经解决,噢耶!
敢问是怎么解决的
解决了不分享下<(-︿-)>
阿莫电子论坛, 原"中国电子开发网"求助关于用模拟I2C读取HMC5883L磁罗盘数据的问题_百度知道
求助关于用模拟I2C读取HMC5883L磁罗盘数据的问题
我有更好的答案
你手上的这个器件,器件才会响应输入的命令,因此这样的结果让你感到很困惑。有些兼容产品没有严格按照协议进行全面的设计,验证和测试如果严格按协议来将,很有可能是兼容产品,市场上这个器件的供应商非常多。 不过,器件地址必须相同
其他类似问题
为您推荐:
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁四轴飞行器开发(2)
& &霍&#23612;韦尔 HMC5883L 是一种表面贴装的高集成模块,并带有数字接口的弱磁传感器芯片,应用于低成本罗盘和磁场检测领域。HMC5883L 包括最先进的高分辨率 HMC118X 系列磁阻传感器,并附带霍&#23612;韦尔专利的集成电路包括放大器、自动消磁驱动器、偏差校准、能使罗盘精度控制在 1°~2°的 12 位模数转换器.简易的 I2C 系列总线接口。HMC5883L 是采用无铅表面封装技术,带有 16 引脚,尺寸为 3.0X3.0X0.9mm。HMC5883L 的所应用领域有手机、笔记本电脑、消费类电子、汽车导航系统和个人导航系统
& &HMC5883主要有接口是IIC,同时提供一个数据中断引脚,一般而言,电路设计如下
& 该传感器芯片的驱动并不复杂,主要是设置几个寄存器,如下所示
//HMC5883寄存器定义
//寄存器地址定义
#define HMC_CONFIG_A_REG 0X00 //配置寄存器A
//bit0-bit1 xyz是否使用偏压,默认为0正常配置
//bit2-bit4 数据输出速率, 110为最大75HZ 100为15HZ 最小000 0.75HZ
//bit5-bit5每次采样平均数 11为8次 00为一次
#define HMC_CONFIG_B_REG 0X01 //配置寄存器B
//bit7-bit5磁场增益 数据越大,增益越小 默认001
#define HMC_MODE_REG
0X02 //模式设置寄存器
//bit0-bit1 模式设置 00为连续测量 01为单一测量
#define HMC_XMSB_REG
0X03 //X输出结果
#define HMC_XLSB_REG
#define HMC_ZMSB_REG
0X05 //Z输出结果
#define HMC_ZLSB_REG
#define HMC_YMSB_REG
0X07 //Y输出结果
#define HMC_YLSB_REG
#define HMC_STATUS_REG
0X09 //只读的状态
//bit1 数据更新时该位自动锁存,等待用户读取,读取到一半的时候防止数据改变
//bit0 数据已经准备好等待读取了,DRDY引脚也能用
#define HMC_CHEAK_A_REG
0X0A //三个识别寄存器,用于检测芯片完整性
#define HMC_CHEAK_B_REG
#define HMC_CHEAK_C_REG
#define HMC_CHECKA_VALUE 0x48 //三个识别寄存器的默认值
#define HMC_CHECKB_VALUE 0x34
#define HMC_CHECKC_VALUE 0x33
建议选择最大速率,八倍采样输出,同时该传感器支持读写地址指针自动变化,但是针对随机读取的驱动而言,该特性不重要
另外,一般而言,地址为0x3c,驱动代码如下
#include &hmc5883.h&
#include &math.h&
struct HMCVALUE hmcV
u8 dataReady = 0;
//IO方向设置
#define HMC_SDA_IN()
{GPIOC-&CRH&=0XFFFFFFF0;GPIOC-&CRH|=8;}
#define HMC_SDA_OUT() {GPIOC-&CRH&=0XFFFFFFF0;GPIOC-&CRH|=3;}
//IO操作函数
#define HMC_SCL
PCout(9) //SCL
#define HMC_SDA
PCout(8) //SDA
#define HMC_READ_SDA
#define HMC_DRDY PCin(7)
/**************************HMC5883 IIC驱动函数*********************************/
static void Hmc5883IOInit(void)
GPIO_InitTypeDef GPIO_InitS
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//PC7 drdy引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
//浮空输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
HMC_SCL = 1;
HMC_SDA = 1;
//发送IIC起始信号
static void ComStart(void)
HMC_SDA_OUT();
//sda线输出
HMC_SDA=1;
HMC_SCL=1;
DelayUs(5);
HMC_SDA=0;//START:when CLK is high,DATA change form high to low
DelayUs(5);
HMC_SCL=0;//钳住I2C总线,准备发送或接收数据
//发送IIC停止信号
static void ComStop(void)
HMC_SDA_OUT();//sda线输出
HMC_SDA=0;//STOP:when CLK is high DATA change form low to high
HMC_SCL=1;
DelayUs(5);
HMC_SDA=1;//发送I2C总线结束信号
DelayUs(5);
//等待ACK,为1代表无ACK 为0代表等到了ACK
static u8 ComWaitAck(void)
u8 waitTime = 0;
HMC_SDA_OUT();//sda线输出
HMC_SDA = 1;
DelayUs(5);
HMC_SDA_IN();
//SDA设置为输入
HMC_SCL=1;
DelayUs(5);
while(HMC_READ_SDA)
waitTime++;
DelayUs(1);
if(waitTime & HMC_ACK_WAIT_TIME)
ComStop();
HMC_SCL = 0;
static void ComSendAck(void)
HMC_SCL = 0;
HMC_SDA_OUT();
HMC_SDA = 0;
DelayUs(2);
HMC_SCL = 1;
DelayUs(5);
HMC_SCL = 0;
DelayUs(5);
static void ComSendNoAck(void)
HMC_SCL = 0;
HMC_SDA_OUT();
HMC_SDA = 1;
DelayUs(2);
HMC_SCL = 1;
DelayUs(5);
HMC_SCL = 0;
DelayUs(5);
//返回0 写入收到ACK 返回1写入未收到ACK
static u8 ComSendByte(u8 byte)
HMC_SDA_OUT();
for(t=0;t&8;t++)
HMC_SDA=(byte&0x80)&&7;
HMC_SCL=1;
DelayUs(5);
HMC_SCL=0;
DelayUs(5);
return ComWaitAck();
static void ComReadByte(u8* byte)
u8 i,receive=0;
HMC_SDA_IN();//SDA设置为输入
for(i=0;i&8;i++ )
receive &&= 1;
HMC_SCL=1;
DelayUs(5);
if(HMC_READ_SDA)receive++;
HMC_SCL=0;
DelayUs(5);
/**************************HMC5883 IIC驱动函数*********************************/
//向HMC写入一个字节数据,失败返回1 成功返回0
u8 Hmc5883WriteReg(u8 regValue,u8 setValue)
ComStart();
//起始信号
res = ComSendByte(HMC_ADDR);
//发送设备地址+写信号
#ifdef HMC_DEBUG
printf(&file=%s,func=%s,line=%d\r\n&,__FILE__,__FUNCTION__,__LINE__);
res = ComSendByte(regValue);
//内部寄存器地址
#ifdef HMC_DEBUG
printf(&file=%s,func=%s,line=%d\r\n&,__FILE__,__FUNCTION__,__LINE__);
res = ComSendByte(setValue);
//内部寄存器数据
#ifdef HMC_DEBUG
printf(&file=%s,func=%s,line=%d\r\n&,__FILE__,__FUNCTION__,__LINE__);
ComStop();
//发送停止信号
//**************************************
//从I2C设备读取一个字节数据
//**************************************
u8 Hmc5883ReadReg(u8 regAddr,u8* readValue)
ComStart();
//起始信号
res = ComSendByte(HMC_ADDR);
//发送设备地址+写信号
#ifdef HMC_DEBUG
printf(&file=%s,func=%s,line=%d\r\n&,__FILE__,__FUNCTION__,__LINE__);
res = ComSendByte(regAddr);
//发送存储单元地址,从0开始
#ifdef HMC_DEBUG
printf(&file=%s,func=%s,line=%d\r\n&,__FILE__,__FUNCTION__,__LINE__);
ComStart();
//起始信号
res = ComSendByte(HMC_ADDR+1);
//发送设备地址+读信号
#ifdef HMC_DEBUG
printf(&file=%s,func=%s,line=%d\r\n&,__FILE__,__FUNCTION__,__LINE__);
ComReadByte(readValue);
//读出寄存器数据
ComSendNoAck();
//发送非应答信号
ComStop();
//停止信号
static void HmcDefaultConfig(void)
Hmc5883WriteReg(HMC_CONFIG_A_REG,HMC_DEFAULT_CONFIGA_VALUE);
Hmc5883WriteReg(HMC_CONFIG_B_REG,HMC_DEFAULT_CONFIGB_VALUE);
Hmc5883WriteReg(HMC_MODE_REG,HMC_DEFAULT_MODE_VALUE);
//配置HMC drdy引脚中断
void HmcDrdyPinIntInit(void)
EXTI_InitTypeDef EXTI_InitS
NVIC_InitTypeDef NVIC_InitS
//GPIOC.7 中断线以及中断初始化配置
下降沿触发
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource7);
EXTI_InitStructure.EXTI_Line=EXTI_Line7;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_I
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_F //下降沿中断
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
//使能所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = HMC_DRDY_PreemptionP //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = HMC_DRDY_SubP
//子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//使能外部中断通道
NVIC_Init(&NVIC_InitStructure);
//对应的外部中断处理函数
void EXTI9_5_IRQHandler()
if(EXTI_GetFlagStatus(EXTI_Line7) == SET)
EXTI_ClearFlag(EXTI_Line7);
dataReady = 1;
//失败返回1,初始化通过之后基本通讯就没有问题了就可以不再判定通讯结果了
u8 HmcInit(void)
u8 hmcCheckValue = 0x00;
u8 res = 0;
Hmc5883IOInit(); //接口初始化
while(HMC_DRDY == 1);//等待数据引脚正常
HmcDrdyPinIntInit();//配置中断
DelayMs(100);
//验证A识别
res = Hmc5883ReadReg(HMC_CHEAK_A_REG,&hmcCheckValue);
#ifdef HMC_DEBUG
printf(&file=%s,func=%s,line=%d\r\n&,__FILE__,__FUNCTION__,__LINE__);
if(hmcCheckValue != HMC_CHECKA_VALUE) //自检通过
//验证B识别
res = Hmc5883ReadReg(HMC_CHEAK_B_REG,&hmcCheckValue);
#ifdef HMC_DEBUG
printf(&file=%s,func=%s,line=%d\r\n&,__FILE__,__FUNCTION__,__LINE__);
if(hmcCheckValue != HMC_CHECKB_VALUE) //自检通过
//验证C识别
res = Hmc5883ReadReg(HMC_CHEAK_C_REG,&hmcCheckValue);
#ifdef HMC_DEBUG
printf(&file=%s,func=%s,line=%d\r\n&,__FILE__,__FUNCTION__,__LINE__);
if(hmcCheckValue != HMC_CHECKC_VALUE) //自检通过
HmcDefaultConfig();
//全部验证通过
void Hmc5883Reflush(void)
u16 xValue = 0x00,yValue = 0x00,zValue = 0x00;
Hmc5883ReadReg(HMC_XMSB_REG,&temp);
xValue &&=8;
Hmc5883ReadReg(HMC_XLSB_REG,&temp);
Hmc5883ReadReg(HMC_ZMSB_REG,&temp);
zValue &&=8;
Hmc5883ReadReg(HMC_ZLSB_REG,&temp);
Hmc5883ReadReg(HMC_YMSB_REG,&temp);
yValue &&=8;
Hmc5883ReadReg(HMC_YLSB_REG,&temp);
hmcValue.hmcXvalue = (s16)xV
hmcValue.hmcYvalue = (s16)yV
hmcValue.hmcZvalue = (s16)zV
hmcValue.hmcAxis = atan2((double)hmcValue.hmcYvalue,(double)hmcValue.hmcXvalue) * (180 / 3.) + 180; // angle in degrees
#ifdef HMC_DEBUG
printf(&x = %d \t y = %d \t z = %d \t axis = %f\r\n&,xValue,yValue,zValue,hmcValue.hmcAxis);
头文件定义如下(中断有优先级请自行定义)
#ifndef __HMC5883_H_
#define __HMC5883_H_
#include &common.h&
#include &stm32f10x.h&
#include &delay.h&
#include &ioremap.h&
#include &uart.h&
#define HMC_DEBUG 1 //是否输出调试信息
//没有主机改变地址的话地址是可以自动更新的,不过该驱动没有用这个模式
//HMC5883寄存器定义
//寄存器地址定义
#define HMC_CONFIG_A_REG 0X00 //配置寄存器A
//bit0-bit1 xyz是否使用偏压,默认为0正常配置
//bit2-bit4 数据输出速率, 110为最大75HZ 100为15HZ 最小000 0.75HZ
//bit5-bit5每次采样平均数 11为8次 00为一次
#define HMC_CONFIG_B_REG 0X01 //配置寄存器B
//bit7-bit5磁场增益 数据越大,增益越小 默认001
#define HMC_MODE_REG
0X02 //模式设置寄存器
//bit0-bit1 模式设置 00为连续测量 01为单一测量
#define HMC_XMSB_REG
0X03 //X输出结果
#define HMC_XLSB_REG
#define HMC_ZMSB_REG
0X05 //Z输出结果
#define HMC_ZLSB_REG
#define HMC_YMSB_REG
0X07 //Y输出结果
#define HMC_YLSB_REG
#define HMC_STATUS_REG
0X09 //只读的状态
//bit1 数据更新时该位自动锁存,等待用户读取,读取到一半的时候防止数据改变
//bit0 数据已经准备好等待读取了,DRDY引脚也能用
#define HMC_CHEAK_A_REG
0X0A //三个识别寄存器,用于检测芯片完整性
#define HMC_CHEAK_B_REG
#define HMC_CHEAK_C_REG
#define HMC_CHECKA_VALUE 0x48 //三个识别寄存器的默认值
#define HMC_CHECKB_VALUE 0x34
#define HMC_CHECKC_VALUE 0x33
//HMC5883地址定义
#define HMC_ADDR
//写地址,读地址+1
//HMC5883 初始化宏定义
#define HMC_DEFAULT_CONFIGA_VALUE
//75hz 8倍采样 正常配置
#define HMC_DEFAULT_CONFIGB_VALUE
//+-0.88GA增益
#define HMC_DEFAULT_MODE_VALUE
//连续测量模式
#define HMC_ACK_WAIT_TIME 200
//iic通讯时的ack等待时间
//HMC5883驱动结构体定义
typedef struct HMCVALUE
double hmcA
}HMCVALUE;
u8 HmcInit(void);
u8 Hmc5883WriteReg(u8 regValue,u8 setValue);
u8 Hmc5883ReadReg(u8 regAddr,u8* readValue);
void Hmc5883Reflush(void);
extern struct HMCVALUE hmcV
extern u8 dataR
引脚连接电路如下
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:28585次
排名:千里之外
原创:60篇
评论:14条

我要回帖

更多关于 hmc5883l 的文章

 

随机推荐