C8051F410单片机开发HMC5883L 3轴数字罗盘

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

#include
#include // SFR declarations
#include
#define SYSCLK 24500000 // System clock frequency in Hz

#define SMB_FREQUENCY 50000 // Target SCL clock rate
// This example supports between 10kHz
// and 100kHz (以修改为100kHz)

#define WRITE 0x00 // SMBus WRITE command
#define READ 0x01 // SMBus READ command

// Device addresses (7 bits, LSB is a don't care)
#define SLAVE_ADDR 0x3C // Device address for slave target 从目标设备地址

unsigned char* pReceWord; // Global holder for SMBus data
// All receive data is written here所有接收数据写在这里

unsigned char sendWord; // Global holder for SMBus data.
// All transmit data is read from here

bit SMB_BUSY = 0; // Software flag to indicate when the
// SMB_Read() or SMB_Write() functions
// have claimed the SMBus

bit SMB_RW; // Software flag to indicate the

// direction of the current transfer
bit SMB_SENDWORDADDR;
bit SMB_RANDOMREAD; // 是否伪读
bit SMB_ACKPOLL; // 是否重复发送START 信号,轮询
unsigned char WORD_ADDR; //从寄存器地址

//sbit LED = P0^5;

sbit SDA = P0^2; // SMBus on P0.0 (原配置,现已修改)
sbit SCL = P0^3; // and P0.1
unsigned char Rec_Data[6];
//-----------------------------------------------------------------------------
// Function PROTOTYPES
//-----------------------------------------------------------------------------

void SMBus_Init (void);
void Timer1_Init (void);
void Timer3_Init (void);
void Port_Init (void);

void SMBus_ISR (void);
void Timer3_ISR (void);

void SMB_Write(unsigned char addr, unsigned char dat);
void SMB_Read(unsigned char addr);
void T0_Wait_ms(unsigned char ms);

//初始化HMC5883,根据需要请参考pdf进行修改****
void HMC5883_Init(void)
{
SMB_Write(0x02,0x00); //改变测量模式到连续测量模式
}

void main (void)
{
int X,Y,Z;
double Angle;
unsigned int Acr;
PCA0MD &= ~0x40; // WDTE = 0 (watchdog timer enable bit)

OSCICN |= 0x07; // Set internal oscillator to highest
// setting of 24500000 (内部振荡器按编程频率运行,且内部振荡器不分频)

Port_Init (); // Initialize Crossbar and GPIO 初始化数据交叉开关和GPIO

Timer1_Init (); // Configure Timer1 for use a

s SMBus
// clock source

Timer3_Init (); // Configure Timer3 for use with SMBus
// low timeout detect
SMBus_Init (); // Configure and enable SMBus
EIE1 |= 0x01; // Enable the SMBus interrupt 中断允许请求位,允许SMB0 的中断请求。

// LED = 0;
EA = 1; // Global interrupt enable

HMC5883_Init();
T0_Wait_ms (5);

do
{

SMB_Read (0x03);//连续读出数据(不知道怎么实现??),存储在Rec_Data[]中
T0_Wait_ms (1000);

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;
Acr=(unsigned int)Angle;

T0_Wait_ms (100);
}
while(1);
}

//-----------------------------------------------------------------------------
// Initialization Routines 初始化例程

// SMBus_Init

// SMBus configured as follows:
// - SMBus enabled
// - Slave mode inhibited 从模式禁止
// - Timer1 used as clock source. The maximum SCL frequency will be
// approximately 1/3 the Timer1 overflow rate 作为时钟源定时器。最大SCL频率将约1/3定时器1的溢出率
// - Setup and hold time extensions enabled 建立和保持时间延长启用
// - Bus Free and SCL Low timeout detection enabled 总线空闲和SCL低电平超时检测启用
//
void SMBus_Init (void)
{
SMB0CF = 0x5D; // Use Timer1 overflows as SMBus clock
// source;
// Disable slave mode;
// Enable setup & hold time
// extensions;
// Enable SMBus Free timeout detect; 使能SMBus空闲超时检测;
// Enable SCL low timeout detect; 使SCL低电平超时检测

SMB0CF |= 0x80; // Enable SMBus; 使能SMBus接口
}

