qinyunti 发表于 2022-12-3 22:59

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

<div class='showpostmsg'><h1>7a96246a3c5bdd90b9749e6f275596b1<br />
&nbsp;</h1>

<h1><b>前言</b></h1>

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

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

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

<p >&nbsp;</p>

<h1 ><b>过程</b></h1>

<p >使用c示例工程,</p>

<p >添加draw.c和draw.h文件</p>

<p > &nbsp;</p>

<p >draw.c</p>

<div class="parsedown-markdown">
<p>#include &quot;LCD_1in28.h&quot;</p>

<p>#include &lt;math.h&gt;</p>

<p>#include &lt;stdint.h&gt;</p>

<p>&nbsp;</p>

<p>#define DIM 240</p>

<p>#define DM1 (DIM-1)</p>

<p>#define _sq(x) ((x)*(x)) // square88ikkkkkkkkkkkkkkkkkk</p>

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

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

<p>&nbsp;</p>

<p>void draw_test1(void)</p>

<p>{</p>

<p>&nbsp; &nbsp; unsigned char RD1(int i,int j){</p>

<p>&nbsp; &nbsp; return (char)(_sq(cos(atan2(j-DIM/2,i-DIM/2)/2))*255);</p>

<p>&nbsp; &nbsp; }</p>

<p>&nbsp;</p>

<p>&nbsp; &nbsp; unsigned char GR1(int i,int j){</p>

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

<p>&nbsp; &nbsp; }</p>

<p>&nbsp;</p>

<p>&nbsp; &nbsp; unsigned char BL1(int i,int j){</p>

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

<p>&nbsp; &nbsp; }</p>

<p>&nbsp;</p>

<p>&nbsp; &nbsp; uint8_t r;</p>

<p>&nbsp; &nbsp; uint8_t g;</p>

<p>&nbsp; &nbsp; uint8_t b;</p>

<p>&nbsp; &nbsp; for(volatile int j=0;j&lt;DIM;j++)</p>

<p>&nbsp; &nbsp; {</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; for(volatile int i=0;i&lt;DIM;i++)</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; {</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r = RD1(i,j)&amp;255;</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g = GR1(i,j)&amp;255;</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b = BL1(i,j)&amp;255;</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LCD_1IN28_DisplayPoint(i, j, (((uint16_t)r&gt;&gt;3)&lt;&lt;11) | (((uint16_t)g&gt;&gt;2)&lt;&lt;5) | (((uint16_t)b&gt;&gt;3)&lt;&lt;0));</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; }</p>

<p>&nbsp; &nbsp; }</p>

<p>&nbsp;</p>

<p>}</p>

<p><br />
&nbsp;</p>

<p>void draw_test2(void)</p>

<p>{</p>

<p>&nbsp; &nbsp; unsigned char RD2(int i,int j){</p>

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

<p>&nbsp; &nbsp; }</p>

<p>&nbsp;</p>

<p>&nbsp; &nbsp; unsigned char GR2(int i,int j){</p>

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

<p>&nbsp; &nbsp; }</p>

<p>&nbsp;</p>

<p>&nbsp; &nbsp; unsigned char BL2(int i,int j){</p>

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

<p>&nbsp; &nbsp; }</p>

<p>&nbsp; &nbsp; uint8_t r;</p>

<p>&nbsp; &nbsp; uint8_t g;</p>

<p>&nbsp; &nbsp; uint8_t b;</p>

<p>&nbsp; &nbsp; for(volatile int j=0;j&lt;DIM;j++)</p>

<p>&nbsp; &nbsp; {</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; for(volatile int i=0;i&lt;DIM;i++)</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; {</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r = RD2(i,j)&amp;255;</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g = GR2(i,j)&amp;255;</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b = BL2(i,j)&amp;255;</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LCD_1IN28_DisplayPoint(i, j, ((r&gt;&gt;3)&lt;&lt;11) | ((g&gt;&gt;2)&lt;&lt;5) | ((b&gt;&gt;3)&lt;&lt;0));</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp; }</p>

<p>&nbsp; &nbsp; }</p>

<p>}</p>

<p>&nbsp;</p>

<p>void draw_test(void)</p>

<p>{</p>

<p>&nbsp; &nbsp; draw_test1();</p>

<p>&nbsp; &nbsp; DEV_Delay_ms(2000);</p>

<p>&nbsp; &nbsp; draw_test2();</p>

<p>&nbsp; &nbsp; DEV_Delay_ms(2000);</p>

<p>}</p>
</div>

<p >draw.h</p>

<div class="parsedown-markdown">
<p>#ifndef DRAW_H</p>

<p>#define DRAW_H</p>

<p>&nbsp;</p>

<p>void draw_test(void);</p>

<p>&nbsp;</p>

<p>#endif</p>
</div>

<p >&nbsp;</p>

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

<div class="parsedown-markdown">
<p>int&nbsp;LCD_1in28_test(void)</p>

<p >{</p>

<p >&nbsp; &nbsp; if&nbsp;(DEV_Module_Init() != 0)</p>

<p >&nbsp; &nbsp; {</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp;-1;</p>

<p >&nbsp; &nbsp; }</p>

<p >&nbsp; &nbsp; adc_init();</p>

<p >&nbsp; &nbsp; adc_gpio_init(29);</p>

<p >&nbsp; &nbsp; adc_select_input(3);</p>

<p >&nbsp; &nbsp; LCD_1IN28_Init(HORIZONTAL);</p>

<p >&nbsp; &nbsp; LCD_1IN28_Clear(WHITE);</p>

<p >&nbsp; &nbsp; DEV_SET_PWM(60);</p>

<p >&nbsp; &nbsp; while(1)</p>

<p >&nbsp; &nbsp; {</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; draw_test();</p>

<p >&nbsp; &nbsp; }</p>

<p >&nbsp;</p>

<p >&nbsp; &nbsp; DEV_Module_Exit();</p>

<p >&nbsp; &nbsp; return&nbsp;0;</p>

<p >}</p>
</div>

