AT32F421C8T7利用SPI读取ICM42670原始数据并得到姿态角

这篇具有很好参考价值的文章主要介绍了AT32F421C8T7利用SPI读取ICM42670原始数据并得到姿态角。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

网上其他型号代码借鉴编写来的,如果有错误,请多担待,并请指出错误,谢谢指导。

AT32A单片机的准备,我是keil,下载的keil5包

AT32F421C8T7利用SPI读取ICM42670原始数据并得到姿态角,单片机

 利用的j-link烧录。

下面是程序

icm42670.c

#include "ICM42670.h"

static float accSensitivity   = 0.244f;   //加速度的最小分辨率 mg/LSB
static float gyroSensitivity  = 32.8f;


extern signed short ax;
extern signed short ay;
extern signed short az;

extern signed short gx;
extern signed short gy;
extern signed short gz;

void spi1_init(void)
{
	gpio_init_type gpio_init_struct;
	spi_init_type spi_init_struct;
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_SPI1_PERIPH_CLOCK, TRUE);

	gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;  //cs
  gpio_init_struct.gpio_pull           = GPIO_PULL_UP;
  gpio_init_struct.gpio_mode           = GPIO_MODE_OUTPUT;
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_pins = GPIO_PINS_4;   
  gpio_init(GPIOA, &gpio_init_struct);
	//gpio_bits_set(GPIOA,GPIO_PINS_4);
	
	gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE5, GPIO_MUX_0);  //这个muxing 百度翻译也整不明白,是不是管角复用的意思?看到数据手册是乎是5的第1功能为SPI1
  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE6, GPIO_MUX_0);
  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE7, GPIO_MUX_0);

	gpio_default_para_init(&gpio_init_struct);		
	gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_pull           = GPIO_PULL_DOWN;
  gpio_init_struct.gpio_mode           = GPIO_MODE_MUX;
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_pins = GPIO_PINS_5;   
  gpio_init(GPIOA, &gpio_init_struct);

  gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_pull           = GPIO_PULL_UP;
  gpio_init_struct.gpio_mode           = GPIO_MODE_MUX;
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_pins =  GPIO_PINS_6 | GPIO_PINS_7;
  gpio_init(GPIOA, &gpio_init_struct);
	
	spi_default_para_init(&spi_init_struct);
	spi_init_struct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
  spi_init_struct.master_slave_mode = SPI_MODE_MASTER;
  spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_8;
  spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;
  spi_init_struct.frame_bit_num = SPI_FRAME_8BIT;
  spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;
  spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE;
  spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
  spi_init(SPI1, &spi_init_struct);
	spi_enable(SPI1, TRUE);
}


 uint8_t spi1_readwritebyte(uint8_t dat)
{
	while (spi_i2s_flag_get(SPI1, SPI_I2S_TDBE_FLAG) == RESET);
	spi_i2s_data_transmit(SPI1, dat);	
	while (spi_i2s_flag_get(SPI1, SPI_I2S_RDBF_FLAG) == RESET);
	return spi_i2s_data_receive(SPI1);
}

//uint8_t icm42670_readwritebyte(uint8_t dat)
//{
//	return spi1_readwritebyte(dat);
//}

void spi_receice(uint8_t* pdata, uint16_t len)
{
	uint16_t i = 0;
	for( i = 0; i < len; i ++)
	{
		pdata[i] = spi1_readwritebyte(0);
//     pdata++;
	//spi1_readwritebyte(pdata[i]);
	}
}

