QMC5883L与msp430FG4618--IIC通信

标签: 单片机IIC通讯

QMC5883L芯片的参数要求

1.QMC5883l(以下简称5883)他需要传感器每次传一位的时间是5us左右,我这么说的原因是我用示波器测量过传出一位的时间。
2. 最开始的时候,需要给5883传输起始信号,这个和停止信号没有时间要求,但是SCL和SDA的时序要对的上,什么意思呢? 简单点来说就是,当起始信号的时候,你要确保SDA被拉低的时候,SCL为高点平,可以多次循环,但是可以不管时间。

void IIC_Start(void)
{       
  uchar i = 0;
    SDA_H;
    SCL_H;
    
    
     for (i=0; i<5; i++)
    {
        Delay(4);
 
        SDA_L;
        Delay(4);
        Delay(4);
        SCL_L;        
 
        //after end of start condition both SDA and SCL will be low
    }

  
}

3.有些时候,我们无法确定延时函数的时间是否准确,因为一个工作周期的时间是由你所选择的时钟所确定的,而你选择的时钟与哪个晶振或者内部的振荡器是有直接的关系的,因为我用的开发板是32768的外部晶振,不能提供足够的时钟周期,于是我的老师建议我采用内部的时钟源–DCO,DCO也分很多种8M、12M,都有的,选8M就够了,有的6M好像也够用,但是内部的DCO有点小问题,不准,并不是他会跳变,而是你选择的是5M,但是他有可能是6M左右,这就出现了一个问题,你的延时函数不够准确。但是这并不致命。
最致命的问题:当你使用RS-232或者485把数据传出来的时候,就完了,你不确定时钟的频率,你就不能确定串口通信的数值该多大,再这卡的时间几乎和调IIC的时间是一样的了。而且你换一块芯片,只要你采用内部的振荡器,就要调很久,这几乎让我调到怀疑人生。Oh,My God。

void ModBus_Init()
{       
  P4SEL|= BIT0 + BIT1;                //设置IO口为第二功能模式,启用UART功能
  P4DIR|= BIT0;                       //设置TXD0口方向为输出
  U1CTL|= CHAR;                //SWRST=1,CHAR=1,8位数据模式
  
  
  
  ME2|= UTXE1 + URXE1;         //UTXE0=1,串口0发送允许,UART0发送使能
  U1TCTL |= SSEL1 + SSEL0 + URXSE;          // UCLK = SMCLK, start edge detect
  U1BR0 = 0x8a;                             // 6MHz 9600
  U1BR1 = 0x02;                             // 6MHz 9600
  U1MCTL = 0x00;                            // 6MHz 9600modulation
  U1CTL &= ~SWRST;                          // Initialize USART state machine
  IE2 |= URXIE1;                            // Enable USART1 RX interrupt
  

}

4.当你把IIC调通,485或者232也调通,把程序当中的地址寄存器也都也好以后,记得保留你在接收ACK时的设置,例如当接受ACK时,点亮一个小灯,这么做是为了日后设备出现问题时,可以确定是哪里的问题。嗯,好吧,这也是一个痛。痛彻心扉。

话不多数上程序

IIC通讯程序



#include <math.h>

#define CPU_F ((double)8000000) 
#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0)) 
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0)) 

#define uchar unsigned char
#define uint  unsigned int
#define ulong unsigned long

#define HMC5883L_DIR   P10DIR
#define HMC5883L_IN    P10IN
#define HMC5883L_OUT   P10OUT
#define SCL  BIT5     //IIC??????????
#define SDA  BIT4     //IIC???????????   
                      //DRDY ???? 
#define SCL_H  (HMC5883L_DIR|=SCL,HMC5883L_OUT|=SCL)
#define SCL_L  (HMC5883L_DIR|=SCL,HMC5883L_OUT&=~SCL)
#define SDA_H  (HMC5883L_DIR|=SDA,HMC5883L_OUT|=SDA)
#define SDA_L  (HMC5883L_DIR|=SDA,HMC5883L_OUT&=~SDA)
#define SlaveAddress  0x1a         //??????????IIC?????е????
uchar Rec_Data[6];
int x,y,z;
double Angle;
uint Acr;
uint qian=0,bai=0,shi=0,ge=0;                //???????????
uchar Buf[6];
/*???????*/
void Delay(uint t)
{
  t=t/4;
while(t--);
}

/*??????*/
void IIC_Start(void)
{       
  uchar i = 0;
    SDA_H;
    SCL_H;
    
    
     for (i=0; i<5; i++)
    {
        Delay(4);
 
        SDA_L;
        Delay(4);
        Delay(4);
        SCL_L;        
 
        //after end of start condition both SDA and SCL will be low
    }

  
}

