【微雪RP2040双核开发板】艺术表盘生成+避坑指南
<div class='showpostmsg'><h1>7a96246a3c5bdd90b9749e6f275596b1<br /> </h1>
<h1><b>前言</b></h1>
<p >前面一篇我们介绍了C开发环境的搭建,并使用官方的Demo体验了LCD的显示。</p>
<p >我们看到圆形LCD显示效果不错。一看到圆形LCD肯定想到的就是表盘了,</p>
<p >这一篇我们就来生成一些具备艺术性的表盘。</p>
<p > </p>
<h1 ><b>过程</b></h1>
<p >使用c示例工程,</p>
<p >添加draw.c和draw.h文件</p>
<p > </p>
<p >draw.c</p>
<div class="parsedown-markdown">
<p>#include "LCD_1in28.h"</p>
<p>#include <math.h></p>
<p>#include <stdint.h></p>
<p> </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> </p>
<p>void draw_test1(void)</p>
<p>{</p>
<p> unsigned char RD1(int i,int j){</p>
<p> return (char)(_sq(cos(atan2(j-DIM/2,i-DIM/2)/2))*255);</p>
<p> }</p>
<p> </p>
<p> unsigned char GR1(int i,int j){</p>
<p> return (char)(_sq(cos(atan2(j-DIM/2,i-DIM/2)/2-2*acos(-1)/3))*255);</p>
<p> }</p>
<p> </p>
<p> unsigned char BL1(int i,int j){</p>
<p> return (char)(_sq(cos(atan2(j-DIM/2,i-DIM/2)/2+2*acos(-1)/3))*255);</p>
<p> }</p>
<p> </p>
<p> uint8_t r;</p>
<p> uint8_t g;</p>
<p> uint8_t b;</p>
<p> for(volatile int j=0;j<DIM;j++)</p>
<p> {</p>
<p> for(volatile int i=0;i<DIM;i++)</p>
<p> {</p>
<p> r = RD1(i,j)&255;</p>
<p> g = GR1(i,j)&255;</p>
<p> b = BL1(i,j)&255;</p>
<p> LCD_1IN28_DisplayPoint(i, j, (((uint16_t)r>>3)<<11) | (((uint16_t)g>>2)<<5) | (((uint16_t)b>>3)<<0));</p>
<p> }</p>
<p> }</p>
<p> </p>
<p>}</p>
<p><br />
</p>
<p>void draw_test2(void)</p>
<p>{</p>
<p> unsigned char RD2(int i,int j){</p>
<p> static double k;k+=rand()/1./RAND_MAX;int l=k;l%=DIM/2;return l>255?DIM/2-1-l:l;</p>
<p> }</p>
<p> </p>
<p> unsigned char GR2(int i,int j){</p>
<p> static double k;k+=rand()/1./RAND_MAX;int l=k;l%=DIM/2;return l>255?DIM/2-1-l:l;</p>
<p> }</p>
<p> </p>
<p> unsigned char BL2(int i,int j){</p>
<p> static double k;k+=rand()/1./RAND_MAX;int l=k;l%=DIM/2;return l>255?DIM/2-1-l:l;</p>
<p> }</p>
<p> uint8_t r;</p>
<p> uint8_t g;</p>
<p> uint8_t b;</p>
<p> for(volatile int j=0;j<DIM;j++)</p>
<p> {</p>
<p> for(volatile int i=0;i<DIM;i++)</p>
<p> {</p>
<p> r = RD2(i,j)&255;</p>
<p> g = GR2(i,j)&255;</p>
<p> b = BL2(i,j)&255;</p>
<p> LCD_1IN28_DisplayPoint(i, j, ((r>>3)<<11) | ((g>>2)<<5) | ((b>>3)<<0));</p>
<p> }</p>
<p> }</p>
<p>}</p>
<p> </p>
<p>void draw_test(void)</p>
<p>{</p>
<p> draw_test1();</p>
<p> DEV_Delay_ms(2000);</p>
<p> draw_test2();</p>
<p> 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> </p>
<p>void draw_test(void);</p>
<p> </p>
<p>#endif</p>
</div>
<p > </p>
<p >c/examples/LCD_1in28_test.c中调用测试函数</p>
<div class="parsedown-markdown">
<p>int LCD_1in28_test(void)</p>
<p >{</p>
<p > if (DEV_Module_Init() != 0)</p>
<p > {</p>
<p > return -1;</p>
<p > }</p>
<p > adc_init();</p>
<p > adc_gpio_init(29);</p>
<p > adc_select_input(3);</p>
<p > LCD_1IN28_Init(HORIZONTAL);</p>
<p > LCD_1IN28_Clear(WHITE);</p>
<p > DEV_SET_PWM(60);</p>
<p > while(1)</p>
<p > {</p>
<p > draw_test();</p>
<p > }</p>
<p > </p>
<p > DEV_Module_Exit();</p>
<p > return 0;</p>
<p >}</p>
</div>
<p > </p>
<p >编译</p>
<p >cd到RP2040-LCD-1.28/c/build路径</p>
<p >export PICO_SDK_PATH="/home/lhj/pico-setup/pico/pico-sdk" && cmake ..</p>
<p >make</p>
<p >生成的程序位于当前路径下</p>
<p >复制到windows下,下载到开发板运行</p>
<p >cp main.uf2 /mnt/d</p>
<p > </p>
<h1 ><b>测试</b></h1>
<p > </p>
<p > </p>
<p > </p>
<p > </p>
<h1 ><b>避坑</b></h1>
<h2 ><b>写点函数不能显示</b></h2>
<div class="parsedown-markdown">
<p>void LCD_1IN28_DisplayPoint(UWORD X, UWORD Y, UWORD Color)</p>
<p >{</p>
<p > LCD_1IN28_SetWindows(X,Y,X,Y);</p>
<p > LCD_1IN28_SendData_16Bit(Color);</p>
<p >}</p>
</div>
<p > </p>
<p > </p>
<p >Xend和Yend都-1了</p>
<div class="parsedown-markdown">
<p>void LCD_1IN28_SetWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend)</p>
<p >{</p>
<p > //set the X coordinates</p>
<p > LCD_1IN28_SendCommand(0x2A);</p>
<p > LCD_1IN28_SendData_8Bit(0x00);</p>
<p > LCD_1IN28_SendData_8Bit(Xstart);</p>
<p > LCD_1IN28_SendData_8Bit((Xend-1)>>8);</p>
<p > LCD_1IN28_SendData_8Bit(Xend-1);</p>
<p > </p>
<p > //set the Y coordinates</p>
<p > LCD_1IN28_SendCommand(0x2B);</p>
<p > LCD_1IN28_SendData_8Bit(0x00);</p>
<p > LCD_1IN28_SendData_8Bit(Ystart);</p>
<p > LCD_1IN28_SendData_8Bit((Xend-1)>>8);</p>
<p > LCD_1IN28_SendData_8Bit(Yend-1);</p>
<p > </p>
<p > LCD_1IN28_SendCommand(0X2C);</p>
<p >}</p>
</div>
<p > </p>
<p > </p>
<p >所以要改为</p>
<div class="parsedown-markdown">
<p>void LCD_1IN28_DisplayPoint(UWORD X, UWORD Y, UWORD Color)</p>
<p >{</p>
<p > LCD_1IN28_SetWindows(X,Y,X+1,Y+1);</p>
<p > LCD_1IN28_SendData_16Bit(Color);</p>
<p >}</p>
</div>
<p > </p>
<p > </p>
<h2 ><b>刷屏不能显示</b></h2>
<p > </p>
<div class="parsedown-markdown">
<p>for(int j=0;j<DIM;j++)</p>
<p > {</p>
<p > for(int i=0;i<DIM;i++)</p>
<p > {</p>
<p > r = RD2(i,j)&255;</p>
<p > g = GR2(i,j)&255;</p>
<p > b = BL2(i,j)&255;</p>
<p > LCD_1IN28_DisplayPoint(i, j, ((r>>3)<<11) | ((g>>2)<<5) | ((b>>3)<<0));</p>
<p > }</p>
<p > }</p>
</div>
<p > </p>
<p > </p>
<p >改为</p>
<div class="parsedown-markdown">
<p> for(volatile int j=0;j<DIM;j++)</p>
<p > {</p>
<p > for(volatile int i=0;i<DIM;i++)</p>
<p > {</p>
<p > r = RD2(i,j)&255;</p>
<p > g = GR2(i,j)&255;</p>
<p > b = BL2(i,j)&255;</p>
<p > LCD_1IN28_DisplayPoint(i, j, ((r>>3)<<11) | ((g>>2)<<5) | ((b>>3)<<0));</p>
<p > }</p>
<p > }</p>
</div>
<p > </p>
<p > </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
刷新有点跟不上呀。
<p>文中有说明,故意做的运算一个bit显示一个bit,为了演示画图的过程.</p>
<p>实际就肯定是先写道缓冲区,再一次刷新。</p>
页:
[1]