void ICM42670_Init(void)
{
	
	uint8_t reg_val = 0;
	reg_val = icm42670_read_reg(ICM42670_WHO_AM_I);
	icm42670_write_reg(ICM42670_PWR_MGMT0,0x00);
  delay_sec(1);
	icm42670_write_reg(ICM42670_DEVICE_CONFIG, 0x04);//4线spi
	icm42670_write_reg(ICM42670_FIFO_CONFIG1, 0x00);//Stream-to-FIFO Mode
	
	reg_val = icm42670_read_reg(ICM42670_INT_SOURCE0);

	icm42670_write_reg(ICM42670_INT_SOURCE0, 0x00);
  icm42670_write_reg(ICM42670_FIFO_CONFIG2, 0x00); // watermark
  icm42670_write_reg(ICM42670_FIFO_CONFIG3, 0x02); // watermark
  icm42670_write_reg(ICM42670_INT_SOURCE0, reg_val);
  icm42670_write_reg(ICM42670_FIFO_CONFIG1, 0x33); // Enable the accel and gyro to the FIFO

  icm42670_write_reg(ICM42670_INT_CONFIG, 0x36);
  reg_val = icm42670_read_reg(ICM42670_INT_SOURCE0);
  reg_val |= (1 << 2); //FIFO_THS_INT1_ENABLE
  icm42670_write_reg(ICM42670_INT_SOURCE0, reg_val);

  bsp_Icm42670GetAres(AFS_8G);
  reg_val = icm42670_read_reg(ICM42670_ACCEL_CONFIG0);//page74
  reg_val |= (AFS_8G << 5);   //量程 ±8g
  reg_val |= (AODR_50Hz);     //输出速率 50HZ
  icm42670_write_reg(ICM42670_ACCEL_CONFIG0, reg_val);

  bsp_Icm42670GetGres(GFS_1000DPS);
  reg_val = icm42670_read_reg(ICM42670_GYRO_CONFIG0);
	//page73
  reg_val |= (GFS_1000DPS << 5);   //量程 ±1000dps
  reg_val |= (GODR_50Hz);     //输出速率 50HZ
  icm42670_write_reg(ICM42670_GYRO_CONFIG0, reg_val);

  reg_val = icm42670_read_reg(ICM42670_PWR_MGMT0); //读取PWR—MGMT0当前寄存器的值(page72)
        //reg_val &= ~(1 << 5);//使能温度测量
  reg_val |= ((3) << 2);//设置GYRO_MODE  0:关闭 1:待机 2:预留 3:低噪声
  reg_val |= (3);//设置ACCEL_MODE 0:关闭 1:关闭 2:低功耗 3:低噪声
  icm42670_write_reg(ICM42670_PWR_MGMT0, reg_val);
  delay_sec(1); //操作完PWR—MGMT0寄存器后 200us内不能有任何读写寄存器的操作  
//	return 0;
}



uint8_t icm42670_read_reg(uint8_t reg)
{
	uint8_t regval = 0;
  ICM_SPI_CS_LOW();
	reg |= 0x80;
	spi1_readwritebyte(reg);
	//spi1_readwritebyte(&regval,1);
	spi_receice(&regval,1);
	ICM_SPI_CS_HIGH();
	//gpio_bits_set(GPIOA,GPIO_PINS_4);
	return regval;
}

uint8_t icm42670_read_regs(uint8_t reg, uint8_t* buf, uint16_t len)
{

    reg |= 0x80;
    ICM_SPI_CS_LOW();
    /* 写入要读的寄存器地址 */
    spi1_readwritebyte(reg);
    /* 读取寄存器数据 */
    spi_receice(buf,len);
    ICM_SPI_CS_HIGH();
}


static uint8_t icm42670_write_reg(uint8_t reg, uint8_t value)
{
	uint8_t status;
  ICM_SPI_CS_LOW();
	status = spi1_readwritebyte(reg);
	spi1_readwritebyte(value);
	//spi_receice(&value, 1);
	ICM_SPI_CS_HIGH();
	return status;
	//return 0;
}

int8_t bsp_IcmGetAccelerometer()
{
    uint8_t buffer[6] = {0};

    icm42670_read_regs(ICM42670_ACCEL_XOUT_H, buffer, 6);

    ax =  ((uint16_t)buffer[0] << 8) | buffer[1];
    ay =  ((uint16_t)buffer[2] << 8) | buffer[3];
    az =  ((uint16_t)buffer[4] << 8) | buffer[5];

    ax = (int16_t)(ax * accSensitivity);
    ay = (int16_t)(ay * accSensitivity);
    az = (int16_t)(az * accSensitivity);

    return 0;
}

