基于MAX78000的运动游戏机
——《基于MAX78000的运动姬》的最终版
序言
在我看到这次活动之后,首先对活动使用的MAX78000FTHR开发板进行了初步了解,发现MAX78000是一款基于Arm® Cortex® M4F的处理器,这引起了我浓厚的学习兴趣。为了弥补没有使用过Arm系列处理器的遗憾,决定参加本次活动。
在具体项目内容方面,考虑到开发环境的限制(笔记本训练太慢),决定放弃硬件的卷积神经网络 (CNN) 加速器的使用。把目标集中到MP3和运动传感器,经过对两个方向相关资料的查阅,决定先从相对容易的“运动传感器数据采集分析(存SD卡内)”,做一个运动游戏机。
板卡介绍
MAX78000FTHR为快速开发平台,帮助工程师利用MAX78000 Arm® Cortex® M4F处理器快速实施超低功耗、人工智能(AI)方案,器件集成卷积神经网络加速器。评估板包括MAX20303 PMIC,用于电池和电源管理。评估板规格为0.9in x 2.6in、双排连接器,兼容Adafruit Feather Wing外设扩展板。评估板包括各种外设,例如CMOS VGA图像传感器、数字麦克风、低功耗立体声音频CODEC、1MB QSPI SRAM、micro SD存储卡连接器、RGB指示LED和按键。
MAX78000微控制器
- 双核:Arm Cortex-M4 FPU处理器,100MHz;RISC-V协处理器,60MHz
- 512KB闪存
- 128KB SRAM
- 16KB缓存
- 卷积神经网络加速器
- 12位并行摄像头接口
- MAX20303可穿戴PMIC,带电量计
- 通过USB充电
- 板载DAPLink调试和编程(MAX32625)
- Arm Cortex-M4 FPU处理器接口
- 兼容面包板的连接头
- Micro USB连接器
- Micro SD卡连接器
- 集成外设
- RGB指示LED
- 用户按钮
- CMOS VGA图像传感器(OVM769)
- 低功耗、立体声音频编解码器(MAX9867)
- SPH0645LM4H-B数字麦克风
- SWD调试器
- 虚拟UART控制台
- 10引脚Cortex调试接头,用于RISC-V协处理器
项目目标及里程碑
- 实现字符串写入SD卡。已完成。
- 实现传感器数据读取和解析。已完成。
- 设计游戏屏幕的UI界面和触摸操作。已完成。
- 设计游戏后台运行程序。已完成。
- 系统联调。已完成。
资料收集
FatFs——通用的FAT文件系统模块
(取自http://elm-chan.org/fsw/ff/00index_e.html)
FatFs是用于小型嵌入式系统的通用FAT/exFAT文件系统模块。FatFs模块是按照ANSI C (C89)编写的,完全与磁盘I/O层分离。因此,它独立于平台。可集成到资源有限的小型微控制器中,如8051、PIC、AVR、ARM、Z80、RX等。
应用程序接口
FatFs为应用程序提供如下所示的各种文件系统功能。
文件访问
- f_open—打开/创建文件
- f_close—关闭打开的文件
- f_read—从文件中读取数据
- f_write—将数据写入文件
- f_lseek -移动读写指针,扩大大小
- f_truncate -截断文件大小
- f_sync -刷新缓存数据
- f_forward—将数据转发到流
- f_expand—为文件分配一个连续块
- f_gets -读取字符串
- f_putc -写一个字符
- f_puts -写一个字符串
- f_printf -写入格式化字符串
- f_tell -获取当前读/写指针
- f_eof -测试文件结束符
- f_size -获取大小
- f_error -测试错误
目录访问
- f_opendir—打开目录
- f_closedir—关闭打开的目录
- f_readdir—读取目录项
- f_findfirst—打开一个目录并读取匹配的第一个项
- f_findnext—读取匹配的下一个项
“文件和目录管理”
- f_stat -检查文件或子目录是否存在
- f_unlink -删除文件或子目录
- f_rename -重命名/移动文件或子目录
- f_chmod—修改文件或子目录的属性
- f_utime—修改文件或子目录的时间戳
- f_mkdir—创建子目录
- f_chdir—更改当前目录
- f_chdrive—更改当前驱动器
- f_getcwd -检索当前目录和驱动器
卷管理和系统配置
- f_mount—注册/注销卷的工作区
- f_mkfs—在逻辑驱动器上创建FAT卷
- f_fdisk -在物理磁盘上创建分区
- f_getfree—获取卷上的空闲空间
- f_getlabel—获取卷标签
- f_setlabel—设置卷标签
- f_setcp -设置活动代码页
JY60产品介绍
产品概述
该产品是基于MEMS技术的高性能三维运动姿态测量系统。它包含三轴陀螺仪、三轴加速度计。通过集成各种高性能传感器和运用自主研发的姿态动力学核心算法引擎,结合高动态卡尔曼滤波融合算法,为客户提供高精度、高动态、实时补偿的三轴姿态角度,通过对各类数据的灵活选择配置,满足不同的应用场景。领先的基于 Kalman 滤波原理并具有自主知识产权的传感器融合算法,可以实时提供高达 20Hz 更新率的数据,从而满足各种高精度的应用需求,实现准确的动作捕捉和姿态估计。拥有国内领先的高精度转台设备仪器,产品内部集成自主研发的高精度校准和标定算法,提高产品的测量精度。同时提供用户所需要的各种上位机、使用说明、开发手册、开发代码,使得针对各类需求的研发时间降至最低。
产品特点
- 模块集成高精度的陀螺仪、加速度计,采用高性能的微处理器和先进的动力学解算与卡尔曼动态滤波算法,能够快速求解出模块当前的实时运动姿态。
- 采用先进的数字滤波技术,能有效降低测量噪声,提高测量精度。
- 模块内部集成了姿态解算器,配合动态卡尔曼滤波算法,能够在动态环境下准确输出模块的当前姿态,姿态测量精度2°,稳定性极高,性能甚至优于某些专业的倾角仪。
- 模块内部自带电压稳定电路,工作电压3~5V,引脚电平兼容3.3V/5V的嵌入式系统,连接方便。
- 支持串口,串口速率9600bps不可调,
- 输出内容固定,输出速率20Hz。
- 采用邮票孔镀金工艺,可嵌入用户的PCB板中。
- 4层PCB板工艺,更薄、更小、更可靠。
参数指标
加速度计参数
参数 |
条件 |
典型值 |
量程 |
|
±16g |
分辨率 |
±16g |
0.0005(g/LSB) |
RMS噪声 |
带宽=100Hz |
0.75~1mg-rms |
静止零漂 |
水平放置 |
±20~40mg |
温漂 |
-40°C ~ +85°C |
±0.15mg/℃ |
带宽 |
|
5~256Hz |
陀螺仪参数
参数 |
条件 |
典型值 |
量程 |
|
±2000°/s |
分辨率 |
±2000°/s |
0.061(°/s)/(LSB) |
RMS噪声 |
带宽=100Hz |
0.005(°/s) |
静止零漂 |
水平放置 |
±0.5~1°/s |
温漂 |
-40°C ~ +85°C |
±0.005~0.015 (°/s)/℃ |
带宽 |
|
5~256Hz |
俯仰、横滚角参数
参数 |
条件 |
典型值 |
量程 |
|
X:±180° |
Y:±90° |
||
倾角精度 |
|
0.2° |
分辨率 |
水平放置 |
0.0055° |
温漂 |
-40°C ~ +85°C |
±0.5~1° |
航向角参数
参数 |
条件 |
典型值 |
量程 |
|
Z:±180° |
航向精度 |
6轴算法,静态 |
0.5°(动态存在积分累计误差) |
分辨率 |
水平放置 |
0.0055° |
注:
【1】在有些震动环境下,会有累计误差,具体误差不可估计,具体根据实际测试为准
模组参数
基本参数
参数 |
条件 |
最小值 |
默认 |
最大值 |
通信接口 |
UART |
9600bps |
9600bps |
9600bps |
输出内容 |
|
3轴加速度、3轴角速度、3轴角度 |
||
输出速率 |
|
20HZ |
20HZ |
20HZ |
工作温度 |
|
-40℃ |
|
85℃ |
存储温度 |
|
-40℃ |
|
100℃ |
耐冲击 |
|
|
|
20000g |
电气参数
参数 |
条件 |
最小值 |
默认 |
最大值 |
供电电压 |
|
3.3V |
5V |
5.5V |
工作电流 |
工作(5V) |
|
10mA |
|
休眠(5V) |
|
10uA |
|
产品尺寸
引脚定义及连接
引脚说明
引脚序号 |
引脚名称 |
引脚功能 |
1 |
D0 |
NC 预留端口 |
2 |
VCC |
模块电源3.3~5V |
3 |
RX |
串行数据输入,TTL 电平 |
4 |
TX |
串行数据输出,TTL 电平 |
5 |
GND |
地线 |
6 |
SWIM |
SWIM 数据接口 |
7 |
D2 |
NC 预留端口 |
8 |
VCC |
模块电源3.3~5V |
9 |
SCL |
NC 预留端口 |
10 |
SDA |
NC 预留端口 |
11 |
GND |
地线 |
12 |
D3 |
NC 预留端口 |
模块UART与MCU连接
JY60通信协议
读格式
数据是按照16进制方式发送的,不是ASCII码。
每个数据分低字节和高字节依次传送,二者组合成一个有符号的short类型的数据。例如数据DATA1,其中DATA1L为低字节,DATA1H为高字节。转换方法如下:假设DATA1为实际的数据,DATA1H为其高字节部分,DATA1L为其低字节部分,
那么:DATA1=(short)((short)DATA1H<<8|DATA1L)。这里一定要注意DATA1H需要先强制转换为一个有符号的short类型的数据以后再移位,并且DATA1的数据类型也是有符号的short类型,这样才能表示出负数。
协议头 |
数据内容 |
数据低8位 |
数据高8位 |
数据低8位 |
数据高8位 |
数据低8位 |
数据高8位 |
数据低8位 |
数据高8位 |
SUMCRC |
0x55 |
TYPE【1】 |
DATA1L[7:0] |
DATA1H[15:8] |
DATA2L[7:0] |
DATA2H[15:8] |
DATA3L[7:0] |
DATA3H[15:8] |
DATA4L[7:0] |
DATA4H[15:8] |
SUMCRC【2】 |
【1】TYPE(数据内容):
TYPE |
备注 |
0x51 |
加速度 |
0x52 |
角速度 |
0x53 |
角度 |
【2】SUMCRC(数据和校验):
SUMCRC=0x55+TYPE+DATA1L+DATA1H+DATA2L+DATA2H+DATA3L+DATA3H+DATA4L+DATA4H
SUMCRC为char型,取校验和的低8位
加速度输出
0x55 |
0x51 |
AxL |
AxH |
AyL |
AyH |
AzL |
AzH |
TL |
TH |
SUM |
名称 |
描述 |
备注 |
AxL |
加速度X低8位 |
加速度X=((AxH<<8)|AxL)/32768*16g (g为重力加速度,可取9.8m/s2) |
AxH |
加速度X高8位 |
|
AyL |
加速度Y低8位 |
加速度Y=((AyH<<8)|AyL)/32768*16g (g为重力加速度,可取9.8m/s2) |
AyH |
加速度Y高8位 |
|
AzL |
加速度Z低8位 |
加速度Z=((AzH<<8)|AzL)/32768*16g (g为重力加速度,可取9.8m/s2) |
AzH |
加速度Z高8位 |
|
TL |
温度低8位 |
温度计算公式: 温度=((TH<<8)|TL) / 32768 * 96.38 + 36.53 |
TH |
温度高8位 |
|
SUM |
校验和 |
SUM=0x55+0x51+AxL+AxH+AyL+AyH+AzL+AzH+TL+Th |
角速度输出
0x55 |
0x52 |
WxL |
WxH |
WyL |
WyH |
WzL |
WzH |
VolL |
VolH |
SUM |
名称 |
描述 |
备注 |
WxL |
角速度X低8位 |
角速度X=((WxH<<8)|WxL)/32768*2000°/s |
WxH |
角速度X高8位 |
|
WyL |
角速度Y低8位 |
角速度Y=((WyH<<8)|WyL)/32768*2000°/s |
WyH |
角速度Y高8位 |
|
WzL |
角速度Z低8位 |
角速度Z=((WzH<<8)|WzL)/32768*2000°/s |
WzH |
角速度Z高8位 |
|
VolL |
电压低8位 |
(非蓝牙产品,该数据无效)电压计算公式: 电压=((VolH<<8)|VolL) /100 ℃ |
VolH |
电压高8位 |
|
SUM |
校验和 |
SUM=0x55+0x52+WxL+WxH+WyL+WyH+WzL+WzH+VolH+VolL |
角度输出
0x55 |
0x53 |
RollL |
RollH |
PitchL |
PitchH |
YawL |
YawH |
VL |
VH |
SUM |
名称 |
描述 |
备注 |
RollL |
滚转角X低8位 |
滚转角X=((RollH<<8)|RollL)/32768*180(°) |
RollH |
滚转角X高8位 |
|
PitchL |
俯仰角Y低8位 |
俯仰角Y=((PitchH<<8)|PitchL)/32768*180(°) |
PitchH |
俯仰角Y高8位 |
|
YawL |
偏航角Z低8位 |
偏航角Z=((YawH<<8)|YawL)/32768*180(°) |
YawH |
偏航角Z高8位 |
|
VL |
版本号低8位 |
版本号计算公式: (注意:无版本号数据) 版本号=(VH<<8)|VL |
VH |
版本号高8位 |
|
SUM |
校验和 |
SUM=0x55+0x53+RollH+RollL+PitchH+PitchL+YawH+YawL+VH+VL |
已经实现内容简介
在本工程中的连接方式:
JY60引脚名称 |
MAX78000FTHR引脚名称 |
VCC |
3V3 |
RX |
UART2_TX |
TX |
UART2_RX |
GND |
GND |
在本工程中的通信方式:
MAX78000FTHR的UART2来接收JY60的数据,将数据存入一个66字节的环形存储空间。
由于JY60的数据共计33字节,所以总能找到需要的部分。本工程使用数据中的角度部分,格式如下
0x55 |
0x53 |
RollL |
RollH |
PitchL |
PitchH |
YawL |
YawH |
VL |
VH |
SUM |
在环形存储空间中找0x55 0x53,将共计11个字节放入一个数组中,对其进行校验,无误后进行解算,将结果通过MAX78000FTHR调试串口打印和写入SD卡。
本工程主要使用如下几个函数
- f_open—打开/创建文件
- f_close—关闭打开的文件
- f_lseek -移动读写指针,扩大大小
- f_printf -写入格式化字符串
将传感器的的角度值解算出来以字符的形式存入SD卡中。
结果如下:
文件名: senserlog.txt
文本中第一列名称: Angle
第二列数据序号: ( 4a0f) :
第三列α角度: -10
第四列β角度: 8
第五列γ角度: -13
仍在构思的内容
游戏如何进行屏幕显示、触摸的交互?
游戏的运行规则?
整个设备运行时如何均衡任务?
硬件设计
硬件构成有三部分:运动传感器(JY60)、主控板(max78000、TF卡)、显示屏。
各个模块之间通过串口来通信。
六轴运动传感器与MAX78000的UART2连接,波特率是9600。
显示屏与MAX78000的UART0连接,波特率是115200。
硬件框图如下:
实物照片:
软件设计
主控软件主要有以下几个部分:运动传感器数据读取、SDHC卡记录数据、屏幕刷新、RTC时间读取等。
初始化完成后,程序将一直运行在这个while中
while (1)
{
printf("\nstep----------0");
subclk_100ms = RTC_Polling()%100/10;
printf("\nstep----------1");
MXC_UART_TransactionDMA(&read_req);
/*-------------------write senser log into SDHC --------*/
if(T_log == 100)
{
senserlog();
T_log = 0;
printTime();
printf("step----------6\n");
}
/*-------------------update display--------*/
if((subclk_100ms == 0)&&(subclk_temp != 0))
{
subclk_temp = subclk_100ms;
printf("\nstep----------2");
}
else
{
memcpy(&RxtempA,&RxData,66);
for(i = 0; i < BUFF_SIZE_66byte/2; i++ )
{
printf("%x\t",RxtempA[i]);
if((RxtempA[i] == 0x55)&&(RxtempA[i+1] == 0x51))
{
memcpy(&stcAngle,&RxtempA[i+11+11+2],8);
}
}
user_car = (int)(((float )stcAngle.Angle[0])/32768*180);
subclk_temp = HMI_run(subclk_100ms,subclk_temp,user_car);//run my car
}
printf("\nstep----------5");
}
subclk_100ms是一个从RTC获取的100ms的节拍,用来实现屏幕定时刷新,SDHC卡定时记录数据等。
senserlog();是SDHC卡记录运动传感器数据的函数。记录格式如下
f_printf(&file,"@%02d:%02d:%02d:%02d\t", day, hr, min, sec);
@日:时:分:秒 是时间戳,可以显示记录数据的时间,也可以在之后的查看中来排查问题。
f_printf(&file,"Angle\t(%10x)\t:\t%9d\t%9d\t%9d\t%9d\n",j++,
(int)(((float )stcAngle.Angle[0])/32768*180),
(int)(((float )stcAngle.Angle[1])/32768*180),
(int)(((float )stcAngle.Angle[2])/32768*180),
(int)(((float )stcAngle.Angle[3])/32768*180));
这些是对应运动传感器的三个角度信息和一个温度信息。
存入SDHC卡的运动传感器数据如下:
@00:00:00:19 Angle ( 0) : -41 0 13 -169
@00:00:00:32 Angle ( 1) : 43 0 2 -169
@00:00:00:45 Angle ( 2) : -59 -13 12 -169
@00:00:00:58 Angle ( 3) : -16 -4 5 -169
@00:00:01:11 Angle ( 4) : -35 -2 3 -169
@00:00:01:23 Angle ( 5) : 32 2 -6 -169
@00:00:01:36 Angle ( 6) : -64 -10 2 -169
@00:00:01:49 Angle ( 7) : 73 7 0 -169
memcpy(&RxtempA,&RxData,66);
for(i = 0; i < BUFF_SIZE_66byte/2; i++ )
{
printf("%x\t",RxtempA[i]);
if((RxtempA[i] == 0x55)&&(RxtempA[i+1] == 0x51))
{
memcpy(&stcAngle,&RxtempA[i+11+11+2],8);
}
这一部分是运动传感器串口发来的数据帧的获取。本工程使用数据中的角度部分,格式如下
0x55 |
0x53 |
RollL |
RollH |
PitchL |
PitchH |
YawL |
YawH |
VL |
VH |
SUM |
在环形存储空间中找0x55 0x53,将共计11个字节放入一个数组中,
HMI_run();包括游戏后台逻辑,屏幕刷新等功能。
屏幕界面设计如下:
这个是loading界面,在软件初始化过程中显示这个画面。
这个是RUN界面,显示内容包括玩家车辆、警车、逃脱次数、投降按钮和背景等。整个画面已10FPS的流畅帧率进行刷新。
这个是END界面,当游戏中玩家车辆被警车拦下或按下投降按钮后进入此界面,点击上面图片可以正常进入游戏,界面下方的星星数量是成功逃脱的次数。
存在问题与改进建议
程序中有一些多余的串口打印信息,作用是绕过一些未知原因的bug:打印转义字符会造成console串口发生阻塞。后面可以寻找原因。
致谢
非常感谢硬禾团队提供的这次学习交流的活动,让我有机会也有动力去学习新的技能,培养自己的兴趣。
同时,感谢群里的各位大佬分享自己的心得体会,这让我受益匪浅!
谢谢!