STM32F429-DISC1 上的陀螺仪表现异常
Gyroscope on STM32F429-DISC1 is behaving strangely
我是 STM32 世界的新手,我对 STM32F429-DISC1 板上的板载 L3GD20 陀螺仪有疑问。
我在获取它时遇到了麻烦运行(陀螺仪不断发送相同的数据,即使在重置或断电后也是如此)并且在我终于设法让它工作之后(通过发送指令几次) ),我看到了奇怪的结果(在 x 轴、y 和 z 轴上)(见下图)。
我是不是遗漏了什么,或者我应该对原始数据做些什么来平滑它?是否有可能,IC 有缺陷?
我在 STM32 和 STM32F429-DISC1 上使用 Atollic TrueStudio v9.0。
这是我的代码:
#include "stm32f4xx.h"
#include "stm32f429i_discovery.h"
#include "stdio.h"
volatile uint32_t elapsed = 0;
#define CS_gyro_start GPIO_ResetBits( GPIOC, GPIO_Pin_1 )
#define CS_gyro_stop GPIO_SetBits( GPIOC, GPIO_Pin_1 )
void DelayMS( int time ){
elapsed = time;
while( elapsed > 0 );
}
void SysTick_Handler(){
if( elapsed > 0 ) --elapsed;
}
void SendChar( char ch ){
while( USART_GetFlagStatus( USART1, USART_FLAG_TXE ) == RESET ){}
USART_SendData( USART1, ch );
}
void sendString( const char *s ){
while( *s ){
SendChar( *s++ );
}
}
int _write( int file, char *ptr, int len ){
sendString( ptr );
return len;
} //sadly this doesn't work with float variables
void initialize( void ){
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA |
RCC_AHB1Periph_GPIOC |
RCC_AHB1Periph_GPIOF, ENABLE );
RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI5 |
RCC_APB2Periph_SYSCFG |
RCC_APB2Periph_USART1, ENABLE );
GPIO_InitTypeDef gpio;
USART_InitTypeDef usart;
SPI_InitTypeDef spi;
GPIO_StructInit( &gpio );
USART_StructInit( &usart );
SPI_StructInit( &spi );
//usart
GPIO_PinAFConfig( GPIOA, GPIO_PinSource10, GPIO_AF_USART1 );
GPIO_PinAFConfig( GPIOA, GPIO_PinSource9, GPIO_AF_USART1 );
gpio.GPIO_Mode = GPIO_Mode_AF;
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
gpio.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_Init( GPIOA, &gpio );
usart.USART_BaudRate = 115200;
USART_Init( USART1, &usart );
USART_Cmd( USART1, ENABLE );
//spi
GPIO_PinAFConfig( GPIOF, GPIO_PinSource7, GPIO_AF_SPI5 );
GPIO_PinAFConfig( GPIOF, GPIO_PinSource9, GPIO_AF_SPI5 );
GPIO_PinAFConfig( GPIOF, GPIO_PinSource8, GPIO_AF_SPI5 );
//SS
gpio.GPIO_Pin = GPIO_Pin_1;
gpio.GPIO_Mode = GPIO_Mode_OUT;
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init( GPIOC, &gpio );
GPIO_SetBits( GPIOC, GPIO_Pin_1 );
//SCK, MOSI
gpio.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_7;
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_Mode = GPIO_Mode_AF;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init( GPIOF, &gpio );
//MISO
gpio.GPIO_Pin = GPIO_Pin_8;
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_Mode = GPIO_Mode_AF;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init( GPIOF, &gpio );
spi.SPI_Mode = SPI_Mode_Master;
spi.SPI_NSS = SPI_NSS_Soft;
spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_Init( SPI5, &spi );
SPI_Cmd( SPI5, ENABLE );
}
uint8_t SPI_sendByte( uint8_t byte_ ){
while( SPI_I2S_GetFlagStatus( SPI5, SPI_I2S_FLAG_TXE ) == RESET ){}
SPI_I2S_SendData( SPI5, byte_ );
while( SPI_I2S_GetFlagStatus( SPI5, SPI_I2S_FLAG_RXNE ) == RESET ){}
return SPI_I2S_ReceiveData( SPI5 );
}
void SPI_writeData( uint8_t address, uint8_t byteToWrite ){
CS_gyro_start;
SPI_sendByte( address );
SPI_sendByte( byteToWrite );
CS_gyro_stop;
}
void GetGyroValues( uint16_t *x, uint16_t *y, uint16_t *z ){
CS_gyro_start;
SPI_sendByte( 0x29 | 0x80 );
*x = SPI_sendByte( 0xff );
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x28 | 0x80 );
*x |= (SPI_sendByte( 0xff ) << 8);
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2B | 0x80 );
*y = SPI_sendByte( 0xff );
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2A | 0x80 );
*y |= (SPI_sendByte( 0xff ) << 8);
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2D | 0x80 );
*z = SPI_sendByte( 0xff );
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2C | 0x80 );
*z |= (SPI_sendByte( 0xff ) << 8);
CS_gyro_stop;
}
int main( void ){
SysTick_Config( SystemCoreClock / 1000 );
initialize();
SPI_writeData(0x20, 0xff); //power on, settings from TM-library & datasheet
SPI_writeData(0x21, 0x00); //high-pass filter settings
SPI_writeData(0x24, 0x10); //high-pass filter en
SPI_writeData(0x23, 0x20); //scale 2000
uint16_t x, y, z;
while( 1 ){
GetGyroValues( &x, &y, &z );
printf( "x: %d\r\n", x );
DelayMS( 100 );
}
}
uint32_t sEE_TIMEOUT_UserCallback(void)
{
/* TODO, implement your code here */
while (1)
{
}
}// This is required by Atollic
这是一个示例图,显示了 x 轴上的变化。 (发现板或多或少在 45 度,当它在 0 度时 - 放下,然后输出是稳定的 65000)
注意最后一部分"expressed as a two’s complement number";您错误地将数据解释为 unsigned。看起来该值徘徊在零附近;或者实际上看起来你在一个位置上相当不稳定地握住它,但肯定不会以稳定的速度连续旋转它。该设备是 陀螺仪 而不是 加速度计 。它测量 angular 速度 而不是 加速度(或倾斜 - 即重力加速度)。在静止时,您会期望所有轴上都为零。您的图表显示的可能是您试图将其保持在 45 度时手抖。
void GetGyroValues( int16_t *x, int16_t *y, int16_t *z )
应该会比较成功,当然还有:
int16_t x, y, z;
您可以通过积分 angular 速度而不是绝对角度获得 角度变化 的近似测量。即使那样,您也可能不得不经常校准零 - 积分中的小 non-zero 偏差将表现为错误的缓慢旋转。
根据数据表 L3GD20、table 17,OUT_XL 位于地址 0x28,OUT_XH 位于地址 0x29。
所以你必须左移地址为 0x29 而不是 0x28 的值,反之亦然。
这也有 Y 和 Z 值。
void GetGyroValues( int16_t *x, int16_t *y, int16_t *z ){
CS_gyro_start;
SPI_sendByte( 0x28 | 0x80 );
*x = SPI_sendByte( 0xff );
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x29 | 0x80 );
*x |= (SPI_sendByte( 0xff ) << 8);
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2A | 0x80 );
*y = SPI_sendByte( 0xff );
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2B | 0x80 );
*y |= (SPI_sendByte( 0xff ) << 8);
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2C | 0x80 );
*z = SPI_sendByte( 0xff );
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2D | 0x80 );
*z |= (SPI_sendByte( 0xff ) << 8);
CS_gyro_stop;
}
我是 STM32 世界的新手,我对 STM32F429-DISC1 板上的板载 L3GD20 陀螺仪有疑问。
我在获取它时遇到了麻烦运行(陀螺仪不断发送相同的数据,即使在重置或断电后也是如此)并且在我终于设法让它工作之后(通过发送指令几次) ),我看到了奇怪的结果(在 x 轴、y 和 z 轴上)(见下图)。
我是不是遗漏了什么,或者我应该对原始数据做些什么来平滑它?是否有可能,IC 有缺陷?
我在 STM32 和 STM32F429-DISC1 上使用 Atollic TrueStudio v9.0。
这是我的代码:
#include "stm32f4xx.h"
#include "stm32f429i_discovery.h"
#include "stdio.h"
volatile uint32_t elapsed = 0;
#define CS_gyro_start GPIO_ResetBits( GPIOC, GPIO_Pin_1 )
#define CS_gyro_stop GPIO_SetBits( GPIOC, GPIO_Pin_1 )
void DelayMS( int time ){
elapsed = time;
while( elapsed > 0 );
}
void SysTick_Handler(){
if( elapsed > 0 ) --elapsed;
}
void SendChar( char ch ){
while( USART_GetFlagStatus( USART1, USART_FLAG_TXE ) == RESET ){}
USART_SendData( USART1, ch );
}
void sendString( const char *s ){
while( *s ){
SendChar( *s++ );
}
}
int _write( int file, char *ptr, int len ){
sendString( ptr );
return len;
} //sadly this doesn't work with float variables
void initialize( void ){
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA |
RCC_AHB1Periph_GPIOC |
RCC_AHB1Periph_GPIOF, ENABLE );
RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI5 |
RCC_APB2Periph_SYSCFG |
RCC_APB2Periph_USART1, ENABLE );
GPIO_InitTypeDef gpio;
USART_InitTypeDef usart;
SPI_InitTypeDef spi;
GPIO_StructInit( &gpio );
USART_StructInit( &usart );
SPI_StructInit( &spi );
//usart
GPIO_PinAFConfig( GPIOA, GPIO_PinSource10, GPIO_AF_USART1 );
GPIO_PinAFConfig( GPIOA, GPIO_PinSource9, GPIO_AF_USART1 );
gpio.GPIO_Mode = GPIO_Mode_AF;
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
gpio.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_Init( GPIOA, &gpio );
usart.USART_BaudRate = 115200;
USART_Init( USART1, &usart );
USART_Cmd( USART1, ENABLE );
//spi
GPIO_PinAFConfig( GPIOF, GPIO_PinSource7, GPIO_AF_SPI5 );
GPIO_PinAFConfig( GPIOF, GPIO_PinSource9, GPIO_AF_SPI5 );
GPIO_PinAFConfig( GPIOF, GPIO_PinSource8, GPIO_AF_SPI5 );
//SS
gpio.GPIO_Pin = GPIO_Pin_1;
gpio.GPIO_Mode = GPIO_Mode_OUT;
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init( GPIOC, &gpio );
GPIO_SetBits( GPIOC, GPIO_Pin_1 );
//SCK, MOSI
gpio.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_7;
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_Mode = GPIO_Mode_AF;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init( GPIOF, &gpio );
//MISO
gpio.GPIO_Pin = GPIO_Pin_8;
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_Mode = GPIO_Mode_AF;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init( GPIOF, &gpio );
spi.SPI_Mode = SPI_Mode_Master;
spi.SPI_NSS = SPI_NSS_Soft;
spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_Init( SPI5, &spi );
SPI_Cmd( SPI5, ENABLE );
}
uint8_t SPI_sendByte( uint8_t byte_ ){
while( SPI_I2S_GetFlagStatus( SPI5, SPI_I2S_FLAG_TXE ) == RESET ){}
SPI_I2S_SendData( SPI5, byte_ );
while( SPI_I2S_GetFlagStatus( SPI5, SPI_I2S_FLAG_RXNE ) == RESET ){}
return SPI_I2S_ReceiveData( SPI5 );
}
void SPI_writeData( uint8_t address, uint8_t byteToWrite ){
CS_gyro_start;
SPI_sendByte( address );
SPI_sendByte( byteToWrite );
CS_gyro_stop;
}
void GetGyroValues( uint16_t *x, uint16_t *y, uint16_t *z ){
CS_gyro_start;
SPI_sendByte( 0x29 | 0x80 );
*x = SPI_sendByte( 0xff );
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x28 | 0x80 );
*x |= (SPI_sendByte( 0xff ) << 8);
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2B | 0x80 );
*y = SPI_sendByte( 0xff );
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2A | 0x80 );
*y |= (SPI_sendByte( 0xff ) << 8);
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2D | 0x80 );
*z = SPI_sendByte( 0xff );
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2C | 0x80 );
*z |= (SPI_sendByte( 0xff ) << 8);
CS_gyro_stop;
}
int main( void ){
SysTick_Config( SystemCoreClock / 1000 );
initialize();
SPI_writeData(0x20, 0xff); //power on, settings from TM-library & datasheet
SPI_writeData(0x21, 0x00); //high-pass filter settings
SPI_writeData(0x24, 0x10); //high-pass filter en
SPI_writeData(0x23, 0x20); //scale 2000
uint16_t x, y, z;
while( 1 ){
GetGyroValues( &x, &y, &z );
printf( "x: %d\r\n", x );
DelayMS( 100 );
}
}
uint32_t sEE_TIMEOUT_UserCallback(void)
{
/* TODO, implement your code here */
while (1)
{
}
}// This is required by Atollic
这是一个示例图,显示了 x 轴上的变化。 (发现板或多或少在 45 度,当它在 0 度时 - 放下,然后输出是稳定的 65000)
注意最后一部分"expressed as a two’s complement number";您错误地将数据解释为 unsigned。看起来该值徘徊在零附近;或者实际上看起来你在一个位置上相当不稳定地握住它,但肯定不会以稳定的速度连续旋转它。该设备是 陀螺仪 而不是 加速度计 。它测量 angular 速度 而不是 加速度(或倾斜 - 即重力加速度)。在静止时,您会期望所有轴上都为零。您的图表显示的可能是您试图将其保持在 45 度时手抖。
void GetGyroValues( int16_t *x, int16_t *y, int16_t *z )
应该会比较成功,当然还有:
int16_t x, y, z;
您可以通过积分 angular 速度而不是绝对角度获得 角度变化 的近似测量。即使那样,您也可能不得不经常校准零 - 积分中的小 non-zero 偏差将表现为错误的缓慢旋转。
根据数据表 L3GD20、table 17,OUT_XL 位于地址 0x28,OUT_XH 位于地址 0x29。 所以你必须左移地址为 0x29 而不是 0x28 的值,反之亦然。 这也有 Y 和 Z 值。
void GetGyroValues( int16_t *x, int16_t *y, int16_t *z ){
CS_gyro_start;
SPI_sendByte( 0x28 | 0x80 );
*x = SPI_sendByte( 0xff );
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x29 | 0x80 );
*x |= (SPI_sendByte( 0xff ) << 8);
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2A | 0x80 );
*y = SPI_sendByte( 0xff );
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2B | 0x80 );
*y |= (SPI_sendByte( 0xff ) << 8);
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2C | 0x80 );
*z = SPI_sendByte( 0xff );
CS_gyro_stop;
CS_gyro_start;
SPI_sendByte( 0x2D | 0x80 );
*z |= (SPI_sendByte( 0xff ) << 8);
CS_gyro_stop;
}