[原创] 【微雪RP2040双核开发板】艺术表盘生成+避坑指南

qinyunti   2022-12-3 22:59 楼主

669ca4b3c5667b19996273f5efaa6e20

 

前言

前面一篇我们介绍了C开发环境的搭建,并使用官方的Demo体验了LCD的显示。

我们看到圆形LCD显示效果不错。一看到圆形LCD肯定想到的就是表盘了,

这一篇我们就来生成一些具备艺术性的表盘。

 

过程

使用c示例工程,

添加draw.c和draw.h文件

image-20221203225412-1.png  

draw.c

#include "LCD_1in28.h"

#include <math.h>

#include <stdint.h>

 

#define DIM 240

#define DM1 (DIM-1)

#define _sq(x) ((x)*(x)) // square88ikkkkkkkkkkkkkkkkkk

#define _cb(x) abs((x)*(x)*(x)) // absolute value of cube

#define _cr(x) (unsigned char)(pow((x),1.0/3.0)) // cube root

 

void draw_test1(void)

{

    unsigned char RD1(int i,int j){

    return (char)(_sq(cos(atan2(j-DIM/2,i-DIM/2)/2))*255);

    }

 

    unsigned char GR1(int i,int j){

    return (char)(_sq(cos(atan2(j-DIM/2,i-DIM/2)/2-2*acos(-1)/3))*255);

    }

 

    unsigned char BL1(int i,int j){

    return (char)(_sq(cos(atan2(j-DIM/2,i-DIM/2)/2+2*acos(-1)/3))*255);

    }

 

    uint8_t r;

    uint8_t g;

    uint8_t b;

    for(volatile int j=0;j<DIM;j++)

    {

        for(volatile int i=0;i<DIM;i++)

        {

            r = RD1(i,j)&255;

            g = GR1(i,j)&255;

            b = BL1(i,j)&255;

            LCD_1IN28_DisplayPoint(i, j, (((uint16_t)r>>3)<<11) | (((uint16_t)g>>2)<<5) | (((uint16_t)b>>3)<<0));

        }

    }

 

}


 

void draw_test2(void)

{

    unsigned char RD2(int i,int j){

    static double k;k+=rand()/1./RAND_MAX;int l=k;l%=DIM/2;return l>255?DIM/2-1-l:l;

    }

 

    unsigned char GR2(int i,int j){

    static double k;k+=rand()/1./RAND_MAX;int l=k;l%=DIM/2;return l>255?DIM/2-1-l:l;

    }

 

    unsigned char BL2(int i,int j){

    static double k;k+=rand()/1./RAND_MAX;int l=k;l%=DIM/2;return l>255?DIM/2-1-l:l;

    }

    uint8_t r;

    uint8_t g;

    uint8_t b;

    for(volatile int j=0;j<DIM;j++)

    {

        for(volatile int i=0;i<DIM;i++)

        {

            r = RD2(i,j)&255;

            g = GR2(i,j)&255;

            b = BL2(i,j)&255;

            LCD_1IN28_DisplayPoint(i, j, ((r>>3)<<11) | ((g>>2)<<5) | ((b>>3)<<0));

        }

    }

}

 

void draw_test(void)

{

    draw_test1();

    DEV_Delay_ms(2000);

    draw_test2();

    DEV_Delay_ms(2000);

}

draw.h

#ifndef DRAW_H

#define DRAW_H

 

void draw_test(void);

 

#endif

 

c/examples/LCD_1in28_test.c中调用测试函数

int LCD_1in28_test(void)

{

    if (DEV_Module_Init() != 0)

    {

        return -1;

    }

    adc_init();

    adc_gpio_init(29);

    adc_select_input(3);

    LCD_1IN28_Init(HORIZONTAL);

    LCD_1IN28_Clear(WHITE);

    DEV_SET_PWM(60);

    while(1)

    {

        draw_test();

    }

 

    DEV_Module_Exit();

    return 0;

}

 

