├── MorepUI ├── menu.c ├── menu.h ├── mpkey.c ├── mpkey.h └── oled.c └── README.md /MorepUI/menu.c: -------------------------------------------------------------------------------- 1 | #include "menu.h" 2 | #include "oled.h" 3 | 4 | /* Page*/ 5 | xpMenu NowPage; 6 | xMenu 7 | MainPage, // 一级Page 8 | Page1, Page2, Page3, Page4, Page5, // 二级Page 9 | No3Page1, No3Page2, No3Page3; // 三级Page 10 | 11 | /* item */ 12 | // 一级Page的item 13 | xpItem Selectitm; 14 | xItem Mainitem1, Mainitem2, Mainitem3, Mainitem4, Mainitem5, Mainitem6; 15 | // 二级Page的item 16 | xItem Page1item1, Page1item2, Page1item3; 17 | xItem Page2item1, Page2item2, Page2item3; 18 | xItem Page3item1, Page3item2, Page3item3; 19 | xItem Page4item1, Page4item2, Page4item3; 20 | xItem Page5item1, Page5item2, Page5item3; 21 | // 三级Page的item 22 | xItem No3Pageitem1, No3Pageitem2, No3Pageitem3; 23 | 24 | void AddPage(uint8_t *name, xpMenu page) 25 | { 26 | page->PageName = name; 27 | page->itemHead = NULL; 28 | page->itemTail = NULL; 29 | } 30 | 31 | void AddItem(uint8_t *Name, xpItem item, xpMenu LocalPage, xpMenu nextpage) 32 | { 33 | item->itemName = Name; 34 | item->location = LocalPage; 35 | item->JumpPage = nextpage; 36 | /* 新建item的下一个肯定是null */ 37 | item->nextiTem = NULL; 38 | /* 如果可以跳转,那么此item是跳转页面的父级 */ 39 | if (nextpage != NULL) 40 | nextpage->ParentiTem = item; 41 | /* 链式结构创建item */ 42 | if (LocalPage->itemHead == NULL) // 如果是第一个iTem 43 | { 44 | item->lastiTem = NULL; 45 | LocalPage->itemHead = item; 46 | LocalPage->itemTail = item; 47 | LocalPage->len = 1; 48 | } 49 | else // 不是第一个item 50 | { 51 | item->lastiTem = LocalPage->itemTail; // 新item的last指向Local的tailitem 52 | LocalPage->itemTail->nextiTem = item; // 让尾巴的next指向新的item,连接起来 53 | LocalPage->itemTail = LocalPage->itemTail->nextiTem; // 让尾巴指向新的item 54 | LocalPage->len++; 55 | } 56 | } 57 | void DrawPage(uint8_t pos, xpMenu Page, uint8_t LineSpacing) 58 | { 59 | MP_DrawStr(pos, FirstLine, Page->PageName, 6); 60 | xpItem temp = Page->itemHead; 61 | for (int i = 1; i <= Page->len; i++) 62 | { 63 | MP_DrawStr(pos, FirstLine + i * LineSpacing, temp->itemName, 6); 64 | temp = temp->nextiTem; 65 | } 66 | } 67 | 68 | void Menu_Init(void) 69 | { 70 | NowPage = &MainPage; 71 | Selectitm = &Mainitem1; 72 | MainPage.ParentiTem = NULL; 73 | 74 | AddPage("[MainPage]", &MainPage); 75 | AddItem(" -Application", &Mainitem1, &MainPage, &Page1); 76 | AddItem(" -Text", &Mainitem2, &MainPage, &Page2); 77 | AddItem(" -Image", &Mainitem3, &MainPage, &Page3); 78 | AddItem(" -Reset All", &Mainitem4, &MainPage, &Page4); 79 | AddItem(" -About", &Mainitem5, &MainPage, &Page5); 80 | 81 | AddPage("[Application]", &Page1); 82 | AddItem(" -VsCode", &Page1item1, &Page1, &No3Page1); 83 | AddItem(" -STM32CubeMX", &Page1item2, &Page1, &No3Page2); 84 | AddItem(" -Altium", &Page1item3, &Page1, &No3Page3); 85 | 86 | AddPage("[VsCode]", &No3Page1); 87 | AddItem(" -File1", &No3Pageitem1, &No3Page1, NULL); 88 | AddItem(" -File2", &No3Pageitem2, &No3Page1, NULL); 89 | AddItem(" -File3", &No3Pageitem3, &No3Page1, NULL); 90 | 91 | AddPage("[Text]", &Page2); 92 | AddItem(" -New Project", &Page2item1, &Page2, NULL); 93 | AddItem(" -New Project", &Page2item2, &Page2, NULL); 94 | AddItem(" -New Project", &Page2item3, &Page2, NULL); 95 | 96 | AddPage("[Image]", &Page3); 97 | AddItem(" -New Project", &Page3item1, &Page3, NULL); 98 | AddItem(" -New Project", &Page3item2, &Page3, NULL); 99 | AddItem(" -New Project", &Page3item3, &Page3, NULL); 100 | 101 | AddPage("[Reset All]", &Page4); 102 | AddItem(" -Reset Name", &Page4item1, &Page4, NULL); 103 | AddItem(" -Reset Time", &Page4item2, &Page4, NULL); 104 | AddItem(" -Reset Setting", &Page4item3, &Page4, NULL); 105 | 106 | AddPage("[About]", &Page5); 107 | AddItem(" -Github", &Page5item1, &Page5, NULL); 108 | AddItem(" -Bilibili", &Page5item2, &Page5, NULL); 109 | AddItem(" -ReadME", &Page5item3, &Page5, NULL); 110 | } 111 | -------------------------------------------------------------------------------- /MorepUI/menu.h: -------------------------------------------------------------------------------- 1 | #ifndef __MENU_H__ 2 | #define __MENU_H__ 3 | 4 | #include "main.h" 5 | 6 | #define BoxWidth 80 7 | #define BoxHeight 10 8 | #define FirstLine 9 9 | #define LineSpace 10 10 | 11 | typedef struct MenuPage *xpMenu; 12 | typedef struct Item *xpItem; 13 | typedef struct MenuPage 14 | { 15 | uint8_t *PageName; 16 | uint8_t len; 17 | xpItem ParentiTem; 18 | xpItem itemHead; 19 | xpItem itemTail; 20 | } xMenu; 21 | 22 | typedef struct Item 23 | { 24 | uint8_t *itemName; 25 | xpMenu location; 26 | xpMenu JumpPage; 27 | xpItem lastiTem; 28 | xpItem nextiTem; 29 | } xItem; 30 | 31 | // Page 32 | extern xMenu MainPage, Page1, Page2, Page3, Page4, Page5, No3Page1, No3Page2; 33 | extern xpMenu NowPage; 34 | // item 35 | extern xpItem Selectitm; 36 | extern xItem Mainitem1, Mainitem2, Mainitem3, Mainitem4, Mainitem5, Mainitem6; 37 | extern xItem Page1item1, Page1item2, Page1item3; 38 | extern xItem Page2item1, Page2item2, Page2item3; 39 | extern xItem No3Pageitem1, No3Pageitem2, No3Pageitem3; 40 | void Menu_Init(void); 41 | void AddPage(uint8_t *name, xpMenu page); 42 | void AddItem(uint8_t *Name, xpItem item, xpMenu LocalPage, xpMenu NextPage); 43 | 44 | void DrawPage(uint8_t pos, xpMenu Page, uint8_t LineSpacing); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /MorepUI/mpkey.c: -------------------------------------------------------------------------------- 1 | #include "mpkey.h" 2 | #include "oled.h" 3 | 4 | static pmpkey_t head = NULL, tail = NULL; 5 | static uint8_t ITPeriod = 1; // Ts = 1ms 6 | 7 | void MpKey_Init(pmpkey_t key) 8 | { 9 | key->status = Release; 10 | key->next = NULL; 11 | if (head == NULL) 12 | { 13 | head = key; 14 | tail = key; 15 | } 16 | else 17 | { 18 | // 使用next连接每一个Key 19 | tail->next = key; 20 | tail = tail->next; 21 | } 22 | key->isPressed = 0; 23 | key->isHoled = 0; 24 | } 25 | 26 | mpkey_t Key1, Key2; 27 | 28 | __weak void MpKeyScanLoop(pmpkey_t key) 29 | { 30 | if (key == &Key1) 31 | key->value = HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin); 32 | if (key == &Key2) 33 | key->value = HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin); 34 | key->prevalue = key->value; 35 | } 36 | 37 | __weak void MpKeyPressCallback(mpkey_t *key) 38 | { 39 | key->isPressed = 1; 40 | } 41 | __weak void MpKeyLongHoldCallback(mpkey_t *key) 42 | { 43 | } 44 | __weak void MpKeyFirstlongHoldCallback(mpkey_t *key) 45 | { 46 | key->isHoled = 1; 47 | } 48 | __weak void MpKeylongReleaseCallback(mpkey_t *key) 49 | { 50 | } 51 | 52 | void MpKeyLoop(void) 53 | { 54 | // 轮询按键 55 | for (pmpkey_t key = head; key != NULL; key = key->next) 56 | { 57 | // 每一个按键都扫描 58 | MpKeyScanLoop(key); 59 | // key->value未按下, !key->value按下 60 | if (key->value) 61 | key->PressTime = 0; 62 | if ((!key->prevalue) & (!key->value)) 63 | { 64 | key->PressTime += ITPeriod; 65 | } 66 | 67 | switch (key->status) 68 | { 69 | case Release: 70 | if (!key->value) 71 | key->status = Prepress; 72 | break; 73 | 74 | case Prepress: 75 | if (key->value) 76 | key->status = Release; 77 | else if (key->PressTime > ClickMinTime) 78 | { 79 | key->status = Prelong; 80 | } 81 | break; 82 | 83 | case Prelong: 84 | { 85 | if (key->value) 86 | { 87 | key->status = Release; 88 | MpKeyPressCallback(key); 89 | } 90 | else if (key->PressTime > LongpressMinTime) 91 | { 92 | key->status = Longpress; 93 | key->LongHoldToggle = LongpressToggleTime; 94 | MpKeyFirstlongHoldCallback(key); 95 | } 96 | } 97 | break; 98 | 99 | case Longpress: 100 | if (key->LongHoldToggle > 0) 101 | key->LongHoldToggle -= ITPeriod; 102 | else 103 | { 104 | key->LongHoldToggle = LongpressToggleTime; 105 | MpKeyLongHoldCallback(key); 106 | } 107 | if (key->value) 108 | { 109 | key->status = Release; 110 | MpKeylongReleaseCallback(key); 111 | } 112 | break; 113 | 114 | default: 115 | #ifdef USE_HAL_DRIVER 116 | Error_Handler(); 117 | #endif 118 | break; 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /MorepUI/mpkey.h: -------------------------------------------------------------------------------- 1 | #ifndef __MPKEY_H__ 2 | #define __MPKEY_H__ 3 | 4 | #include "main.h" 5 | 6 | #ifdef USE_HAL_DRIVER 7 | #include "gpio.h" 8 | #endif 9 | 10 | #define ClickMinTime 30 11 | #define LongpressMinTime 450 12 | #define LongpressToggleTime 300 13 | 14 | typedef struct mpkey 15 | { 16 | uint8_t value : 1; 17 | uint8_t prevalue : 1; 18 | uint32_t PressTime; 19 | uint32_t LongHoldToggle; 20 | enum 21 | { 22 | Release = 0, 23 | Prepress, 24 | Prelong, 25 | Longpress 26 | } status; 27 | struct mpkey *next; 28 | uint8_t isPressed; 29 | uint8_t isHoled; 30 | } mpkey_t, *pmpkey_t; 31 | 32 | extern mpkey_t Key1, Key2; 33 | 34 | void MpKey_Init(pmpkey_t key); 35 | void MpKeyScanLoop(pmpkey_t key); 36 | void MpKeyLoop(void); 37 | void MpKeyPressCallback(mpkey_t *key); 38 | void MpKeyLongHoldCallback(mpkey_t *key); 39 | void MpKeyFirstlongHoldCallback(mpkey_t *key); 40 | void MpKeylongReleaseCallback(mpkey_t *key); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /MorepUI/oled.c: -------------------------------------------------------------------------------- 1 | #include "oled.h" 2 | #include "oledfont.h" 3 | #include "main.h" 4 | #include "spi.h" 5 | 6 | unsigned char DisplayBuffer[128][8]; // 1024Byte = 1KB 7 | 8 | void OLED_WR_Byte(uint8_t dat, uint8_t cmd) 9 | { 10 | if (cmd) 11 | { 12 | OLED_DC_Set(); // Cmd 13 | } 14 | else 15 | OLED_DC_Clr(); // Data 16 | OLED_CS_Clr(); 17 | HAL_SPI_Transmit(&hspi1, &dat, 1, 1000); 18 | OLED_CS_Set(); 19 | OLED_DC_Set(); 20 | } 21 | 22 | void OLED_Set_Pos(unsigned char x, unsigned char y) 23 | { 24 | OLED_WR_Byte(0xb0 + y, OLED_CMD); 25 | OLED_WR_Byte(((x & 0xf0) >> 4) | 0x10, OLED_CMD); 26 | OLED_WR_Byte((x & 0x0f), OLED_CMD); 27 | } 28 | 29 | void OLED_Display_On(void) 30 | { 31 | OLED_WR_Byte(0X8D, OLED_CMD); 32 | OLED_WR_Byte(0X14, OLED_CMD); 33 | OLED_WR_Byte(0XAF, OLED_CMD); 34 | } 35 | 36 | void OLED_Display_Off(void) 37 | { 38 | OLED_WR_Byte(0X8D, OLED_CMD); 39 | OLED_WR_Byte(0X10, OLED_CMD); 40 | OLED_WR_Byte(0XAE, OLED_CMD); 41 | } 42 | 43 | void OLED_Clear(void) 44 | { 45 | uint8_t i, n; 46 | for (i = 0; i < 8; i++) 47 | { 48 | OLED_WR_Byte(0xb0 + i, OLED_CMD); 49 | OLED_WR_Byte(0x02, OLED_CMD); 50 | OLED_WR_Byte(0x10, OLED_CMD); 51 | for (n = 0; n < 128; n++) 52 | OLED_WR_Byte(0, OLED_DATA); 53 | } 54 | } 55 | 56 | /** 57 | * @brief 显示一个字符 58 | * @param x 59 | * @param y 60 | * @param chr 61 | * @param size 16 or 12 62 | */ 63 | void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t size) 64 | { 65 | unsigned char c = 0, i = 0; 66 | c = chr - ' '; 67 | if (x > Max_Column - size) 68 | { 69 | x = 0; 70 | y = y + 1; 71 | } 72 | if (size == 16) 73 | { 74 | OLED_Set_Pos(x, y); 75 | for (i = 0; i < 8; i++) 76 | OLED_WR_Byte(F8X16[c * 16 + i], OLED_DATA); 77 | OLED_Set_Pos(x, y + 1); 78 | for (i = 0; i < 8; i++) 79 | OLED_WR_Byte(F8X16[c * 16 + i + 8], OLED_DATA); 80 | } 81 | else 82 | { 83 | OLED_Set_Pos(x, y); 84 | for (i = 0; i < 6; i++) 85 | OLED_WR_Byte(F6x8[c][i], OLED_DATA); 86 | } 87 | } 88 | 89 | uint32_t oled_pow(uint8_t m, uint8_t n) 90 | { 91 | uint32_t result = 1; 92 | while (n--) 93 | result *= m; 94 | return result; 95 | } 96 | 97 | /** 98 | * @brief 显示数字 99 | * @param x 100 | * @param y 101 | * @param num 0 ~ 4294967295 102 | * @param size 6 or 8 103 | */ 104 | void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t size) 105 | { 106 | uint8_t t, temp; 107 | uint32_t templen; 108 | uint8_t enshow = 0; 109 | uint8_t len = 0; 110 | templen = num; 111 | while (templen > 0) 112 | { 113 | templen = templen / 10; 114 | len++; 115 | } 116 | for (t = 0; t < len; t++) 117 | { 118 | temp = (num / oled_pow(10, len - t - 1)) % 10; 119 | if (enshow == 0 && t < (len - 1)) 120 | { 121 | if (temp == 0) 122 | { 123 | OLED_ShowChar(x + size * t, y, ' ', size); 124 | continue; 125 | } 126 | else 127 | enshow = 1; 128 | } 129 | OLED_ShowChar(x + size * t, y, temp + '0', size); 130 | } 131 | } 132 | 133 | /** 134 | * @brief 显示图片 135 | * @param x0 0 ~ 127 136 | * @param y0 0 ~ 7 137 | * @param x1 0 ~ 127 138 | * @param y1 0 ~ 7 139 | * @param BMP 140 | */ 141 | void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t BMP[]) 142 | { 143 | unsigned int j = 0; 144 | unsigned char x, y; 145 | 146 | if (y1 % 8 == 0) 147 | y = y1 / 8; 148 | else 149 | y = y1 / 8 + 1; 150 | for (y = y0; y < y1; y++) 151 | { 152 | OLED_Set_Pos(x0, y); 153 | for (x = x0; x < x1; x++) 154 | { 155 | OLED_WR_Byte(BMP[j++], OLED_DATA); 156 | } 157 | } 158 | } 159 | 160 | void OLED_Init(void) 161 | { 162 | OLED_RST_Clr(); 163 | HAL_Delay(200); 164 | OLED_RST_Set(); 165 | HAL_Delay(200); 166 | 167 | OLED_WR_Byte(0xAE, OLED_CMD); //--turn off oled panel 168 | OLED_WR_Byte(0x00, OLED_CMD); //---set low column address 169 | OLED_WR_Byte(0x10, OLED_CMD); //---set high column address 170 | OLED_WR_Byte(0x40, OLED_CMD); //--set start line address Set Mapping RAM Display Start Line (0x00~0x3F) 171 | OLED_WR_Byte(0x81, OLED_CMD); //--set contrast control register 172 | OLED_WR_Byte(0xCF, OLED_CMD); // Set SEG Output Current Brightness 173 | OLED_WR_Byte(0xA1, OLED_CMD); //--Set SEG/Column Mapping 0Xa0左右反置 0Xa1正常 174 | OLED_WR_Byte(0xA6, OLED_CMD); //--set normal display 175 | OLED_WR_Byte(0xA8, OLED_CMD); //--set multiplex ratio(1 to 64) 176 | OLED_WR_Byte(0x3F, OLED_CMD); //--1/64 duty 177 | OLED_WR_Byte(0xC8, OLED_CMD); // Set COM/Row Scan Direction 0Xc0上下反置 0Xc8正常 178 | OLED_WR_Byte(0xD3, OLED_CMD); //-set display offset Shift Mapping RAM Counter (0x00~0x3F) 179 | OLED_WR_Byte(0x00, OLED_CMD); //-not offset 180 | OLED_WR_Byte(0xD5, OLED_CMD); //--set display clock divide ratio/oscillator frequency 181 | OLED_WR_Byte(0x80, OLED_CMD); //--set divide ratio, Set Clock as 100 Frames/Sec 182 | OLED_WR_Byte(0xD9, OLED_CMD); //--set pre-charge period 183 | OLED_WR_Byte(0xF1, OLED_CMD); // Set Pre-Charge as 15 Clocks & Discharge as 1 Clock 184 | OLED_WR_Byte(0xDA, OLED_CMD); //--set com pins hardware configuration 185 | OLED_WR_Byte(0x12, OLED_CMD); 186 | OLED_WR_Byte(0xDB, OLED_CMD); //--set vcomh 187 | OLED_WR_Byte(0x40, OLED_CMD); // Set VCOM Deselect Level 188 | OLED_WR_Byte(0x8D, OLED_CMD); //--set Charge Pump enable/disable 189 | OLED_WR_Byte(0x14, OLED_CMD); //--set(0x10) disable 190 | OLED_WR_Byte(0xAF, OLED_CMD); /*display ON*/ 191 | OLED_Clear(); 192 | } 193 | 194 | /** 195 | * @file oled.c 196 | * @author 電学渣 197 | * @brief The New UI Called Morep 198 | * @version 0.1 199 | * @date 2023-03-06 200 | * 201 | * @copyright Copyright (c) 2023 202 | * 203 | */ 204 | void MP_SendBuffer(void) 205 | { 206 | uint8_t x, y; 207 | for (y = 0; y < 8; y++) 208 | { 209 | OLED_WR_Byte(0xb0 + y, OLED_CMD); 210 | OLED_WR_Byte(0x00, OLED_CMD); // set low column address 211 | OLED_WR_Byte(0x10, OLED_CMD); // set high column address 212 | for (x = 0; x < 128; x++) 213 | { 214 | OLED_WR_Byte(DisplayBuffer[x][y], OLED_DATA); 215 | } 216 | } 217 | } 218 | 219 | /** 220 | * @brief 清除Buffer,不发送 221 | * 222 | */ 223 | void MP_ClearBuffer(void) 224 | { 225 | uint8_t x, y; 226 | for (y = 0; y < 8; y++) 227 | { 228 | for (x = 0; x < 128; x++) 229 | { 230 | DisplayBuffer[x][y] = 0; 231 | } 232 | } 233 | } 234 | /** 235 | * @brief 画一个点 236 | * @param x 0 ~ 127 237 | * @param y 0 ~ 63 238 | */ 239 | void MP_DrawPoint(uint8_t x, uint8_t y) 240 | { 241 | /* if y = 66, m = 8, n = 2*/ 242 | uint8_t m, n, i; 243 | m = y / 8; 244 | n = y % 8; 245 | i = 1 << n; 246 | if (m < 8) 247 | DisplayBuffer[x][m] |= i; 248 | else 249 | return; 250 | } 251 | /** 252 | * @brief 反相显示(异或) 253 | * @param x 254 | * @param y 255 | */ 256 | void MP_DrawPointInV(uint8_t x, uint8_t y) 257 | { 258 | uint8_t m, n, i; 259 | m = y / 8; 260 | n = y % 8; 261 | i = 1 << n; 262 | if (m < 8) 263 | DisplayBuffer[x][m] = DisplayBuffer[x][m] ^ i; 264 | else 265 | return; 266 | } 267 | 268 | void MP_ClearPoint(uint8_t x, uint8_t y) 269 | { 270 | uint8_t i, m, n; 271 | i = y / 8; 272 | m = y % 8; 273 | n = 1 << m; 274 | DisplayBuffer[x][i] = ~DisplayBuffer[x][i]; 275 | DisplayBuffer[x][i] |= n; 276 | DisplayBuffer[x][i] = ~DisplayBuffer[x][i]; 277 | } 278 | 279 | /** 280 | * @brief 显示一个字符 281 | * @param x 0 ~ 127 282 | * @param y 0 ~63 283 | * @param chr 字符 284 | * @param size 6 285 | */ 286 | void MP_DrawChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t size) 287 | { 288 | uint8_t i, m, chartemp, temp; 289 | uint8_t y0 = y; 290 | chartemp = chr - ' '; // 获取起始位置 291 | for (i = 0; i < 6; i++) 292 | { 293 | temp = F6x8[chartemp][i]; // 获取当前一列0x 294 | for (m = 0; m < 8; m++) 295 | { 296 | if (temp & 0x80) 297 | MP_DrawPoint(x, y0 - m); // 自下往上画点 298 | else 299 | MP_ClearPoint(x, y0 - m); 300 | temp <<= 1; 301 | y++; 302 | if ((y - y0) == 8) 303 | { 304 | y = y0; 305 | x++; 306 | break; 307 | } 308 | } 309 | } 310 | } 311 | /** 312 | * @brief 显示字符串 313 | * @param x 1 ~ 128 314 | * @param y 1 ~ 64 315 | * @param string 字符串 316 | * @param size 6 317 | */ 318 | void MP_DrawStr(uint8_t x, uint8_t y, uint8_t *string, uint8_t size) 319 | { 320 | x--; 321 | y--; 322 | while ((*string >= ' ') && (*string <= '~')) 323 | { 324 | MP_DrawChar(x, y, *string, size); 325 | x += size; 326 | if (x > 127 - size) 327 | break; 328 | string++; 329 | } 330 | } 331 | 332 | uint8_t MP_StrWidth(uint8_t *string) 333 | { 334 | uint8_t len = 0; 335 | while ((*string >= ' ') && (*string <= '~')) 336 | { 337 | len++; 338 | string++; 339 | } 340 | return len; 341 | } 342 | /** 343 | * @brief 画一条线 344 | * @param x 0 ~ 128 345 | * @param y 0 ~ 63 346 | * @param len 1 ~ 128 347 | * @param dir UP or RIGHT or DOWN or LEFT 348 | */ 349 | void MP_DrawHVLine(uint8_t x, uint8_t y, uint8_t len, uint8_t dir) 350 | { 351 | if (dir == UP) 352 | for (int i = 0; i < len; i++) 353 | MP_DrawPoint(x, y - i); 354 | else if (dir == RIGHT) 355 | for (int i = 0; i < len; i++) 356 | MP_DrawPoint(x + i, y); 357 | else if (dir == DOWN) 358 | for (int i = 0; i < len; i--) 359 | MP_DrawPoint(x, y + i); 360 | else 361 | for (int i = 0; i < len; i++) 362 | MP_DrawPoint(x - i, y); 363 | } 364 | void MP_DrawHVLineInV(uint8_t x, uint8_t y, uint8_t len, uint8_t dir) 365 | { 366 | if (dir == UP) 367 | for (int i = 0; i < len; i++) 368 | MP_DrawPointInV(x, y - i); 369 | else if (dir == RIGHT) 370 | for (int i = 0; i < len; i++) 371 | MP_DrawPointInV(x + i, y); 372 | else if (dir == DOWN) 373 | for (int i = 0; i < len; i--) 374 | MP_DrawPointInV(x, y + i); 375 | else 376 | for (int i = 0; i < len; i++) 377 | MP_DrawPointInV(x - i, y); 378 | } 379 | 380 | /** 381 | * @brief 画Box 382 | * @param x 1 ~ 128 383 | * @param y 1 ~ 64 384 | * @param width 长度 385 | * @param height 高度 386 | * @param R 圆角 387 | * @param mode Normal or Invert 388 | */ 389 | void MP_DrawRBox(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t R, uint8_t mode) 390 | { 391 | if (x + width - 1 > 128 || y - height < 0) 392 | return; 393 | R++; 394 | x--; 395 | y--; 396 | if (mode == Normal) 397 | { 398 | for (int R1 = 0; R1 < R - 1; R1++) 399 | MP_DrawHVLine(x + R - 1 - R1, y - height + 1 + R1, width - 2 * (R - 1) + 2 * R1, RIGHT); 400 | for (int i = 0; i < height - 2 * (R - 1); i++) 401 | MP_DrawHVLine(x, y - R + 1 - i, width, RIGHT); 402 | for (int R2 = 0; R2 < R - 1; R2++) 403 | MP_DrawHVLine(x + R - 1 - R2, y - R2, width - 2 * (R - 1) + 2 * R2, RIGHT); 404 | } 405 | else if (mode == Invert) 406 | { 407 | for (int R1 = 0; R1 < R - 1; R1++) 408 | MP_DrawHVLineInV(x + R - 1 - R1, y - height + 1 + R1, width - 2 * (R - 1) + 2 * R1, RIGHT); 409 | for (int i = 0; i < height - 2 * (R - 1); i++) 410 | MP_DrawHVLineInV(x, y - R + 1 - i, width, RIGHT); 411 | for (int R2 = 0; R2 < R - 1; R2++) 412 | MP_DrawHVLineInV(x + R - 1 - R2, y - R2, width - 2 * (R - 1) + 2 * R2, RIGHT); 413 | } 414 | } 415 | 416 | /** 417 | * @brief Transition animation 418 | * 419 | * @param pos 420 | * @param Tar 421 | * @param speed 422 | */ 423 | void MP_RunGui(uint8_t *pos, uint8_t *Tar, uint8_t speed) 424 | { 425 | if (*pos < *Tar) 426 | { 427 | if (*Tar - *pos > speed) 428 | *pos = *pos + speed; 429 | else 430 | *pos = *pos + 1; 431 | } 432 | else if (*pos > *Tar) 433 | { 434 | if (*pos - *Tar > speed) 435 | *pos = *pos - speed; 436 | else 437 | *pos = *pos - 1; 438 | } 439 | else 440 | { 441 | return; 442 | } 443 | } 444 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MorepUI 2 | * menu.c 关于菜单的创建,菜单的绘制等函数 3 | 4 | * oled.c 绘制字符串,选择框,oled初始化等函数 5 | 6 | * mpkey.c 按键函数 7 | 8 | * 按键采用链式结构 9 | 10 | * Page中的item也采用链式结构 11 | 12 | 相关视频看这里[非常流畅的菜单,求大佬指点下一步如何进行](https://www.bilibili.com/video/BV1Yj411u7R6/) 13 | --------------------------------------------------------------------------------