<p >&nbsp;</p>

<p >编译</p>

<p >cd到RP2040-LCD-1.28/c/build路径</p>

<p >export PICO_SDK_PATH=&quot;/home/lhj/pico-setup/pico/pico-sdk&quot; &amp;&amp; cmake ..</p>

<p >make</p>

<p >生成的程序位于当前路径下</p>

<p >复制到windows下,下载到开发板运行</p>

<p >cp main.uf2 /mnt/d</p>

<p >&nbsp;</p>

<h1 ><b>测试</b></h1>

<p > &nbsp;</p>

<p >&nbsp;</p>

<p > &nbsp;</p>

<p > &nbsp;</p>

<h1 ><b>避坑</b></h1>

<h2 ><b>写点函数不能显示</b></h2>

<div class="parsedown-markdown">
<p>void&nbsp;LCD_1IN28_DisplayPoint(UWORD&nbsp;X, UWORD&nbsp;Y, UWORD&nbsp;Color)</p>

<p >{</p>

<p >&nbsp; &nbsp; LCD_1IN28_SetWindows(X,Y,X,Y);</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendData_16Bit(Color);</p>

<p >}</p>
</div>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >Xend和Yend都-1了</p>

<div class="parsedown-markdown">
<p>void&nbsp;LCD_1IN28_SetWindows(UWORD&nbsp;Xstart, UWORD&nbsp;Ystart, UWORD&nbsp;Xend, UWORD&nbsp;Yend)</p>

<p >{</p>

<p >&nbsp; &nbsp; //set the X coordinates</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendCommand(0x2A);</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendData_8Bit(0x00);</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendData_8Bit(Xstart);</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendData_8Bit((Xend-1)&gt;&gt;8);</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendData_8Bit(Xend-1);</p>

<p >&nbsp;</p>

<p >&nbsp; &nbsp; //set the Y coordinates</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendCommand(0x2B);</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendData_8Bit(0x00);</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendData_8Bit(Ystart);</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendData_8Bit((Xend-1)&gt;&gt;8);</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendData_8Bit(Yend-1);</p>

<p >&nbsp;</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendCommand(0X2C);</p>

<p >}</p>
</div>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >所以要改为</p>

<div class="parsedown-markdown">
<p>void&nbsp;LCD_1IN28_DisplayPoint(UWORD&nbsp;X, UWORD&nbsp;Y, UWORD&nbsp;Color)</p>

<p >{</p>

<p >&nbsp; &nbsp; LCD_1IN28_SetWindows(X,Y,X+1,Y+1);</p>

<p >&nbsp; &nbsp; LCD_1IN28_SendData_16Bit(Color);</p>

<p >}</p>
</div>

<p >&nbsp;</p>

<p >&nbsp;</p>

<h2 ><b>刷屏不能显示</b></h2>

<p >&nbsp; &nbsp;</p>

<div class="parsedown-markdown">
<p>for(int&nbsp;j=0;j&lt;DIM;j++)</p>

<p >&nbsp; &nbsp; {</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; for(int&nbsp;i=0;i&lt;DIM;i++)</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; {</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r = RD2(i,j)&amp;255;</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g&nbsp;= GR2(i,j)&amp;255;</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b&nbsp;= BL2(i,j)&amp;255;</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LCD_1IN28_DisplayPoint(i, j, ((r&gt;&gt;3)&lt;&lt;11) | ((g&gt;&gt;2)&lt;&lt;5) | ((b&gt;&gt;3)&lt;&lt;0));</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; }</p>

<p >&nbsp; &nbsp; }</p>
</div>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >改为</p>

<div class="parsedown-markdown">
<p>&nbsp; &nbsp; for(volatile&nbsp;int&nbsp;j=0;j&lt;DIM;j++)</p>

<p >&nbsp; &nbsp; {</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; for(volatile&nbsp;int&nbsp;i=0;i&lt;DIM;i++)</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; {</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r = RD2(i,j)&amp;255;</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g&nbsp;= GR2(i,j)&amp;255;</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b&nbsp;= BL2(i,j)&amp;255;</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LCD_1IN28_DisplayPoint(i, j, ((r&gt;&gt;3)&lt;&lt;11) | ((g&gt;&gt;2)&lt;&lt;5) | ((b&gt;&gt;3)&lt;&lt;0));</p>

<p >&nbsp; &nbsp; &nbsp; &nbsp; }</p>

<p >&nbsp; &nbsp; }</p>
</div>

<p >&nbsp;</p>

<p >&nbsp;</p>

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

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

<h1 ><b>总结</b></h1>

<ol>
        <li >上述生成图像为了看到过程,所以是一个点一个点运算再画出来了,所以有刷屏的过程,实际应用需要先写到缓冲区,再以此刷屏。</li>
        <li >艺术图像由公式生成,实际就是函数图像的彩色显示,可以自再去找一些有意思的生成函数。</li>
        <li >Demo代码写点函数有BUG</li>
        <li >嵌套循环写点可能被优化需要volatile修饰变量,避免优化。</li>
</ol>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

lugl4313820 发表于 2022-12-5 09:15

刷新有点跟不上呀。

qinyunti 发表于 2022-12-5 09:58

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

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

<p>实际就肯定是先写道缓冲区,再一次刷新。</p>
页: [1]
查看完整版本: 【微雪RP2040双核开发板】艺术表盘生成+避坑指南