2023年寒假在家一起练-基于MSP430实现一个加速度传感器控制的彩灯
基于MSP430实现一个加速度传感器控制的彩灯, 完全重新开发了控制st7735的带framebuffer驱动
标签
MSP430
2023年寒假在家一起练
james
更新2023-03-28
338

大家好, 我是james. 我是一名hacker, 我希望能创造出属于未来的机器.

项目介绍
2023年寒假在家一起练参加了第四个平台, 基于MSP430实现一个加速度传感器控制的彩灯, 其实由于时间原因挑选了一个相对比较简单的任务, 过程中大部分时间花在了重新实现st7735驱动代码的实现上. 现已可以使用framebuffer进行屏幕更新, 中间过程也对游戏图形和用户界面图形的区别进行了思考.

MSP-EXP430F5529LP是一款针对MSP430F5529 USB微控 制器的廉价而简单的开发套件。它为MSP430 MCU提供了一种简单的方法,具有用于编程和调试的板载仿真,以及用于简单用户界面的按钮和LED。

实现功能

IO扩展板上有三轴加速度传感器,读出传感器的数值显示在屏幕上,并且板子上有RGB彩灯,使用三轴加速度控制彩灯出现不同颜色。在板子静置30秒后,彩灯规律周期变化。

将板子朝向不同摆放时,屏幕显示的数字不同,并且手持板子转到不同方位彩灯颜色跟随变化。在板子静置30秒后,彩灯的颜色呈现周期变化。

设计思路
游戏图形需要实时更新屏幕, 一般选择带有双缓冲的屏幕内容更新, 但是这要求具有比较大的带宽, 对于MSP430f5529主频只有25Mhz, 经过计算, 即便CPU什么都不做只更新屏幕内容, 也只能做到100fps的速度, 而且这是在一个CPU周期进行刷新一次的超理想情况下, 实际要低得多, 所以并不适合这种刷新方法.

选择带有region的局部刷新可以减少带宽使用和数据吞吐的要求. 所以在实现sge的时候笔者也考虑到这种情况, 实现了局部刷新的逻辑.

这款st7735屏幕给的参考驱动实现了最简单的图形和字体显示, 不支持帧缓冲, 笔者从数据手册出发, 重新实现了上层的绘图函数, 能够使用内存帧缓冲, 降低了绘图逻辑的复杂度, 可以实现绘制完成一帧后直接输出, 无需多次设定输出区域,  无需多次启动SPI进行数据传输.

彩灯的控制逻辑比较简单, 用了常规的经验法则(rules of thumb)来实现, 得益于arduino的简洁, 通过不断尝试, 得到了可行的算法.

FsqQiN3LtCbg92ol71DIg4v-FfNZ

项目实现

为了更明确地区分项目中需要不同技能的任务, 笔者将任务分为"软件系统实现"和"硬件实现":

1) 软件系统实现

主要的Loop函数实现, 使用了arduino中的各种函数:

void loop() {
    static long cnt     = 0;
    static long cntout  = 0;
    char buf[17] = {0};
    float ax,ay,az;
    int8_t x, y, z;

    acc.getXYZ(&x,&y,&z);

    // Serial.print("x = ");
    // Serial.println(x);
    // Serial.print("y = ");
    // Serial.println(y);
    // Serial.print("z = ");
    // Serial.println(z);


    if(acc.getAcceleration(&ax,&ay,&az))
    {
      print("get data ok: ", 0, 64 - 8);
      //Serial.print("get data ok: ");
    }
    else
    {
      print("time out: ", 0, 64 - 16);
      //Serial.print("time out: ");
    }
    
    // Serial.println("accleration of X/Y/Z: ");
    // Serial.print(ax);
    // Serial.println(" g");
    // Serial.print(ay);
    // Serial.println(" g");
    // Serial.print(az);
    // Serial.println(" g");
    // Serial.println();

    print("  X,  Y,  Z", 0, 0);
    sprintf(buf, "%+3d,%+3d,%+3d", x, y, z);
    print(buf, 0, 8);

    if (x > 5 || x < -5 || y > 5 || y < -5) {
      delayStart = millis();
      analogWrite(LED_R, 150 + 100 * x / 25.0);
      analogWrite(LED_G, 150 + 100 * y / 25.0);
      analogWrite(LED_B, 150 + 100 * z / 25.0);
    }
    
    if (millis() - delayStart > 30 * 1000) {
      stable_led_cycle();
      print("STABLE", 0, 16);
    } else {
      print("MOVE  ", 0, 16);
    }
    sge_cycle();
    delay(50);
}

实现了framebuffer, 例如_draw_internal函数, 用来对屏幕上的像素进行更新:

void _draw_internal(uint8_t x, uint8_t y, uint8_t w, uint8_t h) {
  unsigned char i, j, i_pixel, color_pair, x2, y2;
  unsigned char *p_scanline;

  x2 = x + w; y2 = y + h;
  LCD_Address_Set(x * 2, y * 2, x2 * 2 - 1, y2 * 2 - 1);
  for (j = y; j < y2; ++j) {
    p_scanline = fb + FB_WIDTH * j;
    for (i = x; i < x2; ++i) {
      color_pair = *(p_scanline + i / 2);
      i_pixel = (i / 2) * 4;
      scanline[i_pixel] = color_table[HIGH_NIPPLE(color_pair)];
      scanline[i_pixel + 1] = scanline[i_pixel];
      scanline[i_pixel + 2] = color_table[LOW_NIPPLE(color_pair)];
      scanline[i_pixel + 3] = scanline[i_pixel + 2];
    }
    // flush line to canvas
    for (i = x * 2; i < x2 * 2; ++i) {
      LCD_WR_DATA(scanline[i]);
    }
    for (i = x * 2; i < x2 * 2; ++i) {
      LCD_WR_DATA(scanline[i]);
    }
  }
}

2) 硬件系统实现
没有修改硬件, 为了更安全, 加热电阻小心控制.

心得体会
1) platformio是一个比较好的构建系统, 主要优势在于方便, 支持的板卡多, 但是不支持windows/cygwin是比较遗憾, 其实就是chalk库的依赖问题没有解决.
2) msp430用来实现控制是比较合适的平台, 16位的字长正好能方便掌握, 汇编和C都方便.

Code&Future

红色的开发板配上彩色屏幕, 和黑色的拓展版, 看起来很不错, MSP430也为面向寄存器, 面向C语言, 面向Arduino编程提供了很好的平台支持. 整个开发过程体验很好, 除了energia(msp430的arduino)库无法使用最新的gcc以外其他都很好.

后续继续学习MSP430, 熟悉数据手册的更多内容, 尝试driverlib等官方工具包, 可以在MSP430低功耗的优势下完成更多有意思的小项目.

最后,感谢硬禾学堂和得捷电子,让我接触到了msp430红色开发板,让我能在业余时间参与更多有趣项目的学习,也感谢群的小伙伴提供很多种实现题目功能的思路,感谢大家一路的折腾与陪伴,谢谢!

附件下载
an-msp430-project.zip
团队介绍
indie
团队成员
james
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号