C8051F410单片机开发HMC5883L 3轴数字罗盘
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include
#include
#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
// 2) Call SMB_Write()
// 3) Read input data from
//写入寄存器地址,然后读出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
// 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
}