一、项目介绍
本项目实现了一个基于STM32G031的核心模块的扩展板的设计,具有陀螺仪的功能,可以检测加速度,经过设计还可以实现计步器功能(计步器没有采用)。通过一个核心板连接pcb设计的扩展板子,使用SPI协议的oled显示屏和IIC通信的MPU6050,以及蓝牙模块HC05,从而实现一个简单的陀螺仪数据显示功能。
二、项目设计思路(含设计框图)
STM32G031核心板,通过IIC协议采集MPU6050的加速度和陀螺仪数据,并且由USART1发送数据到HC05,由HC05发送数据到手机端口,同时,把采集到的数据显示在显示屏上面。第二个流程:导入库文件,加入结构体,初始化设置,读取IIC数据,输出数据至串口,oled获得数据并显示,led根据时间跳变。
三、搜集素材的思路
首先看到这个尺寸的核心板,然后又因为这次要做扩展板,所以直接就想到了计步器,当然也包括直播课里面使用了mpu6050的影响,然后就是去翻mpu6050的官方资料,然后发现里面有个dmp库,然后就移植,试玩后发现效果不是我想的那样,然后就只取了陀螺仪和加速度的数据,至于显示部分,其实是身边有什么显示屏就用什么,lcd或者串口屏太大了,不符合设计扩展板当初考虑的轻便,再加上查找一些真实案例,做出取舍,综上,得到最后的方案。
讲一下设计到实现的一个大概过程:
1、先有思路,然后去设计,知道要使用什么模块后,分配引脚,大概有个思路
2、引脚分配好后,考虑现有材料的问题,如,核心板无5V,所以若模块需要5V,需要考虑电路
3、想到这点后,三个方法,一、把ch340的5v扒出来,物理破坏,有风险;二、设计一个电路,3.3转5V,考虑到扩展板,取消;三、直接给扩展板单独做一个供电,然后设计一个typec即可,降压使得5和3.3都有。
4、开始设计PCB,考虑到失误率,外接排针出来,这样子既便有一小部分问题,也可也补救。
5、打板,焊接,先测供电,供电正常就可以接模块了,然后调代码。
6、代码部分,首先是oled显示,这个简单,新建个文件夹,把oled.c、oled.h、oledfont.h这三个放进去,然后添加就行
7、移植mpu6050,注:M0+的核,需要解压官网文件,市面上教程都是f1的M3和f4的M4偏多,不要直接移植他们的代码,要移植对应的,libmpllib(就这个名字)。
8、改一部分文件,根据自己的调用调试,这一步根据手册或者教程资料等等操作。
9、先用正常的串口调试助手监测数据,在数据正常之后,移植蓝牙的代码,然后切换,最后完成成品。
四、画原理图、PCB制板过程中遇到的问题,以及解决方法
本次电路图不难,基本上没什么问题,一遍就过了。
1、连接6050的IIC两条线时,没接核心板,然后DRC移到了核心板那个部分,我以为是核心板接错了,然后发现是没把核心板接到模块上。
2、因为引脚的封装问题,由于这个核心板,只需要几个排针就能组好,系统虽然报错,但是丝印或者什么贴到一起的改改就行了。
五、实现结果展示(调试过程中遇到什么问题)
调试基本上没遇到什么太大的问题,也就是代码做了些东西,展示的话,主要是如下几个功能:mpu6050的数据、oled的显示、扩展板单独的供电、HC05的显示
1、数据,调试时,通过串口就可以知道结果了,VOFA采集如下:
2、oled显示,代码调试时是数字,后面因为小数,改一下显示三位数,如下:
3、单独供电,这个比较简单,降压给两个模块,原先供电给HC054、蓝牙端口的截图:
9.08补充修改:
1、PCB正反面图+焊接后
2、实物未上电
3、上电后的实物
六、关键代码及说明
1、头文件,需要添加oled和mpu6050的库
//头文件包含,其中要移植mpu6050和oled的驱动
#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"
#include "oled.h"
#include "mpu6050.h"
#include <stdio.h>
2、初始化
//这个部分是初始化(注意,oled初始化在时钟后面。两年前刚学oled的时候放的前面,现在想想有点傻)
OLED_Init();
OLED_Clear();
OLED_Display_On();
while (MPU6050_Init(&hi2c2) == 1); MX_GPIO_Init();
MX_I2C2_Init();
MX_USART1_UART_Init();
3、主函数部分,主要都在循环里面
//while循环部分
//前面是MPU6050的数据
MPU6050_Read_All(&hi2c2, &MPU6050);
printf("加速度 x:%.2f \t y:%.2f \t z:%.2f\n",MPU6050.Ax,MPU6050.Ay,MPU6050.Az);
printf("陀螺仪 x:%.2f \t y:%.2f \t z:%.2f\n",MPU6050.Gx,MPU6050.Gy,MPU6050.Gz);
printf("温度 %.2f\n",MPU6050.Temperature);
// 读取加速度
MPU6050_Read_Accel(&hi2c2, &MPU6050);
printf("只更新加速度 x:%.2f \t y:%.2f \t z:%.2f\n",MPU6050.Ax,MPU6050.Ay,MPU6050.Az);
// 读取陀螺仪
MPU6050_Read_Gyro(&hi2c2, &MPU6050);
printf("只更新陀螺仪 x:%.2f \t y:%.2f \t z:%.2f\n",MPU6050.Gx,MPU6050.Gy,MPU6050.Gz);
// 读取温度
MPU6050_Read_Temp(&hi2c2, &MPU6050);
printf("只更新温度 %.2f\n",MPU6050.Temperature);
//这一部分是 oled显示
OLED_ShowString(0,5,"X1:");//显示字符丿
OLED_ShowString(0,25,"Y1:");//显示字符丿
OLED_ShowString(0,45,"Z1:");//显示字符丿
OLED_ShowString(64,5,"X2:");//显示字符丿
OLED_ShowString(64,25,"Y2:");//显示字符丿
OLED_ShowString(64,45,"Z2:");//显示字符丿
//刚开始没用小数,后面反应过来改了。具体操作直接看库里面的函数怎么用就行了,按需操作
// OLED_ShowNumber(18,0,MPU6050.Ax,3,13);//显示数字
// OLED_ShowNumber(18,20,MPU6050.Ay,3,13);//显示数字
// OLED_ShowNumber(18,40,MPU6050.Az,3,13);//显示数字
// OLED_ShowNumber(80,0,MPU6050.Gx,3,13);//显示数字
// OLED_ShowNumber(80,20,MPU6050.Gy,3,13);//显示数字
// OLED_ShowNumber(80,40,MPU6050.Gz,3,13);//显示数字
OLED_ShowFloat(MPU6050.Ax,2,18,0);
OLED_ShowFloat(MPU6050.Ay,2,18,20);
OLED_ShowFloat(MPU6050.Az,2,18,40);
OLED_ShowFloat(MPU6050.Gx,2,80,0);
OLED_ShowFloat(MPU6050.Gy,2,80,20);
OLED_ShowFloat(MPU6050.Gz,2,80,40);
OLED_Refresh_Gram();//刷新
//翻转led
// HAL_Delay(100);
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);//点亮led
HAL_Delay(500);
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);//熄灭LED
4、oled库
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNumber(u8 x,u8 y,u32 num,u8 len,u8 size)
{
u8 t,temp;
u8 enshow=0;
for(t=0;t<len;t++)
{
temp=(num/oled_pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(size/2)*t,y,' ',size,1);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(size/2)*t,y,temp+'0',size,1);
}
}
//显示字符串
//x,y:起点坐标
//*p:字符串起始地址
//用16字体
void OLED_ShowString(u8 x,u8 y,const u8 *p)
{
#define MAX_CHAR_POSX 122
#define MAX_CHAR_POSY 58
while(*p!='\0')
{
if(x>MAX_CHAR_POSX){x=0;y+=16;}
if(y>MAX_CHAR_POSY){y=x=0;OLED_Clear();}
OLED_ShowChar(x,y,*p,12,1);
x+=8;
p++;
}
}
//显示浮点数字
//x,y :起点坐标
//value :要显示的值
//decimalPlaces,小数点后位数,
// 显示浮点数函数
void OLED_ShowFloat(float value, uint8_t decimalPlaces, uint8_t x, uint8_t y)
{
char buffer[16];
// 将浮点数转换为字符串格式,并指定小数位数
snprintf(buffer, sizeof(buffer), "%.*f", decimalPlaces, value);
// 在指定位置显示字符串
for (uint8_t i = 0; i < strlen(buffer); i++)
{
OLED_ShowChar(x + i * 8, y, buffer[i], 16, 1);
}
}
七、STM32G031核心模块的优势与局限
1、个人觉得,这个核心模块的下载方式很麻烦,每次要重新加载,都要断开串口,然后BOOT重新连接。(如果有解决方法更好)
2、外设数量少,首先接了一个ch340下载,那就让本不丰富的引脚雪上加霜
3、资源少,时钟速度慢,这个在需要高速场合下估计难绷
4、优势也挺多的,首先是尺寸,非常mini,这个尺寸非常适合去做小尺寸的功能,类似计步器,手表,等等。
5、虽然BOOT我觉得麻烦,但是这种不需要stlink的,使用CH340串口下载的方式还是相对方便的。
6、低功耗, STM32G031系列的微控制器设计用于低功耗应用。具有多种低功耗模式,可延长电池寿命,适用于电池供电的设备。
7、丰富的外设: 既便IO少,但是STM32G031仍具有丰富的外设,包括通信接口(如SPI、I2C、USART等)、模拟模块(如ADC和DAC)以及定时器等,使其适用于各种应用领域。
8、集成的安全功能: 一些型号具有硬件加密模块,可用于增强系统的安全性。(查资料才知道的)
9、丰富的开发生态系统: STMicroelectronics提供了丰富的开发工具和支持文档,以帮助开发人员快速开始项目。(资料确实算全)
10、存储容量有限,一些型号的Flash存储容量相对较小,可能不适用于需要大量存储空间的应用。
11、内核性能有限, 尽管Cortex-M0+内核足够用于许多应用,但对于需要更高性能的应用,可能需要考虑更强大的微控制器。
八、原理图/PCB图(放在项目附件)
九、可编译下载的代码(放在项目的附件,用于验证)
见附件