/*?????*/
void IIC_Stop(void)
{       
    uchar i = 0;
    SDA_L;
    Delay(4);
    SCL_H;    
    for(i=0;i<8;i++){
      Delay(4);
    }
    SDA_H;
    Delay(4);
    i=0;
   //ensure bus is in default condition ( freed by slave)
  while(!(HMC5883L_IN&SDA)) // i is just a variable to control the while loop run time.
  {
    SCL_H;
    Delay(4);
    SCL_L;
    Delay(4);
    Delay(4);
    i++;
    if( i > 25)
    {
        break;
    }
  }
  SCL_H;
  //After generating stop condition SCL and SDA are both high. Default condition for I2C bus.

}

/*??????????*/
void IIC_SendAck(char Ack)
{   
    if(Ack)      //ack (0:ACK 1:NACK)
    SDA_H;
    else SDA_L;
    SCL_H;
    Delay(4);
    SCL_L;
    Delay(4);
}

/*??????????*/
char IIC_RecAck(void)
{   
    char CY;
    HMC5883L_DIR&=~SDA;
    SCL_H; 
    Delay(4);
    if(HMC5883L_IN&SDA)
      CY=1;
    else CY=0;    
    SCL_L;
    Delay(4);
    if(!CY){
    P7DIR = 0x00; 
    }
    return CY;
}

/*??IIC?????????????????*/
void HMC5883_Send_Byte(uchar Dat)
{
    uchar i;
    SCL_L;
    for(i=0;i<8;i++)
    {
        if(Dat&BIT7)
        SDA_H;
        else SDA_L;  
        Delay(2);
        SCL_H; 
        Dat<<=1;
        Delay(4);
        SCL_L;
        Delay(4);
        if(i == 7){
          SDA_H;
        }
    }
    Delay(2);
    IIC_RecAck();
}

/*??IIC?????????????????*/
uchar HMC5883_Rec_Byte(void)
{
    uchar i,Dat=0;
    SDA_H;
    Delay(4);
    HMC5883L_DIR&=~SDA;
    for(i=0;i<8;i++)
    {
        Dat<<=1;
        SCL_H;
        Delay(4);
        
        if((HMC5883L_IN&SDA)==SDA)
        Dat|=BIT0;
        
        SCL_L;
        Delay(4);
    }
    return Dat;
}

/*?????дHMC5883*/
void Single_Write_HMC5883(uchar Address,uchar Dat)
{
    IIC_Start();
    HMC5883_Send_Byte(SlaveAddress);
    HMC5883_Send_Byte(Address);
    HMC5883_Send_Byte(Dat);
    IIC_Stop();
}

/*??????HMC5883*/
uchar Single_Read_HMC5883(uchar Addr)
{
    uchar Value;
    IIC_Start();
//    HMC5883_Send_Byte(SlaveAddress);
    HMC5883_Send_Byte(Addr);
    IIC_Start();
//    HMC5883_Send_Byte(SlaveAddress+1);
    Value=HMC5883_Rec_Byte();
    IIC_SendAck(1);
    IIC_Stop();
    return Value;
}

/*??????HMC5883*/
void Multiple_Read_HMC5883(void)
{
    uchar i;  //????????HMC5883????????????????Χ0x3~0x5
    IIC_Start();
    HMC5883_Send_Byte(SlaveAddress);
    HMC5883_Send_Byte(0x00);//????洢??????????0x03??? 
    IIC_Start();
    HMC5883_Send_Byte(SlaveAddress+1);
    for(i=0;i<6;i++) //???????6???????????洢??Rec_Data
    {
        Rec_Data[i]=HMC5883_Rec_Byte();
        if(i==5)
            IIC_SendAck(1); //???????????????NOACK
        else
            IIC_SendAck(0); //???ACK
    }
    IIC_Stop();
    Delay(100);
}

//初始化QMC5883,根据需要请参考pdf进行修改****
void Init_QMC5883()
{
	Single_Write_HMC5883(0x09,0x0d);  //控制寄存器配置
	Single_Write_HMC5883(0x0b,0x01);  //设置清除时间寄存器
	Single_Write_HMC5883(0x20,0x40);  //
	Single_Write_HMC5883(0x21,0x01);  //	
}

/********************??????????????*******************/
/********************0?? x??????************************/
void get_angle()
{       
   Init_QMC5883();
   Multiple_Read_HMC5883();//??????????????洢??Rec_Data[]??
   x=Rec_Data[0]<<8 | Rec_Data[1];//Combine MSB and LSB of X Data output register
   z=Rec_Data[2]<<8 | Rec_Data[3];//Combine MSB and LSB of Z Data output register
   y=Rec_Data[4]<<8 | Rec_Data[5];//Combine MSB and LSB of Y Data output register

   Angle= atan2((double)y,(double)x)*(180/3.14159265)+180;//??λ????? (0~360)  
   //Angle*=10; 
   Delay(50000);
}

