找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9333|回复: 10
打印 上一主题 下一主题
收起左侧

HMC5883L电子指南针单片机程序

  [复制链接]
跳转到指定楼层
楼主
ID:127035 发表于 2016-12-19 21:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
HMC5883L电子指南针
完整的单片机源程序下载:
2014年6月7日 指南针 1602.rar (45.92 KB, 下载次数: 187)

预览:
  1. #include <reg52.h>                 //调用单片机头文件
  2. #define uchar unsigned char  //无符号字符型 宏定义        变量范围0~255
  3. #define uint  unsigned int         //无符号整型 宏定义        变量范围0~65535
  4. #include  <math.h>    //Keil library  
  5. #include  <stdio.h>   //Keil library        
  6. #include  <INTRINS.H>

  7. sbit rs=P2^3;         //寄存器选择信号 H:数据寄存器          L:指令寄存器
  8. sbit rw=P2^4;         //寄存器选择信号 H:数据寄存器          L:指令寄存器
  9. sbit e =P2^5;         //片选信号   下降沿触发

  10. sbit SCL=P1^1;      //IIC时钟引脚定义
  11. sbit SDA=P1^0;      //IIC数据引脚定义

  12. #define        SlaveAddress   0x3C                 //定义器件在IIC总线中的从地址
  13. uchar BUF[8];                        //接收数据缓存区              
  14. uchar ge,shi,bai,qian,wan;           //显示变量
  15. int  dis_data;                       //变量

  16. /******************1ms 延时函数*******************/
  17. void delay_1ms(uint q)
  18. {
  19.         uint i,j;
  20.         for(i=0;i<q;i++)
  21.                 for(j=0;j<120;j++);
  22. }


  23. /***********************延时函数************************/
  24. void delay_uint(uint q)
  25. {
  26.         while(q--);
  27. }

  28. /**************************************
  29. 延时5微秒(STC90C52RC@12M)
  30. 不同的工作环境,需要调整此函数,注意时钟过快时需要修改
  31. 当改用1T的MCU时,请调整此延时函数
  32. **************************************/
  33. void Delay5us()
  34. {
  35.              _nop_();_nop_();_nop_();_nop_();
  36.              _nop_();_nop_();_nop_();_nop_();
  37.         _nop_();_nop_();_nop_();_nop_();
  38.         _nop_();_nop_();_nop_();_nop_();
  39.               _nop_();_nop_();_nop_();_nop_();
  40.         _nop_();_nop_();_nop_();_nop_();
  41.         _nop_();_nop_();_nop_();_nop_();
  42.              _nop_();_nop_();_nop_();_nop_();

  43. }

  44. /***********************lcd1602写命令函数************************/
  45. void write_com(uchar com)
  46. {
  47.         e=0;
  48.         rs=0;
  49.         rw=0;
  50.         P0=com;
  51.         delay_uint(3);
  52.         e=1;
  53.         delay_uint(25);
  54.         e=0;
  55. }

  56. /***********************lcd1602写数据函数************************/
  57. void write_data(uchar dat)
  58. {
  59.         e=0;
  60.         rs=1;
  61.         rw=0;
  62.         P0=dat;
  63.         delay_uint(3);
  64.         e=1;
  65.         delay_uint(25);
  66.         e=0;        
  67. }

  68. /***********************lcd1602上显示特定的字符************************/
  69. void write_zifu(uchar hang,uchar add,uchar date)
  70. {
  71.         if(hang==1)   
  72.                 write_com(0x80+add);
  73.         else
  74.                 write_com(0x80+0x40+add);
  75.         write_data(date);        
  76. }

  77. /***********************lcd1602上显示这字符函数************************/
  78. void write_string(uchar hang,uchar add,uchar *p)
  79. {
  80.         if(hang==1)   
  81.                 write_com(0x80+add);
  82.         else
  83.                 write_com(0x80+0x40+add);
  84.         while(1)                                                                                                                 
  85.         {
  86.                 if(*p == '\0')  break;
  87.                 write_data(*p);
  88.                 p++;
  89.         }        
  90. }


  91. /***********************lcd1602初始化设置************************/
  92. void init_1602()         //lcd1602初始化设置
  93. {
  94.         write_com(0x38);        //
  95.         write_com(0x0c);
  96.         write_com(0x06);
  97.         delay_uint(1000);
  98.         write_string(1,0,"  zhi nan zhen ");               
  99.         write_string(2,0,"               ");        
  100.         write_zifu(2,11,0xdf);  //显示度        
  101. }

  102. /***********************lcd1602上显示两位十进制数************************/
  103. void write_jiaodu(uchar hang,uchar add,uint date)
  104. {
  105.         if(hang==1)   
  106.                 write_com(0x80+add);
  107.         else
  108.                 write_com(0x80+0x40+add);
  109.         write_data(0x30+date/1000%10);
  110.         write_data(0x30+date/100%10);
  111.         write_data(0x30+date/10%10);
  112.         write_data('.');
  113.         write_data(0x30+date%10);        
  114. }

  115. /**************************************
  116. 起始信号
  117. **************************************/
  118. void HMC5883_Start()
  119. {
  120.     SDA = 1;                    //拉高数据线
  121.     Delay5us();                 //延时
  122.     SDA = 0;                    //产生下降沿
  123.     Delay5us();                 //延时
  124.     SCL = 0;                    //拉低时钟线
  125. }

  126. /**************************************
  127. 停止信号
  128. **************************************/
  129. void HMC5883_Stop()
  130. {
  131.     SDA = 0;                    //拉低数据线
  132.     SCL = 1;                    //拉高时钟线
  133.     Delay5us();                 //延时
  134.     SDA = 1;                    //产生上升沿
  135.     Delay5us();                 //延时
  136. }

  137. /**************************************
  138. 发送应答信号
  139. 入口参数:ack (0:ACK 1:NAK)
  140. **************************************/
  141. void HMC5883_SendACK(bit ack)
  142. {
  143.     SDA = ack;                  //写应答信号
  144.     SCL = 1;                    //拉高时钟线
  145.     Delay5us();                 //延时
  146.     SCL = 0;                    //拉低时钟线
  147.     Delay5us();                 //延时
  148. }

  149. /**************************************
  150. 接收应答信号
  151. **************************************/
  152. bit HMC5883_RecvACK()
  153. {
  154.     SCL = 1;                    //拉高时钟线
  155.     Delay5us();                 //延时
  156.     CY = SDA;                   //读应答信号
  157.     SCL = 0;                    //拉低时钟线
  158.     Delay5us();                 //延时

  159.     return CY;
  160. }

  161. /**************************************
  162. 向IIC总线发送一个字节数据
  163. **************************************/
  164. void HMC5883_SendByte(uchar dat)
  165. {
  166.     uchar i;

  167.     for (i=0; i<8; i++)         //8位计数器
  168.     {
  169.         dat <<= 1;              //移出数据的最高位
  170.         SDA = CY;               //送数据口
  171.         SCL = 0;                //拉高时钟线
  172.         Delay5us();             //延时
  173.         SCL = 1;                //拉低时钟线
  174.         Delay5us();             //延时
  175.     }
  176.     HMC5883_RecvACK();
  177. }

  178. /**************************************
  179. 从IIC总线接收一个字节数据
  180. **************************************/
  181. uchar HMC5883_RecvByte()
  182. {
  183.     uchar i;
  184.     uchar dat = 0;

  185.     SDA = 1;                    //使能内部上拉,准备读取数据,
  186.     for (i=0; i<8; i++)         //8位计数器
  187.     {
  188.         dat <<= 1;
  189.         SCL = 1;                //拉高时钟线
  190.         Delay5us();             //延时
  191.         dat |= SDA;             //读数据               
  192.         SCL = 0;                //拉低时钟线
  193.         Delay5us();             //延时
  194.     }
  195.     return dat;
  196. }

  197. //***************************************************

  198. void Single_Write_HMC5883(uchar REG_Address,uchar REG_data)
  199. {
  200.     HMC5883_SendByte(SlaveAddress);   //发送设备地址+写信号
  201.     HMC5883_SendByte(REG_Address);    //内部寄存器地址,请参考中文pdf
  202.     HMC5883_SendByte(REG_data);       //内部寄存器数据,请参考中文pdf
  203. }

  204. //******************************************************
  205. //
  206. //连续读出HMC5883内部角度数据,地址范围0x3~0x8
  207. //
  208. //******************************************************
  209. void Multiple_read_HMC5883(void)
  210. {   uchar i;
  211.     HMC5883_Start();                          //起始信号
  212.     HMC5883_SendByte(SlaveAddress);           //发送设备地址+写信号
  213.     HMC5883_SendByte(0x03);                   //发送存储单元地址,从0x3开始        
  214.     HMC5883_Start();                          //起始信号
  215.     HMC5883_SendByte(SlaveAddress+1);         //发送设备地址+读信号
  216.         for (i=0; i<6; i++)                      //连续读取6个地址数据,存储中BUF
  217.     {
  218.         BUF[i] = HMC5883_RecvByte();          //BUF[0]存储数据
  219.         if (i == 5)
  220.         {
  221.            HMC5883_SendACK(0);                //最后一个数据需要回NOACK
  222.         }
  223.         else
  224.         {
  225.           HMC5883_SendACK(1);                //回应ACK
  226.        }
  227.    }
  228.     delay_1ms(5);
  229. }

  230. //初始化HMC5883,根据需要请参考pdf进行修改****
  231. void Init_HMC5883()
  232. {
  233.      Single_Write_HMC5883(0x02,0x00);  //
  234. }


  235. /*****************主函数********************/
  236. void main()
  237. {        
  238.     int x,y,z,jiadu;
  239.     double angle;
  240.         P0 = P1 = P2 = P3 = 0xff;                //单片机IO口初始化为1
  241.     Init_HMC5883();
  242.         init_1602();                 //lcd1602初始化
  243.         while(1)
  244.         {   
  245.             Multiple_read_HMC5883();      //连续读出数据,存储在BUF中
  246.         //---------显示X轴
  247.             x=BUF[0] << 8 | BUF[2]; //Combine MSB and LSB of X Data output register
  248.             z=BUF[2] << 8 | BUF[4]; //Combine MSB and LSB of Z Data output register
  249.         
  250.             angle= atan2((double)y,(double)x) * (180 / 3.14); // angle in degrees
  251.                 jiadu = angle;
  252.                 write_jiaodu(2,6,angle);        //显示角度
  253.                 if((angle >= 3380) || (angle <= 220))          //北 N
  254.                         write_string(2,0,"  N  ");        
  255.                 if((angle >= 230) && (angle <= 670))          //东 北
  256.                         write_string(2,0," E N ");        
  257.                 if((angle >= 680) && (angle <= 1120))          //东 E
  258.                         write_string(2,0,"  E  ");        
  259.                 if((angle >= 1130) && (angle <= 1570))          //东 南
  260.                         write_string(2,0," E S ");        
  261.                 if((angle >= 1580) && (angle <= 2010))          //南  S
  262.                         write_string(2,0,"  S  ");        
  263.                 if((angle >= 2020) && (angle <= 2460))          //西 南  
  264.                         write_string(2,0," W S ");        
  265.                 if((angle >= 2470) && (angle <= 2910))          //西  W  
  266.                         write_string(2,0,"  W  ");        
  267.                 if((angle >= 2920) && (angle <= 3360))          //西  北  
  268.                         write_string(2,0," W N  ");        
  269.                 delay_1ms(300);

  270.         }
  271. }