int8_t bsp_IcmGetGyroscope()
{
    uint8_t buffer[6] = {0};

    icm42670_read_regs(ICM42670_GYRO_XOUT_H, buffer, 6);

    gx = ((uint16_t)buffer[0] << 8) | buffer[1];
    gy = ((uint16_t)buffer[2] << 8) | buffer[3];
    gz = ((uint16_t)buffer[4] << 8) | buffer[5];

    gx = (int16_t)(gx * gyroSensitivity);
    gy = (int16_t)(gy * gyroSensitivity);
    gz = (int16_t)(gz * gyroSensitivity);
    return 0;
}

int8_t bsp_IcmGetRawData()
{
    uint8_t buffer[12] = {0};

    icm42670_read_regs(ICM42670_ACCEL_XOUT_H, buffer, 12);

    ax  = ((uint16_t)buffer[0] << 8)  | buffer[1];
    ay  = ((uint16_t)buffer[2] << 8)  | buffer[3];
    az  = ((uint16_t)buffer[4] << 8)  | buffer[5];
    gx = ((uint16_t)buffer[6] << 8)  | buffer[7];
    gy = ((uint16_t)buffer[8] << 8)  | buffer[9];
    gz = ((uint16_t)buffer[10] << 8) | buffer[11];

    ax = (int16_t)(ax * accSensitivity);
    ay = (int16_t)(ay * accSensitivity);
    az = (int16_t)(az * accSensitivity);

    gx = (int16_t)(gx * gyroSensitivity);
    gy = (int16_t)(gy * gyroSensitivity);
    gz = (int16_t)(gz * gyroSensitivity);

    return 0;
}

//int8_t bsp_IcmGetRawData(icm42670RawData_t* accData, icm42670RawData_t* GyroData)
//{
//    uint8_t buffer[12] = {0};

//    icm42670_read_regs(ICM42670_ACCEL_XOUT_H, buffer, 12);

//    ax = accData->x  = ((uint16_t)buffer[0] << 8)  | buffer[1];
//    ay = accData->y  = ((uint16_t)buffer[2] << 8)  | buffer[3];
//    az = accData->z  = ((uint16_t)buffer[4] << 8)  | buffer[5];
//    gx = GyroData->x = ((uint16_t)buffer[6] << 8)  | buffer[7];
//    gy = GyroData->y = ((uint16_t)buffer[8] << 8)  | buffer[9];
//    gz = GyroData->z = ((uint16_t)buffer[10] << 8) | buffer[11];

//    ax = accData->x = (int16_t)(accData->x * accSensitivity);
//    ay = accData->y = (int16_t)(accData->y * accSensitivity);
//    az = accData->z = (int16_t)(accData->z * accSensitivity);

//    gx = GyroData->x = (int16_t)(GyroData->x * gyroSensitivity);
//    gy = GyroData->y = (int16_t)(GyroData->y * gyroSensitivity);
//    gz = GyroData->z = (int16_t)(GyroData->z * gyroSensitivity);

//    return 0;
//}

float bsp_Icm42670GetAres(uint8_t Ascale)
{
    switch(Ascale)
    {
    // Possible accelerometer scales (and their register bit settings) are:
    // 2 Gs (00), 4 Gs (01), 8 Gs (10), and 16 Gs  (11).
    case AFS_2G:
        accSensitivity = 2000 / 32768.0f;
        break;
    case AFS_4G:
        accSensitivity = 4000 / 32768.0f;
        break;
    case AFS_8G:
        accSensitivity = 8000 / 32768.0f;
        break;
    case AFS_16G:
        accSensitivity = 16000 / 32768.0f;
        break;
    }

    return accSensitivity;
}

float bsp_Icm42670GetGres(uint8_t Gscale)
{
    switch(Gscale)
    {    
    case GFS_250DPS:
        gyroSensitivity = 250.0f / 32768.0f;
        break;
    case GFS_500DPS:
        gyroSensitivity = 500.0f / 32768.0f;
        break;
    case GFS_1000DPS:
        gyroSensitivity = 1000.0f / 32768.0f;
        break;
    case GFS_2000DPS:
        gyroSensitivity = 2000.0f / 32768.0f;
        break;
    }
    return gyroSensitivity;
}