//-----------------------------------------------------------------------------
// Timer1_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Timer1 configured as the SMBus clock source as follows:
// - Timer1 in 8-bit auto-reload mode
// - SYSCLK or SYSCLK / 4 as Timer1 clock source
// - Timer1 overflow rate => 3 * SMB_FREQUENCY
// - The resulting SCL clock rate will be ~1/3 the Timer1 overflow rate
// - Timer1 enabled
//
void Timer1_Init (void)
{

// Make sure the Timer can produce the appr

opriate frequency in 8-bit mode
//确定定时器可产生相应频率在8位模式
// Supported SMBus Frequencies range from 10kHz to 100kHz. The CKCON register
//支持SMBus的频率范围从10kHz到100kHz。该寄存器CKCON
// settings may need to change for frequencies outside this range.设置可能需要更改此范围之外的频率。
#if ((SYSCLK/SMB_FREQUENCY/3) < 255)
#define SCALE 1
CKCON |= 0x08; // Timer1 clock source = SYSCLK
#elif ((SYSCLK/SMB_FREQUENCY/4/3) < 255)
#define SCALE 4
CKCON |= 0x01;
CKCON &= ~0x0A; // Timer1 clock source = SYSCLK / 4
#endif

TMOD = 0x20; // Timer1 in 8-bit auto-reload mode

// Timer1 configured to overflow at 1/3 the rate defined by SMB_FREQUENCY
TH1 = -(SYSCLK/SMB_FREQUENCY/SCALE/3);

TL1 = TH1; // Init Timer1

TR1 = 1; // Timer1 enabled
}

//-----------------------------------------------------------------------------
// Timer3_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Timer3 configured for use by the SMBus low timeout detect feature as
// follows:
// - Timer3 in 16-bit auto-reload mode
// - SYSCLK/12 as Timer3 clock source
// - Timer3 reload registers loaded for a 25ms overflow period
// - Timer3 pre-loaded to overflow after 25ms
// - Timer3 enabled

void Timer3_Init (void)
{
TMR3CN = 0x00; // Timer3 configured for 16-bit auto-
// reload, low-byte interrupt disabled

CKCON &= ~0x40; // Timer3 uses SYSCLK/12

TMR3RLL = -(SYSCLK/12/40); // Timer3 configured to overflow after
TMR3L = TMR3RLL; // ~25ms (for SMBus low timeout detect):
// 1/.025 = 40 有问题吗?**************************

EIE1 |= 0x80; // Timer3 interrupt enable 定时器3中断允许位
TMR3CN |= 0x04; // Start Timer3
}

//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configure the Crossbar and GPIO ports.
//
// P0.0 digital open-drain SMBus SDA
// P0.1 digital open-drain SMBus SCL
//
// P2.1 digital push-pull LED
//
// all other port pins unused
//
// Note: If the SMBus is moved, the SCL and SDA sbit declarations must also
// be adjusted.
//
void PORT_Init (void)
{
P0MDOUT = 0x00; // All P0 pins open-drain output P0口漏极开路
P0SKIP = 0x03; //p0.0,p0.1被交叉开关跳过 (自己加上的,有用?)

XBR0 = 0x04; // Enable SMBus

pins (SMBus I/O 连到端口引脚)
XBR1 = 0x40; // Enable crossbar and weak pull-ups 允许交叉开关和弱上拉

P0 = 0xFF; //使SCL 和SDA 位都为高电平 ?
}

//-----------------------------------------------------------------------------
// Interrupt Service Routines 中断服务程序

void SMBus_ISR (void) interrupt 7
{
bit FAIL = 0; // Used by the ISR to flag failed transfers 标记失败的ISR传输所使用
static char i,j; // 收发字节个数
static bit SEND_START = 0; // Send a start 发送一个开始

switch (SMB0CN & 0xF0) // Status vector
{
case 0xE0: // Master Transmitter/Receiver: START condition transmitted.起始条件已发出。
SMB0DAT = SLAVE_ADDR; // Load address of the target slave
SMB0DAT &= 0xFE; // Clear the LSB of the address for the R/W bit
SMB0DAT |= SMB_RW; // Load R/W bit
STA = 0; // Manually clear START bit
i = 0;
j = 0; // Reset data byte counter
break;

case 0xC0: // Master Transmitter: Data byte (or Slave Address) transmitted
if (ACK) // Slave Address or Data Byte Acknowledged?
{
if (SEND_START)
{
STA = 1; //又产生一次起始条件 为了写入 7bit+读
SEND_START = 0;
break; // 这个break是用来退出,然后再向从器件写入 读地址 进行读数据此时SMB0CN=1110****
}

if(SMB_SENDWORDADDR)
{
SMB_SENDWORDADDR = 0; //用于第二次发送数据时不进入这个if中
SMB0DAT = WORD_ADDR; //从机的寄存器地址

if (SMB_RANDOMREAD)
{
SEND_START = 1; // Send a START after the next ACK cycle
SMB_RW = READ; //准备读数据
}

break; //这里的break是跳出switch循环,因为每次只能写8字节
}

if (SMB_RW==WRITE)
{
if (i < 1) //只写一个字节
{
SMB0DAT = sendWord;
i++;
}

else
{
STO = 1; // Set STO to terminte transfer 停止发送
SMB_BUSY = 0; // Clear software busy flag
}
}

else {}

}

else // If slave NACK,
{
if(SMB_ACKPOLL)
{
STA = 1; // Restart transfer
}

else
{
FAIL = 1; // Indicate failed transfer
} // and handle at end of ISR
}

break;

case 0x80: // Master Receiver: byte received
if ( j < 6 ) // 读6字节
{
*pReceWord = SMB0DAT; // Store received byte
Rec_Data[j] = *pReceWord;
j++; // Increment number of bytes received
ACK = 1; // Set ACK bit (may be cleared later in the code)
}

if (j == 6) // This is the last byte
{
SMB_BUSY = 0; // Free SMBus interface
ACK = 0; // Send NACK to indicate last byte of this transfer
STO = 1; // Send STOP to terminate transfer
}
break;


default:
FAIL = 1; // Indicate failed transfer and handle at end of ISR
break;
}

if (FAIL) // If the transfer failed,
{
SMB0CF &= ~0x80; // Reset communication
SMB0CF |= 0x80;
STA = 0;
STO = 0;
ACK = 0;

SMB_BUSY = 0; // Free SMBus
FAIL = 0;
}

SI = 0; // Clear interrupt flag
}