复制代码


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1 发表于 2017-1-3 00:01 | 只看该作者
51黑有你更精彩!!!
回复

使用道具 举报

板凳
ID:198094 发表于 2017-5-8 14:58 | 只看该作者
大神您好,能帮忙解释一下如下程序中,角度值为什么这样设置吗?

angle= atan2((double)y,(double)x) * (180 / 3.14); // angle in degrees
                jiadu = angle;
                write_jiaodu(2,6,angle);        //显示角度
                if((angle >= 3380) || (angle <= 220))          //北 N
                        write_string(2,0,"  N  ");        
                if((angle >= 230) && (angle <= 670))          //东 北
                        write_string(2,0," E N ");        
                if((angle >= 680) && (angle <= 1120))          //东 E
                        write_string(2,0,"  E  ");        
                if((angle >= 1130) && (angle <= 1570))          //东 南
                        write_string(2,0," E S ");        
                if((angle >= 1580) && (angle <= 2010))          //南  S
                        write_string(2,0,"  S  ");        
                if((angle >= 2020) && (angle <= 2460))          //西 南  
                        write_string(2,0," W S ");        
                if((angle >= 2470) && (angle <= 2910))          //西  W  
                        write_string(2,0,"  W  ");        
                if((angle >= 2920) && (angle <= 3360))          //西  北  
                        write_string(2,0," W N  ");        
                delay_1ms(300);
