用MSP430实现一个加速度传感器控制的彩灯
本项目使用Arduino开发框架进行开发,通过程序获取三轴传感器的信息,来判断开发板+扩展板倾斜的方向,从而控制扩展板上的RGB灯显示不同的颜色,当静置开发板和扩展板一段时间后,RGB灯将会周期性的闪烁交替显示。
标签
嵌入式系统
MSP430
2023寒假在家练
三轴传感器
RGB
ST7735
HonestQiao
更新2023-03-28
522

项目介绍:

本项目使用Arduino开发框架进行开发,通过程序获取三轴传感器的信息,来判断MSP-EXP430F5529LP开发板+扩展板倾斜的方向,从而控制扩展板上的RGB灯显示不同的颜色,并驱动扩展板上的ST7735显示当前的各项数据。当静置开发板和扩展板一段时间后,RGB灯将会周期性的闪烁交替显示。

 

设计思路:

要实现本项目的功能,需要完成以下几项工作:

  1. 三轴传感器信息的获取
  2. ST7735显示屏的控制
  3. 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控制信息:

FkVbSkxmnJ8xmwvu9C-HmT-j0xb9

据此得到对照关系图:

Fg0A9lVHDvlJIuKNW5_WcKthSWCA

从上可以得知:

  1. 板载三轴传感器为MMA7660FC,使用I2C接口通信,对应的GPIO口为:
    1. SCL:P4.2
    2. SDA:P4.1
    3. 因为使用的是硬件I2C,所以在代码中不需要设置改信息,直接使用即可
  2. 板载ST7735对应的GPIO为:
    1. LCD_SCL:P3.2
    2. LCD_SDA:P3.0
    3. LCD_DCx:P2.7
    4. LCD_CSn:P2.6
    5. LCD_RSTn:P3.7
    6. 该ST7735使用硬件SPI通信,所以SCL、SDA不用在代码中特殊设置即可使用
  3. 板载RGB三色LED对应的控制GPIO:
    1. LED1:P2.5
    2. LED2:P2.4
    3. LED3:P1.5

因为扩展板提供了上述外设完整的连接和控制线路,所以无需其他辅助,仅使用MSP核心板+扩展板就可以完成全部工作。

 

实现功能:

基于Arduino开发框架,本项目最终视线了如下的功能:

  1. 获取三轴传感器的信息,并将其对应的信息分别显示到屏幕和输出到串口
  2. 通过获取的信息,判断开发板左右倾斜和前后倾斜的情况,通过该情况,来控制LED1、LED2、LED3的实际先许昌
  3. 当静置开发板30秒以后,将会依次闪烁LED1、LED2、LED3,每个灯每次闪烁三次,然后切换到下一个灯。
  4. 闪烁的初始间隔时间为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();
}

 

上述代码中的注释较为详细,有几个关键点进行说明:

  1. 各设备的初始化:
    1. 三轴传感器:MMA7660 acc;
    2. ST7735:Ucglib_ST7735_18x128x160_HWSPI ucg(/*cd=*/P2_7, /*cs=*/P2_6, /*reset=*/P3_7);
    3. LED:pinMode(LED1, OUTPUT);

如之前所说,使用的I2C、SPI都是硬件提供,不是软件实现的,所以不用设置其对应的GPIO口。

不过ST7735还有DC、CS、RST接口所以需要进行设置。

 

ST7735库的主要调用如下:

  1. 初始化:ucg.begin(UCG_FONT_MODE_TRANSPARENT);
  2. 清屏:ucg.clearScreen();
  3. 字体:ucg.setFont(ucg_font_ncenR12_tr);
  4. 颜色:ucg.setColor(0, 255, 255, 255); // 后三位设置RGB颜色值
  5. 坐标:ucg.setPrintPos(10, 50); //前者为x,后者为y
  6. 显示字符:ucg.print("ax:"); // 直接输出字符串
  7. 显示数字:ucg.print((double)ax, 2); // 输出双精度数据,第二个参数为小数位数
  8. 画框:ucg.drawBox(50, 0, 75, 25); //前两者为xy坐标,后两者为宽高

 

MMA7660库主要有3个调用:

  1. 初始化:acc.init();
  2. 获取寄存器信息:acc.getXYZ(&x, &y, &z);
  3. 获取加速度信息: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秒。

 

操作步骤:

  1. 在VSCode的PlatformIO面板中,新建项目,使用MSP430的arduino-blink例子:
    1. FjbJrNOTT3bKkrRV_OG7a_RSQ3a4
  2. 安装ucglib库支持ST7735:
    1. Fs_AE7h329mEylSjHL0G44EH0EF-
  3. 安装MMA7660支持库:
    1. FnEVxeahpic7jw8X0tiTgSDQnq8K
    2. 不过需要注意的是,该支持库中,有一个结构体属性的定义,与MSP430的寄存器定义冲突了,需要做如下的修改:
      1. Fm0Tfk3Hpt86hRE8RDjvHSKzol2Y
      2. FjRaqaZT0n5amTK2aHQ0oE-V-tfo
  4. 然后编写代码:
    1. Fme5E-LeY25bikXNbmcKzmq-0GEc
  5. 编写完成后,编译代码验证:
    1. Ft5v7w_DxwYjGP_Ar5-eSWDjizE8
  6. 最后下载编译后的固件并监听串口:
    1. FhCalDVanoFFLw-UtaKRpTVEttLn
    2. 需要注意的是,烧录完成后,到打开串口监听,可能需要间隔较长的时间,请耐心等待。
  7. 操作开发板+扩展板,观察ST7735显示屏上的信息及对应的状态:
    1. 倾斜开发板+扩展板,查看RGB灯的状态;
    2. 静置,然后查看RGB灯的状态
    3. FhSL9PNQ4SAELusUExFHMFLytPOI

 

附件下载
代码提交.zip
MSP430项目代码
团队介绍
一个狂热的开源爱好者和传播者,同时也是一名极客爱好者,长期关注嵌入式发展和少儿创客教育,既擅长互联网系统架构设计与研发,又拥有丰富的嵌入式研发经验。为人精力充沛,古道热肠,圈内人称乔大妈、乔帮主。
团队成员
HonestQiao
狂热的开源爱好者和传播者
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号