void QMC5883_IIC(void)
{    
    get_angle();
    
    qian=(int)Angle/1000;
    bai=((int)Angle%1000)/100;
    shi=((int)Angle%100)/10;
    ge=(int)Angle%10;
    
    Buf[0] = qian;
    Buf[1] = bai;
    Buf[2] = shi;
    Buf[3] = ge;
     

       
}

msp430FG4618 --切记不同的芯片选择的时钟也是不一样的

这里面还包含了jt808的一些通讯协议,这个不重要。

#include <msp430xG46x.h>
#include "IICComunication.c"
#define uchar unsigned char        
#define uint  unsigned int
#define ulong unsigned long
#define CPU_F ((double)8000000) 
#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0)) 
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))
#define baud           9600                                            //设置波特率的大小
#define baud_setting   (uint)((ulong)CPU_F/((ulong)baud))               //波特率计算公式
#define baud_h         (uchar)(baud_setting>>8)                         //提取高位
#define baud_l         (uchar)(baud_setting)                              //低位
uchar Adress0=0x30,Adress1=0x30,Adress2=0x30;                              //可更改初始ID号
const uchar ucAdress0=0x30,ucAdress1=0x30,ucAdress2=0x30;//不可更改地址
uchar TxBuffer[255];
uchar TxLen;
uchar RxBuffer[50];
uchar RxLen = 0;
uchar crctemp0,crctemp1,crcresult0,crcresult1;//校验码
uchar hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
uint Buffer[4];
unsigned char buffer[255];
uchar Com= 0x00;//校验位
uint time=0,data0,data1,data2;
uint temp_d0=0,temp_d1=0,temp_d2=0;
int a1[5],a2[5],a3[5];
int m1=0,m2=0,n1=0,n2=0,n3=0;
int temp0[100],temp1[100],temp2[100];
uint TEMP0,TEMP1,TEMP2;
int k=0;
//关闭内部看门狗
void WDT_Init()
{
  WDTCTL = WDTPW + WDTHOLD;      
}
//时钟配置函数
void Clock_Init_XT1()
{
//  FLL_CTL0 |= XCAP18PF;                     // Set load capacitance
//  FLL_CTL1 &= ~XT2OFF;                      // Turn on XT2
FLL_CTL0 |= DCOPLUS;           // DCO+ set, freq = xtal x D x N+1 
SCFI0 |= FN_8;
}
//IO口初始化
void Port_Init()
{
  //RS485
  P3DIR|=BIT6;
  P3DIR|=BIT7;
  P3OUT|=BIT6;
  P3OUT|=BIT7;
  //LED
  P7DIR = 0XFF;
  P7OUT = 0X00;
  //
  P10DIR = 0xFF;    
}

/****************************************************************************
* 函数名称:modBus_Init()
* 函数功能:初始化ModBus通讯所需模块
* 参数:uiBaudRate:9600 波特率 ucDataBits:8 数据位 ucPrity:无校验 奇偶校验
****************************************************************************/
void ModBus_Init()
{       
  P4SEL|= BIT0 + BIT1;                //设置IO口为第二功能模式,启用UART功能
  P4DIR|= BIT0;                       //设置TXD0口方向为输出
  U1CTL|= CHAR;                //SWRST=1,CHAR=1,8位数据模式
  
  
  
  ME2|= UTXE1 + URXE1;         //UTXE0=1,串口0发送允许,UART0发送使能
  U1TCTL |= SSEL1 + SSEL0 + URXSE;          // UCLK = SMCLK, start edge detect
  U1BR0 = 0x8a;                             // 12MHz 9600
  U1BR1 = 0x02;                             // 12MHz 9600
  U1MCTL = 0x00;                            // 12MHz 9600modulation
  U1CTL &= ~SWRST;                          // Initialize USART state machine
  IE2 |= URXIE1;                            // Enable USART1 RX interrupt
  

}

