硬禾项目
项目介绍
- 利用拓展板上的三轴加速度传感器,将读出传感器的数值显示在屏幕上
- 使用三轴加速度控制RGB彩灯出现不同颜色
- 在板子静置30秒后,要求彩灯规律周期变化
设计思路
- 使用FreeRTOS进行模块化处理
- LCD终端显示任务
- LED显示任务
- 加速度计任务
- 加速度计任务
加速度计芯片选用恩智浦公司研发的MMA7600FC,其输出协议为数字I²C,可实现采样频率从每秒1次到120次,拥有3轴1.5 g MEMS传感器和CMOS接口控制器集成在同一个封装中。
在加速度计任务中,使用100Hz的频率对三轴加速度数据进行持续读取,范围为[-32,31],同时对外提供加速度数据接口以供其他任务访问加速度计数据。
- LCD终端显示任务
LCD屏幕驱动采用ST7789芯片,使用4线SPI进行通信。屏幕分辨率为128x128像素,我们配置选择为262K 16位真彩模式。对基本数字和字符按照屏幕显示配置取模,存放于C文件中以数组形式保存。在实现字符显示时,根据ASCII码对数据进行查找选择,使用绘点的方式对字符数组进行逐个绘制,从而显示在屏幕上。该任务以50Hz的频率运行,循环读取三轴加速度接口,将其使用sprintf函数转换为字符串显示并打印在屏幕上。
- LED显示任务
LED为三通道RGB彩灯,可使用PWM模式对彩灯亮度进行控制以实现各种颜色的组合。该任务以50Hz的频率运行,读取加速度计接口提供的数据,将其最大最小归一化后,映射到RGB三通道各自的PWM占空比上,以实现将板子朝向不同摆放时,手持板子转到不同方位彩灯颜色跟随变化。 同时,对加速度数据使用滑动时间窗口思想,读取相邻两次各轴加速度的差值进行循环限幅,设置波动阈值检测板子是否处于静止状态,在30s后检测到静止状态将对LED灯进行循环规律闪烁。
软件流程图
代码控制思路利用在线流程图绘制网站展示如下:
硬件介绍
- MMA7600FC加速度芯片,由恩智浦公司开发,具有6bit精度的三轴加速度计芯片,使用IIC协议进行数据通信。可实现采样频率从每秒1次到120次,拥有3轴1.5 g MEMS传感器和CMOS接口控制器集成在同一个封装中。
- ST7789芯片,用于单片驱动262K色图像TFTLCD, 包含 7202403色) x 320 线输出,可以直接以SPI协议, 或者8位/9位/16位/18位并行连接外部控制器. 显示数据存储在片内240 320 18 bits内存中, 显示内存的读写不需要外部时钟驱动。
- LED彩灯为RGB三通道彩灯,可进行PWM控制,电路使用MOS管控制,为低电平有效。
- 主控选用ESP32-S2模组,,Xtensa® 32-bit LX7 单核处理器,时钟频率高达 240 MHz,支持多种低功耗工作状态:精细时钟门控、动态电压时钟频率调节,具有完整的IIC和SPI以及PWM函数接口,可在Ubantu环境下使用IDE进行编程,便于用户直接调用,快速配置。
实现的功能
- 将板子朝向不同摆放时,屏幕显示的数字不同。
- 将板子朝向不同摆放时,手持板子转到不同方位彩灯颜色跟随变化。
- 在板子静置30秒后,彩灯的颜色呈现周期变化。
代码说明
- main.c文件
//main.c文件
//主函数任务初始化
mma_task_init();
led_task_init();
lcd_task_init();
- led.c文件
//led.c文件
//led任务
static void led_task(void * arg) {
uint32_t count = 0; //30秒计数器
int8_t x = 0, y = 0, z = 0; //x、y、z轴三轴加速度
while (1) {
count++;
x = get_mma7600fc_x();
y = get_mma7600fc_y();
z = get_mma7600fc_z();
//检测30s内是否振动,是则根据加速度计数值变换彩灯颜色;否则对彩灯颜色
进行周期性变换
if (get_mma7600fc_shake()) {
count = 0;
clear_mma7600fc_shake();
}
if (count >= 30000 / 20) {
led_loop();
vTaskDelay(20 / portTICK_PERIOD_MS);
} else {
set_color(x, y, z);
}
vTaskDelay(20 / portTICK_PERIOD_MS);
}
}
- mma7600fc.c文件
//mma7600fc.c文件
//加速度计任务
static void mma_task(void * arg) {
int8_t pr_x = 0, pr_y = 0, pr_z = 0; //上一次加速度值
int8_t del_x = 0, del_y = 0, del_z = 0; //两次加速度误差值
while (1) {
mma7600fc.x = (int)(MMA7660_GetResult(MMA7660_XOUT) & 0x3f) - 32;
mma7600fc.y = (int)(MMA7660_GetResult(MMA7660_YOUT) & 0x3f) - 32;
mma7600fc.z = (int)(MMA7660_GetResult(MMA7660_ZOUT) & 0x3f) - 32;
//震动检测,需要循环限幅
del_x = loop_caculate(((int) mma7600fc.x - pr_x), -32, 31);
del_y = loop_caculate(((int) mma7600fc.y - pr_y), -32, 31);
del_z = loop_caculate(((int) mma7600fc.z - pr_z), -32, 31);
if (del_x > SHAKE_DELTA || del_y > SHAKE_DELTA || del_z > SHAKE_DELTA) {
mma7600fc.shake = 1;
}
pr_x = mma7600fc.x;
pr_y = mma7600fc.y;
pr_z = mma7600fc.z;
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
- st7789.c文件
//st7789.c文件
//LCD显示任务
static void lcd_task(void * arg) {
int8_t x = 0, y = 0, z = 0;
char show_buffer[128] = {
'\0'
};
while (1) {
//调用接口获取加速度计数值
x = get_mma7600fc_x();
y = get_mma7600fc_y();
z = get_mma7600fc_z();
//制作屏幕显示字符串
sprintf(show_buffer, "X-axis=%d \nY-axis=%d \nZ-axis=%d \n", x, y, z);
//调用屏幕显示函数
lcd_show_string(0, 0, 127, 127, show_buffer, 16, 0);
vTaskDelay(20 / portTICK_PERIOD_MS);
}
}
困难与解决方案
1.LCD部分颜色显示与芯片手册不对应,怀疑是LCD裸屏电路硬件管脚问题,暂时未解决。
2.彩灯PWM通道原先直连在串口0上,对于ESP32来说,串口0是不能定义为其他管脚的,但考虑到题目还要求控制这个彩灯。解决方案:使用杜邦线链接未使用的管脚到LED RGB三个控制管脚上,如下图所示:
3.拓展版下载电路部分,无法自动做到软件重启。调试的时候会导致无法编译调试一条龙,需要点击reset按键进行复位操作。同时每次开发板上电后都需要硬件按键复位代码才能启动。在虚拟机Ubantu系统下调试,频繁的USB口断连与链接或导致USB口偶尔出现异常问题。
改进方案是前期未使用PWM调试LED灯时可以在串口0位置飞线链接一块CH340进行调试,增加调试的流畅度。但考虑到使用LED灯与使用串口相矛盾,因此在调试led灯相关任务时务必不能使用串口进行调试打印。
计划或建议
1.改进拓展板,将LED灯的RGB三个管脚与ESP32՟S2的普通GPIO口相连。
2.选择一款稳定的由ST7789芯片驱动的屏幕对自己写的屏幕驱动做测试,检查颜色显示异常是否是硬件原因,如果不是则进行进一步修改查错。
3.改进拓展版下载电路部分,无法自动做到软件重启。调试的时候会导致无法编译调试一条龙,需要点击reset按键进行复位操作。同时每次开发板上电后都需要硬件按键复位代码才能启动。