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()