A digital meter is quite common these days. By the latest TFT controller, LT768x series, developers may make vivid meter displays possible with simple programming.
Related functions are listed below:
void LT768_DMA_24bit_Block // Retrieve data from Flash and transmit them to LT768x SDRAM
(
unsigned char SCS // Select SPI Flash: SCS: 0 SCS: 1
,unsigned char Clk // SPI Clock = System Clock /{(Clk+1)*2}, Clk: 0 ~ 3
,unsigned short X1 // Starting X coordinate in SDRAM layer
,unsigned short Y1 // Starting Y coordinate in SDRAM layer
,unsigned short X_W // Width of the data to be transmitted, e.g. picture width
,unsigned short Y_H // Height of the data to be transmitted, e.g. picture height
,unsigned short P_W // Picture width
,unsigned long Addr // Starting address in Flash (to retrieve the data)
)
void LT768_BTE_Memory_Copy // Move LT768x SDRAM data from one layer to another
(
unsigned long S0_Addr // Starting address (SDRAM) of S0 picture
,unsigned short S0_W // Width of the S0 picture
,unsigned short XS0 // Left-top X coordinate of the S0 picture
,unsigned short YS0 // Left-top Y coordinate of the S0 picture
,unsigned long S1_Addr // Starting address (SDRAM) of S1 picture
,unsigned short S1_W // Width of the S1 picture
,unsigned short XS1 // Left-top X coordinate of the S1 picture
,unsigned short YS1 // Left-top Y coordinate of the S1 picture
,unsigned long Des_Addr // Starting address (SDRAM) of DT picture
,unsigned short Des_W // Width of the DT picture
,unsigned short XDes // Left-top X coordinate of the DT picture
,unsigned short YDes // Left-top Y coordinate of the DT picture
,unsigned int ROP_Code // Refer to "LT768x_AP-Note_V12_ENG.pdf", Table 10-2
,unsigned short X_W // Width of the active window
,unsigned short Y_H // Height of the active window
)
In addition, below function is used to make a pointer that can perform rotation in different angles:
void TEST_DoubleTriangle // Draw two solid triangles to act as a pointer of a meter
(
u16 x // Center X of the triangle
,u16 y // Center Y of the triangle
,u16 L1 // Length of the longer side of the pointer
,u16 L2 // Length of the shorter side of the pointer
,u16 H // Height of the triangle
,u16 a // Angle
,u16 color1 // Filled color for the 1st triangle
,u16 color2 // Filled color for the 2nd triangle
)
The parameters are explained in below figure:
Implementation steps are as shown below:
To start with, the SDRAM is configured to several layers, each layer is 1024x600x2 bytes.
3 of these layers will be used in our example:
LAYER_0: Display layer (Data in this layer will be displayed onto the LCD panel)
LAYER_1: Buffer layer for the background picture of the meter
LAYER_5: Buffer layer for the drawn pointer and the background picture
Step 1: Move the meter picture from flash (address: 0x00000000) to LT768x SDRAM, LAYER_0
LT768_DMA_24bit_Block(1, 0, 0, 0, LCD_XSIZE_TFT, LCD_YSIZE_TFT, LCD_XSIZE_TFT, 0x00000000);
Step 2: Copy the above picture from LAYER_0 to LAYER_1 which is the buffer layer of the background picture.
LT768_BTE_Memory_Copy(
LAYER_0, LCD_XSIZE_TFT, 0, 0, // S0
LAYER_1, LCD_XSIZE_TFT, 0, 0, // S1
LAYER_1, LCD_XSIZE_TFT, 0, 0, // DT
0x0c, // ROP code, 0x0c -> DT = S0
LCD_XSIZE_TFT, LCD_YSIZE_TFT // Data area (width * height)
);
Step 3: Copy the pointer area from LAYER_1 to LAYER_5 which is the buffer layer of the pointer
Pointer area -> left-top coordinate: (340, 105), width * height: 340 * 340
LT768_BTE_Memory_Copy(
LAYER_1, LCD_XSIZE_TFT, 340, 105, // S0
LAYER_1, LCD_XSIZE_TFT, 340, 105, // S1
LAYER_5, LCD_XSIZE_TFT, 340, 105, // DT
0x0c, // ROP code, 0x0c -> DT = S0
340, 340 // Data area (width * height)
);
Step 4: Draw and display the pointer at consecutive angles in loop
Codes are listed below for reference:
/*---------------------------------------------------------------------------------------*/
/* Function: TEST_DoubleTriangle */
/* */
/* Parameters: */
/* x: Center X of the triangle */
/* y: Center Y of the triangle */
/* L1: Length of the longer side of the pointer */
/* L2: Length of the shorter side of the pointer */
/* H: Height of the triangle */
/* A: Angle */
/* color1: Filled color for 1st triangle */
/* color2: Filled color for 2nd triangle */
/* Returns: None */
/* Description: Draw two solid triangles to act as a pointer of a meter */
/*---------------------------------------------------------------------------------------*/
void TEST_DoubleTriangle
(
u16 x
,u16 y
,u16 L1
,u16 L2
,u16 H
,u16 a
,u16 color1
,u16 color2
)
{
float cos_x = 0;
float sin_y = 0;
u16 x1,y1,x2,y2,x3,y3,x4,y4;
if(a<=90)
{
cos_x = cos(a*(3.1415926/180));
sin_y = sin(a*(3.1415926/180));
x1 = x - L1*cos_x;
y1 = y - L1*sin_y;
x2 = x - H*sin_y;
y2 = y + H*cos_x;
x3 = x + H*sin_y;
y3 = y - H*cos_x;
x4 = x + L2*cos_x;
y4 = y + L2*sin_y;
}
else if((a>90)&&(a<180))
{
a = 180 - a;
cos_x = cos(a*(3.1415926/180));
sin_y = sin(a*(3.1415926/180));
x1 = x + L1*cos_x;
y1 = y - L1*sin_y;
x2 = x - H*sin_y;
y2 = y - H*cos_x;
x3 = x + H*sin_y;
y3 = y + H*cos_x;
x4 = x - L2*cos_x;
y4 = y + L2*sin_y;
}
else if((a>=180)&&(a<270))
{
a = a - 180;
cos_x = cos(a*(3.1415926/180));
sin_y = sin(a*(3.1415926/180));
x1 = x + L1*cos_x;
y1 = y + L1*sin_y;
x2 = x + H*sin_y;
y2 = y - H*cos_x;
x3 = x - H*sin_y;
y3 = y + H*cos_x;
x4 = x - L2*cos_x;
y4 = y - L2*sin_y;
}
else if((a>=270)&&(a<360))
{
a = 360 - a;
cos_x = cos(a*(3.1415926/180));
sin_y = sin(a*(3.1415926/180));
x1 = x - L1*cos_x;
y1 = y + L1*sin_y;
x2 = x + H*sin_y;
y2 = y + H*cos_x;
x3 = x - H*sin_y;
y3 = y - H*cos_x;
x4 = x + L2*cos_x;
y4 = y - L2*sin_y;
}
LT768_DrawTriangle_Fill(x1,y1,x2,y2,x4,y4,color1);
LT768_DrawTriangle_Fill(x1,y1,x3,y3,x4,y4,color2);
LT768_DrawCircle_Fill(x,y,3,Red);
}
/*---------------------------------------------------------------------------------------*/
/* Function: Meter_Pointer */
/* */
/* Parameters: None */
/* Returns: None */
/* Description: Demonstrate a meter pointer */
/*---------------------------------------------------------------------------------------*/
void Meter_Pointer(void)
{
// LAYER_0: Display layer
// LAYER_1: Buffer layer for the background picture of a meter
// LAYER_5: Buffer layer for the drawn pointer and the background picture
int state1 = 0, // Flag, 0: rotate clockwisely 1: rotate counterclockwisely
flag1 = 0, // Flag status changes when reach rotating boundry ( <=0, >=358, <=315, >=225 degree)
a1 = 315; // Starting angle
Select_Main_Window_16bpp(); // Set main window color depth
Main_Image_Start_Address(LAYER_0); // Set main window starting address - Display layer
Main_Image_Width(LCD_XSIZE_TFT); // Set main window width
Main_Window_Start_XY(0,0); // Set main window starting coordinate
Canvas_Image_Start_address(LAYER_0); // Set canvas starting address
Canvas_image_width(LCD_XSIZE_TFT); // Set canvas width
Active_Window_XY(0,0); // Set active window starting coordinate
Active_Window_WH(LCD_XSIZE_TFT,LCD_YSIZE_TFT); // Set active window width and height
// Retrieve the background picture from flash and display it to the TFT panel
// Picture address in the SPI Flash: 0x00000000
// Canvas start address: LAYER_0 (display layer)
LT768_DMA_24bit_Block(1, 0, 0, 0, LCD_XSIZE_TFT, LCD_YSIZE_TFT, LCD_XSIZE_TFT, 0x00000000);
// Copy the background picture from LAYER_0 to LAYER_1 which is the buffer layer of the background picture
LT768_BTE_Memory_Copy(
LAYER_0, LCD_XSIZE_TFT, 0, 0, // S0
LAYER_1, LCD_XSIZE_TFT, 0, 0, // S1
LAYER_1, LCD_XSIZE_TFT, 0, 0, // DT
0x0c, // ROP code, 0x0c -> DT = S0
LCD_XSIZE_TFT, LCD_YSIZE_TFT // Data area (width * height)
);
// Copy the pointer area from LAYER_1 to LAYER_5 which is the buffer layer of the pointer
// Pointer area -> left-top coordinate: (340, 105), width * height: 340 * 340
LT768_BTE_Memory_Copy(
LAYER_1, LCD_XSIZE_TFT, 340, 105, // S0
LAYER_1, LCD_XSIZE_TFT, 340, 105, // S1
LAYER_5, LCD_XSIZE_TFT, 340, 105, // DT
0x0c, // ROP code, 0x0c -> DT = S0
340, 340 // Data area (width * height)
);
Canvas_Image_Start_address(LAYER_5); // Set the canvas start address to LAYER_5
while(1)
{
//Draw a pointer to LAYER_5
TEST_DoubleTriangle(510,280,170,20,15,a1,Blue,Blue2);
// Move the pointer data (LAYER_5) to display layer (LAYER_0)
LT768_BTE_Memory_Copy(
LAYER_5, LCD_XSIZE_TFT, 340, 105, // S0
LAYER_1, LCD_XSIZE_TFT, 340, 105, // S1
LAYER_0, LCD_XSIZE_TFT, 340, 105, // DT
0x0c, // ROP code, 0x0c -> DT = S0
340, 340 // Data area (width * height)
);
// Following condition loop allows the pointer to be drawn between 315 and 225 degrees
if(state1 == 0)
{
if(flag1 == 0)
{
a1 += 2;
if(a1 >= 358)
{
a1 = 0;
flag1 = 1;
}
}
else
{
a1 += 2;
if(a1 >= 225)
{
a1 = 225;
flag1 = 0;
state1 = 1;
}
}
}
else
{
if(flag1 == 0)
{
a1 -= 2;
if(a1 <= 0)
{
a1 = 359;
flag1 = 1;
}
}
else
{
a1 -= 2;
if(a1 <= 315)
{
a1 = 315;
flag1 = 0;
state1 = 0;
}
}
}
// Refresh the background picture (only the area overlapped with the pointer)
// before drawing the next pointer
LT768_BTE_Memory_Copy(
LAYER_1, LCD_XSIZE_TFT, 340, 105, // S0, left-top address (340, 105)
LAYER_1, LCD_XSIZE_TFT, 340, 105, // S1, left-top address (340, 105)
LAYER_5, LCD_XSIZE_TFT, 340, 105, // DT, left-top address (340, 105)
0x0c, // ROP code, 0x0c -> DT = S0
340, 340 // Area overlapped with the pointer
);
}
}
Running result is as shown below: