最近一个项目需要用到SCL3300倾角传感器, 在网上买了两个传感器,打了一个小板,就开始测试了。板子焊好,本想一天内解决代码的问题,结果也花了两三天才搞定,现在把调试结果和心得总结一下,希望有朋友用到时不要走弯路。
1) SCL3300传感器资料
特性
3轴测量
带加速度输出和角度输出
-40℃~125℃
3.0V~3.6V工作电压
SPI接口
0.001°/√Hz的噪声
其它的资料可以查看PDF文档
- SCL3300与微处理器的接口
网上查了很多资料,提供的例程都是基于STM32系列处理器,为了降低成本,我采用了STM8S003处理器来作为主控制器和SCL3300通信。STM8S003提供了一个SPI接口
用于和SCL3300通信,电路于下图所示
3: 参考代码
1) IO口以及SPI接口设置
#define READ_ACC_X 0x040000F7
#define READ_ACC_Y 0x080000FD
#define READ_ACC_Z 0x0C0000FB
#define READ_STO 0x100000E9
#define ENABLE_ANGLE_OUTPUTS 0xB0001F6F
#define READ_ANG_X 0x240000C7
#define READ_ANG_Y 0x280000CD
#define READ_ANG_Z 0x2C0000CB
#define READ_TEMPERATURE 0x140000EF
#define READ_STATUS_SUMMARY 0x180000E5
#define READ_ERR_FLAG1 0x1C0000E3
#define READ_ERR_FLAG2 0x200000C1
#define READ_CMD 0x340000DF
#define CHANGE_TO_MODE1 0xB400001F //默认模式,1.8g full-scale 40 Hz 1st order low pass filter
#define CHANGE_TO_MODE2 0xB4000102 //23.6g full-scale 70 Hz 1st order low pass filter
#define CHANGE_TO_MODE3 0xB4000225 //Inclination mode 13 Hz 1st order low pass filter
#define CHANGE_TO_MODE4 0xB4000338 //Inclination mode 13 Hz 1st order low pass filter Low noise mode
#define SET_POWER_DOWN_MODE 0xB400046B
#define WAKE_UP 0xB400001F
#define SW_RESET 0xB4002098
#define READ_ID 0x40000091
#define READ_SERIAL1 0x640000A7
#define READ_SERIAL2 0x680000AD
#define READ_CURRENT_BANK 0x7C0000B3
#define SWITCH_TO_BANK_0 0xFC000073 //默认,读bank1后自动返回
#define SWITCH_TO_BANK_1 0xFC00016E
/* 定义GPIO端口 */
#define PORT_SCK GPIOC
#define PIN_SCK GPIO_PIN_5
#define PORT_DIN GPIOC
#define PIN_DIN GPIO_PIN_6
#define PORT_CS GPIOD
#define PIN_CS GPIO_PIN_3
#define PORT_DRDY GPIOD
#define PIN_DRDY GPIO_PIN_2
#define PORT_DOUT GPIOC
#define PIN_DOUT GPIO_PIN_7
/* 定义口线置0和置1的宏 */
#define CS_0() GPIO_WriteLow(PORT_CS, (GPIO_Pin_TypeDef)PIN_CS)
#define CS_1() GPIO_WriteHigh(PORT_CS, (GPIO_Pin_TypeDef)PIN_CS)
void bsp_InitSCL3300(void)
{
/* 初始化GPIO,配置为推挽输出 /
GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_HIGH_FAST); / 设置推挽输出 CS = 1 /
GPIO_Init (GPIOB, GPIO_PIN_4, GPIO_MODE_OUT_PP_HIGH_FAST);
GPIO_Init(PORT_CS, (GPIO_Pin_TypeDef)PIN_CS, GPIO_MODE_OUT_PP_HIGH_FAST); / 设置推挽输出 CS = 1 /
GPIO_Init(PORT_SCK, (GPIO_Pin_TypeDef)PIN_SCK, GPIO_MODE_OUT_PP_HIGH_FAST); / 设置推挽输出 SCK = 0 /
GPIO_Init(PORT_DIN, (GPIO_Pin_TypeDef)PIN_DIN, GPIO_MODE_OUT_PP_HIGH_FAST); / 设置推挽输出 DI = 1 /
GPIO_Init(PORT_DOUT, (GPIO_Pin_TypeDef)PIN_DOUT, GPIO_MODE_IN_FL_NO_IT);/ 无上拉,无中断 */
CS_1();
}
void SPI_init(void)
{
SPI_DeInit();
CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI,ENABLE);
SPI_Init(SPI_FIRSTBIT_MSB, SPI_BAUDRATEPRESCALER_32, SPI_MODE_MASTER, SPI_CLOCKPOLARITY_LOW, SPI_CLOCKPHASE_1EDGE, SPI_DATADIRECTION_2LINES_FULLDUPLEX, SPI_NSS_SOFT, 8);
SPI_Cmd(ENABLE);
}
//SPI发送及接受数据
u8 SPI_Send_Recv_Byte(u8 sen_data)
{
u8 recv_data;
while(SPI_GetFlagStatus(SPI_FLAG_TXE)== RESET); //while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); //等待发送缓冲为空,发送数据
SPI_SendData(sen_data); //SPI_I2S_SendData(SPI1, sen_data);
while(SPI_GetFlagStatus(SPI_FLAG_RXNE)== RESET); //while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); //等待接收缓冲非空,接受数据
recv_data = SPI_ReceiveData();
return recv_data;
}
void SPI_SCL3300_SendCmd(u32 cmd)
{
unsigned char cmdT1,cmdT2,cmdT3,cmdT4;
cmdT1=(unsigned char)(cmd >> 24);
cmdT2=(unsigned char)(cmd >> 16);
cmdT3=(unsigned char)(cmd >> 8);
cmdT4=(unsigned char)(cmd );
retemp[0] = SPI_Send_Recv_Byte(cmdT1);//SPI_SCL3300_SendByte((cmd >> 24) & 0xFF);
retemp[1] = SPI_Send_Recv_Byte(cmdT2);
retemp[2] = SPI_Send_Recv_Byte(cmdT3);
retemp[3] = SPI_Send_Recv_Byte(cmdT4);
rs = retemp[0] & 0x03;
// rs
//if(rs != 0x01) return -1;
}
u32 SPI_SCL3300_CMD(u32 cmd)
{
u32 Temp1=0;
u32 Temp2=0;
u32 Temp3=0;
u32 Temp4=0;
CS_0(); //SPI_SCL3300_CS_LOW();
Delay_us(200);
SPI_SCL3300_SendCmd(cmd);
Temp4=(u32)retemp[0];
Temp1=retemp[1];
Temp2=retemp[2];
Temp3=retemp[3];
TempReturn=(Temp4<<24)|(Temp1<<16)|(Temp2<<8)|Temp3;
CS_1();
Delay_us(200);
return TempReturn;
}
//===========================================
static uint8_t CRC8(uint8_t BitValue, uint8_t CRC)
{
uint8_t Temp;
Temp = (uint8_t)(CRC & 0x80);
if (BitValue == 0x01)
{
Temp ^= 0x80;
}
CRC <<= 1;
if (Temp > 0)
{
CRC ^= 0x1D;
}
return CRC;
}
//===================================================
uint8_t CalculateCRC(uint32_t Data)
{
uint8_t BitIndex;
uint8_t BitValue;
uint8_t CRC;
CRC = 0xFF;
for (BitIndex = 31; BitIndex > 7; BitIndex–)
{
BitValue = (uint8_t)((Data >> BitIndex) & 0x01);
CRC = CRC8(BitValue, CRC);
}
CRC = (uint8_t)~CRC;
return CRC;
}
//---------------------------------------------------------
void SCL3300_Init(void)
{
CS_1(); //SPI_SCL3300_CS_HIGH();
Delay_ms(20);
SPI_SCL3300_CMD(SW_RESET); //复位
Delay_ms(5);
SPI_SCL3300_CMD(CHANGE_TO_MODE4); //设置工作模式4
Delay_ms(20);
do
{
StatSensor=SPI_SCL3300_CMD(ENABLE_ANGLE_OUTPUTS); //允许角度输出
Delay_ms(50);
StatSensor=SPI_SCL3300_CMD(READ_STATUS_SUMMARY);
StatSensor=SPI_SCL3300_CMD(READ_STATUS_SUMMARY);
StatSensor=SPI_SCL3300_CMD(READ_STATUS_SUMMARY);
Delay_ms(50);
}
while((retemp[0]&0x03)==0x03);
whoami = SPI_SCL3300_CMD(READ_ID);
whoami = SPI_SCL3300_CMD(READ_ID);
Delay_ms(20);
//whoami=0x4100c136;
whoami= (whoami&0xffffff00);//读whoami寄存器后,CRC判断数据对错。
crcDAT=CalculateCRC(whoami);//0xFFFFC136
Delay_ms(20);
}
while (1)
{
z= SPI_SCL3300_CMD(READ_TEMPERATURE);
t = SPI_SCL3300_CMD(READ_ANG_X);
x = SPI_SCL3300_CMD(READ_ANG_Y);
y = SPI_SCL3300_CMD(READ_ANG_Z);
temperature.f = (float)((t >> 8) & 0xffff) / 18.9 - 273;
x_angle.f = (float)((x>>8 ) & 0xffff) * 90 / 16384;
y_angle.f = (float)((y>>8 ) & 0xffff) * 90 / 16384;
z_angle.f = (float)((z>>8) & 0xffff) * 90 / 16384;
Delay_ms(600);
}
SCL3300采用SPI协议,但是和普通的SPI协议有所不同,这一次的结果来自上一次的SPI指令。采用OFF-FRAME的协议格式,即对本次请求的响应要在下次请求时才能发送。
SPI传输实在CSB片选下降沿开始的。数据位采样在SCK的上升沿进行。相当于SPI模式0
每次通过SPI向SCL3300发送指令的时候,SCL3300会将上一次指令的处理结果传上来,
上传的数据包括读写标志,地址,RS,数据,以及CRC
我们可通过RS判断状态是否对错,即!=0x03,可进一步读状态寄存器。status summary.
心得,
我们可以先读取WHOami寄存器,来判读到的序列号是否为0XC1, 如果序列号正确,可以初步判断SPI硬件没有问题
第二步可以读取温度寄存器,通过温度和判断数据是否正确
第三步,通过CRC来判断每次的数据格式是否正确
第四步,读取倾角寄存器。