回复

使用道具 举报

地板
ID:198094 发表于 2017-5-8 15:02 | 只看该作者
大神麻烦解释一下如下程序中,东西南北角度值为何这样设呢?

angle= atan2((double)y,(double)x) * (180 / 3.14); // angle in degrees
                jiadu = angle;
                write_jiaodu(2,6,angle);        //显示角度
                if((angle >= 3380) || (angle <= 220))          //北 N
                        write_string(2,0,"  N  ");        
                if((angle >= 230) && (angle <= 670))          //东 北
                        write_string(2,0," E N ");        
                if((angle >= 680) && (angle <= 1120))          //东 E
                        write_string(2,0,"  E  ");        
                if((angle >= 1130) && (angle <= 1570))          //东 南
                        write_string(2,0," E S ");        
                if((angle >= 1580) && (angle <= 2010))          //南  S
                        write_string(2,0,"  S  ");        
                if((angle >= 2020) && (angle <= 2460))          //西 南  
                        write_string(2,0," W S ");        
                if((angle >= 2470) && (angle <= 2910))          //西  W  
                        write_string(2,0,"  W  ");        
                if((angle >= 2920) && (angle <= 3360))          //西  北  
                        write_string(2,0," W N  ");        
                delay_1ms(300);
回复

使用道具 举报

5#
ID:204529 发表于 2017-5-24 22:37 | 只看该作者
貌似这个程序不好用!
回复

使用道具 举报

6#
ID:229064 发表于 2017-9-12 19:55 | 只看该作者
感谢 您对资源的分享!!!!!
回复

使用道具 举报

7#
ID:225984 发表于 2018-3-31 11:27 | 只看该作者
非常66666,正好用得到
回复

使用道具 举报

8#
ID:316962 发表于 2018-5-6 17:34 | 只看该作者
为什么那个显示的角度不会变呢
回复

使用道具 举报

9#
ID:326147 发表于 2018-5-9 18:12 | 只看该作者
有用!
回复

使用道具 举报

10#
ID:63090 发表于 2020-4-12 13:58 | 只看该作者
角度竟然是固定的18度,怎么转动传感器都不会变啊,这程序有问题啊
回复

使用道具 举报

11#
ID:348295 发表于 2020-5-11 16:50 | 只看该作者
请问我按上面程序载入,只显示 18度,值不会变
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表