1. IMU601联动0.96’OLED

3.1 接线

        由于IMU601需要使用3.3V供电,OLED可使用3.3V或5V供电,STM32F103ZET6可供使用的3.3V引脚仅剩余一个,故两个外设分别接入3.3V和5V电源供电。具体接线对应引脚图如下:

图 3‑1 外设接线引脚对应图

3.2 源码分析

由官方给出的源码资料《ATK-MS601M模块测试实验》中的《精英STM32F103开发板》可知,该代码的demo.c文件负责几个模块功能的实现,包括:LCD UI初始化、LCD显示相关数据信息、Key0获取数据以及具体的运行函数。

3.3 修改OLED函数定义

由于LCD与OLED存在部分引脚连接以及所使用的库不尽相同,若要在OLED上进行数据的显示,需要先对LCD的相关代码进行更改。因此我先从OLED的源码中将以下库函数加入到IMU601的源码中:atk_md0096.c、atk_md0096.h、atk_md0096_8080.c、atk_md0096_8080.h、atk_md0096_font.h。

再于demo.c文件中包含库函数:

#include "./BSP/ATK_MD0096/atk_md0096.h"

第二部需要修改函数定义,将lcd的函数定义更改为oled,具体代码如下:

static void demo_oled_ui_init(void)

{

atk_md0096_init();

    atk_md0096_oled_show_string(0,  0, ATK_MD0096_OLED_FONT_SIZE_16, "Roll :  00.00", ATK_MD0096_OLED_SHOW_MODE_NORMAL); 

    atk_md0096_oled_show_string(0, 20, ATK_MD0096_OLED_FONT_SIZE_16, "Pitch:  00.00", ATK_MD0096_OLED_SHOW_MODE_NORMAL); 

    atk_md0096_oled_show_string(0, 40, ATK_MD0096_OLED_FONT_SIZE_16, "Yaw  :  00.00", ATK_MD0096_OLED_SHOW_MODE_NORMAL);

    atk_md0096_oled_update();

}

这几行代码包括了对oled的初始化、显示字符以及更新显存三项内容。

3.4 对IMU601模块传输的数据进行处理

再接下来,需要定义函数demo_show_data_oled来接收从IMU601模块传来的数据并进行处理,包括数据转换、判断正负、四舍五入、符号处理、处理整数部分、处理小数部分等几个部分,具体代码如下:

static void demo_show_data_oled(atk_ms601m_attitude_data_t *attitude_dat)

{

        /* 声明变量tmp_rolltem_pitchtem_yaw,将得到的rollpitch以及yaw浮点数*100转换为整数 */

        /* (condition ? value_iftrue : value_if_flase的功能是,如果condition为真,则表达式的结果为前者,反之为后者,在该代码中即表示结构体的联合体指针attitude_dat中的rollpitchyaw成员是否<0,进而对原数进行±0.5) */

    int32_t tmp_roll = (int32_t)(attitude_dat->roll * 100 + (attitude_dat->roll < 0 ? -0.5 : 0.5));

    int32_t tmp_pitch = (int32_t)(attitude_dat->pitch * 100 + (attitude_dat->pitch < 0 ? -0.5 : 0.5));

int32_t tmp_yaw = (int32_t)(attitude_dat->yaw * 100 + (attitude_dat->yaw < 0 ? -0.5 : 0.5));

/* 声明变量大小为2的数组用来存储符号,\0为字符串结束符 */

    char roll_sign[2] = {tmp_roll < 0 ? '-' : ' ', '\0'};

    char pitch_sign[2] = {tmp_pitch < 0 ? '-' : ' ', '\0'};

char yaw_sign[2] = {tmp_yaw < 0 ? '-' : ' ', '\0'};

/* 声明变量大小为3的数组用来存储整数 */

    char roll_integer[3];

    char pitch_integer[3];

char yaw_integer[3];

/* snprintf可防止缓冲区溢出,包括目标字符数组integer(整数)、缓冲区大小、格式化字符串以及取绝对值后除100四个参数 */

        snprintf(roll_integer, sizeof(roll_integer), "%02d", abs(tmp_roll)/100);

        snprintf(pitch_integer, sizeof(pitch_integer), "%02d", abs(tmp_pitch)/100);

        snprintf(yaw_integer, sizeof(yaw_integer), "%02d", abs(tmp_yaw)/100);

       

    char roll_decimal[3];

    char pitch_decimal[3];

char yaw_decimal[3];

    snprintf(roll_decimal, sizeof(roll_decimal), "%02d", abs(tmp_roll)%100);

    snprintf(pitch_decimal, sizeof(pitch_decimal), "%02d", abs(tmp_pitch)%100);

snprintf(yaw_decimal, sizeof(yaw_decimal), "%02d", abs(tmp_yaw)%100);

/* 符号处理 */

atk_md0096_oled_show_string(48, 0, ATK_MD0096_OLED_FONT_SIZE_16, roll_sign, ATK_MD0096_OLED_SHOW_MODE_NORMAL);         

atk_md0096_oled_show_string(48, 20, ATK_MD0096_OLED_FONT_SIZE_16, pitch_sign, ATK_MD0096_OLED_SHOW_MODE_NORMAL);

atk_md0096_oled_show_string(48, 40, ATK_MD0096_OLED_FONT_SIZE_16, yaw_sign, ATK_MD0096_OLED_SHOW_MODE_NORMAL);

/* 显示整数 */

atk_md0096_oled_show_string(64, 0, ATK_MD0096_OLED_FONT_SIZE_16, roll_integer, ATK_MD0096_OLED_SHOW_MODE_NORMAL);         

atk_md0096_oled_show_string(64, 20, ATK_MD0096_OLED_FONT_SIZE_16, pitch_integer, ATK_MD0096_OLED_SHOW_MODE_NORMAL);         

atk_md0096_oled_show_string(64, 40, ATK_MD0096_OLED_FONT_SIZE_16, yaw_integer, ATK_MD0096_OLED_SHOW_MODE_NORMAL);

       

       

/* 显示小数 */

atk_md0096_oled_show_string(84, 0, ATK_MD0096_OLED_FONT_SIZE_16, roll_decimal, ATK_MD0096_OLED_SHOW_MODE_NORMAL);

atk_md0096_oled_show_string(84, 20, ATK_MD0096_OLED_FONT_SIZE_16, pitch_decimal, ATK_MD0096_OLED_SHOW_MODE_NORMAL);

atk_md0096_oled_show_string(84, 40, ATK_MD0096_OLED_FONT_SIZE_16, yaw_decimal, ATK_MD0096_OLED_SHOW_MODE_NORMAL);

/* 显示’ */

    atk_md0096_oled_show_string(100, 0, ATK_MD0096_OLED_FONT_SIZE_16, "'", ATK_MD0096_OLED_SHOW_MODE_NORMAL);

    atk_md0096_oled_show_string(100, 20, ATK_MD0096_OLED_FONT_SIZE_16, "'", ATK_MD0096_OLED_SHOW_MODE_NORMAL);

    atk_md0096_oled_show_string(100, 40, ATK_MD0096_OLED_FONT_SIZE_16, "'", ATK_MD0096_OLED_SHOW_MODE_NORMAL);

}

