项目介绍:
本项目使用Arduino开发框架进行开发,通过程序获取三轴传感器的信息,来判断MSP-EXP430F5529LP开发板+扩展板倾斜的方向,从而控制扩展板上的RGB灯显示不同的颜色,并驱动扩展板上的ST7735显示当前的各项数据。当静置开发板和扩展板一段时间后,RGB灯将会周期性的闪烁交替显示。
设计思路:
要实现本项目的功能,需要完成以下几项工作:
- 三轴传感器信息的获取
- ST7735显示屏的控制
- RGB灯的控制
因为习惯用Arduino开发,所以计划用Arduino框架进行开发。但Arduino IDE本身不支持MSP430,而430官方的Energia IDE又年久失修无法使用。
经过了解,PlatformIO能够提供对MSP430的Arduino开发框架的支持,相关的文档地址:https://docs.platformio.org/en/latest/platforms/timsp430.html
所以在VSCode+PlatformIO上,配置好了开发环境,并且找到了以上几项工作的实现方法。
但MSP430的整个工具链环境不是较新的,所以很多现有的第三方库都不能使用,需要好好寻找可以使用的库。
板载的三轴传感器芯片为MMA7660,对应的第三方库为:https://github.com/mcauser/Grove-3Axis-Digital-Accelerometer-1.5g-MMA7660FC,这个库在platformio里面可以直接安装。
板载的ST7735,也只能使用较老的第三方库,可用的为:https://github.com/olikraus/Ucglib_Arduino ,这个库在platformio里面可以直接安装,也可以从git下载了安装使用。不过该库支持板载的ST7735有点小问题,会在右边有一点点的白边。感兴趣的同学,可以调整位移来消除。
RGB灯的控制就比较简单了,通过数字IO端口控制即可。
当通过三轴传感器读取到信息后,克将对应各轴的信息,显示到ST7735屏幕上。
然后,通过XY方向的数据,判断倾斜的情况,从而控制RGB(LED1、LED2、LED3)的显示。
硬件介绍:
本项目使用的硬件,有硬禾提供:
通过开发板的实用手册、原理图来获取对应的GPIO控制信息:
据此得到对照关系图:
从上可以得知:
- 板载三轴传感器为MMA7660FC,使用I2C接口通信,对应的GPIO口为:
- SCL:P4.2
- SDA:P4.1
- 因为使用的是硬件I2C,所以在代码中不需要设置改信息,直接使用即可
- 板载ST7735对应的GPIO为:
- LCD_SCL:P3.2
- LCD_SDA:P3.0
- LCD_DCx:P2.7
- LCD_CSn:P2.6
- LCD_RSTn:P3.7
- 该ST7735使用硬件SPI通信,所以SCL、SDA不用在代码中特殊设置即可使用
- 板载RGB三色LED对应的控制GPIO:
- LED1:P2.5
- LED2:P2.4
- LED3:P1.5
因为扩展板提供了上述外设完整的连接和控制线路,所以无需其他辅助,仅使用MSP核心板+扩展板就可以完成全部工作。
实现功能:
基于Arduino开发框架,本项目最终视线了如下的功能:
- 获取三轴传感器的信息,并将其对应的信息分别显示到屏幕和输出到串口
- 通过获取的信息,判断开发板左右倾斜和前后倾斜的情况,通过该情况,来控制LED1、LED2、LED3的实际先许昌
- 当静置开发板30秒以后,将会依次闪烁LED1、LED2、LED3,每个灯每次闪烁三次,然后切换到下一个灯。
- 闪烁的初始间隔时间为100毫秒,如果持续静置,则每个循环中增加5毫秒,直到最大1秒为止。如果检测到三轴传感器达到倾斜位置,则自动恢复根据倾斜方向控制LED的状态。
代码说明:
本项目最终的代码如下:
#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <driverlib.h>
#include "MMA7660.h"
#include "Ucglib.h"
// LED设置
#define LED1 P2_5
#define LED2 P2_4
#define LED3 P1_5
// 最大静置时间
#define REST_TIME_MAX 30
// ST7735定义
Ucglib_ST7735_18x128x160_HWSPI ucg(/*cd=*/P2_7, /*cs=*/P2_6, /*reset=*/P3_7);
// 三轴传感器定义
MMA7660 acc;
// 三轴传感器状态数据
float ax, ay, az;
int8_t x, y, z;
// 三周传感器检测中间变量
int8_t step = 0;
int8_t ix = 0;
int8_t iy = 0;
// 静置时间变量
unsigned long rest_time_count = 0;
unsigned long rest_time_prev = 0;
bool rest_time_status = 0;
// 开发板自身LED状态
bool red_led_status = 0;
// RGB灯索引
uint8_t led_idx = 1;
uint8_t leds_status = 0;
// 延时时间
uint32_t delay_time = 100;
void setup()
{
// disableWatchDog();
// 三轴传感器初始化
acc.init();
// 串口初始化
Serial.begin(115200);
// V-HEAD,关闭加热
pinMode(P1_4, OUTPUT);
digitalWrite(P1_4, LOW);
// 初始化数字IO
pinMode(RED_LED, OUTPUT);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
// 初始化屏幕
ucg.begin(UCG_FONT_MODE_TRANSPARENT);
ucg.clearScreen();
// 设置屏幕字体
ucg.setFont(ucg_font_ncenR12_tr);
// 在屏幕显示坐标名称
ucg.setColor(0, 255, 255, 255);
ucg.setPrintPos(10, 25);
ucg.print("ax:");
ucg.setPrintPos(10, 50);
ucg.print("ay:");
ucg.setPrintPos(10, 75);
ucg.print("az:");
}
void loop()
{
// 获取三周传感器数据
acc.getXYZ(&x, &y, &z);
#if 0
Serial.print("x = ");
Serial.print(x);
Serial.print(", y = ");
Serial.print(y);
Serial.print(", z = ");
Serial.print(z);
#endif
// 获取三周传感加速度器数据
if (acc.getAcceleration(&ax, &ay, &az))
{
Serial.print("get data ok: ");
}
else
{
Serial.print("tiem out: ");
}
Serial.print("accleration of X/Y/Z: ");
Serial.print(ax);
Serial.print(" g, ");
Serial.print(ay);
Serial.print(" g, ");
Serial.print(az);
Serial.print(" g; ");
// Serial.println();
// 依次显示三轴信息
ucg.setColor(0, 0, 0, 0);
ucg.drawBox(50, 0, 75, 25);
ucg.setColor(0, 255, 255, 255);
ucg.setPrintPos(50, 25);
ucg.print((double)ax, 2);
ucg.setColor(0, 0, 0, 0);
ucg.drawBox(50, 25, 75, 25);
ucg.setColor(0, 255, 255, 255);
ucg.setPrintPos(50, 50);
ucg.print((double)ay, 2);
ucg.setColor(0, 0, 0, 0);
ucg.drawBox(50, 50, 75, 25);
ucg.setColor(0, 255, 255, 255);
ucg.setPrintPos(50, 75);
ucg.print((double)az, 2);
// 控制开发板自身LED闪烁
digitalWrite(RED_LED, red_led_status ? HIGH : LOW);
red_led_status = !red_led_status;
// 根据一定阈值检测xy方向的倾斜情况
if (ax > 0.5 && ax < 1.0)
{
ix = 0;
}
else if (ax < -0.5 && ax > -1.0)
{
ix = 2;
}
else
{
ix = 1;
}
if (ay > 0.5 && ay < 1.0)
{
iy = 0;
}
else if (ay < -0.5 && ay > -1.0)
{
iy = 2;
}
else
{
iy = 1;
}
Serial.print("( ");
Serial.print(ix);
Serial.print(", ");
Serial.print(iy);
Serial.print(" )");
if (ix == 1 && iy == 1)
{
if (rest_time_prev > 0)
{
rest_time_count += millis() - rest_time_prev;
}
rest_time_prev = millis();
// 判断是否达到静置时间
if (rest_time_count > REST_TIME_MAX * 1000)
{
rest_time_status = 1;
// 闪烁时间增加
if (delay_time <= 1000)
{
delay_time += 5;
}
}
else
{
rest_time_status = 0;
}
}
else
{
// 未静置,全部清零
rest_time_prev = 0;
rest_time_count = 0;
rest_time_status = 0;
delay_time = 100;
}
Serial.print(" rest_time_count:");
Serial.print(rest_time_count);
Serial.print(" rest_time_status:");
Serial.println(rest_time_status);
// 检查是否静置状态
if (rest_time_status and ix == 1 and iy == 1)
{
// 处于静置状态
if (led_idx == 1 || led_idx == 3 || led_idx == 5)
{
leds_status = 0b100;
}
else if (led_idx == 7 || led_idx == 9 || led_idx == 11)
{
leds_status = 0b010;
}
else if (led_idx == 13 || led_idx == 15 || led_idx == 17)
{
leds_status = 0b001;
}
else
{
leds_status = 0b000;
}
led_idx++;
if (led_idx > 18)
{
led_idx = 1;
}
}
else
{
if (ix == 0 and iy == 0)
{
// 斜角触发
leds_status = 0b001;
}
else if (ix == 0 and iy == 1)
{
// X-左
leds_status = 0b100;
}
else if (ix == 0 and iy == 2)
{
// 斜角触发
leds_status = 0b001;
}
else if (ix == 1 and iy == 0)
{
// Y-前
leds_status = 0b010;
}
else if (ix == 1 and iy == 1)
{
// 全亮
leds_status = 0b111;
}
else if (ix == 1 and iy == 2)
{
// Y-后
leds_status = 0b110;
}
else if (ix == 2 and iy == 0)
{
// 斜角触发
leds_status = 0b001;
}
else if (ix == 2 and iy == 1)
{
// X-右
leds_status = 0b101;
}
else if (ix == 2 and iy == 2)
{
// 斜角触发
leds_status = 0b001;
}
}
// 控制LED
digitalWrite(LED1, leds_status & 0b100 ? !HIGH : !LOW);
digitalWrite(LED2, leds_status & 0b010 ? !HIGH : !LOW);
digitalWrite(LED3, leds_status & 0b001 ? !HIGH : !LOW);
// 延时
delay(delay_time);
// enableWatchDog();
}
上述代码中的注释较为详细,有几个关键点进行说明:
- 各设备的初始化:
- 三轴传感器:MMA7660 acc;
- ST7735:Ucglib_ST7735_18x128x160_HWSPI ucg(/*cd=*/P2_7, /*cs=*/P2_6, /*reset=*/P3_7);
- LED:pinMode(LED1, OUTPUT);
如之前所说,使用的I2C、SPI都是硬件提供,不是软件实现的,所以不用设置其对应的GPIO口。
不过ST7735还有DC、CS、RST接口所以需要进行设置。
ST7735库的主要调用如下:
- 初始化:ucg.begin(UCG_FONT_MODE_TRANSPARENT);
- 清屏:ucg.clearScreen();
- 字体:ucg.setFont(ucg_font_ncenR12_tr);
- 颜色:ucg.setColor(0, 255, 255, 255); // 后三位设置RGB颜色值
- 坐标:ucg.setPrintPos(10, 50); //前者为x,后者为y
- 显示字符:ucg.print("ax:"); // 直接输出字符串
- 显示数字:ucg.print((double)ax, 2); // 输出双精度数据,第二个参数为小数位数
- 画框:ucg.drawBox(50, 0, 75, 25); //前两者为xy坐标,后两者为宽高
MMA7660库主要有3个调用:
- 初始化:acc.init();
- 获取寄存器信息:acc.getXYZ(&x, &y, &z);
- 获取加速度信息:acc.getAcceleration(&ax, &ay, &az)
实际使用主要使用后者的数据进行进一步的处理。
通过获取到的加速度信息,根据ax、ay的情况进行判断,如果达到一定的阈值,则认为处于倾斜状态,并设置对应的LED状态。
代码中,控制LED1、LED2、LED3,使用了一个 leds_status = 0b101; 的方式来设置其值,实际显示的时候,则使用如下的代码:
// 控制LED
digitalWrite(LED1, leds_status & 0b100 ? !HIGH : !LOW);
digitalWrite(LED2, leds_status & 0b010 ? !HIGH : !LOW);
digitalWrite(LED3, leds_status & 0b001 ? !HIGH : !LOW);
这样可以避免在中途写较多的digitalWrite()调用。
另外需要注意的是,需要设置低电平,LED才会点亮,所以以上都是用!取反。
在上述的代码中,当处于持续静置状态的时候,delay_time += 5; 是的闪烁间隔时间边长,最长为1000ms,也就是1秒。
操作步骤:
- 在VSCode的PlatformIO面板中,新建项目,使用MSP430的arduino-blink例子:
- 安装ucglib库支持ST7735:
- 安装MMA7660支持库:
- 不过需要注意的是,该支持库中,有一个结构体属性的定义,与MSP430的寄存器定义冲突了,需要做如下的修改:
- 不过需要注意的是,该支持库中,有一个结构体属性的定义,与MSP430的寄存器定义冲突了,需要做如下的修改:
- 然后编写代码:
- 编写完成后,编译代码验证:
- 最后下载编译后的固件并监听串口:
- 需要注意的是,烧录完成后,到打开串口监听,可能需要间隔较长的时间,请耐心等待。
- 操作开发板+扩展板,观察ST7735显示屏上的信息及对应的状态:
- 倾斜开发板+扩展板,查看RGB灯的状态;
- 静置,然后查看RGB灯的状态