icm42670.h

#ifndef __ICM42670_H__
#define __ICM42670_H__


#include <stdint.h>
#include "stdio.h"
#include "at32f421.h"

#define ICM42670_DEVICE_CONFIG              0x01
#define ICM42670_DRIVE_CONFIG1              0x03
#define ICM42670_DRIVE_CONFIG2              0x04
#define ICM42670_DRIVE_CONFIG3              0x05
#define ICM42670_INT_CONFIG                 0x06
#define ICM42670_FIFO_CONFIG1               0x28
#define ICM42670_FIFO_CONFIG2               0x29
#define ICM42670_FIFO_CONFIG3               0x2A
//#define ICM42670_TEMP_DATA1                 0x09
//#define ICM42670_TEMP_DATA0                 0x0A
#define ICM42670_SIGNAL_PATH_RESET          0x02
#define ICM42670_INT_SOURCE0                0x2B
#define ICM42670_INT_SOURCE1                0x2C
#define ICM42670_INT_SOURCE3                0x2D
#define ICM42670_INT_SOURCE4                0x2E
#define ICM42670_WHO_AM_I   0x75

#define AFS_2G  0x03
#define AFS_4G  0x02
#define AFS_8G  0x01
#define AFS_16G 0x00  // default

#define GFS_2000DPS   0x00 // default
#define GFS_1000DPS   0x01
#define GFS_500DPS    0x02
#define GFS_250DPS    0x03


#define AODR_1600Hz   0x05
#define AODR_800Hz    0x06 // default
#define AODR_400Hz    0x07
#define AODR_200Hz    0x08
#define AODR_100Hz    0x09
#define AODR_50Hz     0x0A
#define AODR_25Hz     0x0B
#define AODR_12_5Hz   0x0C
#define AODR_6_25Hz   0x0D
#define AODR_3_125Hz  0x0E
#define AODR_1_5625Hz 0x0F


#define GODR_1600Hz  0x05
#define GODR_800Hz   0x06 // default
#define GODR_400Hz   0x07
#define GODR_200Hz   0x08
#define GODR_100Hz   0x09
#define GODR_50Hz    0x0A
#define GODR_25Hz    0x0B
#define GODR_12_5Hz  0x0C


#define ICM42670_GYRO_CONFIG0       0x20
#define ICM42670_ACCEL_CONFIG0      0x21
#define ICM42670_GYRO_CONFIG1       0x23
//#define ICM42670_GYRO_ACCEL_CONFIG0 0x52
#define ICM42670_ACCEL_CONFIG1      0x24

#define DEVICE_CONFIG     0x01
#define DRIVE_CONFIG3     0x05

#define ICM42670_ACCEL_XOUT_H 0x0B
#define ICM42670_ACCEL_XOUT_L 0x0C
#define ICM42670_ACCEL_YOUT_H 0x0D
#define ICM42670_ACCEL_YOUT_L 0x0E
#define ICM42670_ACCEL_ZOUT_H 0x0F
#define ICM42670_ACCEL_ZOUT_L 0x10

#define ICM42670_GYRO_XOUT_H 0x11
#define ICM42670_GYRO_XOUT_L 0x12
#define ICM42670_GYRO_YOUT_H 0x13
#define ICM42670_GYRO_YOUT_L 0x14
#define ICM42670_GYRO_ZOUT_H 0x15
#define ICM42670_GYRO_ZOUT_L 0x16

//#define SELF_TEST_CONFIG 0X70

#define ICM42670_PWR_MGMT0  0x1F //电源管理,典型值:0x00(正常启用)

#define ICM_SPI_CS_LOW()             gpio_bits_reset(GPIOA, GPIO_PINS_4)
#define ICM_SPI_CS_HIGH()            gpio_bits_set(GPIOA, GPIO_PINS_4)


