1 /*
2 * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3 */
4
5 #include "sh1106.h"
6 #include "aos/hal/gpio.h"
7 #include "aos/hal/spi.h"
8 #include "hal_iomux_haas1000.h"
9 #include "ulog/ulog.h"
10 #include "sh1106_hdconfig.h"
11 #include <math.h>
12 #include <stdio.h>
13 #include <time.h>
14
15 #if USE_SOFT_SPI == 1
16 #include <sys/ioctl.h>
17 #include <vfsdev/gpio_dev.h>
18 #include <drivers/char/u_device.h>
19 #include <drivers/u_ld.h>
20 #include "aos/vfs.h"
21 static int fd = 0;
22 #endif
23
24 #define OLED_PAGE_SIZES 132
25 #define SPI_MAX_BLOCK 60000
26
27 #define PI 3.1415926535
28
29 uint8_t OLED_GRAM[8][OLED_PAGE_SIZES];
30 uint8_t oled_remote_buffer[8 * OLED_PAGE_SIZES * 2];
31
32 static spi_dev_t spi_sh1106 = {0};
33 static gpio_dev_t gpio_sh1106_dc;
34 static gpio_dev_t gpio_sh1106_reset;
35
36 struct timeval tv;
37
38 #if USE_SOFT_SPI == 0
spi_write(const void * data,uint32_t size)39 static inline void spi_write(const void *data, uint32_t size)
40 {
41 if (size > SPI_MAX_BLOCK) {
42 uint32_t rest = size;
43 uint32_t start = 0;
44 while (rest > SPI_MAX_BLOCK) {
45 hal_spi_send(&spi_sh1106, (const void *)(data + start),
46 SPI_MAX_BLOCK, 10);
47 start += SPI_MAX_BLOCK;
48 rest -= SPI_MAX_BLOCK;
49 }
50 hal_spi_send(&spi_sh1106, (const void *)(data + start), rest, 10);
51 } else {
52 hal_spi_send(&spi_sh1106, (const void *)data, (uint16_t)size, 10);
53 }
54 }
OLED_GPIO_Init()55 static inline int OLED_GPIO_Init()
56 {
57 // printf("hardware_init START\r\n");
58
59 gpio_sh1106_dc.port = SPI1_DC_PIN;
60 gpio_sh1106_dc.config = OUTPUT_PUSH_PULL;
61 hal_gpio_init(&gpio_sh1106_dc);
62
63 gpio_sh1106_reset.port = SPI1_RESET_PIN;
64 gpio_sh1106_reset.config = OUTPUT_PUSH_PULL;
65 hal_gpio_init(&gpio_sh1106_reset);
66
67 hal_gpio_output_high(&gpio_sh1106_dc);
68
69 hal_gpio_output_low(&gpio_sh1106_reset);
70 aos_msleep(1000);
71 hal_gpio_output_high(&gpio_sh1106_reset);
72
73 // printf("hal_gpio_init done\r\n");
74 return 0;
75 }
76
OLED_SPI_Init()77 static inline int OLED_SPI_Init()
78 {
79 spi_sh1106.port = 1;
80 spi_sh1106.config.mode = SPI_WORK_MODE_3; // CPOL = 1; CPHA = 1
81 spi_sh1106.config.freq = 26000000;
82 spi_sh1106.config.role = SPI_ROLE_MASTER;
83 spi_sh1106.config.firstbit = SPI_FIRSTBIT_MSB;
84 spi_sh1106.config.t_mode = SPI_TRANSFER_NORMAL;
85 spi_sh1106.config.serial_len = 8;
86 spi_sh1106.config.data_size = SPI_DATA_SIZE_8BIT;
87 spi_sh1106.config.cs = SPI_CS_DIS;
88
89 hal_spi_init(&spi_sh1106);
90 printf("hal_spi_init done\r\n");
91 return 0;
92 }
93
write_command(uint8_t c)94 static inline void write_command(uint8_t c)
95 {
96 hal_gpio_output_low(&gpio_sh1106_dc);
97 spi_write(&c, sizeof(c));
98 hal_gpio_output_high(&gpio_sh1106_dc);
99 }
100
write_data(uint8_t d)101 static inline void write_data(uint8_t d)
102 {
103 hal_gpio_output_high(&gpio_sh1106_dc);
104 spi_write(&d, sizeof(d));
105 hal_gpio_output_high(&gpio_sh1106_dc);
106 }
107
write_data_page(uint8_t * data,uint16_t size)108 static inline void write_data_page(uint8_t *data, uint16_t size)
109 {
110 uint8_t i;
111 hal_gpio_output_high(&gpio_sh1106_dc);
112 spi_write(data, size);
113 }
114 #else
OLED_GPIO_Init()115 static inline int OLED_GPIO_Init()
116 {
117 gpio_dev_t oled_gpio;
118
119 // 对各个PIN进行初始化
120 oled_gpio.port = OLED_CLK_PIN;
121 oled_gpio.config = OUTPUT_PUSH_PULL;
122 hal_gpio_init(&oled_gpio);
123
124 oled_gpio.port = OLED_SDA_PIN;
125 oled_gpio.config = OUTPUT_PUSH_PULL;
126 hal_gpio_init(&oled_gpio);
127
128 oled_gpio.port = OLED_RES_PIN;
129 oled_gpio.config = OUTPUT_PUSH_PULL;
130 hal_gpio_init(&oled_gpio);
131
132 oled_gpio.port = OLED_DC_PIN;
133 oled_gpio.config = OUTPUT_PUSH_PULL;
134 hal_gpio_init(&oled_gpio);
135
136 OLED_DC(1);
137 /* 复位 */
138 OLED_RES(0);
139 aos_msleep(1000);
140 OLED_RES(1);
141
142 fd = open("/dev/gpio", 0);
143 printf("open gpio %s, fd:%d\r\n", fd >= 0 ? "success" : "fail", fd);
144 return 0;
145 }
146
OLED_GPIO_Set(unsigned char port,unsigned char leve)147 static void OLED_GPIO_Set(unsigned char port, unsigned char leve)
148 {
149 struct gpio_io_config config;
150
151 config.id = port;
152 config.config = GPIO_IO_OUTPUT | GPIO_IO_OUTPUT_PP;
153 if (leve == 1) {
154 config.data = 1;
155 } else if (leve == 0) {
156 config.data = 0;
157 } else {
158 return;
159 }
160 ioctl(fd, IOC_GPIO_SET, (unsigned long)&config);
161 }
162
OLED_SCLK(uint8_t x)163 void OLED_SCLK(uint8_t x)
164 {
165 if (x == 1) {
166 OLED_GPIO_Set(OLED_CLK_PIN, 1);
167 } else if (x == 0) {
168 OLED_GPIO_Set(OLED_CLK_PIN, 0);
169 }
170 }
171
OLED_RES(uint8_t x)172 void OLED_RES(uint8_t x)
173 {
174 if (x == 1) {
175 OLED_GPIO_Set(OLED_RES_PIN, 1);
176 } else if (x == 0) {
177 OLED_GPIO_Set(OLED_RES_PIN, 0);
178 }
179 }
180
OLED_DC(uint8_t x)181 void OLED_DC(uint8_t x)
182 {
183 if (x == 1) {
184 OLED_GPIO_Set(OLED_DC_PIN, 1);
185 } else if (x == 0) {
186 OLED_GPIO_Set(OLED_DC_PIN, 0);
187 }
188 }
189
OLED_SDIN(uint8_t x)190 void OLED_SDIN(uint8_t x)
191 {
192 struct gpio_io_config config;
193
194 config.id = OLED_SDA_PIN;
195 config.config = GPIO_IO_OUTPUT | GPIO_IO_OUTPUT_PP;
196 if (x == 0x80) {
197 config.data = 1;
198 } else if (x == 0) {
199 config.data = 0;
200 }
201 ioctl(fd, IOC_GPIO_SET, (unsigned long)&config);
202 }
203
OLED_SPI_Init()204 static inline int OLED_SPI_Init()
205 {
206 // Nothing to do
207 return 0;
208 }
209
write_command(uint8_t cmd)210 static inline void write_command(uint8_t cmd)
211 {
212 uint8_t i, k;
213 /*写命令拉低DC */
214 OLED_DC(0);
215
216 for (i = 0; i < 8; i++) {
217 /* 时钟线,上升沿有效 */
218 OLED_SCLK(0);
219 k = cmd & (0x80);
220 OLED_SDIN(k);
221 OLED_SCLK(1);//high valid
222 cmd <<= 1;
223 }
224 OLED_DC(1);
225 }
226
write_data(uint8_t data)227 static inline void write_data(uint8_t data)
228 {
229 uint8_t i, k;
230 /* 写数据拉高DC */
231 OLED_DC(1);
232
233 for (i = 0; i < 8; i++) {
234 /* 时钟线,上升沿有效 */
235 OLED_SCLK(0);
236 k = data & (0x80);
237 OLED_SDIN(k);
238 OLED_SCLK(1);
239 data <<= 1;
240 }
241 OLED_DC(1);
242 }
243
write_data_page(uint8_t * data,uint16_t size)244 static inline void write_data_page(uint8_t *data, uint16_t size)
245 {
246 uint8_t i, j, k, d;
247
248 for (j = 0; j < size; j++) {
249 d = data[j];
250 for (i = 0; i < 8; i++) {
251 OLED_SCLK(0);
252 k = d & (0x80);
253 OLED_SDIN(k);
254 OLED_SCLK(1);
255 d <<= 1;
256 }
257 }
258 OLED_DC(1);
259 }
260 #endif
261
262 #if RECORD_SCREEN == 1
zip_oled_gram(uint8_t * des,uint16_t * des_len)263 static uint16_t zip_oled_gram(uint8_t *des, uint16_t *des_len)
264 {
265 uint8_t buf = OLED_GRAM[0][0];
266 uint8_t cnt = 0;
267 *des_len = 0;
268 for (int i = 0; i < 8; i++) {
269 for (int j = 0; j < 132; j++) {
270 if (OLED_GRAM[i][j] == buf) {
271 cnt++;
272 if (cnt == 0xff) {
273 des[(*des_len)++] = buf;
274 des[(*des_len)++] = cnt;
275 cnt = 0;
276 }
277 }
278 if (OLED_GRAM[i][j] != buf) {
279 des[(*des_len)++] = buf;
280 des[(*des_len)++] = cnt;
281 cnt = 1;
282 buf = OLED_GRAM[i][j];
283 }
284 }
285 }
286 des[(*des_len)++] = buf;
287 des[(*des_len)++] = cnt;
288 return *des_len;
289 }
290 #endif
291
OLED_Refresh_GRAM(void)292 void OLED_Refresh_GRAM(void)
293 {
294 #if FB_FRAME_EN == 1
295 //fb frame todo:
296 #else
297 for (uint8_t i = 0; i < 8; i++) {
298 /* 设置显示的起始地址 */
299 write_command(0xB0 + i); // 设置页地址(行)
300 write_command(0x00); // 设置列地址的低四位
301 write_command(0x10); // 设置列地址的高四位
302 write_data_page(OLED_GRAM[i], OLED_PAGE_SIZES);
303 }
304 #endif
305 #if RECORD_SCREEN == 1
306 uint16_t zip_len = 0;
307 zip_oled_gram(oled_remote_buffer, &zip_len);
308
309 gettimeofday(&tv, NULL);
310
311 if (zip_len <= 8 * 132) {
312 // 压缩有效
313 printf("pyszip|%d%d.", tv.tv_sec, tv.tv_usec / 1000);
314 printf("%03ld|", tv.tv_usec / 1000);
315 uint16_t cnt = 0;
316 for (int i = 0; i < zip_len; i++) {
317 printf("%02X", oled_remote_buffer[i]);
318 cnt += (i % 2 ? oled_remote_buffer[i] : 0);
319 }
320 printf("|%d\n", cnt);
321 } else {
322 // 压缩无效
323 printf("pysorg|%d%d.", tv.tv_sec, tv.tv_usec / 1000);
324 printf("%03ld|", tv.tv_usec / 1000);
325 for (int i = 0; i < 8; i++) {
326 for (int j = 0; j < 132; j++) {
327 printf("%02X", OLED_GRAM[i][j]);
328 }
329 }
330 printf("|1056\n");
331 }
332 #endif
333 }
334
OLED_Clear(void)335 void OLED_Clear(void)
336 {
337 uint8_t i, j;
338 for (i = 0; i < 8; i++)
339 for (j = 0; j < OLED_PAGE_SIZES; j++)
340 OLED_GRAM[i][j] = 0x0;
341 }
342
OLED_Full(void)343 void OLED_Full(void)
344 {
345 uint8_t i, j;
346 for (i = 0; i < 8; i++)
347 for (j = 0; j < OLED_PAGE_SIZES; j++)
348 OLED_GRAM[i][j] = 0xff;
349 }
350
OLED_Frame_Draw(uint8_t frame[][132])351 void OLED_Frame_Draw(uint8_t frame[][132])
352 {
353 uint8_t i, j;
354 for (i = 0; i < 8; i++) {
355 for (j = 0; j < OLED_PAGE_SIZES; j++) {
356 OLED_GRAM[i][j] = frame[i][j];
357 }
358 printf("OLED_GRAM[%d][0] = %02X;\n", i, OLED_GRAM[i][0]);
359 }
360 }
361
362 // OLED_Icon_Draw(-10, -10, icon_t *icon, 0)
363 // 0 完全不覆盖
364 // 1 完全覆盖
365 // 2 mask覆盖
OLED_Icon_Draw(int16_t x,int16_t y,icon_t * icon,uint8_t mode)366 void OLED_Icon_Draw(int16_t x, int16_t y, icon_t *icon, uint8_t mode)
367 {
368 int16_t width_byte = icon->width;
369 int16_t height_byte = icon->height / 8 + (icon->height % 8 != 0);
370 int16_t column_0 = x;
371 int16_t page_0 = (y < 0) ? (y / 8 - (y % 8 != 0)) : (y / 8);
372 int8_t bit_offset = (y % 8 < 0) ? (y % 8 + 8) : (y % 8);
373 if (mode == 2 && icon->p_icon_mask == NULL) {
374 mode = 0;
375 }
376 for (int byte_y = 0; (byte_y < height_byte) && (byte_y + page_0 < 8);
377 byte_y++) {
378 if (page_0 + byte_y + 1 < 0)
379 continue;
380 for (int byte_x = 0; (byte_x < width_byte) && (byte_x + column_0 < 132);
381 byte_x++) {
382 if (byte_x + column_0 < 0)
383 continue;
384 // 绘画处在当前 page 的部分
385 if (page_0 + byte_y >= 0) {
386 if (mode == 1) {
387 OLED_GRAM[page_0 + byte_y][column_0 + byte_x] &=
388 ~(0xff << bit_offset);
389 }
390 if (mode == 2) {
391 OLED_GRAM[page_0 + byte_y][column_0 + byte_x] &=
392 ~((icon->p_icon_mask[byte_y * width_byte + byte_x])
393 << bit_offset);
394 }
395 OLED_GRAM[page_0 + byte_y][column_0 + byte_x] |=
396 (icon->p_icon_data[byte_y * width_byte + byte_x])
397 << bit_offset;
398 }
399 // 绘画处在下一个 page 的部分
400 if (bit_offset > 0 && page_0 + byte_y + 1 >= 0 &&
401 page_0 + byte_y + 1 < 8) {
402 if (mode == 1) {
403 OLED_GRAM[page_0 + byte_y + 1][column_0 + byte_x] &=
404 ~(0xff >> (8 - bit_offset));
405 }
406 if (mode == 2) {
407 OLED_GRAM[page_0 + byte_y + 1][column_0 + byte_x] &=
408 ~((icon->p_icon_mask[byte_y * width_byte + byte_x]) >>
409 (8 - bit_offset));
410 }
411 OLED_GRAM[page_0 + byte_y + 1][column_0 + byte_x] |=
412 (icon->p_icon_data[byte_y * width_byte + byte_x]) >>
413 (8 - bit_offset);
414 }
415 }
416 }
417 }
418
419 /* 画点函数,以屏幕像素点为单位,以左上角为原点 x:0~127 y:0~63
420 (x,y)坐标换算:OLED_GRAM[x][7-y/8]|=1<<(7-y%8);
421 mode取1正显,取0反显
422 */
OLED_DrawPoint(int16_t x,int16_t y,uint8_t mode)423 void OLED_DrawPoint(int16_t x, int16_t y, uint8_t mode)
424 {
425 if ((x > (131)) || (y > 63) || x < 0 || y < 0)
426 return;
427
428 uint8_t page = y / 8;
429 uint8_t bit_offset = y % 8;
430 uint8_t mask = 0x01 << bit_offset;
431
432 if (mode == 0)
433 OLED_GRAM[page][x] &= ~mask;
434 if (mode == 1)
435 OLED_GRAM[page][x] |= mask;
436 if (mode == 2)
437 OLED_GRAM[page][x] ^= mask;
438 }
439
440 /* 在(x,y)坐标正显/反显指定大小字符chr
441 mode:0是反显,1是正常显示
442 size:12/16/24
443 ASCII字符集:
444 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOP
445 QRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
446 */
OLED_Show_Char(uint8_t x,uint8_t y,uint8_t chr,uint8_t size,uint8_t mode)447 void OLED_Show_Char(uint8_t x,
448 uint8_t y,
449 uint8_t chr,
450 uint8_t size,
451 uint8_t mode)
452 {
453 /* temp是当前对应的一个字节的点集,y0是初始坐标 */
454 uint8_t temp, t, t1;
455 uint8_t y0 = y;
456 /* csize是单个字符所占字节的多少 */
457 uint8_t csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2);
458 /* 求出偏移的地址差,即得到该字符在字库中的序号(从零开始) */
459 /* chr会锁定字符在字库中的的序号 */
460 // LOGI("APP", "++++ char=%c size=%d\n", chr, csize);
461 chr = chr - ' ';
462 /* 相应字符点集有多少个字节 */
463 for (t = 0; t < csize; t++) {
464 /* 根据字符的大小选择相应字库,根据chr得到具体的字符地址 */
465 switch (size) {
466 case 12:
467 temp = sh1106_asc2_1206[chr][t];
468 break; // 12x6(行x列)
469 case 16:
470 temp = sh1106_asc2_1608[chr][t];
471 break; // 16x8
472 case 24:
473 temp = sh1106_asc2_2412[chr][t];
474 break; // 24x12
475 default :
476 return; // 没有相应字库
477 }
478 // LOGI("APP", " new char x= %d,y=%d,t =%d %d\n", x, y, t, temp);
479 /* 画出每一列的点 */
480 for (t1 = 0; t1 < 8; t1++) {
481 if (temp & 0x80)
482 OLED_DrawPoint(x, y, mode);
483 else
484 OLED_DrawPoint(x, y, !mode);
485
486 temp <<= 1;
487 y++;
488 // LOGI("APP", "x= %d,y=%d\n",x,y);
489 /* 根据给出每一列的像素点的多少,判断列是否满:
490 满了就换列,不满继续在此列画点 (与字库画点原理相关)
491 */
492 if ((y - y0) == size) {
493 // LOGI("APP", "new line\n");
494 y = y0;
495 x++;
496 /* 一列满,跳出循环,直接转到下一个字节点集的打印 */
497 break;
498 }
499 }
500 }
501 }
502 /* (x,y)是显示的坐标,*p是字符串的首地址,size是字符点集大小 */
OLED_Show_String(uint8_t x,uint8_t y,const uint8_t * p,uint8_t size,uint8_t mode)503 void OLED_Show_String(uint8_t x,
504 uint8_t y,
505 const uint8_t *p,
506 uint8_t size,
507 uint8_t mode)
508 {
509 /* 判断是否合法字符,同时也限定了范围 */
510 while ((*p <= '~') && (*p >= ' ')) {
511 /* 如果初始行放不下,移动到下一行 */
512 if (x > (OLED_PAGE_SIZES - (size / 2))) {
513 x = 0;
514 y = y + size;
515 }
516 if (y > (64 - size)) {
517 x = y = 0;
518 OLED_Clear();
519 }
520
521 OLED_Show_Char(x, y, *p, size, mode);
522 /* 移动到下一个字符位置,size/2是因为做点集时就是:行X列,而且
523 * 行=2X列,所以size就是行数 */
524 x = x + size / 2;
525 p++;
526 }
527 // OLED_Refresh_GRAM();
528 }
529 // end native
530
command_list(void)531 static void command_list(void)
532 {
533 /* 开始写入初始化命令 */
534 write_command(0xAE); // 关闭显示
535 write_command(0xD5); // 设置时钟分频因子
536 write_command(80);
537
538 write_command(0xA8); // 设置驱动路数
539 write_command(0x3F); // 路数默认0x3F(1/64)
540
541 write_command(0xD3); // 设置显示偏移
542 write_command(0x00); // 偏移默认为0
543
544 write_command(0x40); // 设置显示开始行[5:0]
545
546 write_command(0x8D); // 电荷泵设置
547 write_command(0x14); // bit2,开启/关闭
548
549 write_command(0x20); // 设置内存地址模式
550 write_command(0x02); // [1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
551
552 write_command(0xA1); // 段重定义设置,bit0:0,0->0;1,0->127;
553 write_command(0xC8); // 设置COM扫描方向;bit3:0,普通模式;1,重定义模式
554 // COM[N-1]->COM0;N:驱动路数
555 write_command(0xDA); // 设置COM硬件引脚配置
556 write_command(0x12); // [5:4]配置
557
558 write_command(0x81); // 对比度设置
559 write_command(0xEF); // 默认0x7F(范围1~255,越大越亮)
560
561 write_command(0xD9); // 设置预充电周期
562 write_command(0xF1); // [3:0],PHASE 1;[7:4],PHASE 2;
563
564 write_command(0xDB); // 设置VCOMH 电压倍率
565 write_command(0x30); // [6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
566
567 write_command(0xA4); // 全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
568 write_command(0xA6); // 设置显示方式;bit0:1,反相显示;0,正常显示
569
570 write_command(0xAF); // 开启显示
571
572 OLED_Clear();
573 OLED_Refresh_GRAM();
574 aos_msleep(500);
575 }
576
OLED_DrawLine(int16_t x1,int16_t y1,int16_t x2,int16_t y2,uint8_t mode)577 void OLED_DrawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t mode)
578 {
579 uint16_t t;
580 int xerr = 1, yerr = 1, delta_x, delta_y, distance;
581 int incx, incy, uRow, uCol;
582
583 delta_x = x2 - x1;
584 delta_y = y2 - y1;
585
586 uRow = x1;
587 uCol = y1;
588 if (delta_x > 0) {
589 incx = 1;
590 } else if (delta_x == 0) {
591 incx = 0;
592 } else {
593 incx = -1;
594 delta_x = -delta_x;
595 }
596
597 if (delta_y > 0) {
598 incy = 1;
599 } else if (delta_y == 0) {
600 incy = 0;
601 } else {
602 incy = -1;
603 delta_y = -delta_y;
604 }
605
606 if (delta_x > delta_y)
607 distance = delta_x;
608 else
609 distance = delta_y;
610
611 for (t = 0; t <= distance; t++) {
612 OLED_DrawPoint(uRow, uCol, mode);
613 xerr += delta_x;
614 yerr += delta_y;
615
616 if (xerr > distance / 2) {
617 xerr -= distance;
618 uRow += incx;
619 }
620 if (yerr > distance) {
621 yerr -= distance;
622 uCol += incy;
623 }
624 }
625 }
626
OLED_DrawLine_ByAngle(int16_t x0,int16_t y0,int16_t angle,int16_t length,uint8_t mode)627 void OLED_DrawLine_ByAngle(int16_t x0,
628 int16_t y0,
629 int16_t angle,
630 int16_t length,
631 uint8_t mode)
632 {
633 int16_t x1 = x0 + length * cos(angle * PI / 180.0);
634 int16_t y1 = y0 + length * sin(angle * PI / 180.0);
635 OLED_DrawLine(x0, y0, x1, y1, mode);
636 }
637
OLED_DrawHorizontalLine(uint8_t x,uint8_t y,uint8_t length,uint8_t mode)638 void OLED_DrawHorizontalLine(uint8_t x, uint8_t y, uint8_t length, uint8_t mode)
639 {
640 if (y < 0 || y >= 64) {
641 return;
642 }
643
644 if (x < 0) {
645 length += x;
646 x = 0;
647 }
648
649 if ((x + length) > 132) {
650 length = (132 - x);
651 }
652
653 if (length <= 0) {
654 return;
655 }
656
657 while (length--) {
658 OLED_DrawPoint(x + length, y, mode);
659 }
660 }
661
OLED_DrawVerticalLine(uint8_t x,uint8_t y,uint8_t length,uint8_t mode)662 void OLED_DrawVerticalLine(uint8_t x, uint8_t y, uint8_t length, uint8_t mode)
663 {
664 if (x < 0 || x >= 132) {
665 return;
666 }
667
668 if (x < 0) {
669 length += x;
670 x = 0;
671 }
672
673 if ((y + length) > 64) {
674 length = (64 - x);
675 }
676
677 if (length <= 0) {
678 return;
679 }
680
681 while (length--) {
682 OLED_DrawPoint(x, y + length, mode);
683 }
684 }
685
OLED_DrawRect(uint8_t x,uint8_t y,uint8_t width,uint8_t height,uint8_t mode)686 void OLED_DrawRect(uint8_t x,
687 uint8_t y,
688 uint8_t width,
689 uint8_t height,
690 uint8_t mode)
691 {
692 OLED_DrawHorizontalLine(x, y, width, mode);
693 OLED_DrawVerticalLine(x, y, height, mode);
694 OLED_DrawVerticalLine(x + width - 1, y, height, mode);
695 OLED_DrawHorizontalLine(x, y + height - 1, width, mode);
696 }
697
OLED_FillRect(uint8_t xMove,uint8_t yMove,uint8_t width,uint8_t height,uint8_t mode)698 void OLED_FillRect(uint8_t xMove,
699 uint8_t yMove,
700 uint8_t width,
701 uint8_t height,
702 uint8_t mode)
703 {
704 for (uint8_t x = xMove; x < xMove + width; x++) {
705 OLED_DrawVerticalLine(x, yMove, height, mode);
706 }
707 }
708
OLED_DrawCircle(uint8_t x0,uint8_t y0,uint8_t radius,uint8_t width,uint8_t mode)709 void OLED_DrawCircle(uint8_t x0,
710 uint8_t y0,
711 uint8_t radius,
712 uint8_t width,
713 uint8_t mode)
714 {
715 OLED_FillCircle(x0, y0, radius, mode);
716 OLED_FillCircle(x0, y0, radius - width, !mode);
717 }
718
OLED_FillCircle(uint8_t x0,uint8_t y0,uint8_t r,uint8_t mode)719 void OLED_FillCircle(uint8_t x0, uint8_t y0, uint8_t r, uint8_t mode)
720 {
721 int x, y;
722 int deltax, deltay;
723 int d;
724 int xi;
725 x = 0;
726 y = r;
727 deltax = 3;
728 deltay = 2 - r - r;
729 d = 1 - r;
730
731 OLED_DrawPoint(x + x0, y + y0, mode);
732 OLED_DrawPoint(x + x0, -y + y0, mode);
733 for (xi = -r + x0; xi <= r + x0; xi++)
734 OLED_DrawPoint(xi, y0, mode);
735 while (x < y) {
736 if (d < 0) {
737 d += deltax;
738 deltax += 2;
739 x++;
740 } else {
741 d += (deltax + deltay);
742 deltax += 2;
743 deltay += 2;
744 x++;
745 y--;
746 }
747 for (xi = -x + x0; xi <= x + x0; xi++) {
748 OLED_DrawPoint(xi, -y + y0, mode);
749 OLED_DrawPoint(xi, y + y0, mode);
750 }
751 for (xi = -y + x0; xi <= y + x0; xi++) {
752 OLED_DrawPoint(xi, -x + y0, mode);
753 OLED_DrawPoint(xi, x + y0, mode);
754 }
755 }
756 }
757
hardware_init(void)758 static uint8_t hardware_init(void)
759 {
760 uint8_t ret = 0;
761
762 ret |= OLED_SPI_Init();
763
764 ret |= OLED_GPIO_Init();
765
766 if (ret) {
767 printf("hardware_init fail\r\n");
768 return ret;
769 }
770 return ret;
771 }
772
773 /* (x,y)是显示的坐标,*p是字符串的首地址,size是字符点集大小 */
sh1106_show_string(uint8_t x,uint8_t y,const uint8_t * p,uint8_t size,uint8_t mode)774 void sh1106_show_string(uint8_t x,
775 uint8_t y,
776 const uint8_t *p,
777 uint8_t size,
778 uint8_t mode)
779 {
780 /* 判断是否合法字符,同时也限定了范围 */
781 while ((*p <= '~') && (*p >= ' ')) {
782 /* 如果初始行放不下,移动到下一行 */
783 if (x > (OLED_PAGE_SIZES - (size / 2))) {
784 x = 0;
785 y = y + size;
786 }
787 if (y > (64 - size)) {
788 x = y = 0;
789 OLED_Clear();
790 }
791
792 OLED_Show_Char(x, y, *p, size, mode);
793 /* 移动到下一个字符位置,size/2是因为做点集时就是:行X列,而且
794 * 行=2X列,所以size就是行数 */
795 x = x + size / 2;
796 p++;
797 }
798 OLED_Refresh_GRAM();
799 }
800
sh1106_init(void)801 uint8_t sh1106_init(void)
802 {
803 uint8_t err_code;
804
805 err_code = hardware_init();
806 if (err_code != 0) {
807 return err_code;
808 }
809 command_list();
810 return err_code;
811 }
812