3.5 显示数据的函数定义

定义一个函数demo_key0_fun用于获取数据,具体包括姿态角数据、陀螺仪数据以及加速度计数据,并且在OLED上显示数据,代码如下:

static void demo_key0_fun(void)

{

        /* 由于在头文件attk_ms601m.h中已经声明了姿态角、陀螺仪以及加速度计的数据结构,因此在此处可以直接声明传感器结构体数据函数 */

atk_ms601m_attitude_data_t attitude_dat;

atk_ms601m_gyro_data_t gyro_dat;

atk_ms601m_accelerometer_data_t accelerometer_dat;

/* 获取601数据,包括姿态角、陀螺仪以及加速度计 */

atk_ms601m_get_attitude(&attitude_dat, 100);

atk_ms601m_get_gyro_accelerometer(&gyro_dat, &accelerometer_dat, 100);

/*OLED显示数据*/

demo_show_data_oled(&attitude_dat);

/* 串口打印数据 */

    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("****************************************\r\n\r\n");

}

3.6 入口函数的定义以及运行

定义函数demo_run来进行对IMU数据的存储、初始化状态显示于OLED、初始化IMU601、报错显示、UI初始化、主动读取传感器数据以及按键读取传感器数据几个部分,具体代码如下:

void demo_run(void)

{

    uint8_t ret;

uint8_t key;

/* 定义数据结构体来存储IMU601数据 */

        atk_ms601m_attitude_data_t attitude_dat;

       

        /* 初始化OLED状态显示 */

        atk_md0096_init();

    atk_md0096_oled_clear();

    atk_md0096_oled_show_string(0, 0, ATK_MD0096_OLED_FONT_SIZE_16, "Initializing...", ATK_MD0096_OLED_SHOW_MODE_NORMAL);

atk_md0096_oled_update();

/* 初始化IMU601 */

ret = atk_ms601m_init(115200);

/* 报错显示 */

if (ret != 0)

{

        atk_md0096_oled_clear();

        atk_md0096_oled_show_string(0, 0, ATK_MD0096_OLED_FONT_SIZE_16, "ERROR:", ATK_MD0096_OLED_SHOW_MODE_NORMAL);

        atk_md0096_oled_show_string(0, 20, ATK_MD0096_OLED_FONT_SIZE_16, "MS601M Not Found", ATK_MD0096_OLED_SHOW_MODE_NORMAL);

        atk_md0096_oled_update();

                 /* LED0灯闪烁 */

        while (1)

        {

            LED0_TOGGLE();

            delay_ms(500);

        }

    }

   

printf("ATK-MS601M init success!\r\n\n");

/* OLEDUI初始化 */

demo_oled_ui_init();

/* 分两种方式读取IMU601数据 */

    while (1)

{

                /* 主动读取数据 */

                 if(atk_ms601m_get_attitude(&attitude_dat, 100) == 0)

                 {

                         demo_show_data_oled(&attitude_dat);

                         atk_md0096_oled_update();

                 }

                

                /* 按键更新读取数据 */

                 key = key_scan(0);

        switch (key)

        {

            case KEY0_PRES:

            {

                /* 获取并且显示IMU601数据 */

                demo_key0_fun();

                break;

            }

            default:

            {

                break;

            }

        }

        delay_ms(50);

        }

}

        至此,完成IMU601模块以及OLED模块的联动,效果图如图所示:

图 3‑2 IMU601联动OLED

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