mspm0G3507使用正点原子ATK-IMU901十轴陀螺仪模块的教程(附keil源码)_ms901m
开始:硬件连接
源代码链接:链接: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循环中就能使用了,效果如下:(打印的初始化错误是错的,实际上没有问题,我懒得去修改了),可以看见有很多参数,这就是这款陀螺仪的好处,参数很多,角度,加速度,还有磁力计,四元数,气压,海拔高度等