//-----------------------------------------------------------------------------
// Timer3 Interrupt Service Routine (ISR)
//-----------------------------------------------------------------------------
//
// A Timer3 interrupt indicates an SMBus SCL low timeout.
// The SMBus is disabled and re-enabled here
//
void Timer3_ISR (void) interrupt 14
{
SMB0CF &= ~0x80; // Disable SMBus
SMB0CF |= 0x80; // Re-enable SMBus
TMR3CN &= ~0x80; // Clear Timer3 interrupt-pending flag
SMB_BUSY = 0; // Free SMBus
}

//-----------------------------------------------------------------------------
// Support Functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// SMB_Write
//-----------------------------------------------------------------------------
void SMB_Write(unsigned char addr, unsigned char dat)
{
while (SMB_BUSY);

// Wait for SMBus to be free.
SMB_BUSY = 1; // Claim SMBus (set to busy)

SMB_RW = WRITE; // Mark next transfer as a write
SMB_SENDWORDADDR = 1;
SMB_RANDOMREAD = 0; // Do not send a START signal after the word address
SMB_ACKPOLL = 1; // Enable Acknowledge Polling (The ISR
// will automatically restart the transfer if the slave does not acknoledge its address.

WORD_ADDR = addr;
sendWord = dat;
STA = 1; // Initiate SMBus Transfer
}
//-----------------------------------------------------------------------------
// SMB_Read
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Reads a single byte from the slave with address specified by the
// variable.
// Calling sequence:
// 1) Write target slave address to the variable
// 2) Call SMB_Write()
// 3) Read input data from variable

//写入寄存器地址,然后读出6字节数据放入Rec_Data[6]
void SMB_Read(unsigned char addr)
{
// unsigned char retval; // Holds the return value

while (SMB_BUSY); // Wait for SMBus to be free.
SMB_BUSY = 1; // Claim SMBus (set to busy)

SMB_RW = WRITE; //是因为要写入读取的寄存器地址所以先写一个字节地址
SMB_SENDWORDADDR = 1;
SMB_RANDOMREAD = 1; // Send a START after the word address
SMB_ACKPOLL = 1; // Enable Acknowledge Polling启用应答查询

WORD_ADDR = addr;
// pReceWord = &retval;

STA = 1; // Initiate SMBus Transfer
while(SMB_BUSY); // Wait until data is read

// return retval;
}


//-----------------------------------------------------------------------------
// T0_Wait_ms
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters :
// 1) unsigned char ms - number of milliseconds to wait
// range is full range of character: 0 to 255
//
// Configure Timer0 to wait for milliseconds using SYSCLK as its time
// base.

void T0_Wait_ms(unsigned char ms)
{
TCON &= ~0x30; // Stop Timer0; Clear TF0
TMOD &= ~0x0f; // 16-bit free run mode
TMOD |= 0x01;

CKCON |= 0x04; // Timer0 counts SYSCLKs

while (ms)
{
TR0 = 0; // Stop Timer0
TH0 = -(SYS

CLK/1000 >> 8); // Overflow in 1ms
TL0 = -(SYSCLK/1000);
TF0 = 0; // Clear overflow indicator
TR0 = 1; // Start Timer0
while (!TF0); // Wait for overflow
ms--; // Update ms counter
}
TR0 = 0; // Stop Timer0
}

相关文档
最新文档