• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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