求助 如何编写三轴加速度传感器SMB380的读写子程序 【恢复】
我在用三轴加速度传感器SMB380做倾角计。自己写了一个读写子程序,子程序没有工作。子程序完成读传感器芯片ID,再用串口发送到PC。 芯片特点:
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_474359.jpg
图片2 (原文件名:2008-10-29 0000.jpg)
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_474360.jpg
图片3 (原文件名:2008-10-29 0001.jpg)
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_474361.jpg
图片4 (原文件名:2008-10-29 0002.jpg)
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_474362.jpg
图片1 (原文件名:2008-10-29 0003.jpg)
SMB380
工作温度 -40°C to +85°C
工作电压 2.3V-3.6V
电流消耗 600 μA.(10位分辨率)
500μA.(7位分辨率)
温度测量范围 -40°C to +85°C
加速度测量范围 2g to 200g
分辨率 4mg
非线性度 ±0.5%FS
启动时间 ——
尺寸 4x4x1.2mm
应用
自由落体保护
数据输入
菜单、光标控制
倾斜型滚动
自动显示方位
导航
背景意识
游戏
英文资料网址:
http://www.fuanda.com/products/sensor_type.asp?id=0,1,41,
英文资料如下:
英文资料ourdev_474358.pdf(文件大小:487K) (原文件名:SMB380_Datasheet.doc.pdf)
程序如下:
//ICC AVR 6.31 编泽
/* ATmega16 clk:7.3728Mhz
加速度传感器:SMB380
创建日期:20081028
修改日期:
*/
#include <iom16v.h>
#define _SEI() asm("sei") //开总中断宏定义
#define _CLI() asm("cli") //关总中断宏定义
#define uchar unsigned char
#define uint unsigned int
uchar i,temp0,rdata;
/****************串口初始化****************/
void uart_init()
{
UCSRA=0x02; //异步正常模式 UX2位置1 倍速发送
UCSRB=0x18; //允许发送接受中断和使能
UCSRC=0x06; //8位数据
UBRRH=0x00;
UBRRL=0x5F; //波特率位9600 UBRR=95=0x5F 晶振:7.3728 MHz
//波特率位9600 UBRR=12=0x0B 晶振:1.000000 MHz
DDRD |=(1<<PD1);
PORTD =0x02;
}
void display(uint ddata)
{
UCSRB|=(1<<TXEN); //异步串口发送使能
while(!(UCSRA&(1<<UDRE))); //等待发送准备完备
UDR=0xFE;
while(!(UCSRA&(1<<UDRE)));
UDR=ddata>>8;
while(!(UCSRA&(1<<UDRE)));
UDR=ddata;
while(!(UCSRA&(1<<UDRE)));
UDR=0xFF;
while(!(UCSRA&(1<<UDRE)));
}
/*SPI接口主机模式初始化*/
void SPI_MasterInit(void) {
DDRB |= (1<<PB5) | (1<<PB7); /* 设置MOSI 和SCK 为输出,其他为输入 */
SPCR = (1<<SPE) | (1<<MSTR)
| (1<<SPR1) | (1<<SPR0); /* 使能SPI主机模式,设置时钟速率为fck/128 */
}
/*SPI接口从机模式初始化*/
void SPI_SlaveInit(void)
{
DDRB |= (1<<PB6) ; /* 设置MISO 为输出,其他为输入 */
SPCR |=(1<<SPE); /* 使能SPI从机模式*/
}
/*SPI数据发送*/
void SPI_MasterTransmit(uchar Sdata)
{
SPDR = Sdata; /* 启动数据传输 */
while (!(SPSR & (1<<SPIF))); /* 等待传输结束 */
}
/*SPI数据接收*/
void SPI_SlaveReceive()
{
while(!(SPSR&(1<<SPIF)))
i=SPDR;
//return i;
}
/*SMB380写1个字节数据子程序*/
SMB380_write_byte(uint wdata)
{
_CLI(); //关总中断
temp0=wdata>>8;
SPI_MasterTransmit(wdata); //发送写命令
SPI_MasterTransmit(temp0); //发送数据
_SEI(); //开总中断
}
/*SMB380读1个字节数据子程序*/
SMB380_reade_byte()
{
_CLI(); //关总中断 SPI_SlaveInit() ; //SPI接口从机模式初始化
SPI_SlaveReceive(); //接收数据
_SEI(); //开总中断
}
/*主函数*/
main()
{
uart_init(); //串口初始化
SPI_MasterInit(); //SPI接口主机模式初始化
SPI_MasterTransmit(0x00); //发送读命令
SPI_SlaveInit(); //SPI接口从机模式初始化
SMB380_reade_byte(); //读数据
display(i); //发送读出的数据
} 【2楼】 lnc361 :
SMB380 读写子程序
我将你给的改了一下,用于在ICCAVR 6。31A中编译。
加入了用串口发送到串口调试软件。
读出的几个寄存器全是0,是不是传感器SMB380 没响应,还是我的程序改的有问题?请帮忙看一下。谢谢!
/*******************************
*程序名称:功能函数集
*设 计:
*功能:IO口模拟I2C总线
*数据线:IO----PC1 时钟线:SCK----PC0
*单片机:ATmega16
*编译:ICC AVR 6.31A
*晶 振:8.000000Mhz
*日 期:2008-12-01
****************************/
#include <iom16v.h>
#include <macros.h>
/*双向数据*/
#define IO_CLR PORTC &= ~(1 << PC1) /*电平置低*/
#define IO_SET PORTC |= (1 << PC1) /*电平置高*/
#define IO_R PINC & (1 << PC1) /*电平读取*/
#define IO_IN DDRC &= ~(1 << PC1) /*方向输入*/
#define IO_OUT DDRC |= (1 << PC1) /*方向输出*/
/*时钟信号*/
#define SCK_CLR PORTC &= ~(1 << PC0) /*时钟信号*/
#define SCK_SET PORTC |= (1 << PC0) /*电平置高*/
#define SCK_IN DDRC &= ~(1 << PC0) /*方向输入*/
#define SCK_OUT DDRC |= (1 << PC0) /*方向输出*/
#define uchar unsigned char
#define uint unsigned int
#define mclk 8000000
uint Axis;
//uint ReadData; 加入 6个数据的数组
//sbit IO_R = P1^3;
//sbit I2C_SCL = P1^4;
#define SMB380_ADDR_WRITE 0x70
#define SMB380_ADDR_READ 0x71
//Registers address
#define OPER_REG 0x15 //Wake_up(bit 0),Wake_up_pause(bit1,bit2),Shadow_dis(bit3),
//latch_int(bit4),new_data_int(bit5),enable_adv_int(bit6)
#define OPER_SET 0x14 //rang(bit4'3),bandwith(bit2'1'0)
#define DUR_HYST 0x11 //any_motion_dur(bit6'7),hg_hyst(bit5'4'3),lg_hyst(bit5'4'3)
#define ANY_MOTION_TRES 0x10
#define HG_DUR 0x0F
#define HG_THRES 0x0E
#define LG_DUR 0x0D
#define LG_THRES 0X0C
#define INTERRUPT_SET 0x0B //enable_lg(bit0),enble_hg(bit1),counter_lg(bit2'3),
//counter_hg(bit4'5),any_motion(bit6),alert(bit7)
#define CONTROL_REG 0x0A //sleep(bit0),soft_reset(bit1),self_test0(bit2),self_test1(bit3),
//ee_w(bit4),updata_image(bit5),reset_int(bit6),
#define STATUS_REG 0x09 //status_hg(bit0),status_lg(bit1),hg_latch(bit2),lg_latch(bit3),
//alert(bit4),st_result(bit7)
#define ACC_Z_MSB 0x07
#define ACC_Z_LSB 0x06 //ACC_Z_BIT0'1(bit6'7),new_data_z(bit0)
#define ACC_Y_MSB 0x05
#define ACC_Y_LSB 0x04 //ACC_Y_BIT0'1(bit6'7),new_data_y(bit0)
#define ACC_X_MSB 0x03
#define ACC_X_LSB 0x02 //ACC_X_BIT0'1(bit6'7),new_data_x(bit0)
//延时n个ms子程序
void delay_ms(uint ms)
{
uint i,j;
for(i=0;i<ms;i++)
{
for(j=0;j<1141;j++);
}
}
/*串口初始化*/
void uart_init(uint baud)
{
UCSRB=0x00;
UCSRA=0x00; //控制寄存器清零
UCSRC=(1<<URSEL)|(0<<UPM0)|(3<<UCSZ0);
//选择UCSRC,异步模式,禁止
// 校验,1位停止位,8位数据位
baud=mclk/16/baud-1 ; //波特率最大为65K
UBRRL=baud;
UBRRH=baud>>8; //设置波特率
UCSRB=(1<<TXEN)|(1<<RXEN)|(1<<RXCIE);
//接收、发送使能,接收中断使能
SREG=BIT(7); //全局中断开放
DDRD|=0X02; //配置TX为输出(很重要)
}
/*串口发送一个字节*/
void uart_sendB(uchar data)
{
while(!(UCSRA&(BIT(UDRE)))) ;
UDR=data;
while(!(UCSRA&(BIT(TXC))));
UCSRA|=BIT(TXC);
}
/******************************************************************************
函数:I2C_Delay( void )
功能:模拟I2C总线延时
说明:请根据具体情况调整延时值
******************************************************************************/
void I2C_Delay( void )
{
NOP();NOP();NOP();NOP();
NOP();NOP();NOP();NOP();
NOP();NOP();NOP();NOP();
NOP();NOP();NOP();NOP();
}
/******************************************************************************
函数:I2C_Start()
功能:产生I2C总线的起始条件
说明:SCL处于高电平期间,当SDA出现下降沿时启动I2C总线
本函数也用来产生重复起始条件
******************************************************************************/
void I2C_Start()
{
IO_SET; NOP();
SCK_SET; I2C_Delay();
IO_CLR; I2C_Delay();
SCK_CLR; NOP();NOP();
}
/******************************************************************************
函数:I2C_Write()
功能:向I2C总线写1个字节的数据
参数:dat是要写到总线上的数据
******************************************************************************/
void I2C_Write( uchar dat )
{
uchar t = 8;
for( ; t>0; t-- )
{
if( dat & 0x80 )
IO_SET;
else
IO_CLR;
NOP();
dat <<= 1;
SCK_SET;
I2C_Delay();
I2C_Delay();
SCK_CLR;
I2C_Delay();
}
}
/******************************************************************************
函数:I2C_Read()
功能:从从机读取1个字节的数据
返回:读取的1个字节数据
******************************************************************************/
uchar I2C_Read( )
{
uint dat=0;
uchar t = 8;
//P1M |= 0x08; //加入 bit3 置1
PORTC |= 0x01; //加入 SDA PC0 置1
IO_SET; //在读取数据之前,要把SDA拉高,使之处于输入状态
for( ; t>0; t-- )
{
SCK_SET;
I2C_Delay();
dat <<= 1;
if ( IO_R )
dat++;
SCK_CLR;
I2C_Delay();
}
IO_CLR;
//P1M &= 0xF7; //加入 bit3 清0
PORTC &= 0x01; //加入 SDA PC0 清0
return dat;
}
/******************************************************************************
函数:I2C_GetAck()
功能:读取从机应答位(应答或非应答),用于判断:从机是否成功接收主机数据
返回:0-从机应答
1-从机非应答
说明:从机在收到每一个字节后都要产生应答位,主机如果收到非应答则应当终止传输
******************************************************************************/
uchar I2C_GetAck( void )
{
uchar Ack;
//P1M |= 0x08;
PORTC |= 0x01; //加入 SDA PC0 置1
IO_SET;
I2C_Delay();
SCK_SET;
Ack = IO_R;
I2C_Delay();
IO_CLR;
//P1M &= 0xF7;
PORTC &= 0x01; //加入 SDA PC0 清0
SCK_CLR;
I2C_Delay();
return Ack;
}
/****************************************************************************
函数:I2C_PutAck()
功能:主机产生应答位(应答或非应答),用于通知从机:主机是否成功接收从机数据
参数:Ack = 0:主机应答
Ack = 1:主机非应答
说明:主机在收到每一个字节后都要产生应答,在收到最后一个字节时,应当产生非应答
******************************************************************************/
void I2C_PutAck( uchar Ack )
{
//I2C_SDA = Ack;
if(Ack) //加入
IO_SET; //Ack = 1:主机非应答
else
IO_CLR; //Ack = 0:主机应答
I2C_Delay();
SCK_SET;
I2C_Delay();
SCK_CLR;
I2C_Delay();
IO_CLR;
}
/******************************************************************************
函数:I2C_Stop()
功能:产生I2C总线的停止条件
说明:SCL处于高电平期间,当SDA出现上升沿时停止I2C总线
******************************************************************************/
void I2C_Stop()
{
IO_CLR; NOP();NOP();
SCK_SET; I2C_Delay();
IO_SET; I2C_Delay();
}
/******************************************************************************
函数:void I2C_Send()
功能:启动I2C总线发数据
返回:0-正常,1-异常(无应答)
******************************************************************************/
//从机地址, 子地址, 写数据缓冲区
uchar I2C_Send( uchar SLA, uchar Addr, uchar WriteBuf )
{
I2C_Start( );
if ( !(SLA&0x01) )
{
I2C_Write( SLA );
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
I2C_Write( Addr );
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
I2C_Write( WriteBuf );//发送数据
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
I2C_Stop( );
return 0;
}
I2C_Stop( );
return 1;
}
/******************************************************************************
函数:void I2C_Rev()
功能:启动I2C总线收数据
返回:0-正常,1-异常(无应答)
******************************************************************************/
//从机地址, 子地址, 读数据缓冲区, 读数据长度
uchar I2C_Rev( uchar SLA, uchar Addr, uint *ReadBuf, uchar Size )
{
I2C_Start( );
I2C_Write( SLA&0xFE );
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
I2C_Write( Addr );
if ( I2C_GetAck() )
return 1;
I2C_Stop();
I2C_Start( );
I2C_Write( SLA );
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
for( ; ; )
{
*ReadBuf++ = I2C_Read( );
if ( (--Size) == 0 )
{
I2C_PutAck(1); //接收完最后一个数据时发送NAK
break;
}
I2C_PutAck(0);
}
I2C_Stop();
return 0;
}
void main( )
{
uchar i;
uart_init(19200); //串口初始化
I2C_Send( SMB380_ADDR_WRITE, 0x15, 0x22 ); //加入new_data_INT bit5 置1
//Wake_up_pause bit2,1 0x01 每80ms自动唤醒
//从机地址, 子地址, 读数据缓冲区, 读数据长度
I2C_Rev( SMB380_ADDR_READ, 0x14, Axis, 0x0A );
I2C_Send( SMB380_ADDR_WRITE, 0x14, ((Axis&0xE0)|0x02) ); //先读取0x14寄存器的值,
//再写入使保留位不变的设定值。
I2C_Send( SMB380_ADDR_WRITE, 0x0B, 0x00 ); //加入 关闭其它所有中断
I2C_Rev( SMB380_ADDR_READ, 0x0A, Axis, 0x01 );
I2C_Send( SMB380_ADDR_WRITE, 0x0A, ((Axis&0x80)|0x20) );
//加入你要的其它程序
delay_ms(40);
while(1)
{
I2C_Rev( SMB380_ADDR_READ, 0x00, Axis, 0x06 ); //指定地址读一个字节数据
for(i=0;i<6;i++)
{
uart_sendB(Axis);
}
}
} MARK!!!好东西 lnc361 :非常感谢你的热心帮助!
我今天才看到。我试一下!请问你的程序实际测试过吗?你用过这个传感器,做成产品后他的灵敏度可以到多少? INT16U Axis;
//INT16U ReadData;
sbit I2C_SDA = P1^3;
sbit I2C_SCL = P1^4;
#define SMB380_ADDR_WRITE 0x70
#define SMB380_ADDR_READ 0x71
//Registers address
#define OPER_REG 0x15 //Wake_up(bit 0),Wake_up_pause(bit1,bit2),Shadow_dis(bit3),
//latch_int(bit4),new_data_int(bit5),enable_adv_int(bit6)
#define OPER_SET 0x14 //rang(bit4'3),bandwith(bit2'1'0)
#define DUR_HYST 0x11 //any_motion_dur(bit6'7),hg_hyst(bit5'4'3),lg_hyst(bit5'4'3)
#define ANY_MOTION_TRES 0x10
#define HG_DUR 0x0F
#define HG_THRES 0x0E
#define LG_DUR 0x0D
#define LG_THRES 0X0C
#define INTERRUPT_SET 0x0B //enable_lg(bit0),enble_hg(bit1),counter_lg(bit2'3),
//counter_hg(bit4'5),any_motion(bit6),alert(bit7)
#define CONTROL_REG 0x0A //sleep(bit0),soft_reset(bit1),self_test0(bit2),self_test1(bit3),
//ee_w(bit4),updata_image(bit5),reset_int(bit6),
#define STATUS_REG 0x09 //status_hg(bit0),status_lg(bit1),hg_latch(bit2),lg_latch(bit3),alert(bit4),st_result(bit7)
#define ACC_Z_MSB 0x07
#define ACC_Z_LSB 0x06 //ACC_Z_BIT0'1(bit6'7),new_data_z(bit0)
#define ACC_Y_MSB 0x05
#define ACC_Y_LSB 0x04 //ACC_Y_BIT0'1(bit6'7),new_data_y(bit0)
#define ACC_X_MSB 0x03
#define ACC_X_LSB 0x02 //ACC_X_BIT0'1(bit6'7),new_data_x(bit0)
/******************************************************************************
函数:I2C_Delay( void )
功能:模拟I2C总线延时
说明:请根据具体情况调整延时值
******************************************************************************/
void I2C_Delay( void )
{
nop;nop;nop;nop;
nop;nop;nop;nop;
nop;nop;nop;nop;
nop;nop;nop;nop;
}
/******************************************************************************
函数:I2C_Start()
功能:产生I2C总线的起始条件
说明:SCL处于高电平期间,当SDA出现下降沿时启动I2C总线
本函数也用来产生重复起始条件
******************************************************************************/
void I2C_Start()
{
I2C_SDA = 1; nop;
I2C_SCL = 1; I2C_Delay();
I2C_SDA = 0; I2C_Delay();
I2C_SCL = 0; nop;nop;
}
/******************************************************************************
函数:I2C_Write()
功能:向I2C总线写1个字节的数据
参数:dat是要写到总线上的数据
******************************************************************************/
void I2C_Write( INT8U dat )
{
INT8U t = 8;
for( ; t>0; t-- )
{
if( dat & 0x80 )
I2C_SDA = 1;
else
I2C_SDA = 0;
nop;
dat <<= 1;
I2C_SCL = 1;
I2C_Delay();
I2C_Delay();
I2C_SCL = 0;
I2C_Delay();
}
}
/******************************************************************************
函数:I2C_Read()
功能:从从机读取1个字节的数据
返回:读取的1个字节数据
******************************************************************************/
INT8U I2C_Read( )
{
INT16U dat=0;
INT8U t = 8;
P1M |= 0x08;
I2C_SDA = 1; //在读取数据之前,要把SDA拉高,使之处于输入状态
for( ; t>0; t-- )
{
I2C_SCL = 1;
I2C_Delay();
dat <<= 1;
if ( I2C_SDA )
dat++;
I2C_SCL = 0;
I2C_Delay();
}
I2C_SDA = 0;
P1M &= 0xF7;
return dat;
}
/******************************************************************************
函数:I2C_GetAck()
功能:读取从机应答位(应答或非应答),用于判断:从机是否成功接收主机数据
返回:0-从机应答
1-从机非应答
说明:从机在收到每一个字节后都要产生应答位,主机如果收到非应答则应当终止传输
******************************************************************************/
INT8U I2C_GetAck( void )
{
INT8U Ack;
P1M |= 0x08;
I2C_SDA = 1;
I2C_Delay();
I2C_SCL = 1;
Ack = I2C_SDA;
I2C_Delay();
I2C_SDA = 0;
P1M &= 0xF7;
I2C_SCL = 0;
I2C_Delay();
return Ack;
}
/****************************************************************************
函数:I2C_PutAck()
功能:主机产生应答位(应答或非应答),用于通知从机:主机是否成功接收从机数据
参数:Ack = 0:主机应答
Ack = 1:主机非应答
说明:主机在收到每一个字节后都要产生应答,在收到最后一个字节时,应当产生非应答
******************************************************************************/
void I2C_PutAck( INT8U Ack )
{
I2C_SDA = Ack;
I2C_Delay();
I2C_SCL = 1;
I2C_Delay();
I2C_SCL = 0;
I2C_Delay();
I2C_SDA = 0;
}
/******************************************************************************
函数:I2C_Stop()
功能:产生I2C总线的停止条件
说明:SCL处于高电平期间,当SDA出现上升沿时停止I2C总线
******************************************************************************/
void I2C_Stop()
{
I2C_SDA = 0; nop;nop;
I2C_SCL = 1; I2C_Delay();
I2C_SDA = 1; I2C_Delay();
}
/******************************************************************************
函数:void I2C_Send()
功能:启动I2C总线发数据
返回:0-正常,1-异常(无应答)
******************************************************************************/
//从机地址, 子地址, 写数据缓冲区
INT8U I2C_Send( INT8U SLA, INT8U Addr, INT8U WriteBuf )
{
I2C_Start( );
if ( !(SLA&0x01) )
{
I2C_Write( SLA );
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
I2C_Write( Addr );
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
I2C_Write( WriteBuf );//发送数据
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
I2C_Stop( );
return 0;
}
I2C_Stop( );
return 1;
}
/******************************************************************************
函数:void I2C_Rev()
功能:启动I2C总线收数据
返回:0-正常,1-异常(无应答)
******************************************************************************/
//从机地址, 子地址, 读数据缓冲区, 读数据长度
INT8U I2C_Rev( INT8U SLA, INT8U Addr, INT16U *ReadBuf, INT8U Size )
{
I2C_Start( );
I2C_Write( SLA&0xFE );
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
I2C_Write( Addr );
if ( I2C_GetAck() )
return 1;
I2C_Stop();
I2C_Start( );
I2C_Write( SLA );
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
for( ; ; )
{
*ReadBuf++ = I2C_Read( );
if ( (--Size) == 0 )
{
I2C_PutAck(1); //接收完最后一个数据时发送NAK
break;
}
I2C_PutAck(0);
}
I2C_Stop();
return 0;
}
void main( )
{
I2C_Send( SMB380_ADDR_WRITE, 0x15, 0x22 );
I2C_Rev( SMB380_ADDR_READ, 0x14, Axis, 0x0A );
I2C_Send( SMB380_ADDR_WRITE, 0x14, ((Axis&0xE0)|0x02) ); //先读取0x14寄存器的值,再写入使保留位不变的设定值。
I2C_Send( SMB380_ADDR_WRITE, 0x0B, 0x00 );
I2C_Rev( SMB380_ADDR_READ, 0x0A, Axis, 0x01 );
I2C_Send( SMB380_ADDR_WRITE, 0x0A, ((Axis&0x80)|0x20) );
//加入你要的其它程序
} LZ你出点费用,让有能力的人帮你世纪吧。 现在已经用AVR的硬件SPI和I2C成功对SMB380进行读写。并实现了1米跌落保护的样板。 我想请教一下,那个selftest1是怎么用的,先谢谢! 请问bma150与smb380有什么区别呢,我怎么看文档没看出来呢? 明白了,只是封装不同而已 回复【6楼】32446975
-----------------------------------------------------------------------
怎么读出来的数据就是不对呢?可否请教一下!qq:715372488 【10楼】 xlb1833:qq:281342118 好东西 mark
页:
[1]