/** * @file gc9a01.c * @brief Implémentation du driver pour écran TFT rond GC9A01 240x240 */ #include "gc9a01.h" #include #include //============================================================================== // Variables privées //============================================================================== static SPI_HandleTypeDef *hspi_gc9a01 = NULL; // Police simple 8x8 (bitmap) static const uint8_t font8x8_basic[128][8] = { // A partir du caractère ' ' (32) [32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // space [33] = { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // ! [34] = { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // " [35] = { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // # [36] = { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // $ [37] = { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // % [38] = { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // & [39] = { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // ' [40] = { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // ( [41] = { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // ) [42] = { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // * [43] = { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // + [44] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x06, 0x00}, // , [45] = { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // - [46] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // . [47] = { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // / [48] = { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // 0 [49] = { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // 1 [50] = { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // 2 [51] = { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // 3 [52] = { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // 4 [53] = { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // 5 [54] = { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // 6 [55] = { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // 7 [56] = { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // 8 [57] = { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // 9 [58] = { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // : [65] = { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // A [66] = { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // B [67] = { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // C [68] = { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // D [69] = { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // E [70] = { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // F [71] = { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // G [72] = { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // H [73] = { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // I [74] = { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // J [75] = { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // K [76] = { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // L [77] = { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // M [78] = { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // N [79] = { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // O [80] = { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // P [81] = { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // Q [82] = { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // R [83] = { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // S [84] = { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // T [85] = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U [86] = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // V [87] = { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // W [88] = { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // X [89] = { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // Y [90] = { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // Z }; //============================================================================== // Fonctions privées //============================================================================== static void GC9A01_WriteCommand(uint8_t cmd) { HAL_GPIO_WritePin(GC9A01_DC_GPIO_Port, GC9A01_DC_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi_gc9a01, &cmd, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_SET); } static void GC9A01_WriteData(uint8_t data) { HAL_GPIO_WritePin(GC9A01_DC_GPIO_Port, GC9A01_DC_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi_gc9a01, &data, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_SET); } static void GC9A01_WriteDataBuffer(uint8_t *buffer, uint16_t len) { HAL_GPIO_WritePin(GC9A01_DC_GPIO_Port, GC9A01_DC_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi_gc9a01, buffer, len, HAL_MAX_DELAY); HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_SET); } static void GC9A01_SetAddressWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { // Column address set GC9A01_WriteCommand(GC9A01_CASET); GC9A01_WriteData(x0 >> 8); GC9A01_WriteData(x0 & 0xFF); GC9A01_WriteData(x1 >> 8); GC9A01_WriteData(x1 & 0xFF); // Row address set GC9A01_WriteCommand(GC9A01_RASET); GC9A01_WriteData(y0 >> 8); GC9A01_WriteData(y0 & 0xFF); GC9A01_WriteData(y1 >> 8); GC9A01_WriteData(y1 & 0xFF); // Write to RAM GC9A01_WriteCommand(GC9A01_RAMWR); } //============================================================================== // Fonctions publiques //============================================================================== bool GC9A01_Init(SPI_HandleTypeDef *hspi) { hspi_gc9a01 = hspi; // Reset de l'écran GC9A01_Reset(); HAL_Delay(100); // Séquence d'initialisation GC9A01 GC9A01_WriteCommand(GC9A01_INREGEN2); GC9A01_WriteCommand(GC9A01_SPI2DATA); GC9A01_WriteCommand(0xEB); GC9A01_WriteData(0x14); GC9A01_WriteCommand(GC9A01_INREGEN2); GC9A01_WriteCommand(GC9A01_SPI2DATA); GC9A01_WriteCommand(0x84); GC9A01_WriteData(0x40); GC9A01_WriteCommand(0x85); GC9A01_WriteData(0xFF); GC9A01_WriteCommand(0x86); GC9A01_WriteData(0xFF); GC9A01_WriteCommand(0x87); GC9A01_WriteData(0xFF); GC9A01_WriteCommand(0x88); GC9A01_WriteData(0x0A); GC9A01_WriteCommand(0x89); GC9A01_WriteData(0x21); GC9A01_WriteCommand(0x8A); GC9A01_WriteData(0x00); GC9A01_WriteCommand(0x8B); GC9A01_WriteData(0x80); GC9A01_WriteCommand(0x8C); GC9A01_WriteData(0x01); GC9A01_WriteCommand(0x8D); GC9A01_WriteData(0x01); GC9A01_WriteCommand(0x8E); GC9A01_WriteData(0xFF); GC9A01_WriteCommand(0x8F); GC9A01_WriteData(0xFF); GC9A01_WriteCommand(GC9A01_DFUNCTR); GC9A01_WriteData(0x00); GC9A01_WriteData(0x20); GC9A01_WriteCommand(GC9A01_MADCTL); GC9A01_WriteData(0x08); GC9A01_WriteCommand(GC9A01_COLMOD); GC9A01_WriteData(0x05); GC9A01_WriteCommand(0x90); GC9A01_WriteData(0x08); GC9A01_WriteData(0x08); GC9A01_WriteData(0x08); GC9A01_WriteData(0x08); GC9A01_WriteCommand(0xBD); GC9A01_WriteData(0x06); GC9A01_WriteCommand(0xBC); GC9A01_WriteData(0x00); GC9A01_WriteCommand(0xFF); GC9A01_WriteData(0x60); GC9A01_WriteData(0x01); GC9A01_WriteData(0x04); GC9A01_WriteCommand(GC9A01_PWCTR2); GC9A01_WriteData(0x13); GC9A01_WriteCommand(GC9A01_PWCTR3); GC9A01_WriteData(0x13); GC9A01_WriteCommand(GC9A01_PWCTR4); GC9A01_WriteData(0x22); GC9A01_WriteCommand(0xBE); GC9A01_WriteData(0x11); GC9A01_WriteCommand(0xE1); GC9A01_WriteData(0x10); GC9A01_WriteData(0x0E); GC9A01_WriteCommand(0xDF); GC9A01_WriteData(0x21); GC9A01_WriteData(0x0c); GC9A01_WriteData(0x02); GC9A01_WriteCommand(GC9A01_GAMMA1); GC9A01_WriteData(0x45); GC9A01_WriteData(0x09); GC9A01_WriteData(0x08); GC9A01_WriteData(0x08); GC9A01_WriteData(0x26); GC9A01_WriteData(0x2A); GC9A01_WriteCommand(GC9A01_GAMMA2); GC9A01_WriteData(0x43); GC9A01_WriteData(0x70); GC9A01_WriteData(0x72); GC9A01_WriteData(0x36); GC9A01_WriteData(0x37); GC9A01_WriteData(0x6F); GC9A01_WriteCommand(GC9A01_GAMMA3); GC9A01_WriteData(0x45); GC9A01_WriteData(0x09); GC9A01_WriteData(0x08); GC9A01_WriteData(0x08); GC9A01_WriteData(0x26); GC9A01_WriteData(0x2A); GC9A01_WriteCommand(GC9A01_GAMMA4); GC9A01_WriteData(0x43); GC9A01_WriteData(0x70); GC9A01_WriteData(0x72); GC9A01_WriteData(0x36); GC9A01_WriteData(0x37); GC9A01_WriteData(0x6F); GC9A01_WriteCommand(0xED); GC9A01_WriteData(0x1B); GC9A01_WriteData(0x0B); GC9A01_WriteCommand(0xAE); GC9A01_WriteData(0x77); GC9A01_WriteCommand(0xCD); GC9A01_WriteData(0x63); GC9A01_WriteCommand(0x70); GC9A01_WriteData(0x07); GC9A01_WriteData(0x07); GC9A01_WriteData(0x04); GC9A01_WriteData(0x0E); GC9A01_WriteData(0x0F); GC9A01_WriteData(0x71); GC9A01_WriteData(0xEF); GC9A01_WriteData(0x70); GC9A01_WriteData(0x70); GC9A01_WriteCommand(0x63); GC9A01_WriteData(0x18); GC9A01_WriteData(0x11); GC9A01_WriteData(0x71); GC9A01_WriteData(0xF1); GC9A01_WriteData(0x70); GC9A01_WriteData(0x70); GC9A01_WriteData(0x18); GC9A01_WriteData(0x13); GC9A01_WriteData(0x71); GC9A01_WriteData(0xF3); GC9A01_WriteData(0x70); GC9A01_WriteData(0x70); GC9A01_WriteCommand(0x64); GC9A01_WriteData(0x28); GC9A01_WriteData(0x29); GC9A01_WriteData(0xF1); GC9A01_WriteData(0x01); GC9A01_WriteData(0xF1); GC9A01_WriteData(0x00); GC9A01_WriteData(0x07); GC9A01_WriteCommand(0x66); GC9A01_WriteData(0x3C); GC9A01_WriteData(0x00); GC9A01_WriteData(0xCD); GC9A01_WriteData(0x67); GC9A01_WriteData(0x45); GC9A01_WriteData(0x45); GC9A01_WriteData(0x10); GC9A01_WriteData(0x00); GC9A01_WriteData(0x00); GC9A01_WriteData(0x00); GC9A01_WriteCommand(0x67); GC9A01_WriteData(0x00); GC9A01_WriteData(0x3C); GC9A01_WriteData(0x00); GC9A01_WriteData(0x00); GC9A01_WriteData(0x00); GC9A01_WriteData(0x01); GC9A01_WriteData(0x54); GC9A01_WriteData(0x10); GC9A01_WriteData(0x32); GC9A01_WriteData(0x98); GC9A01_WriteCommand(0x74); GC9A01_WriteData(0x10); GC9A01_WriteData(0x85); GC9A01_WriteData(0x80); GC9A01_WriteData(0x00); GC9A01_WriteData(0x00); GC9A01_WriteData(0x4E); GC9A01_WriteData(0x00); GC9A01_WriteCommand(0x98); GC9A01_WriteData(0x3e); GC9A01_WriteData(0x07); GC9A01_WriteCommand(GC9A01_SLPOUT); HAL_Delay(120); GC9A01_WriteCommand(GC9A01_DISPON); HAL_Delay(20); return true; } void GC9A01_Reset(void) { HAL_GPIO_WritePin(GC9A01_RST_GPIO_Port, GC9A01_RST_Pin, GPIO_PIN_RESET); HAL_Delay(10); HAL_GPIO_WritePin(GC9A01_RST_GPIO_Port, GC9A01_RST_Pin, GPIO_PIN_SET); HAL_Delay(10); } void GC9A01_DisplayOn(void) { GC9A01_WriteCommand(GC9A01_DISPON); } void GC9A01_DisplayOff(void) { GC9A01_WriteCommand(GC9A01_DISPOFF); } void GC9A01_SetRotation(uint8_t rotation) { GC9A01_WriteCommand(GC9A01_MADCTL); switch (rotation) { case 0: GC9A01_WriteData(0x08); break; case 1: GC9A01_WriteData(0x68); break; case 2: GC9A01_WriteData(0xC8); break; case 3: GC9A01_WriteData(0xA8); break; } } void GC9A01_FillScreen(uint16_t color) { GC9A01_SetAddressWindow(0, 0, GC9A01_WIDTH-1, GC9A01_HEIGHT-1); uint8_t color_high = color >> 8; uint8_t color_low = color & 0xFF; HAL_GPIO_WritePin(GC9A01_DC_GPIO_Port, GC9A01_DC_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_RESET); for (uint32_t i = 0; i < GC9A01_WIDTH * GC9A01_HEIGHT; i++) { uint8_t data[2] = {color_high, color_low}; HAL_SPI_Transmit(hspi_gc9a01, data, 2, HAL_MAX_DELAY); } HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_SET); } void GC9A01_SetPixel(uint16_t x, uint16_t y, uint16_t color) { if (x >= GC9A01_WIDTH || y >= GC9A01_HEIGHT) return; GC9A01_SetAddressWindow(x, y, x, y); uint8_t data[2] = {color >> 8, color & 0xFF}; GC9A01_WriteDataBuffer(data, 2); } void GC9A01_DrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color) { int16_t dx = abs(x1 - x0); int16_t dy = abs(y1 - y0); int16_t sx = (x0 < x1) ? 1 : -1; int16_t sy = (y0 < y1) ? 1 : -1; int16_t err = dx - dy; while (1) { GC9A01_SetPixel(x0, y0, color); if (x0 == x1 && y0 == y1) break; int16_t e2 = 2 * err; if (e2 > -dy) { err -= dy; x0 += sx; } if (e2 < dx) { err += dx; y0 += sy; } } } void GC9A01_DrawRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) { GC9A01_DrawLine(x, y, x + width - 1, y, color); GC9A01_DrawLine(x + width - 1, y, x + width - 1, y + height - 1, color); GC9A01_DrawLine(x + width - 1, y + height - 1, x, y + height - 1, color); GC9A01_DrawLine(x, y + height - 1, x, y, color); } void GC9A01_FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) { if (x >= GC9A01_WIDTH || y >= GC9A01_HEIGHT) return; if (x + width > GC9A01_WIDTH) width = GC9A01_WIDTH - x; if (y + height > GC9A01_HEIGHT) height = GC9A01_HEIGHT - y; GC9A01_SetAddressWindow(x, y, x + width - 1, y + height - 1); uint8_t color_high = color >> 8; uint8_t color_low = color & 0xFF; HAL_GPIO_WritePin(GC9A01_DC_GPIO_Port, GC9A01_DC_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_RESET); for (uint32_t i = 0; i < width * height; i++) { uint8_t data[2] = {color_high, color_low}; HAL_SPI_Transmit(hspi_gc9a01, data, 2, HAL_MAX_DELAY); } HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_SET); } void GC9A01_DrawCircle(uint16_t x, uint16_t y, uint8_t radius, uint16_t color) { int16_t f = 1 - radius; int16_t ddF_x = 1; int16_t ddF_y = -2 * radius; int16_t x1 = 0; int16_t y1 = radius; GC9A01_SetPixel(x, y + radius, color); GC9A01_SetPixel(x, y - radius, color); GC9A01_SetPixel(x + radius, y, color); GC9A01_SetPixel(x - radius, y, color); while (x1 < y1) { if (f >= 0) { y1--; ddF_y += 2; f += ddF_y; } x1++; ddF_x += 2; f += ddF_x; GC9A01_SetPixel(x + x1, y + y1, color); GC9A01_SetPixel(x - x1, y + y1, color); GC9A01_SetPixel(x + x1, y - y1, color); GC9A01_SetPixel(x - x1, y - y1, color); GC9A01_SetPixel(x + y1, y + x1, color); GC9A01_SetPixel(x - y1, y + x1, color); GC9A01_SetPixel(x + y1, y - x1, color); GC9A01_SetPixel(x - y1, y - x1, color); } } void GC9A01_FillCircle(uint16_t x, uint16_t y, uint8_t radius, uint16_t color) { for (int16_t dy = -radius; dy <= radius; dy++) { for (int16_t dx = -radius; dx <= radius; dx++) { if (dx*dx + dy*dy <= radius*radius) { GC9A01_SetPixel(x + dx, y + dy, color); } } } } void GC9A01_DrawChar(uint16_t x, uint16_t y, char c, uint16_t color, uint16_t bg_color, uint8_t size) { if (c < 32 || c > 127) c = '?'; for (int i = 0; i < 8; i++) { uint8_t line = font8x8_basic[c][i]; for (int j = 0; j < 8; j++) { if (line & (1 << j)) { if (size == 1) { GC9A01_SetPixel(x + j, y + i, color); } else { GC9A01_FillRect(x + j * size, y + i * size, size, size, color); } } else if (bg_color != color) { if (size == 1) { GC9A01_SetPixel(x + j, y + i, bg_color); } else { GC9A01_FillRect(x + j * size, y + i * size, size, size, bg_color); } } } } } void GC9A01_DrawString(uint16_t x, uint16_t y, const char *str, uint16_t color, uint16_t bg_color, uint8_t size) { while (*str) { GC9A01_DrawChar(x, y, *str, color, bg_color, size); x += 8 * size; str++; } } uint16_t GC9A01_RGB565(uint8_t r, uint8_t g, uint8_t b) { return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); } bool GC9A01_IsInCircle(uint16_t x, uint16_t y) { int16_t dx = x - GC9A01_RADIUS; int16_t dy = y - GC9A01_RADIUS; return (dx*dx + dy*dy) <= (GC9A01_RADIUS * GC9A01_RADIUS); } // Fonctions spécifiques pour interface moto void GC9A01_DrawGauge(uint16_t center_x, uint16_t center_y, uint8_t radius, float value, float min_val, float max_val, uint16_t color, const char* label) { // Dessiner le cercle extérieur GC9A01_DrawCircle(center_x, center_y, radius, GC9A01_WHITE); // Calculer l'angle (de -90° à +90°, soit 180° total) float normalized = (value - min_val) / (max_val - min_val); if (normalized < 0) normalized = 0; if (normalized > 1) normalized = 1; float angle = -90.0f + (normalized * 180.0f); // -90° à +90° float rad = angle * M_PI / 180.0f; // Dessiner l'aiguille int16_t needle_x = center_x + (radius - 5) * cos(rad); int16_t needle_y = center_y + (radius - 5) * sin(rad); GC9A01_DrawLine(center_x, center_y, needle_x, needle_y, color); // Dessiner le centre GC9A01_FillCircle(center_x, center_y, 3, color); // Afficher la valeur char value_str[10]; snprintf(value_str, sizeof(value_str), "%.1f", value); GC9A01_DrawString(center_x - 20, center_y + radius + 10, value_str, color, GC9A01_BLACK, 1); // Afficher le label if (label) { GC9A01_DrawString(center_x - strlen(label) * 4, center_y - radius - 20, label, GC9A01_WHITE, GC9A01_BLACK, 1); } } void GC9A01_DrawAngleIndicator(float roll, float pitch) { uint16_t center_x = GC9A01_WIDTH / 2; uint16_t center_y = GC9A01_HEIGHT / 2; // Effacer la zone central GC9A01_FillCircle(center_x, center_y, 50, GC9A01_BLACK); // Dessiner l'horizon artificiel GC9A01_DrawCircle(center_x, center_y, 50, GC9A01_WHITE); // Ligne d'horizon (basée sur le pitch) int16_t horizon_offset = (int16_t)(pitch * 2); // Facteur d'échelle GC9A01_DrawLine(center_x - 40, center_y + horizon_offset, center_x + 40, center_y + horizon_offset, GC9A01_CYAN); // Indicateur de roulis (triangle au centre) float roll_rad = roll * M_PI / 180.0f; int16_t tri_x = center_x + 20 * sin(roll_rad); int16_t tri_y = center_y - 20 * cos(roll_rad); GC9A01_DrawLine(center_x, center_y, tri_x, tri_y, GC9A01_RED); GC9A01_FillCircle(tri_x, tri_y, 3, GC9A01_RED); // Afficher les valeurs numériques char roll_str[10], pitch_str[10]; snprintf(roll_str, sizeof(roll_str), "R:%.1f", roll); snprintf(pitch_str, sizeof(pitch_str), "P:%.1f", pitch); GC9A01_DrawString(10, 10, roll_str, GC9A01_WHITE, GC9A01_BLACK, 1); GC9A01_DrawString(10, 25, pitch_str, GC9A01_WHITE, GC9A01_BLACK, 1); } void GC9A01_DrawStateIndicator(const char* state, uint16_t color) { // Effacer la zone du bas GC9A01_FillRect(0, GC9A01_HEIGHT - 30, GC9A01_WIDTH, 30, GC9A01_BLACK); // Centrer le texte uint16_t text_width = strlen(state) * 8; uint16_t start_x = (GC9A01_WIDTH - text_width) / 2; GC9A01_DrawString(start_x, GC9A01_HEIGHT - 20, state, color, GC9A01_BLACK, 1); }A01_WriteData(0x09); GC9A01_WriteData(0x07); GC9A01_WriteData(0x08); GC9A01_WriteData(0x03); GC9A01_WriteCommand(GC9A01_FRAMERATE); GC9A01_WriteData(0x34); GC9A01_WriteCommand(0x62); GC9A01_WriteData(0x18); GC9A01_WriteData(0x0D); GC9A01_WriteData(0x71); GC9A01_WriteData(0xED); GC9A01_WriteData(0x70); GC9A01_WriteData(0x70); GC9A01_WriteData(0x18); GC9A01_WriteData(0x0F); GC9