1 /*
2 * Copyright (c) 2021 LOCKZHINER Electronic Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "lz_hardware.h"
16 #include "oled.h"
17 #include "oled_font.h"
18
19 /* OLED通信协议模式 ==>
20 * 0 = gpio模拟i2c
21 * 1 = i2c模块
22 */
23 #define OLED_I2C_ENABLE 1
24
25 /* OLED的从设备地址 */
26 #define OLED_I2C_ADDRESS 0x3C
27
28 #if !OLED_I2C_ENABLE
29 /* GPIO0_C1 => I2C1_SDA_M1 */
30 #define GPIO_I2C_SDA GPIO0_PC1
31 /* GPIO0_C2 => I2C1_SCL_M1 */
32 #define GPIO_I2C_SCL GPIO0_PC2
33
34 /* SCLK引脚的输出高/低电平 */
35 #define OLED_SCLK_Clr() LzGpioSetVal(GPIO_I2C_SCL, LZGPIO_LEVEL_LOW)
36 #define OLED_SCLK_Set() LzGpioSetVal(GPIO_I2C_SCL, LZGPIO_LEVEL_HIGH)
37
38 /* SDIN引脚的输出高/低电平 */
39 #define OLED_SDIN_Clr() LzGpioSetVal(GPIO_I2C_SDA, LZGPIO_LEVEL_LOW)
40 #define OLED_SDIN_Set() LzGpioSetVal(GPIO_I2C_SDA, LZGPIO_LEVEL_HIGH)
41
42 /* RST引脚的输出高/低电平 */
43 #define OLED_RST_Clr()
44 #define OLED_RST_Set()
45 #else
46 #define OLED_I2C_BUS 1
47 static I2cBusIo m_i2cBus = {
48 .scl = {
49 .gpio = GPIO0_PC2,
50 .func = MUX_FUNC5,
51 .type = PULL_NONE,
52 .drv = DRIVE_KEEP,
53 .dir = LZGPIO_DIR_KEEP,
54 .val = LZGPIO_LEVEL_KEEP
55 },
56 .sda = {
57 .gpio = GPIO0_PC1,
58 .func = MUX_FUNC5,
59 .type = PULL_NONE,
60 .drv = DRIVE_KEEP,
61 .dir = LZGPIO_DIR_KEEP,
62 .val = LZGPIO_LEVEL_KEEP
63 },
64 .id = FUNC_ID_I2C1,
65 .mode = FUNC_MODE_M1,
66 };
67 static unsigned int m_i2c_freq = 400000;
68 #endif
69
70 /* 定义OLED读写操作 */
71 #define OLED_CMD 0 // OLED的命令操作标记
72 #define OLED_DATA 1 // OLED的数据操作标记
73
74 /* 字节的bits数目 */
75 #define BYTE_TO_BITS 8
76
77 /***************************************************************
78 * 函数名称: oled_pow
79 * 说 明: 计算m^n
80 * 参 数:
81 * @m:计算m^n的m
82 * @n:计算m^n中的n
83 * 返 回 值: 计算结果值
84 ***************************************************************/
oled_pow(uint8_t m,uint8_t n)85 static uint32_t oled_pow(uint8_t m, uint8_t n)
86 {
87 uint32_t result = 1;
88
89 while (n--) {
90 result *= m;
91 }
92
93 return result;
94 }
95
96
97 #if !OLED_I2C_ENABLE
98 /***************************************************************
99 * 函数名称: iic_start
100 * 说 明: i2c的起始条件
101 * 参 数: 无
102 * 返 回 值: 无
103 ***************************************************************/
iic_start(void)104 static inline void iic_start(void)
105 {
106 OLED_SCLK_Set();
107 OLED_SDIN_Set();
108 OLED_SDIN_Clr();
109 OLED_SCLK_Clr();
110 }
111
112
113 /***************************************************************
114 * 函数名称: iic_stop
115 * 说 明: i2c的结束条件
116 * 参 数: 无
117 * 返 回 值: 无
118 ***************************************************************/
iic_stop(void)119 static inline void iic_stop(void)
120 {
121 OLED_SCLK_Set() ;
122 OLED_SDIN_Clr();
123 OLED_SDIN_Set();
124 }
125
126
127 /***************************************************************
128 * 函数名称: iic_wait_ack
129 * 说 明: i2c的等待应答
130 * 参 数: 无
131 * 返 回 值: 无
132 ***************************************************************/
iic_wait_ack(void)133 static inline void iic_wait_ack(void)
134 {
135 OLED_SCLK_Set();
136 OLED_SCLK_Clr();
137 }
138
139
140 /***************************************************************
141 * 函数名称: write_iic_byte
142 * 说 明: i2c写单个字节
143 * 参 数:
144 * @IIC_Byte:数值
145 * 返 回 值: 无
146 ***************************************************************/
write_iic_byte(unsigned char iic_byte)147 static inline void write_iic_byte(unsigned char iic_byte)
148 {
149 unsigned char i;
150 unsigned char m, da;
151 da = iic_byte;
152 OLED_SCLK_Clr();
153 for (i = 0; i < BYTE_TO_BITS; i++) {
154 m = da;
155 m = m & 0x80;
156 if (m == 0x80) {
157 OLED_SDIN_Set();
158 } else {
159 OLED_SDIN_Clr();
160 }
161 da = da << 1;
162 OLED_SCLK_Set();
163 OLED_SCLK_Clr();
164 }
165 }
166
167
168 /***************************************************************
169 * 函数名称: write_iic_command
170 * 说 明: 通过i2c通信协议,往芯片写入一个命令
171 * 参 数:
172 * @IIC_Command:命令数值
173 * 返 回 值: 无
174 ***************************************************************/
write_iic_command(unsigned char iic_command)175 static inline void write_iic_command(unsigned char iic_command)
176 {
177 iic_start();
178 /* 从设备地址 + SA0, SA0=0表示写操作 */
179 write_iic_byte((OLED_I2C_ADDRESS << 1) | 0x0);
180 iic_wait_ack();
181 /* 通知芯片,下一个字节是命令 */
182 write_iic_byte(0x00);
183 iic_wait_ack();
184 write_iic_byte(iic_command);
185 iic_wait_ack();
186 iic_stop();
187 }
188
189
190 /***************************************************************
191 * 函数名称: write_iic_data
192 * 说 明: 通过i2c通信协议,往芯片写入一个数据
193 * 参 数:
194 * @IIC_Data:数据数值
195 * 返 回 值: 无
196 ***************************************************************/
write_iic_data(unsigned char iic_data)197 static inline void write_iic_data(unsigned char iic_data)
198 {
199 iic_start();
200 /* 从设备地址 + SA0, SA0=0表示写操作 */
201 write_iic_byte((OLED_I2C_ADDRESS << 1) | 0x0);
202 iic_wait_ack();
203 /* 通知芯片,下一个字节是数据 */
204 write_iic_byte(0x40);
205 iic_wait_ack();
206 write_iic_byte(iic_data);
207 iic_wait_ack();
208 iic_stop();
209 }
210 #else
211 /***************************************************************
212 * 函数名称: write_iic_command
213 * 说 明: 通过i2c通信协议,往芯片写入一个命令
214 * 参 数:
215 * @IIC_Command:命令数值
216 * 返 回 值: 无
217 ***************************************************************/
write_iic_command(unsigned char iic_command)218 static inline void write_iic_command(unsigned char iic_command)
219 {
220 #define BUFFER_MAXSIZE 2 /* 字符串长度 */
221 unsigned char buffer[BUFFER_MAXSIZE];
222 unsigned int ret;
223
224 /* 填充数据,第一个字节是通知OLED芯片,下一个字节是命令 */
225 buffer[0] = 0x00;
226 buffer[1] = iic_command;
227 ret = LzI2cWrite(OLED_I2C_BUS, OLED_I2C_ADDRESS, buffer, BUFFER_MAXSIZE);
228 if (ret != 0) {
229 printf("%s, %s, %d: LzI2cWrite failed(%d)!\n", __FILE__, __func__, __LINE__, ret);
230 }
231 }
232
233
234 /***************************************************************
235 * 函数名称: write_iic_data
236 * 说 明: 通过i2c通信协议,往芯片写入一个数据
237 * 参 数:
238 * @iic_data:数据数值
239 * 返 回 值: 无
240 ***************************************************************/
write_iic_data(unsigned char iic_data)241 static inline void write_iic_data(unsigned char iic_data)
242 {
243 #define BUFFER_MAXSIZE 2 /* 字符串长度 */
244 unsigned char buffer[BUFFER_MAXSIZE];
245 unsigned int ret;
246
247 /* 填充数据,第一个字节是通知OLED芯片,下一个字节是数据 */
248 buffer[0] = 0x40;
249 buffer[1] = iic_data;
250 ret = LzI2cWrite(OLED_I2C_BUS, OLED_I2C_ADDRESS, buffer, BUFFER_MAXSIZE);
251 if (ret != 0) {
252 printf("%s, %s, %d: LzI2cWrite failed(%d)!\n", __FILE__, __func__, __LINE__, ret);
253 }
254 }
255 #endif
256
257
258 /***************************************************************
259 * 函数名称: oled_wr_byte
260 * 说 明: 往芯片写数据
261 * 参 数:
262 * @data:数据数值
263 * @cmd:该数据是命令,还是数据
264 * 返 回 值: 无
265 ***************************************************************/
oled_wr_byte(unsigned dat,unsigned cmd)266 static inline void oled_wr_byte(unsigned dat, unsigned cmd)
267 {
268 if (cmd == OLED_DATA) {
269 write_iic_data(dat);
270 } else if (cmd == OLED_CMD) {
271 write_iic_command(dat);
272 } else {
273 printf("%s, %s, %d: cmd(%d) out of the range!\n", __FILE__, __func__, __LINE__, cmd);
274 }
275 }
276
277
278 /***************************************************************
279 * 函数名称: oled_set_pos
280 * 说 明: 坐标设置
281 * 参 数:
282 * @x:X轴坐标
283 * @y:Y轴坐标
284 * 返 回 值: 无
285 ***************************************************************/
oled_set_pos(unsigned char x,unsigned char y)286 static inline void oled_set_pos(unsigned char x, unsigned char y)
287 {
288 #define BYTE_DIV 4 /* 截取字节部分 */
289 oled_wr_byte(0xb0 + y, OLED_CMD);
290 oled_wr_byte(((x & 0xf0) >> BYTE_DIV) | 0x10, OLED_CMD);
291 oled_wr_byte((x & 0x0f), OLED_CMD);
292 }
293
294 /***************************************************************
295 * 函数名称: oled_init
296 * 说 明: oled初始化
297 * 参 数: 无
298 * 返 回 值: 返回0为成功,反之为失败
299 ***************************************************************/
oled_init(void)300 unsigned int oled_init(void)
301 {
302 uint32_t sleep_msec = 200;
303 #if !OLED_I2C_ENABLE
304 /* GPIO0_C1 => I2C1_SDA_M1 */
305 LzGpioInit(GPIO_I2C_SDA);
306 LzGpioSetDir(GPIO_I2C_SDA, LZGPIO_DIR_OUT);
307 /* GPIO0_C2 => I2C1_SCL_M1 */
308 LzGpioInit(GPIO_I2C_SCL);
309 LzGpioSetDir(GPIO_I2C_SCL, LZGPIO_DIR_OUT);
310 #else
311 if (I2cIoInit(m_i2cBus) != LZ_HARDWARE_SUCCESS) {
312 printf("%s, %d: I2cIoInit failed!\n", __FILE__, __LINE__);
313 return __FILE__;
314 }
315 if (LzI2cInit(OLED_I2C_BUS, m_i2c_freq) != LZ_HARDWARE_SUCCESS) {
316 printf("%s, %d: I2cIoInit failed!\n", __FILE__, __LINE__);
317 return __FILE__;
318 }
319 #endif
320
321 LOS_Msleep(sleep_msec);
322
323 oled_wr_byte(0xAE, OLED_CMD); // --display off
324 oled_wr_byte(0x00, OLED_CMD); // ---set low column address
325 oled_wr_byte(0x10, OLED_CMD); // ---set high column address
326 oled_wr_byte(0x40, OLED_CMD); // --set start line address
327 oled_wr_byte(0xB0, OLED_CMD); // --set page address
328 oled_wr_byte(0x81, OLED_CMD); // contract control
329 oled_wr_byte(0xFF, OLED_CMD); // --128
330 oled_wr_byte(0xA1, OLED_CMD); // set segment remap
331 oled_wr_byte(0xA6, OLED_CMD); // --normal / reverse
332 oled_wr_byte(0xA8, OLED_CMD); // --set multiplex ratio(1 to 64)
333 oled_wr_byte(0x3F, OLED_CMD); // --1/32 duty
334 oled_wr_byte(0xC8, OLED_CMD); // Com scan direction
335 oled_wr_byte(0xD3, OLED_CMD); // -set display offset
336 oled_wr_byte(0x00, OLED_CMD);
337
338 oled_wr_byte(0xD5, OLED_CMD); // set osc division
339 oled_wr_byte(0x80, OLED_CMD);
340
341 oled_wr_byte(0xD8, OLED_CMD); // set area color mode off
342 oled_wr_byte(0x05, OLED_CMD);
343
344 oled_wr_byte(0xD9, OLED_CMD); // Set Pre-Charge Period
345 oled_wr_byte(0xF1, OLED_CMD);
346
347 oled_wr_byte(0xDA, OLED_CMD); // set com pin configuartion
348 oled_wr_byte(0x12, OLED_CMD);
349
350 oled_wr_byte(0xDB, OLED_CMD); // set Vcomh
351 oled_wr_byte(0x30, OLED_CMD);
352
353 oled_wr_byte(0x8D, OLED_CMD); // set charge pump enable
354 oled_wr_byte(0x14, OLED_CMD);
355
356 oled_wr_byte(0xAF, OLED_CMD); // --turn on oled panel
357
358 return 0;
359 }
360
361
362 /***************************************************************
363 * 函数名称: oled_deinit
364 * 说 明: oled销毁
365 * 参 数: 无
366 * 返 回 值: 返回0为成功,反之为失败
367 ***************************************************************/
oled_deinit(void)368 unsigned int oled_deinit(void)
369 {
370 #if !OLED_I2C_ENABLE
371 LzGpioDeinit(GPIO_I2C_SDA);
372 LzGpioDeinit(GPIO_I2C_SCL);
373 #else
374 LzI2cDeinit(OLED_I2C_BUS);
375 #endif
376 return 0;
377 }
378
379
380 /***************************************************************
381 * 函数名称: oled_clear
382 * 说 明: oled清空
383 * 参 数: 无
384 * 返 回 值: 无
385 ***************************************************************/
oled_clear(void)386 void oled_clear(void)
387 {
388 uint8_t i, n;
389
390 for (i = 0; i < BYTE_TO_BITS; i++) {
391 oled_wr_byte(0xb0 + i, OLED_CMD); // 设置页地址(0~7)
392 oled_wr_byte(0x00, OLED_CMD); // 设置显示位置—列低地址
393 oled_wr_byte(0x10, OLED_CMD); // 设置显示位置—列高地址
394 for (n = 0; n < OLED_COLUMN_MAX; n++) {
395 oled_wr_byte(0, OLED_DATA);
396 }
397 }
398 }
399
400
401 /***************************************************************
402 * 函数名称: oled_display_on
403 * 说 明: oled显示开启
404 * 参 数: 无
405 * 返 回 值: 无
406 ***************************************************************/
oled_display_on(void)407 void oled_display_on(void)
408 {
409 oled_wr_byte(0X8D, OLED_CMD); // SET DCDC命令
410 oled_wr_byte(0X14, OLED_CMD); // DCDC ON
411 oled_wr_byte(0XAF, OLED_CMD); // DISPLAY ON
412 }
413
414
415 /***************************************************************
416 * 函数名称: oled_display_off
417 * 说 明: oled显示关闭
418 * 参 数: 无
419 * 返 回 值: 无
420 ***************************************************************/
oled_display_off(void)421 void oled_display_off(void)
422 {
423 oled_wr_byte(0X8D, OLED_CMD); // SET DCDC命令
424 oled_wr_byte(0X10, OLED_CMD); // DCDC OFF
425 oled_wr_byte(0XAE, OLED_CMD); // DISPLAY OFF
426 }
427
428
429 /***************************************************************
430 * 函数名称: oled_show_char
431 * 说 明: oled显示字符
432 * 参 数:
433 * @x:字符的X轴坐标
434 * @y:字符的Y轴坐标
435 * @chr:字符
436 * @chr_size:字符的字体,包括12/16两种字体
437 * 返 回 值: 无
438 ***************************************************************/
oled_show_char(uint8_t x,uint8_t y,uint8_t chr,uint8_t chr_size)439 void oled_show_char(uint8_t x, uint8_t y, uint8_t chr, uint8_t chr_size)
440 {
441 #define F8X16_LINE_DATA 8
442 #define F6X8_LINE_DATA 6
443 #define BYTE_BITS 8
444 #define CHAR_LEN 16
445 #define Y_OFFSET 2
446 unsigned char c = 0, i = 0;
447
448 c = chr - ' '; // 得到偏移后的值
449
450 if (x > (OLED_COLUMN_MAX - 1)) {
451 x = 0;
452 y = y + Y_OFFSET;
453 }
454
455 if (chr_size == OLED_CHR_SIZE_16) {
456 oled_set_pos(x, y);
457 for (i = 0; i < F8X16_LINE_DATA; i++) {
458 oled_wr_byte(F8X16[c * 16 + i], OLED_DATA);
459 }
460 oled_set_pos(x, y + 1);
461 for (i = 0; i < F8X16_LINE_DATA; i++) {
462 oled_wr_byte(F8X16[c * CHAR_LEN + i + BYTE_BITS], OLED_DATA);
463 }
464 } else {
465 oled_set_pos(x, y);
466 for (i = 0; i < F6X8_LINE_DATA; i++) {
467 oled_wr_byte(F6x8[c][i], OLED_DATA);
468 }
469 }
470 }
471
472
473 /***************************************************************
474 * 函数名称: oled_show_num
475 * 说 明: oled显示数字
476 * 参 数:
477 * @x:数字的X轴坐标
478 * @y:数字的Y轴坐标
479 * @num:数字
480 * @len:数字的位数
481 * @size:字体大小
482 * 返 回 值: 无
483 ***************************************************************/
oled_show_num(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size2)484 void oled_show_num(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size2)
485 {
486 #define POWER_BASE 10 /* oled_power的基数 */
487 #define POWER_REMINDER 10 /* oled_power的取余 */
488 uint8_t div = 2;
489 uint8_t t, temp;
490 uint8_t enshow = 0;
491
492 for (t = 0; t < len; t++) {
493 temp = (num / oled_pow(POWER_BASE, len - t - 1)) % POWER_REMINDER;
494 if (enshow == 0 && t < (len - 1)) {
495 if (temp == 0) {
496 oled_show_char(x + (size2 / div)*t, y, ' ', size2);
497 continue;
498 } else {
499 enshow = 1;
500 }
501 }
502 oled_show_char(x + (size2 / div)*t, y, temp + '0', size2);
503 }
504 }
505
506
507 /***************************************************************
508 * 函数名称: oled_show_string
509 * 说 明: oled显示字符串
510 * 参 数:
511 * @x:字符串的X轴坐标
512 * @y:字符串的Y轴坐标
513 * @p:字符串
514 * @chr_size:字符串的位数
515 * 返 回 值: 无
516 ***************************************************************/
oled_show_string(uint8_t x,uint8_t y,uint8_t * chr,uint8_t chr_size)517 void oled_show_string(uint8_t x, uint8_t y, uint8_t *chr, uint8_t chr_size)
518 {
519 uint8_t x_offset = 8;
520 unsigned char j = 0;
521 uint8_t offset = 2;
522
523 while (chr[j] != '\0') {
524 oled_show_char(x, y, chr[j], chr_size);
525 x += x_offset;
526 if (x > OLED_COLUMN_MAX) {
527 x = 0;
528 y += offset;
529 }
530 j++;
531 }
532 }
533
534
535 /***************************************************************
536 * 函数名称: oled_draw_bmp
537 * 说 明: oled显示图片
538 * 参 数:
539 * @x0:图片的起始点X轴坐标,取值为0~127
540 * @y0:图片的起始点Y轴坐标,取值为0~63
541 * @x1:图片的结束点X轴坐标,取值为0~127
542 * @y1:图片的结束点Y轴坐标,取值为0~63
543 * @bmp:图片
544 * 返 回 值: 无
545 ***************************************************************/
oled_draw_bmp(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char bmp[])546 void oled_draw_bmp(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char bmp[])
547 {
548 unsigned char xy_points = 8;
549 unsigned int j = 0;
550 unsigned char x, y;
551
552 if (y1 % xy_points == 0) {
553 y = y1 / xy_points;
554 } else {
555 y = y1 / xy_points + 1;
556 }
557
558 for (y = y0; y < y1; y++) {
559 oled_set_pos(x0, y);
560
561 for (x = x0; x < x1; x++) {
562 oled_wr_byte(bmp[j++], OLED_DATA);
563 }
564 }
565 }
566