//     串口发送数据函数
void UartPutChar(uchar data)
{
  while(!(IFG2&UTXIFG1));          //等待数据发送完毕,发送寄存器空的时候发送数据
   TXBUF1=data;  //串口发送缓冲寄存器
}
//      串口发送字符串函数
void UartPutStr(uchar str[],uchar strlen)
{
  uchar i;
  for(i=0;i<strlen;i++)
  {
    while(!(IFG2&UTXIFG1)); 
    delay_us(1000);//必要的延时,否则低波特率发送会出现误码
    U1TXBUF = str[i]; 
    delay_ms(1);//必要的延时,否则低波特率发送会出现误码
  }
}
void NumToHex(int num)
{
   int i=0,yushu;
   for(i=0;i<4;i++)
   {
     yushu=num%16;
     if((yushu>=0)&&(yushu <=9))
       Buffer[i]=yushu;
     else
       Buffer[i]=yushu-10+0x0a;
     num=num/10; 
   }
}
unsigned char CheckNum(unsigned char* pucMsg){
  int i = 0;
  Com = pucMsg[1];
  for(i=2;i<=20;i++){
    Com ^= pucMsg[i];    
  }
  return Com;
}
//      TIMERA初始化
void TIMERA_Init(void)                         
{
  TACCTL0 = CCIE;                           // TACCR0 interrupt enabled
  TACCR0 = 5000;   //50ms
  TACTL = TASSEL_1 + MC_1;                  // ACLK, up mode
}
void Send_Byte(uchar data)
{
  while(!(IFG2&UTXIFG1));          //等待数据发送完毕,发送寄存器空的时候发送数据
    TXBUF1=data;  //串口发送缓冲寄存器
}

//函数功能:数据接受处理
void ModbusHandle()
{   

  TxBuffer[0] = 0x7E;
  TxBuffer[1] = 0x09;
  TxBuffer[2] = 0x00;
   //  消息体属性
  TxBuffer[3] = 0x00;
  TxBuffer[4] = 0x08;
  //手机号  
  TxBuffer[5] = 0x01;
  TxBuffer[6] = 0x30;
  TxBuffer[7] = 0x81;
  TxBuffer[8] = 0x85;
  TxBuffer[9] = 0x77;
  TxBuffer[10] = 0x97;
  //传感器id、
  TxBuffer[11] = 0x00;
  TxBuffer[12] = 0x07;
  //传感器测重值
  TxBuffer[13] = Rec_Data[5];//z轴的高八位
  TxBuffer[14] = Rec_Data[4];//z轴的低八位
  TxBuffer[15] = Rec_Data[3];//y轴的高八位
  TxBuffer[16] = Rec_Data[2];//y轴的低八位
  //传感器测量温度
  TxBuffer[17] = 0x00;
  TxBuffer[18] = 0x00;
  TxBuffer[19] = 0x00;
  TxBuffer[20] = 0x01;
  //数据校验
  TxBuffer[21] = CheckNum(TxBuffer);
  //截至位r
  TxBuffer[22] = 0x09;
  TxLen=23; 
  UartPutStr(TxBuffer,TxLen);
//  UartPutChar(0x30);
  TxLen = 0;//清除发送缓冲  
    

}
// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{   
    QMC5883_IIC();
    ModbusHandle();
////    while(!(IFG2&UTXIFG1)); 
////    delay_us(100);//必要的延时,否则低波特率发送会出现误码
////    U1TXBUF = 0x32; 
////  
  delay_ms(1000);//必要的延时,否则低波特率发送会出现误码
//  buffer[0]=Rec_Data[0];
//  buffer[1]=Rec_Data[1];
//  buffer[2]=Rec_Data[2];
//  buffer[3]=Rec_Data[3];
//  buffer[4]=Rec_Data[4];
//  buffer[5]=Rec_Data[5];
//  UartPutStr(buffer,6);//这里调了22次,我也是醉了
//   
}

//主函数
void main(void)
{
  WDT_Init();
  Clock_Init_XT1();
  Port_Init();
//  ADC_Init();
  ModBus_Init();
  TIMERA_Init();
  ADC12CTL0 |= ADC12SC;                   // Start conversions

  while(1)
  {
// 
//      P7OUT = 0x00;
//      delay_ms(10);
//      P7OUT = 0xff;
//       delay_ms(10);  
    _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
//    IIC_Start();
//    HMC5883_Send_Byte(SlaveAddress);
  }
      
 
  
}

最后上数据

这个数据是Z方向的数据

--|--|
这玩意是弱磁传感器,磁铁离得太近就完犊子了。

再来一个程序,画图的

import matplotlib.pyplot as plt#约定俗成的写法plt
#首先定义两个函数(正弦&余弦)
import numpy as np
fig,ax = plt.subplots()
plt.xlabel('distance')
plt.ylabel("Magnetic intensity")
X=[29,25,21,18,14,11,9,8,7,6,5,4]
C=[0x56,0x55,0x53,0x4f,0x46,0x34,0x06,0x03,0xce,0x86,0x80,0x1d]
plt.plot(X,C)

#在ipython的交互环境中需要这句话才能显示出来
plt.show()

在这里插入图片描述

版权声明:本文为qq_34761280原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_34761280/article/details/91350224