编译

cd到RP2040-LCD-1.28/c/build路径

export PICO_SDK_PATH="/home/lhj/pico-setup/pico/pico-sdk" && cmake ..

make

生成的程序位于当前路径下

复制到windows下,下载到开发板运行

cp main.uf2 /mnt/d

 

测试

image-20221203225412-2.jpeg  

 

image-20221203225412-3.jpeg  

image-20221203225412-4.jpeg  

避坑

写点函数不能显示

void LCD_1IN28_DisplayPoint(UWORD X, UWORD Y, UWORD Color)

{

    LCD_1IN28_SetWindows(X,Y,X,Y);

    LCD_1IN28_SendData_16Bit(Color);

}

 

 

Xend和Yend都-1了

void LCD_1IN28_SetWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend)

{

    //set the X coordinates

    LCD_1IN28_SendCommand(0x2A);

    LCD_1IN28_SendData_8Bit(0x00);

    LCD_1IN28_SendData_8Bit(Xstart);

    LCD_1IN28_SendData_8Bit((Xend-1)>>8);

    LCD_1IN28_SendData_8Bit(Xend-1);

 

    //set the Y coordinates

    LCD_1IN28_SendCommand(0x2B);

    LCD_1IN28_SendData_8Bit(0x00);

    LCD_1IN28_SendData_8Bit(Ystart);

    LCD_1IN28_SendData_8Bit((Xend-1)>>8);

    LCD_1IN28_SendData_8Bit(Yend-1);

 

    LCD_1IN28_SendCommand(0X2C);

}

 

 

所以要改为

void LCD_1IN28_DisplayPoint(UWORD X, UWORD Y, UWORD Color)

{

    LCD_1IN28_SetWindows(X,Y,X+1,Y+1);

    LCD_1IN28_SendData_16Bit(Color);

}

 

 

刷屏不能显示

   

for(int j=0;j<DIM;j++)

    {

        for(int i=0;i<DIM;i++)

        {

            r = RD2(i,j)&255;

            g = GR2(i,j)&255;

            b = BL2(i,j)&255;

            LCD_1IN28_DisplayPoint(i, j, ((r>>3)<<11) | ((g>>2)<<5) | ((b>>3)<<0));

        }

    }

 

 

改为

    for(volatile int j=0;j<DIM;j++)

    {

        for(volatile int i=0;i<DIM;i++)

        {

            r = RD2(i,j)&255;

            g = GR2(i,j)&255;

            b = BL2(i,j)&255;

            LCD_1IN28_DisplayPoint(i, j, ((r>>3)<<11) | ((g>>2)<<5) | ((b>>3)<<0));

        }

    }

 

 

编译器聪明过头,将双循环优化掉了,虽然不管从什么角度考虑这里都不应该被优化掉(即不是多线程访问全局变量,也不是回调函数中使用全局变量),

所以这也是编译器可能存在弄巧成拙的地方,个人看来这应该算是编译器的BUG,因为这里不管编译等级设置多高都没有理由优化掉。

总结

  1. 上述生成图像为了看到过程,所以是一个点一个点运算再画出来了,所以有刷屏的过程,实际应用需要先写到缓冲区,再以此刷屏。
  2. 艺术图像由公式生成,实际就是函数图像的彩色显示,可以自再去找一些有意思的生成函数。
  3. Demo代码写点函数有BUG
  4. 嵌套循环写点可能被优化需要volatile修饰变量,避免优化。

回复评论 (2)

刷新有点跟不上呀。
点赞  2022-12-5 09:15
引用: lugl4313820 发表于 2022-12-5 09:15 刷新有点跟不上呀。

文中有说明,故意做的运算一个bit显示一个bit,为了演示画图的过程.

实际就肯定是先写道缓冲区,再一次刷新。

点赞  2022-12-5 09:58
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复