669ca4b3c5667b19996273f5efaa6e20
Preface
In the previous article, we introduced the construction of the C development environment and used the official Demo to experience the LCD display.
We can see that the circular LCD has a good display effect. When you see a circular LCD, you will definitely think of the dial.
In this article, we will generate some artistic watch faces.
process
Using the C example project,
Add draw.c and draw.h files
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
Call the test function in c/examples/LCD_1in28_test.c
intLCD_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();
return0;
}
Compile
cd to RP2040-LCD-1.28/c/build path
export PICO_SDK_PATH="/home/lhj/pico-setup/pico/pico-sdk" && cmake ..
make
The generated program is located in the current path
Copy it to Windows, download it to the development board and run it
cp main.uf2 /mnt/d
test
Avoid pitfalls
Write function can not be displayed
voidLCD_1IN28_DisplayPoint(UWORDX, UWORDY, UWORDColor)
{
LCD_1IN28_SetWindows(X,Y,X,Y);
LCD_1IN28_SendData_16Bit(Color);
}
Xend and Yend are both -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);
}
So change it to
voidLCD_1IN28_DisplayPoint(UWORDX, UWORDY, UWORDColor)
{
LCD_1IN28_SetWindows(X,Y,X+1,Y+1);
LCD_1IN28_SendData_16Bit(Color);
}
The screen cannot be displayed
for(intj=0;j<DIM;j++)
{
for(inti=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));
}
}
Change to
for(volatileintj=0;j<DIM;j++)
{
for(volatileinti=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));
}
}
The compiler is too smart and optimizes the double loop, although it should not be optimized away from any perspective (i.e., it is not multi-threaded access to global variables, nor is it the use of global variables in callback functions).
So this is also where the compiler may be self-defeating. Personally, I think this should be considered a compiler bug, because there is no reason to optimize it away no matter how high the compilation level is set.
Summarize
- In order to see the process of generating the above image, the calculation is done point by point and then drawn, so there is a screen refresh process. In actual application, it needs to be written to the buffer first and then refreshed.
- Artistic images are generated by formulas, which are actually color displays of function graphs. You can find some interesting generating functions by yourself.
- There is a bug in the demo code.
- Nested loop write points may be optimized and require volatile modifier variables to avoid optimization.