typedef struct {
  int16_t x; /**< Raw int16_t value from the x axis */
  int16_t y; /**< Raw int16_t value from the y axis */
  int16_t z; /**< Raw int16_t value from the z axis */
} icm42670RawData_t;


float bsp_Icm42670GetAres(uint8_t Ascale);
float bsp_Icm42670GetGres(uint8_t Gscale);

//void GPIO_Init(void);
void spi1_init(void);
uint8_t spi1_readwritebyte(uint8_t dat);
//uint8_t icm42670_readwritebyte(uint8_t dat);
void ICM42670_Init(void);
uint8_t icm42670_read_reg(uint8_t reg);
uint8_t icm42670_read_regs(uint8_t reg, uint8_t* buf, uint16_t len);
static uint8_t icm42670_write_reg(uint8_t reg, uint8_t value);
int8_t bsp_IcmGetAccelerometer();
int8_t bsp_IcmGetGyroscope();
int8_t bsp_IcmGetRawData();
//int8_t bsp_IcmGetRawData(icm42670RawData_t *accData,icm42670RawData_t *GyroData);


#endif

 姿态角代码

icmupdate.c

#include <math.h>


#define Kp 10.0f                  // 这里的KpKi是用于调整加速度计修正陀螺仪的速度
#define Ki 0.008f

#define halfT 0.05f             // 采样周期的一半,用于求解四元数微分方程时计算角增量

float q0 = 1, q1 = 0, q2 = 0, q3 = 0;    // 初始位置姿态角为:0、0、0,对应四元数为:1、0、0、0

float exInt = 0, eyInt = 0, ezInt = 0;    
//重力加速度在三轴上的分量与用当前姿态计算得来的重力在三轴上的分量的误差的积分

float  Q_ANGLE_X= 0, Q_ANGLE_Y = 0, Q_ANGLE_Z = 0;   

