mspm0G3507与ATK-IMU901十轴陀螺仪模块结合使用指南(附Keil源码)
开始:硬件连接
源代码链接:链接:https://pan.baidu.com/–s/1m69UXBf2TM__1FVuUxfPgA?pwd=nhcu
提取码:nhcu
自己去掉中间的“–”,防和谐
电赛来临,相比大家已经做好了很多的准备,我本来使用的是普通的6050陀螺仪,但是发现这个的静态偏差挺大的,所以想着用一个好一点的陀螺仪就买了正点原子的这个陀螺仪。
我使用的是mspm0g3507,但是正点原子并没有给出相应的代码所以就需要自己去移植,自己琢磨了一下,难度不是很高,但是要去翻手册,想必很多萌新都不太愿意去看(也有可能是因为找不到哈哈)就出了这个教程。(L1306理论上也是可以使用的,串口稍微有点区别)
其中我自己遇到了一个问题,因为一次性接受的数据很多,而且有时候发送过来并没有接收就会导致串口FIFO接收满了导致OVERRUN_ERROR(串口接收溢出错误),stm32有很多相关的教程,但是g3507几乎没有,在我翻了driverlib的库和一些stm32的解决办法后将他解决了,就在修改UART.C文件标题里面。话不多说,开始教程吧!
首先我们准备正点原子的陀螺仪模块,如下图
然后将模块的tx 和rx 与我们开发板的串口相连接(tx连接我们主板的rx,rx连接我们主板的tx)
我使用的是串口3(pa13(rx)和pa14(tx),每个人设置的不一样可能有差别)如下图所示
引脚配置:串口3
sysconfig引脚配置如图所示
波特率可以自行修改,interrupt configuration必须是overrun error(接收溢出错误)和receive(接收)两个中断!!!
代码移植:
正点原子代码
开始之前先将串口3的中断进行使能,不然没法用
我们首先要得到一份正点原子官方的代码文件:如下图所示(百度直接搜索正点原子资料下载或者问客服要就行)
路径:
然后我们将精英stm32f103压缩包解压得到一个文件夹,点进去之后进入Drivers这个文件夹下面的BSP,我们会看到以下几个文件夹
拷贝文件:
我们将ATK_MS901M整个文件夹拷贝到你自己的工程下面去!!里面是有四个文件的!!!
添加.c和.h文件
在keil中去添加.c和.h文件(这个不会的话去看野火的stm32教程,开始就讲了,这里就不多说了)
添加好的文件(我是编译过的,前面有个小加号,最开始编译要报很多的错误,先不要编译)
修改UART.h文件
仔细看一下两个.c文件,atk_ms901.c文件里面都是一些功能函数,和陀螺仪读取数据相关的,我们不用去管它(包括atk_ms901.h也不用去管),我们把重点放在(后续为了方便将atk_ms901_uart.c和atk_ms901_uart.h统一叫做uart.c和uart.h)uart.c和uart.h的文件上面
首先我们打开uart.h文件,将引脚定义的代码全部都注释掉,这是基于hal库写的,我们有sysconfig,使能什么的都已经帮我们做好了(缓冲区大小你们没必要写我这么大,原来不变就行)
修改UART.C文件
uart.c文件里面我们主要是要修改以下几个函数
void atk_ms901m_uart_send(uint8_t *dat, uint8_t len)
{
HAL_UART_Transmit(&g_uart_handle, dat, len, HAL_MAX_DELAY);
}
/**
* @brief ATK-MS901M UART初始化
* @param baudrate: UART通讯波特率
* @retval 无
*/
void atk_ms901m_uart_init(uint32_t baudrate)
{
g_uart_handle.Instance = ATK_MS901M_UART_INTERFACE; /* ATK-MS901M UART */
g_uart_handle.Init.BaudRate = baudrate; /* 波特率 */
g_uart_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 数据位 */
g_uart_handle.Init.StopBits = UART_STOPBITS_1; /* 停止位 */
g_uart_handle.Init.Parity = UART_PARITY_NONE; /* 校验位 */
g_uart_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */
g_uart_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */
g_uart_handle.Init.OverSampling = UART_OVERSAMPLING_16; /* 过采样 */
HAL_UART_Init(&g_uart_handle); /* 使能ATK-MS901M UART
* HAL_UART_Init()会调用函数HAL_UART_MspInit()
* 该函数定义在文件usart.c中
*/
g_uart_rx_fifo.size = ATK_MS901M_UART_RX_FIFO_BUF_SIZE; /* UART接收FIFO缓冲大小 */
g_uart_rx_fifo.reader = 0; /* UART接收FIFO读指针 */
g_uart_rx_fifo.writer = 0; /* UART接收FIFO写指针 */
}
/**
* @brief ATK-MS901M UART中断回调函数
* @param 无
* @retval 无
*/
void ATK_MS901M_UART_IRQHandler(void)
{
uint8_t tmp;
if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_ORE) != RESET) /* UART接收过载错误中断 */
{
__HAL_UART_CLEAR_OREFLAG(&g_uart_handle); /* 清除接收过载错误中断标志 */
(void)g_uart_handle.Instance->SR; /* 先读SR寄存器,再读DR寄存器 */
(void)g_uart_handle.Instance->DR;
}
if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_RXNE) != RESET) /* UART接收中断 */
{
HAL_UART_Receive(&g_uart_handle, &tmp, 1, HAL_MAX_DELAY); /* UART接收数据 */
atk_ms901m_uart_rx_fifo_write(&tmp, 1); /* 接收到的数据,写入UART接收FIFO */
}
}
修改后的函数:
void atk_ms901m_uart_send(char *dat, uint8_t len)
{
//HAL_UART_Transmit(&g_uart_handle, dat, len, HAL_MAX_DELAY);
//当前字符串地址不在结尾 并且 字符串首地址不为空
while(*dat!=0&&dat!=0)
{
//发送字符串首地址中的字符,并且在发送完成之后首地址自增
uart3_send_char(*dat++);
}
}
/**
* @brief ATK-MS901M UART初始化
* @param baudrate: UART通讯波特率
* @retval 无
*/
void atk_ms901m_uart_init(uint32_t baudrate)
{
g_uart_rx_fifo.size = ATK_MS901M_UART_RX_FIFO_BUF_SIZE; /* UART接收FIFO缓冲大小 */
g_uart_rx_fifo.reader = 0; /* UART接收FIFO读指针 */
g_uart_rx_fifo.writer = 0; /* UART接收FIFO写指针 */
}
/**
* @brief ATK-MS901M UART中断回调函数
* @param 无
* @retval 无
*/
void UART_3_INST_IRQHandler(void)
{
uint8_t tmp;
switch( DL_UART_getPendingInterrupt(UART_3_INST) )
{
case DL_UART_IIDX_OVERRUN_ERROR:
DL_UART_getRawInterruptStatus(UART_3_INST,DL_UART_IIDX_OVERRUN_ERROR);
DL_UART_Main_receiveData(UART_3_INST);
break;
case DL_UART_IIDX_RX://如果是接收中断
// 接收发送过来的数据保存
tmp = DL_UART_Main_receiveData(UART_3_INST);
atk_ms901m_uart_rx_fifo_write(&tmp, 1);
break;
default://其他的串口中断
break;
}
DL_UART_clearInterruptStatus(UART_3_INST,DL_UART_IIDX_OVERRUN_ERROR);
}
其中uart3_send_char(*dat++);函数的实现如下
void uart3_send_char(char ch)
{
//当串口3忙的时候等待,不忙的时候再发送传进来的字符
while( DL_UART_isBusy(UART_3_INST) == true );
DL_UART_Main_transmitData(UART_3_INST, ch);
}
在修改完中断回调函数之后请将uart.h文件里面的中断回调函数的名称改掉!!!!
调试:DEMO.C
我们返回刚才的精英stm32f103文件夹,进入Projects->MDK-ARM->atk_f103.uvprojx,打开工程文件之后我们点击demo.c文件,copy其中的有用代码,如下所示:
void demo_run(void)
{
uint8_t ret;
uint8_t key;
/* 初始化 ATK-MS901M */
ret = atk_ms901m_init(115200);
if (ret != 0)
{
printf("ATK-MS901M init failed!\r\n");
delay_ms(1000);
}
//printf("ATK-MS901M init success!\r\n\n");
demo_key0_fun();
delay_ms(10);
}
void demo_key0_fun(void)
{
atk_ms901m_attitude_data_t attitude_dat; /* 姿态角数据 */
atk_ms901m_gyro_data_t gyro_dat; /* 陀螺仪数据 */
atk_ms901m_accelerometer_data_t accelerometer_dat; /* 加速度计数据 */
atk_ms901m_magnetometer_data_t magnetometer_dat; /* 磁力计数据 */
atk_ms901m_barometer_data_t barometer_dat; /* 气压计数据 */
/* 获取ATK-MS901数据 */
atk_ms901m_get_attitude(&attitude_dat, 100); /* 获取姿态角数据 */
atk_ms901m_get_gyro_accelerometer(&gyro_dat, &accelerometer_dat, 100); /* 获取陀螺仪、加速度计数据 */
atk_ms901m_get_magnetometer(&magnetometer_dat, 100); /* 获取磁力计数据 */
atk_ms901m_get_barometer(&barometer_dat, 100); /* 获取气压计数据 */
/* 串口打印数据 */
printf("Roll: %.02f Pitch: %.02f Yaw: %.02f\r\n", attitude_dat.roll, attitude_dat.pitch, attitude_dat.yaw);
printf("Gx: %.02f/s Gy: %.02f/s Gz: %.02f/s\r\n", gyro_dat.x, gyro_dat.y, gyro_dat.z);
printf("Ax: %.02fG Ay: %.02fG Az: %.02fG\r\n", accelerometer_dat.x, accelerometer_dat.y, accelerometer_dat.z);
printf("Mx: %d My: %d Mz: %d, Temp: %.02f\r\n", magnetometer_dat.x, magnetometer_dat.y, magnetometer_dat.z, magnetometer_dat.temperature);
printf("Pres: %dPa Alt: %dcm Temp: %.02f\r\n", barometer_dat.pressure, barometer_dat.altitude, barometer_dat.temperature);
printf("****************************************\r\n\r\n");
}
运行:
然后我们将demo_run()文件放在while循环中就能使用了,效果如下:(打印的初始化错误是错的,实际上没有问题,我懒得去修改了),可以看见有很多参数,这就是这款陀螺仪的好处,参数很多,角度,加速度,还有磁力计,四元数,气压,海拔高度等
作者:Aufstiegen aus Ruine