RT-Thread Studio学习(十)MPU9250
简介
本文将基于STM32F407VET芯片介绍如何在RT-Thread Studio开发环境下运用9轴传感器MPU9250。
新建RT-Thread项目并使用外部时钟
详细步骤参考文档《RT-Thread Studio学习(一)使用外部时钟系统》。
设置MPU9250的驱动框架
RT-Thread Studio设置 使能如下组件并进行配置: board.h 文件中使能I2C1:
驱动代码的移植
参考正点原子阿波罗F429的MPU9250实验,进行了相应的移植。 首先是直接移植mpu9250.h 和mpu9250.c 文件,修改为app_mpu9250.h 和app_mpu9250.c 。 app_mpu9250.h 代码如下:
#ifndef APPLICATIONS_APP_MPU9250_H_
#define APPLICATIONS_APP_MPU9250_H_
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_soft_i2c.h"
#define MPU9250_ADDR 0X68
#define MPU6500_ID 0X71
#define AK8963_ADDR 0X0C
#define AK8963_ID 0X48
#define MAG_WIA 0x00
#define MAG_CNTL1 0X0A
#define MAG_CNTL2 0X0B
#define MAG_XOUT_L 0X03
#define MAG_XOUT_H 0X04
#define MAG_YOUT_L 0X05
#define MAG_YOUT_H 0X06
#define MAG_ZOUT_L 0X07
#define MAG_ZOUT_H 0X08
#define MPU_SELF_TESTX_REG 0X0D
#define MPU_SELF_TESTY_REG 0X0E
#define MPU_SELF_TESTZ_REG 0X0F
#define MPU_SELF_TESTA_REG 0X10
#define MPU_SAMPLE_RATE_REG 0X19
#define MPU_CFG_REG 0X1A
#define MPU_GYRO_CFG_REG 0X1B
#define MPU_ACCEL_CFG_REG 0X1C
#define MPU_MOTION_DET_REG 0X1F
#define MPU_FIFO_EN_REG 0X23
#define MPU_I2CMST_CTRL_REG 0X24
#define MPU_I2CSLV0_ADDR_REG 0X25
#define MPU_I2CSLV0_REG 0X26
#define MPU_I2CSLV0_CTRL_REG 0X27
#define MPU_I2CSLV1_ADDR_REG 0X28
#define MPU_I2CSLV1_REG 0X29
#define MPU_I2CSLV1_CTRL_REG 0X2A
#define MPU_I2CSLV2_ADDR_REG 0X2B
#define MPU_I2CSLV2_REG 0X2C
#define MPU_I2CSLV2_CTRL_REG 0X2D
#define MPU_I2CSLV3_ADDR_REG 0X2E
#define MPU_I2CSLV3_REG 0X2F
#define MPU_I2CSLV3_CTRL_REG 0X30
#define MPU_I2CSLV4_ADDR_REG 0X31
#define MPU_I2CSLV4_REG 0X32
#define MPU_I2CSLV4_DO_REG 0X33
#define MPU_I2CSLV4_CTRL_REG 0X34
#define MPU_I2CSLV4_DI_REG 0X35
#define MPU_I2CMST_STA_REG 0X36
#define MPU_INTBP_CFG_REG 0X37
#define MPU_INT_EN_REG 0X38
#define MPU_INT_STA_REG 0X3A
#define MPU_ACCEL_XOUTH_REG 0X3B
#define MPU_ACCEL_XOUTL_REG 0X3C
#define MPU_ACCEL_YOUTH_REG 0X3D
#define MPU_ACCEL_YOUTL_REG 0X3E
#define MPU_ACCEL_ZOUTH_REG 0X3F
#define MPU_ACCEL_ZOUTL_REG 0X40
#define MPU_TEMP_OUTH_REG 0X41
#define MPU_TEMP_OUTL_REG 0X42
#define MPU_GYRO_XOUTH_REG 0X43
#define MPU_GYRO_XOUTL_REG 0X44
#define MPU_GYRO_YOUTH_REG 0X45
#define MPU_GYRO_YOUTL_REG 0X46
#define MPU_GYRO_ZOUTH_REG 0X47
#define MPU_GYRO_ZOUTL_REG 0X48
#define MPU_I2CSLV0_DO_REG 0X63
#define MPU_I2CSLV1_DO_REG 0X64
#define MPU_I2CSLV2_DO_REG 0X65
#define MPU_I2CSLV3_DO_REG 0X66
#define MPU_I2CMST_DELAY_REG 0X67
#define MPU_SIGPATH_RST_REG 0X68
#define MPU_MDETECT_CTRL_REG 0X69
#define MPU_USER_CTRL_REG 0X6A
#define MPU_PWR_MGMT1_REG 0X6B
#define MPU_PWR_MGMT2_REG 0X6C
#define MPU_FIFO_CNTH_REG 0X72
#define MPU_FIFO_CNTL_REG 0X73
#define MPU_FIFO_RW_REG 0X74
#define MPU_DEVICE_ID_REG 0X75
int mpu9250_init(void);
rt_err_t mpu9250_write_reg(rt_uint8_t reg,rt_uint8_t data);
rt_err_t mpu9250_read_reg(rt_uint8_t reg,rt_uint8_t *data);
rt_err_t mpu9250_read_regs(rt_uint8_t reg,rt_uint8_t len,rt_uint8_t *buf);
rt_err_t mpu9250_set_gyro_fsr(rt_uint8_t fsr);
rt_err_t mpu9250_set_accel_fsr(rt_uint8_t fsr);
rt_err_t mpu9250_set_lpf(rt_uint16_t lpf);
rt_err_t mpu9250_set_sample_rate(rt_uint16_t rate);
rt_err_t mpu9250_get_temperature(rt_int16_t *temperature);
rt_err_t mpu9250_get_gyroscope(rt_int16_t *gx,rt_int16_t *gy,rt_int16_t *gz);
rt_err_t mpu9250_get_accelerometer(rt_int16_t *ax,rt_int16_t *ay,rt_int16_t *az);
rt_err_t mpu9250_get_magnetometer(rt_int16_t *mx,rt_int16_t *my,rt_int16_t *mz);
rt_err_t mpu_dmp_write_Len(rt_uint8_t addr,rt_uint8_t reg,rt_uint8_t len,rt_uint8_t *date);
rt_err_t mpu_dmp_read_Len(rt_uint8_t addr,rt_uint8_t reg,rt_uint8_t len,rt_uint8_t *buf);
static void mpu9250_sample();
#endif
app_mpu9250.c 代码如下:
#include <rthw.h>
#include <rtdevice.h>
#include "app_mpu9250.h"
#include "drv_soft_i2c.h"
#define MPU9250_I2CBUS_NAME "i2c1"
#if 1
#define MPUDEBUG rt_kprintf
#else
#define MPUDEBUG(...)
#endif
static struct rt_i2c_bus_device *mpu9250_i2c_bus;
rt_err_t mpu_dmp_write_Len(rt_uint8_t addr, rt_uint8_t reg, rt_uint8_t len, rt_uint8_t *date)
{
rt_uint8_t buf[len + 1];
rt_uint8_t i;
buf[0] = reg;
for (i = 0; i < len; i++)
{
buf[i + 1] = date[i];
}
if (rt_i2c_master_send(mpu9250_i2c_bus, addr, 0, buf, len + 1) == len + 1)
return RT_EOK;
else
return -RT_ERROR;
}
rt_err_t mpu_dmp_read_Len(rt_uint8_t addr, rt_uint8_t reg, rt_uint8_t len, rt_uint8_t *buf)
{
struct rt_i2c_msg msgs[2];
msgs[0].addr = addr;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = ®
msgs[0].len = 1;
msgs[1].addr = addr;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = buf;
msgs[1].len = len;
if (rt_i2c_transfer(mpu9250_i2c_bus, msgs, 2) == 2)
return RT_EOK;
else
return -RT_ERROR;
}
rt_err_t mpu9250_write_reg(rt_uint8_t reg, rt_uint8_t data)
{
rt_uint8_t buf[2];
buf[0] = reg;
buf[1] = data;
if (rt_i2c_master_send(mpu9250_i2c_bus, MPU9250_ADDR, 0, buf, 2) == 2)
return RT_EOK;
else
return -RT_ERROR;
}
rt_err_t mpu9250_write_magnetometer_reg(rt_uint8_t reg, rt_uint8_t data)
{
rt_uint8_t buf[2];
buf[0] = reg;
buf[1] = data;
if (rt_i2c_master_send(mpu9250_i2c_bus, AK8963_ADDR, 0, buf, 2) == 2)
return RT_EOK;
else
return -RT_ERROR;
}
rt_err_t mpu9250_read_reg(rt_uint8_t reg, rt_uint8_t *data)
{
struct rt_i2c_msg msgs[2];
msgs[0].addr = MPU9250_ADDR;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = ®
msgs[0].len = 1;
msgs[1].addr = MPU9250_ADDR;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = data;
msgs[1].len = 1;
if (rt_i2c_transfer(mpu9250_i2c_bus, msgs, 2) == 2)
return RT_EOK;
else
return -RT_ERROR;
}
rt_err_t mpu9250_read_regs(rt_uint8_t reg, rt_uint8_t len, rt_uint8_t *buf)
{
struct rt_i2c_msg msgs[2];
msgs[0].addr = MPU9250_ADDR;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = ®
msgs[0].len = 1;
msgs[1].addr = MPU9250_ADDR;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = buf;
msgs[1].len = len;
if (rt_i2c_transfer(mpu9250_i2c_bus, msgs, 2) == 2)
{
return RT_EOK;
}
else
{
return -RT_ERROR;
}
}
rt_err_t mpu9250_read_magnetometer_regs(rt_uint8_t reg, rt_uint8_t len, rt_uint8_t *buf)
{
struct rt_i2c_msg msgs[2];
msgs[0].addr = AK8963_ADDR;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = ®
msgs[0].len = 1;
msgs[1].addr = AK8963_ADDR;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = buf;
msgs[1].len = len;
if (rt_i2c_transfer(mpu9250_i2c_bus, msgs, 2) == 2)
{
return RT_EOK;
}
else
{
return -RT_ERROR;
}
}
rt_err_t mpu9250_read_magnetometer_reg(rt_uint8_t reg, rt_uint8_t *data)
{
struct rt_i2c_msg msgs[2];
msgs[0].addr = AK8963_ADDR;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = ®
msgs[0].len = 1;
msgs[1].addr = AK8963_ADDR;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = data;
msgs[1].len = 1;
if (rt_i2c_transfer(mpu9250_i2c_bus, msgs, 2) == 2)
return RT_EOK;
else
return -RT_ERROR;
}
rt_err_t mpu9250_set_gyro_fsr(rt_uint8_t fsr)
{
return mpu9250_write_reg(MPU_GYRO_CFG_REG, fsr << 3);
}
rt_err_t mpu9250_set_accel_fsr(rt_uint8_t fsr)
{
return mpu9250_write_reg(MPU_ACCEL_CFG_REG, fsr << 3);
}
rt_err_t mpu9250_set_lpf(rt_uint16_t lpf)
{
rt_uint8_t data = 0;
if (lpf >= 188)data = 1;
else if (lpf >= 98)data = 2;
else if (lpf >= 42)data = 3;
else if (lpf >= 20)data = 4;
else if (lpf >= 10)data = 5;
else data = 6;
return mpu9250_write_reg(MPU_CFG_REG, data);
}
rt_err_t mpu9250_set_sample_rate(rt_uint16_t rate)
{
rt_uint8_t data;
if (rate > 1000)rate = 1000;
if (rate < 4)rate = 4;
data = 1000 / rate - 1;
data = mpu9250_write_reg(MPU_SAMPLE_RATE_REG, data);
return mpu9250_set_lpf(rate / 2);
}
rt_err_t mpu9250_get_temperature(rt_int16_t *temperature)
{
rt_uint8_t buf[2];
rt_int16_t raw;
float temp;
rt_err_t ret;
ret = mpu9250_read_regs(MPU_TEMP_OUTH_REG, 2, buf);
if (ret == RT_EOK)
{
raw = ((rt_uint16_t)buf[0] << 8) | buf[1];
temp = 21 + ((double)raw) / 333.87;
*temperature = temp * 100;
return RT_EOK;
}
else
{
return -RT_ERROR;
}
}
rt_err_t mpu9250_get_gyroscope(rt_int16_t *gx, rt_int16_t *gy, rt_int16_t *gz)
{
rt_uint8_t buf[6], ret;
ret = mpu9250_read_regs(MPU_GYRO_XOUTH_REG, 6, buf);
if (ret == 0)
{
*gx = ((rt_uint16_t)buf[0] << 8) | buf[1];
*gy = ((rt_uint16_t)buf[2] << 8) | buf[3];
*gz = ((rt_uint16_t)buf[4] << 8) | buf[5];
return RT_EOK;
}
else
{
return -RT_ERROR;
}
}
rt_err_t mpu9250_get_accelerometer(rt_int16_t *ax, rt_int16_t *ay, rt_int16_t *az)
{
rt_uint8_t buf[6], ret;
ret = mpu9250_read_regs(MPU_ACCEL_XOUTH_REG, 6, buf);
if (ret == 0)
{
*ax = ((rt_uint16_t)buf[0] << 8) | buf[1];
*ay = ((rt_uint16_t)buf[2] << 8) | buf[3];
*az = ((rt_uint16_t)buf[4] << 8) | buf[5];
return RT_EOK;
}
else
{
return -RT_ERROR;
}
}
rt_err_t mpu9250_get_magnetometer(rt_int16_t *mx, rt_int16_t *my, rt_int16_t *mz)
{
rt_uint8_t buf[6], ret;
ret = mpu9250_read_magnetometer_regs(MAG_XOUT_L, 6, buf);
if (ret == 0)
{
*mx = ((rt_uint16_t)buf[0] << 8) | buf[1];
*my = ((rt_uint16_t)buf[2] << 8) | buf[3];
*mz = ((rt_uint16_t)buf[4] << 8) | buf[5];
return RT_EOK;
}
else
{
return -RT_ERROR;
}
}
void usart1_niming_report(rt_uint8_t fun, rt_uint8_t *data, rt_uint8_t len)
{
rt_uint8_t send_buf[32];
rt_uint8_t i;
if (len > 28)return;
send_buf[len + 3] = 0;
send_buf[0] = 0XAA;
send_buf[1] = 0XAA;
send_buf[2] = fun;
send_buf[3] = len;
for (i = 0; i < len; i++)send_buf[4 + i] = data[i];
for (i = 0; i < len + 4; i++)send_buf[len + 4] += send_buf[i];
for (i = 0; i < len + 5; i++)wireless_putchar(send_buf[i]);
}
void mpu6050_send_data(short aacx, short aacy, short aacz, short gyrox, short gyroy, short gyroz)
{
rt_uint8_t tbuf[18];
tbuf[0] = (aacx >> 8) & 0XFF;
tbuf[1] = aacx & 0XFF;
tbuf[2] = (aacy >> 8) & 0XFF;
tbuf[3] = aacy & 0XFF;
tbuf[4] = (aacz >> 8) & 0XFF;
tbuf[5] = aacz & 0XFF;
tbuf[6] = (gyrox >> 8) & 0XFF;
tbuf[7] = gyrox & 0XFF;
tbuf[8] = (gyroy >> 8) & 0XFF;
tbuf[9] = gyroy & 0XFF;
tbuf[10] = (gyroz >> 8) & 0XFF;
tbuf[11] = gyroz & 0XFF;
tbuf[12] = 0;
tbuf[13] = 0;
tbuf[14] = 0;
tbuf[15] = 0;
tbuf[16] = 0;
tbuf[17] = 0;
usart1_niming_report(0X02, tbuf, 18);
}
void usart1_report_imu(short roll, short pitch, short yaw, short csb, int prs)
{
rt_uint8_t tbuf[12];
tbuf[0] = (roll >> 8) & 0XFF;
tbuf[1] = roll & 0XFF;
tbuf[2] = (pitch >> 8) & 0XFF;
tbuf[3] = pitch & 0XFF;
tbuf[4] = (yaw >> 8) & 0XFF;
tbuf[5] = yaw & 0XFF;
tbuf[6] = (csb >> 8) & 0XFF;
tbuf[7] = csb & 0XFF;
tbuf[8] = (prs >> 24) & 0XFF;
tbuf[9] = (prs >> 16) & 0XFF;
tbuf[10] = (prs >> 8) & 0XFF;
tbuf[11] = prs & 0XFF;
usart1_niming_report(0X01, tbuf, 12);
}
void mpu9250_thread_entry(void *parameter)
{
float pitch, roll, yaw;
short *temp;
while (1)
{
mpu9250_get_temperature(*temp);
rt_thread_delay(rt_tick_from_millisecond(200));
}
}
int mpu9250_init(void)
{
rt_uint8_t res;
rt_device_t dev;
rt_thread_delay(rt_tick_from_millisecond(100));
dev = rt_device_find(MPU9250_I2CBUS_NAME);
if (dev == RT_NULL)
{
MPUDEBUG("can't find mpu9250 %s device\r\n", MPU9250_I2CBUS_NAME);
return -RT_ERROR;
}
if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
{
MPUDEBUG("can't opend mpu9250 %s device\r\n", MPU9250_I2CBUS_NAME);
return -RT_ERROR;
}
mpu9250_i2c_bus = (struct rt_i2c_bus_device *)dev;
mpu9250_write_reg(MPU_PWR_MGMT1_REG,0X80);
rt_thread_delay(100);
mpu9250_write_reg(MPU_PWR_MGMT1_REG,0X00);
mpu9250_set_gyro_fsr(3);
mpu9250_set_accel_fsr(0);
mpu9250_set_sample_rate(50);
mpu9250_write_reg(MPU_INT_EN_REG,0X00);
mpu9250_write_reg(MPU_USER_CTRL_REG,0X00);
mpu9250_write_reg(MPU_FIFO_EN_REG,0X00);
mpu9250_write_reg(MPU_INTBP_CFG_REG,0X82);
mpu9250_read_reg(MPU_DEVICE_ID_REG,res);
if(res==MPU6500_ID)
{
mpu9250_write_reg(MPU_PWR_MGMT1_REG,0X01);
mpu9250_write_reg(MPU_PWR_MGMT2_REG,0X00);
mpu9250_set_sample_rate(50);
}else return -RT_ERROR;
return RT_EOK;
}
static void mpu9250_sample()
{
float pitch,roll,yaw;
rt_int16_t aacx,aacy,aacz;
rt_int16_t gyrox,gyroy,gyroz;
rt_int16_t mx,my,mz;
short temp;
mpu9250_get_temperature(temp);
mpu9250_get_accelerometer(&aacx,&aacy,&aacz);
mpu9250_get_gyroscope(&gyrox,&gyroy,&gyroz);
mpu9250_get_magnetometer(mx, my, mz);
rt_kprintf("%d, %d %d %d, %d %d %d, %d %d %d\r\n", temp, aacx, aacy, aacz,
gyrox, gyroy, gyroz, mx, my, mz);
}
rt_err_t mpu9250_read_reg_sample(int argc, char *argv[])
{
rt_uint8_t reg=0;
rt_uint8_t data=0;
if (argc == 2)
{
reg=argv[1];
}
struct rt_i2c_msg msgs[2];
msgs[0].addr = MPU9250_ADDR;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = ®
msgs[0].len = 1;
msgs[1].addr = MPU9250_ADDR;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = data;
msgs[1].len = 1;
if (rt_i2c_transfer(mpu9250_i2c_bus, msgs, 2) == 2)
{
rt_kprintf("addr=0x%2x, data=0x%x \r\n", reg, data);
return RT_EOK;
}
else
return -RT_ERROR;
}
MSH_CMD_EXPORT(mpu9250_sample, mpu9250 sample);
MSH_CMD_EXPORT(mpu9250_read_reg_sample, mpu9250 read reg sample);
在main.c 的main函数主循环中添加测试代码:
mpu9250_get_temperature(temp);
mpu9250_get_accelerometer(&aacx,&aacy,&aacz);
mpu9250_get_gyroscope(&gyrox,&gyroy,&gyroz);
mpu9250_get_magnetometer(&mx, &my, &mz);
rt_kprintf("%d, %d %d %d, %d %d %d, %d %d %d -- c\r\n", temp, aacx, aacy, aacz,
gyrox, gyroy, gyroz, mx, my, mz);
发现能输出原始数据,但这些原始数据不解算的话没有意义,在调用mpu_dmp_init() 函数时发现了很多问题。 经过反复地仔细地阅读正点原子的代码,发现仅仅将其工程下文件夹DMP复制过来是不行的,需要跟多的修改。首先是将其源代码文件复制过来,包括sys.h、sys.c、delay.h、delay.c、myiic.h、myiic.c、mpu9250.h和mpu9250.c文件。其次是studio项目属性中的设置,
添加宏定义如下: 添加include路径: 添加库文件: 上面第三个图是添加库文件,要选择motion_driver_6.12官方原包里下的gcc编译环境对应的库文件(studio是gcc编译,正点原子是keil编译,方式不同),具体路径是“motion_driver_6.12\mpl libraries\arm\gcc4.9.3\liblibmplmpu_m4_hardfp.zip”,解压出来添加到studio项目。特别要注意的是,在添加库的时候,库文件名的前三个字母“lib”需要去掉。
测试
为了在匿名科创地面站V4显示数据波形和飞控状态,串口波特率设置为500000. 修改main 函数,部分代码如下:
int main(void)
{
int count = 1;
u8 t=0,report=1;
u8 key;
float pitch,roll,yaw;
short aacx,aacy,aacz;
short gyrox,gyroy,gyroz;
short mx,my,mz;
short temp;
sd_rw();
mpu9250_init();
if(MPU9250_Init())
{
rt_kprintf("MPU9250_Init failed! \r\n");
}
while(0) {
temp=MPU_Get_Temperature();
MPU_Get_Accelerometer(&aacx,&aacy,&aacz);
MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);
MPU_Get_Magnetometer(&mx, &my, &mz);
rt_kprintf("%d, %d %d %d, %d %d %d, %d %d %d\r\n", temp, aacx, aacy, aacz,
gyrox, gyroy, gyroz, mx, my, mz);
rt_thread_mdelay(200);
mpu9250_get_temperature(temp);
mpu9250_get_accelerometer(&aacx,&aacy,&aacz);
mpu9250_get_gyroscope(&gyrox,&gyroy,&gyroz);
mpu9250_get_magnetometer(&mx, &my, &mz);
rt_kprintf("%d, %d %d %d, %d %d %d, %d %d %d -- c\r\n", temp, aacx, aacy, aacz,
gyrox, gyroy, gyroz, mx, my, mz);
rt_thread_mdelay(200);
}
rt_kprintf("mpu_dmp_init=%d\r\n",mpu_dmp_init());
while(mpu_dmp_init())
{
rt_kprintf("MPU9250 Error\r\n");
rt_thread_mdelay(500);
}
LOG_D("Enter main!\r\n");
while(1)
{
if(mpu_mpl_get_data(&pitch,&roll,&yaw)==0)
{
temp=MPU_Get_Temperature();
MPU_Get_Accelerometer(&aacx,&aacy,&aacz);
MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);
rt_thread_mdelay(10);
if((t%20)==0)
{
rt_kprintf("%d, %d %d %d, %d %d %d\r\n", temp, aacx, aacy, aacz,
gyrox, gyroy, gyroz);
rt_kprintf("%d, %d, %d \r\n", (int)(roll*100),(int)(pitch*100),(int)(yaw*100),0,0);
}
}
t++;
}
while (count++)
{
rt_thread_mdelay(1000);
}
return RT_EOK;
}
系统启动前,需要将MPU9250模块放平。两种IIC方式对比了下,都没有问题。 最后接入匿名科创地面站V4, 这样就可以在数据波形和飞控状态中看到东西了。
总结
本以为移植mpu9250的驱动是最难的,结果发现启用dmp才是最难的。最后为了省事,直接将正点原子的代码文件小改后复制进项目,搞得有点儿不伦不类。
|