//互补滤波函数
//输入参数:g表陀螺仪角速度(弧度/s),a表加计(m/s2或g都可以,会归一化)
void IMUupdate(float gx, float gy, float gz, float ax, float ay, float az)
{

	float q0temp,q1temp,q2temp,q3temp;//四元数暂存变量,求解微分方程时要用
	float norm; //矢量的模或四元数的范数
	float vx, vy, vz;//当前姿态计算得来的重力在三轴上的分量
	float ex, ey, ez;//当前加计测得的重力加速度在三轴上的分量
	//与用当前姿态计算得来的重力在三轴上的分量的误差

	float q0q0 = q0*q0;
	float q0q1 = q0*q1;
	float q0q2 = q0*q2;
	float q1q1 = q1*q1;
	float q1q3 = q1*q3;
	float q2q2 = q2*q2;
	float q2q3 = q2*q3;
	float q3q3 = q3*q3;
	if(ax*ay*az==0)//加计处于自由落体状态时不进行姿态解算,因为会产生分母无穷大的情况
		return;
	norm = sqrt(ax*ax + ay*ay + az*az);//单位化加速度计,
	ax = ax / norm;// 这样变更了量程也不需要修改KP参数,因为这里归一化了
	ay = ay / norm;
	az = az / norm;
	
	//用当前姿态计算出重力在三个轴上的分量,重力在n系下是[0,0,g],乘以转换矩阵就转到b系
	//参考坐标n系转化到载体坐标b系,用四元数表示的方向余弦矩阵第三行即是
	vx = 2*(q1q3 - q0q2);
	vy = 2*(q0q1 + q2q3);
	vz = q0q0 - q1q1 - q2q2 + q3q3 ;
	
	//计算测得的重力与计算得重力间的误差,这个误差是通过向量外积(也就是叉乘)求出来的
	ex = (ay*vz - az*vy) ;
	ey = (az*vx - ax*vz) ;
	ez = (ax*vy - ay*vx) ;

	exInt = exInt + ex * Ki;  //对误差进行积分
	eyInt = eyInt + ey * Ki;
	ezInt = ezInt + ez * Ki;
	
	gx = gx + Kp*ex + exInt;  //将误差PI(比例和积分项)补偿到陀螺仪角速度
	gy = gy + Kp*ey + eyInt;
	gz = gz + Kp*ez + ezInt;  //没有磁力计的话就无法修正偏航角
	
	//下面进行姿态的更新,也就是四元数微分方程的求解
	q0temp=q0;
	q1temp=q1;
	q2temp=q2;
	q3temp=q3;
	//采用一阶毕卡解法,相关知识可参见《惯性器件与惯性导航系统》P212
	q0 = q0temp + (-q1temp*gx - q2temp*gy -q3temp*gz)*halfT;
	q1 = q1temp + (q0temp*gx + q2temp*gz -q3temp*gy)*halfT;
	q2 = q2temp + (q0temp*gy - q1temp*gz +q3temp*gx)*halfT;
	q3 = q3temp + (q0temp*gz + q1temp*gy -q2temp*gx)*halfT;
	
	//单位化四元数在空间旋转时不会拉伸,仅有旋转角度,这类似线性代数里的正交变换
	norm = sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
	q0 = q0 / norm;
	q1 = q1 / norm;
	q2 = q2 / norm;
	q3 = q3 / norm;
	
	//四元数到欧拉角的转换
	//其中YAW航向角由于加速度计对其没有修正作用,因此此处直接用陀螺仪积分代替
	Q_ANGLE_Z = Q_ANGLE_Z + gz*halfT*2*57.3; // yaw
	//Q_ANGLE_Z = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3;
	Q_ANGLE_Y = asin(-2 * q1 * q3 + 2 * q0* q2)*57.3; // pitch
	Q_ANGLE_X = atan2(2 * q2 * q3 + 2 * q0 * q1,-2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // roll
}

 mian.c

int main(void)
{
	
	spi1_init();
  //system_clock_config();
  at32_board_init();
  uart_print_init(9600);
  ICM42670_Init();
  /* output a message on hyperterminal using printf function */
  
  while(1)
  {
		//printf("usart printf counter: %x\r\n", icm42670_read_reg(0x75));
		bsp_IcmGetAccelerometer();
    printf("2.AccX:%d-AccY:%d-AccZ:%d\r\n",ax,ay,az);

    bsp_IcmGetAccelerometer();
    printf("3.GyroX:%d-GyroY:%d-GyroZ:%d\r\n",gx,gy,gz);

    bsp_IcmGetRawData();
    printf("4.AccX:%d-AccY:%d-AccZ:%d-GyroX:%d-GyroY:%d-GyroZ:%d\r\n",ax,ay,az,gx,gy,gz);
    //bsp_IcmGetRawData(&stAccData,&stGyroData);
    //printf("4.AccX:%d-AccY:%d-AccZ:%d-GyroX:%d-GyroY:%d-GyroZ:%d\r\n",stAccData.x,stAccData.y,stAccData.z,stGyroData.x,stGyroData.y,stGyroData.z);

		IMUupdate((float)gx*500/57.3/65536, (float)gy*500/57.3/65536, (float)gz*500/57.3/65536,
							(float)ax*9.8/16384, (float)ay*9.8/16384, (float)az*9.8/16384);
		printf("pitch:%.2f roll:%.2f yaw:%.2f\r\n",Q_ANGLE_X,Q_ANGLE_Y,Q_ANGLE_Z);
    delay_sec(1);
  }
}

串口显示

AT32F421C8T7利用SPI读取ICM42670原始数据并得到姿态角,单片机 完整代码连接

AT32ICM42zitai-单片机文档类资源-CSDN文库

 文章来源地址https://www.toymoban.com/news/detail-651990.html

 

到了这里,关于AT32F421C8T7利用SPI读取ICM42670原始数据并得到姿态角的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 功耗测评 | STM32F103C8T6

    STM32F103C8T6 MCU越来越广泛的应用在生产生活的各个领域,外接丰富的传感器、功能模块、通信模块、显示存储等可以形成各种可样的产品项目应用。对于功耗要求比较高的产品,一般会选择STM32L系列的MCU,但是从功耗的评测角度,逻辑上是基本相似的。 在很多应用场合中都对

    2024年02月07日
    浏览(33)
  • STM32F103C8T6板子介绍

    STM32简介 STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器 STM32常应用在嵌入式领域,如智能车、无人机、机器人、无线通信、物联网、工业控制、娱乐电子产品等 STM32功能强大、性能优异、片上资源丰富、功耗低,是一款经典的嵌入式微控制器。  STM32F103C8T6 F1XX片上资源

    2024年02月11日
    浏览(38)
  • STM32F103C8T6串口通信

      首先来看一下需要操作的函数,以及配置的步骤: 图1                                                  图2   Code: usart.c #include \\\"usart.h\\\" void ustart_Init(void ) { GPIO_InitTypeDef GPIO_Init_Ustar ; // 定义输出端口TX的结构体对象 USART_InitTypeDef USTART_Init; // 定义串口初始化结构体对象

    2024年02月16日
    浏览(39)
  • [STM32F103C8T6]ADC转换

    什么是ADC转换? ADC转换的全称是: Analog-to-Digital Converter ,指模拟 / 数字转换器 ADC的性能指标: ADC分辨率: SSA与VREF-一起接到地,DDA与VREF+接到3.3v,所以ADC转换的范围是0---3.3v 所以最后的ADC转换值应该是我们的测量值*分辨率    分辨率 = 3.3v/2^12 = (3.3/4096)   12位的转换器所

    2024年02月06日
    浏览(38)
  • STM32F103C8T6串口调试篇

    项目开发中,当出现bug时,由于不知道某个变量的值,所以很难定位问题,针对此问题,串口调试脱颖而出。通过串口printf()实时将需要显示的信息打印出来,这样就很方便的定位问题。 串口设置方法 1.购买调试器pwlink2。参考STM32F103C8T6程序烧录方法_stm32f103c8t6如何烧录_流

    2024年02月12日
    浏览(46)
  • STM32F103C8T6 按键扫描输入

    第一章 STM32F103C8T6 点亮LED灯 系列文章目录 前言 一、原理  1.按键类型  2.按键消抖 3.IO口输入配置 1)模拟输出 2)浮空输入模式 3)下拉输入模式(PULL DOWN) 4)上拉输入模式(PULL UP) 二、代码部分 main.c key.c key.h 总结         上一章我们成功入门了STM32F103C8T6,今天我们来

    2023年04月23日
    浏览(66)
  • STM32F103C8T6移植FreeRTOS

    根据自己开发板型号下载地址:STM32相关内容下载地址 SDK直接下载地址:STM32直接下载地址 下载参考博客 FreeROTS下载地址 选用V9.0.0 版本 个人创建目录如下,可做参考 keil目录 链接头文件 • 修改堆栈大小 • 修改中断函数名 去掉stm32f10x_it.c终端函数 增加FreeRTOS中断 特别解释

    2024年02月12日
    浏览(40)
  • stm32f103c8t6的外部中断

    在单片机中存在着中断系统,这个系统的逻辑和功能在51单片机中已经有所了解。 1.在32单片机中的内核有一个nvic 里面存放许多优先级的设定,外接许多中断源,比如“exti、tim、adc、usart等”接入之后,nvic再通过中断优先级进行排队,再内接入cpu中进行处理,这样子大大减少

    2024年02月09日
    浏览(40)
  • STM32F103C8T6 点亮LED灯

    一、开发板介绍 二、程序实现 1.配置函数 2.程序源码 main.c LED.c LED.h 总结​​​​​​​ 前言         今天我们开始来学习一下STM32F103Z8T6 点灯。这块芯片可用的IO口资源十分丰富,可用的通用IO口为32个 (注意:是在使用ST_LINK 和 J_LINK的情况下) 。这块芯片的操作方法与正

    2024年02月05日
    浏览(65)
  • STM32F103C8T6制作USB键盘

            1、原因:电脑每次开机都需要输入登录密码,感觉很麻烦,就想着能不能用单片机做一个USB键盘,按一下自动给电脑发一串密码实现开机。后来又想,其实不用按键也行,用延时,延时到电脑开机再发送密码就好了,于是便有了这个制作。         2、 功能:将做好

    2024年01月22日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包