狂算三角函数,压榨gpio

分享作者:wechat_15135690968
作者昵称:禹黎151
评测品牌:灵动微电子
评测型号:FTHR-G0001
发布时间:2025-12-26 10:30:14
1
概要
简单粗暴的三角函数循环计算,实现3D效果
开源口碑分享内容

谁说32位MCU不能装X?

我眼皮狂跳地盯着一块0.96寸的"马赛克显示器"——对,就是那块SSD1306驱动的OLED,128×64的分辨率连诺基亚老人机都嫌磕碜。但当我把魔爪伸向这个ICeasy零元购的MM32G0001时,表演开始了:在2D平面上用数学暴力撕开3D空间的裂缝

丐版神器,极致性价比

主角:MM32G0001(主频撑死48MHz,Flash连装个高清表情包都够呛)

画布:0.96寸OLED(像素颗粒大得能当围棋下)

目标:让立方体在128×64的"牢笼"里跳起极乐净土

在江科大的肩膀上耍流氓

首先,我先给OLED.c文件捅了几刀:

OLED.c的变异部分

// 先整一个8×128的显存,把OLED变成你的涂鸦板
static uint8_t OLED_GRAM[8][128]; 

void OLED_Update(void)
{
    // 暴力刷写128×64=8192个bit,每秒干60次能让MCU原地升天
    for (uint8_t page = 0; page < 8; page++)
    {
        OLED_SetCursor(page, 0);
        for (uint8_t col = 0; col < OLED_WIDTH; col++)
            OLED_WriteData(OLED_GRAM[page][col]); // 逐字节喂数据,像喂鸡一样
    }
}

void OLED_ClearFast(void)
{
    // memset?不存在的!我们用16位循环清零,仪式感拉满
    memset(OLED_GRAM, 0, sizeof(OLED_GRAM)); // 好吧我撒谎了,这才是真香
    OLED_Update();
}

void OLED_DrawPixel(int16_t x, int16_t y, uint8_t color)
{
    // 越界?直接火化!
    if (x < 0 || x >= OLED_WIDTH || y < 0 || y >= OLED_HEIGHT) return;
    
    uint8_t page = y >> 3;      // 右移3位,bit操作就是这么朴实无华
    uint8_t bit = y & 0x07;     // 取余8,但要装成位运算大佬
    
    if (color)
        OLED_GRAM[page][x] |= (1 << bit);  // 点亮像素,物理层面点亮
    else
        OLED_GRAM[page][x] &= ~(1 << bit); // 掐灭像素,让它社会性死亡
}

.h文件就得跟上变异


// 这些函数是 cubism(立体主义)的入场券
void OLED_Update(void);          // 刷新!刷新!刷新!
void OLED_ClearFast(void);       // 一键清空你的罪恶
void OLED_DrawPixel(int16_t x, int16_t y, uint8_t color); // 像素级点杀
void OLED_DrawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1); // 画线,但用Bresenham算法
void OLED_CubeFrame(float angle); // 【核心战技】立方体降维打击!

重头戏来了。当STM32玩家还在用硬件浮点单元洋洋得意时,我们的MM32G0001选择用软件浮点硬刚cos/sin函数。每一帧都在燃烧生命,每一秒都在挑战MCU的尊严。

#include <math.h> // 引入数学炸弹

typedef struct { float x, y, z; } Point3D;   // 三维点,但内存很小气
typedef struct { int16_t x, y; } Point2D;   // 二维点,但省到极致

#define SCALE 25.0f      // 缩放倍数,再大胆点就要溢出到异次元
#define OFFSET_X 64      // 屏幕中心X,靠右一点显脸小
#define OFFSET_Y 32      // 屏幕中心Y,靠下一点显腿长

// 【投影魔法】把3D拍扁成2D,损失一个维度,但获得一点逼格
static Point2D project(Point3D p)
{
    Point2D r;
    r.x = (int16_t)(p.x * SCALE) + OFFSET_X;  // X轴,暴力拉伸
    r.y = (int16_t)(-p.y * SCALE) + OFFSET_Y; // Y轴,负号因为屏幕Y朝下
    return r;
}

// 【画线连招】连接两个3D点,中间省略一万次浮点运算
static void DrawLine3D(Point3D a, Point3D b)
{
    Point2D pa = project(a);
    Point2D pb = project(b);
    OLED_DrawLine(pa.x, pa.y, pb.x, pb.y); // 投影完直接用2D画线
}

// 【立方体本体】8个顶点,12条边,极简主义美学
static const Point3D cube[8] = {
    {-1,-1,-1},{ 1,-1,-1},{ 1, 1,-1},{-1, 1,-1},
    {-1,-1, 1},{ 1,-1, 1},{ 1, 1, 1},{-1, 1, 1}
};

static const uint8_t edge[12][2] = { /* 12条边,谁记编号我笑谁 */ };

void OLED_CubeFrame(float angle)
{
    float cy = cosf(angle);          // Y轴旋转cos
    float sy = sinf(angle);          // Y轴旋转sin
    float cx = cosf(angle * 0.5f);   // X轴旋转cos(半速,更风骚)
    float sx = sinf(angle * 0.5f);   // X轴旋转sin
    
    // 遍历12条边,每条边干9次浮点乘加,MCU在哀鸣
    for (int i = 0; i < 12; i++)
    {
        Point3D p = cube[edge[i][0]];
        Point3D q = cube[edge[i][1]];
        
        // Y轴旋转矩阵(手动展开,因为MCU不配用Eigen库)
        float px1 = p.x * cy - p.z * sy;
        float pz1 = p.x * sy + p.z * cy;
        // ...省略另外三个坐标变换...
        
        // X轴再旋转一次,让立方体跳起波浪舞
        float py2 = p.y * cx - pz1 * sx;
        
        DrawLine3D(r0, r1); // 画!就硬画!
    }
}

像素级灾难,概念级胜利

跑起来那一刻,屏幕上的立方体以0.5FPS的"超高速"抽搐旋转,肉眼可见的残影仿佛在说:"老子算不动了!" 每个浮点cos/sin调用都是一次对ARM Cortex-M0的公开处刑,每次OLED_Update()刷写都像在MCU的脸上左右开弓。

但——

当那个由48MHz算力堆砌出来的线框立方体真正转起来时,我哭了。这不是卡顿,这是硬核的浪漫;这不是低分辨率,这是复古未来主义;这更不是失败的尝试,这是硅基生命在极限边缘的嘶吼

CPU占用率:100%,逼格占用率:∞

  • 理论帧率:如果MCU有灵魂,它现在应该在ICU
  • 功耗:比跑while(1)空循环高3mA,每一毫安都在为数学殉道
  • 代码体积:浮点库直接让Flash缩小30%,但换来了次元壁破裂
  • 可扩展性:敢加个光照模型,MM32G0001就会当场起义
全部评论
暂无评论
0/144