电子DIY小家 发表于 2022-10-17 10:21:30

STC驱动教程系列——CDC驱动虚拟OLED显示汉字字符

序言
      一直以来,我都在各大论坛默默潜水,也收获了很多奇奇怪怪的知识,本着开源的精神,最近开始在论坛发文分享知识,之前的论坛发文总有各种限制,甚至文字都会被删减很多,经人推荐决定后面在本论坛发文,在这里我主要分享驱动类的教程(如果此刻屏幕前的看官们需要STC的某些驱动,可以留言给我,如果需要的人多的话我会考虑出一期完整的教程专门讲解)。当然我也会偶尔发一些小项目,主要以STC为主(在这里需要重点感谢一下STC,给我送来的很多的核心板、开发板和调试器,重点实名表扬一下STC的聂(qq:2593903262)和STC的吴(qq:1463035472),感谢他们近期对我开源的大力支持,送了很多开发板,如果你们看完我的文章,有需要板子的朋友也可以去找他们(添加其中一个就可以啦)免费申请(没准报我名字能有额外福利也说不定!当然申请渠道多多,官网电话亦可),只要对电子感兴趣,愿意动手的,想学习STC的,无论你是个人还是单位,无论是学生还是打工人均可以申请),另外在这里还要特别感谢一下STC的姚总,为大家提供了各类免费的开发板学习,为电子这一行做出了巨大的贡献,感谢姚总!!祝愿STC越做越大,越做越强!!
第一次发文,有什么不好的地方欢迎大家指出,也欢迎大家留下好的建议,如果看完了全文希望也能你留下你的足迹,另外希望我的文章能对大家有所帮助,最后祝大家事业有成。
      另外原创不易,转载请注明出处,谢谢。(想联系我的可以加官方入驻的QQ大群:453616422或者个人的QQ小群:884047237,随便加一个群就好了,两个群里都有STC的官方人员可以免费申请板子)

一、前言
      看到STC家最近最新推出了STC32G(PS:STC8H8K64与他功能类似),看到了全网首发的一个USB-CDC的虚拟串口功能,号称不用USB转TTL的芯片,只需要单片机通过USB连接电脑就可以实现串口通信,甚至在ISP软件上还有虚拟的各种设备可以直接驱动看效果(显示效果如下图),果断联系销售要了一个试试性能。


当然,因为DEMO程序可能有些刚入门的小伙伴不会使用,在这里我特出一期教程帮助大家入门,本教程围绕开天斧主板,最终实现功能如下:(详情见演示视频)    1.直接驱动和缓存驱动两种驱动方式;    2.内建汉字字库索引和ascll字符库,能实现汉字和字符的任意显示;    3.缓存驱动实现画点函数和简易划线函数;    4.虚拟键盘实现6个OLED页面的功能演示。
二、实现过程      2.1工程的建立因为已知有现成的OLED的驱动函数,所以我们这里直接寻找一个现成的示例代码导入,当然想要从零新建一个工程的可以直接参考STC8H的手册实现,这里为了精简,我就直接从官网下载一个最新的示例代码库了。直接登录官网http://www.stcmcudata.com/,找到下图中的“开天斧-STC8H-实验板演示程序”下载下来。
      解压出来找到历程包里有如下两个文件随后,我们给他复制到一个新的文件夹,得到一个新的工程,具体如下(有需要的可以给16-STC开头的的那个文件夹改个名字,这里为了演示方便就不修改了),这里前一个文件夹是用户代码,COMM文件夹里是STC的USB相关的驱动库,为了后期方便升级替换,这里就放在了工程目录里然后打开工程文件夹,开始编译工程。打开“16-STC-ISP调试接口通过USB CDC协议驱动虚拟设备”文加夹,双击“stc_usb_ser.uvproj”即可打开工程,然后开始编译,如下图说明编译成功。
2.2工程下载这里选择开天斧作为主控,先按下板子上的P3.2按钮不松开,然后按一下板子上的OFF按钮并松开,此事在松开P3.2按钮,然后打开ISP软件,随后按照下图配置:
2.3工程测试(按照如下图一步一步的设置)
然后分别打开STC调试接口里的“虚拟键盘”和“OLED-128*64”。
然后看到我们的程序里,从按键P到按键NEXT都是关于OLED的操作具体的功能可以见这个程序的注释,可以直接按下这个键盘上对应的按钮进行操作(例如按下虚拟键盘上的R就会打开显示,Q就会关闭显示)。但是看完了这个程序很多人会好奇,怎么只有一个显示图片的程序呢,我就想给他显示一个字母,我要怎么操作呢,怎么这里连显示一个字母的函数都没有呢?
2.4驱动逻辑分析看到“STC调试接口”里的调试接口协议,里面有全部的OLED的驱动函数,可以看到全部的函数如下图所示,仔细分析下来操作屏幕显示的只有一行OLED12864_ShowPicture的函数,所以我们要想在屏幕上显示一个字母,就得首先从这个函数入手。   可以看到这个有这么一个函数:void OLED12864_ShowPicture(BYTE x, BYTE y, BYTE cx, BYTE cy, BYTE *dat);他的入口参数是一个指针,一般都是指向一个数组的首地址,那么显示一个数组的就必须要知道他对应的数组里存放的顺序,我们看到这个SSD1306的手册,重点部分如下截图:已知默认OLED用的水平寻址模式,参考OLED的手册,可以看到该模式下他将128*64的像素点分成了纵向的128列,横向的8个大行(因为一次写8个bit,这里8个大行*8bit(八个小行)刚好64bit),且每个byte的数据发过去高位在下,低位在上。也就是说整屏幕的刷新广汇能源要显示数据一共是128*8个,每次发送的数据在的位数对应下图。横向8行,竖向128列,写入的1024个字节的数据中,第一个字节在第一行第一列,第128个字节在第一行第127列。因为上表中单独一行中,每个列都是1个字节的,换成二进制数就是8个位。例如0X01,这是一个16进制数,也是一个字节的数据,写成二进制数就是0000 0001b,可以看到他前面有7个0,末尾有1个1。我们知道1代表点亮,也就是说这一大行的八个小行里,第一个小行的那个位置会被点亮。
知道了这个驱动逻辑,那我们就可以开始取字模了,首先是写1点亮,这属于阴码格式,以行位单位,每次8个位的写数据,属于列行式,高位在下,低位在上属于逆向。所以取模软件的设置如下。所以到了这里想玩转这个显示屏就很简单了,想点亮作为为(0,0,)的点,我们只需要通过这个函数void OLED12864_ShowPicture(BYTE x, BYTE y, BYTE cx, BYTE cy, BYTE *dat);,将他的x,y坐标都设置为0就可以指向原点位置,cx和cy都设置为1表示只需要输出一个字节,因为点亮的位置是在最上面,所以参数就是0x01即可。一个ascll就是横向写八个字节的数据,在换一行在写8个字节的数据,确定好x和y的地址之后,数据起始的指针指向这个字符对应的数组开始的地方就可以了。
2.5:实际测试(另外,不建议用这个方式,所以这里不细展开讲解了,推荐第三章的方式)    OLED.C文件内容如下:<font size="3">#include "oled.h"
#include <stdio.h>
#include <string.h>
#include "font.h"

/****************************************系统操作****************************************/
void OLED_Init(void)   //OLED初始化
{
    OLED12864_SetContrast(255);       //亮度值(范围0~255)(255);//亮度最大
    OLED12864_ScrollStop(); //停止滚屏
    OLED12864_DisplayOn();             //打开OLED12864的显示
    OLED12864_DisplayContent();      //显示屏幕内容
    OLED12864_SetAddressMode(0x00);    //
}

/****************************************直接驱动****************************************/
void OLED_ShowChar(unsigned char x,unsigned char y,char asc)   //OLED显示一个8*16字符
{
   OLED12864_ShowPicture(x, y, 8, 2, (BYTE *)&Ascll_16[(asc-' ')*2]);
}

void OLED_ShowGBK(unsigned char x,unsigned char y,char *gbk)   //OLED显示一个16*16汉字
{
    unsigned char i;
    for( i=0;i<100;i++ )
    {
      if(( gbk== GBK16.gbn_bum )&&( gbk== GBK16.gbn_bum ))
      {
            OLED12864_ShowPicture(x,y, 16, 2, (BYTE *)&GBK16.gbk_font);
      }
    }
}

void OLED_ShowString(unsigned char x,unsigned char y,char *s)
{
    char s_num;
      while(*s != '\0')       //字符串不为空,循环
      {
      if ((unsigned char)*s < 0x80)   //根据输入数据的大小判断是字符还是汉字,
      {
            OLED_ShowChar(x,y,*s);
            x+=8;
            s++;
      }
      else
      {
            s_num = *s ;
            s_num = *(s+1) ;
            OLED_ShowGBK(x,y,s_num);
            x+=16;
            s+=2;
      }
                if(x>128)
      {
            x=0;
            y+=16;
      }
      }
}</font>OLED.H文件内容如下:<font size="3">#ifndef __OLED_H
#define __OLED_H

#include "../comm/STC8h.h"//包含此头文件后,不需要再包含"reg51.h"头文件
#include "../comm/usb.h"   //USB调试及复位所需头文件


void OLED_Init(void);   //OLED初始化
void OLED_ShowChar(unsigned char x,unsigned char y,char asc);   //OLED显示一个8*16字符
void OLED_ShowGBK(unsigned char x,unsigned char y,char *gbk);   //OLED显示一个16*16汉字
void OLED_ShowString(unsigned char x,unsigned char y,char *s);


#endif</font>FONT.H文件内容如下:(需要显示的内容需要取模放进来哦,不做字模的话无法识别)<font size="3">#ifndef __FONT_H
#define __FONT_H

/****************************************8*16的点阵************************************/
const char code Ascll_16[]=         
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};


    //阴码,列形式,逆向,
struct s_font
{
    unsigned char gbk_font;
    unsigned char gbn_bum;
};

conststruct s_font code GBK16[]=      
{
0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x88,0xF8,0x00,0x00,0x00,
0x00,0x00,0x1F,0x08,0x08,0x08,0x08,0x7F,0x88,0x88,0x88,0x88,0x9F,0x80,0xF0,0x00,"电",//0

0x80,0x82,0x82,0x82,0x82,0x82,0x82,0xE2,0xA2,0x92,0x8A,0x86,0x82,0x80,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,"子",//1

0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x20,0x40,0x80,0x00,0x00,
0x08,0x04,0x03,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x01,0x0E,0x00,"小",//2

0x10,0x2C,0x24,0x24,0xA4,0xA4,0x65,0xA6,0x24,0x24,0x24,0x24,0xA4,0x34,0x0C,0x00,
0x40,0x49,0x49,0x29,0x24,0x14,0x52,0x89,0x7F,0x04,0x0A,0x11,0x10,0x20,0x20,0x00,"家",//3

0x00,0x04,0x04,0xF4,0x94,0x94,0x94,0x9F,0x94,0x94,0x94,0xF4,0x04,0x04,0x00,0x00,
0x40,0x40,0x40,0x7F,0x4A,0x4A,0x4A,0x4A,0x4A,0x4A,0x4A,0x7F,0x40,0x40,0x40,0x00,"直",//4

0x10,0x10,0x10,0xFF,0x10,0x50,0x44,0x54,0x65,0xC6,0x44,0x64,0x54,0x44,0x40,0x00,
0x04,0x44,0x82,0x7F,0x01,0x82,0x82,0x4A,0x56,0x23,0x22,0x52,0x4E,0x82,0x02,0x00,"接",//5

0x02,0xFA,0x82,0x82,0xFE,0x80,0x00,0xFE,0x02,0x12,0x62,0x82,0x62,0x1A,0x02,0x00,
0x08,0x18,0x48,0x84,0x44,0x3F,0x00,0x7F,0x50,0x48,0x46,0x41,0x46,0x58,0x40,0x00,"驱\xfd",//6

0x40,0x44,0xC4,0x44,0x44,0x44,0x40,0x10,0x10,0xFF,0x10,0x10,0x10,0xF0,0x00,0x00,
0x10,0x3C,0x13,0x10,0x14,0xB8,0x40,0x30,0x0E,0x01,0x40,0x80,0x40,0x3F,0x00,0x00,"动",//7

0x20,0x30,0xAC,0x63,0x30,0x02,0x26,0x2A,0xE2,0x26,0x29,0x21,0x29,0x25,0x00,0x00,
0x22,0x67,0x22,0x12,0x52,0x21,0x99,0x87,0x4D,0x55,0x25,0x55,0x4D,0x81,0x81,0x00,"缓",//8

0x04,0x04,0x84,0xE4,0x1C,0x07,0x24,0x24,0x24,0x24,0xA4,0x64,0x24,0x04,0x04,0x00,
0x02,0x01,0x00,0xFF,0x00,0x02,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x02,0x02,0x00,"存",//9

0x00,0x00,0xF8,0x49,0x4A,0x4C,0x48,0xF8,0x48,0x4C,0x4A,0x49,0xF8,0x00,0x00,0x00,
0x10,0x10,0x13,0x12,0x12,0x12,0x12,0xFF,0x12,0x12,0x12,0x12,0x13,0x10,0x10,0x00,"单",//0

0x80,0x80,0x40,0x20,0x10,0x08,0x04,0xC3,0x04,0x08,0x10,0x20,0x40,0x80,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,"个",//1

0x10,0x0C,0x04,0x24,0x24,0x24,0x25,0x26,0xA4,0x64,0x24,0x04,0x04,0x14,0x0C,0x00,
0x02,0x02,0x02,0x02,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,"字",//2

0x10,0x08,0x04,0x87,0x6C,0x14,0x84,0x94,0x88,0x87,0x84,0xEC,0x94,0x84,0x84,0x00,
0x04,0x02,0x01,0xFF,0x00,0x00,0x00,0x02,0x0C,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,"符",//3

0x10,0x60,0x02,0x0C,0xC0,0x02,0x1E,0xE2,0x02,0x02,0x02,0xE2,0x1E,0x00,0x00,0x00,
0x04,0x04,0x7C,0x03,0x80,0x80,0x40,0x20,0x13,0x0C,0x13,0x20,0x40,0x80,0x80,0x00,"汉",//4

0x10,0x0C,0x04,0x24,0x24,0x24,0x25,0x26,0xA4,0x64,0x24,0x04,0x04,0x14,0x0C,0x00,
0x02,0x02,0x02,0x02,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,"字",//5

0x00,0x00,0xC0,0x40,0x40,0x40,0x7F,0x48,0x48,0x48,0x48,0xC8,0x08,0x08,0x00,0x00,
0x80,0x40,0x37,0x04,0x04,0x14,0x64,0x04,0x14,0x64,0x04,0x07,0x10,0xE0,0x00,0x00,"点",//0

0x20,0x30,0xAC,0x63,0x20,0x18,0x80,0x90,0x90,0xFF,0x90,0x49,0x4A,0x48,0x40,0x00,
0x22,0x67,0x22,0x12,0x12,0x12,0x40,0x40,0x20,0x13,0x0C,0x14,0x22,0x41,0xF8,0x00,"线",//1


0x10,0x60,0x02,0x8C,0x00,0x44,0x54,0x54,0x54,0x7F,0x54,0x54,0x54,0x44,0x40,0x00,
0x04,0x04,0x7E,0x01,0x00,0x00,0xFF,0x15,0x15,0x15,0x55,0x95,0x7F,0x00,0x00,0x00,"清",//0

0x00,0x00,0xFE,0x12,0x92,0xB2,0xD2,0x92,0x92,0x92,0xD2,0xB2,0x9E,0x00,0x00,0x00,
0x40,0x30,0x0F,0x04,0x84,0x64,0x1F,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x00,0x00,"屏",//1

0x00,0x10,0x90,0x92,0x52,0x32,0x12,0xFE,0x12,0x31,0x51,0x91,0x90,0x10,0x00,0x00,
0x01,0x81,0x80,0x40,0x31,0x0F,0x01,0x01,0x01,0x4D,0x8B,0x48,0x38,0x01,0x01,0x00,"秀",//2

0x10,0x60,0x02,0x8C,0x00,0x0C,0xA4,0xA4,0xA5,0xE6,0xA4,0xA4,0xA4,0x0C,0x00,0x00,
0x04,0x04,0x7E,0x01,0x00,0x80,0x4F,0x2A,0x0A,0x0F,0x0A,0x2A,0x4F,0x80,0x00,0x00,"演",//0

0x40,0x40,0x42,0x42,0x42,0x42,0x42,0xC2,0x42,0x42,0x42,0x42,0x42,0x40,0x40,0x00,
0x20,0x10,0x08,0x06,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x02,0x04,0x08,0x30,0x00,"示",//1



};

#endif </font>在主函数中,siwtch中只保留这几行,别的都删掉
然后将其中的几行语句改成:<font size="3"> switch (UsbOutBuffer)
                {
                  case VK_DIGIT_0:
                        OLED_Init();
                        break;
                  case VK_DIGIT_2:
                        OLED_ShowChar(0,0,'1');
                        break;
                  case VK_DIGIT_3:
                        OLED_ShowGBK(0,2,"电");
                        break;
                  case VK_DIGIT_4:
                        OLED_ShowString(0,4,"电子DIY小家");                           
break;                  
                }
                   </font>随后按下键盘的0,2,3,4就可以按顺序出现下面的字了。
三、高级驱动首先定义一片缓存区域,因为我们上面讲到一次会输出1024个字节的数据,且这些数据代表了八个大行和128个列。unsigned char xdata ShowBUFF;
3.1点的显示:我们刚刚已经分析过了,怎么去点亮一个点,那么这里先来显示一个点,<font size="3">void OLED_BuffShowPoint(unsigned char x,unsigned char y)   //OLED显示一个dian,x:0-127,y:0-63
{
    ShowBUFF |= 1<<(y%8);
}</font>上面的代码第一个y/8表示他在第几行,因为y坐标的取值是0-63,8个点才显示一行,所以除以8取整数就知道他在第几行了,x坐标取值0-127就直接写到对应的列的位置就好了。因为一次写入一个字节,那么这里就要判断这个点在这个字节中的第几个位置,上面y除以8之后,剩下的余数就是他的第几个位置。例如y取值是4,那么他在4/8也就是第0大行的位置,余数是4,说明他是第四小行,而1<<4就是把1往前移动4位。
3.2:字符的显示<font size="3">void OLED_BuffShowChar(unsigned char x,unsigned char y,char asc)   //OLED显示一个8*16字符
{
    unsigned char j,k;
    for( j=0;j<2;j++ )
    {
      for( k=0;k<8;k++ )
      {
            ShowBUFF=Ascll_16[(asc-' ')*2];
      }
    }   
}</font>首先这里的一个字符是8*16,那么他必然有一个循环两次的for,这样就可以实现两个大行的显示,这里就是 for( j=0;j<2;j++ )。其次他有八个列,那么需要循环八次,这里就是 for( k=0;k<8;k++ ),这样行和列的坐标就可以确定了,每次写的行就是j+y,列就是x+k。最后我们的取模的数组是从‘ ’开始按顺往下序取的,所以字符的开头减去这个就是起始坐标,其次在字库里一个字符分两行,所以第一个字符的坐标就是0,第二个字符就是2,所以这里第一个坐标要写成(asc-' ')*2,第二个坐标就是这个坐标里的第几个数据了,第一行就是k,第二行就是8+k。
3.3:汉字的显示<font size="3">void OLED_BuffShowGBK(unsigned char x,unsigned char y,char *gbk)   //OLED显示一个16*16字符
{
    unsigned char i;
    unsigned char j,k;
    for( i=0;i<150;i++ )
    {
      if(( gbk== GBK16.gbn_bum )&&( gbk== GBK16.gbn_bum ))
      {
            for( j=0;j<2;j++ )
            {
                for( k=0;k<16;k++ )
                {
                  ShowBUFF=GBK16.gbk_font;
                }
            }
            break;
      }
    }   
}</font>这里还有一个汉字显示的程序,大家可以先自己分析一下,这个的实现原理,后面我会单独把答案放评论区里和群里。
3.4汉字和字符的混合现实<font size="3">void OLED_BuffShowString(unsigned char x,unsigned char y,char *s)
{
    char s_num;
      while(*s != '\0')       //字符串不为空,循环
      {
      if ((unsigned char)*s < 0x80)   //根据输入数据的大小判断是字符还是汉字,
      {
            OLED_BuffShowChar(x,y,*s);
            x+=8;
            s++;
      }
      else
      {
            s_num = *s ;
            s_num = *(s+1) ;
            OLED_BuffShowGBK(x,y,s_num);
            x+=16;
            s+=2;
      }
                if(x>127)
      {
            x=0;
            y+=2;
      }
      }      
}</font>    首先这个函数需要在输入的地方,判断输入的地方是不是为空,通过while(*s != '\0') 来实现,然后判断第一个字节的内码。因为在GBK的内码里,一个字符是1个字节,汉字是2个字节,且字符内码小于0x80,所以如果是字符,调用字符的程序,调用完了x坐标+8,然后指向的地址+1,去开始查询下个字节。汉字的内码是2个字节,显示玩一个汉字x坐标+16,指向的地址+2;<font size="3">void OLED_BuffShow(void)   
{
    OLED12864_ShowPicture(0,0, 128,8, (BYTE *)&ShowBUFF);   
}</font>因为用的缓存的办法实现,所有的需要显示的数据都在单片机内存里,需要显示的话一定要给他发出去才行,这里就是将8*128个数据一次性发出去显示出来。
    上述就是实现的全部过程了,程序里还有一个简单的划线函数(通过画点函数实现),留给屏幕前的你们自由发挥和想象,可以改写个画圆,画方的程序出来。
最后在主函数中插入这个:<font size="3"> switch (UsbOutBuffer)
                {
                  
                  case VK_DIGIT_0:
                        OLED_Init();
                        break;
                  case VK_DIGIT_1:
                        OLED_BuffClear();
                        OLED_ShowString(0,0,"OLED直接驱\xfd动演示");
                        OLED_ShowString(80,2,"--字符");
                        OLED_ShowChar(0,4,'1');
                        OLED_ShowString(0,6,"666");
                        break;
                  case VK_DIGIT_2:
                        OLED_BuffClear();
                        OLED_ShowString(0,0,"OLED直接驱\xfd动演示");
                        OLED_ShowString(80,2,"--汉字");
                        OLED_ShowGBK(0,4,"秀");
                        OLED_ShowString(0,6,"电子DIY小家");   //这一行函数可以自动判断汉字或者字符并显示
                        break;
                  case VK_DIGIT_3:
                        OLED_BuffClear();
                        OLED_ShowString(0,0,"OLED清屏");
                        break;                  
                  
                  case VK_DIGIT_5:
                        OLED_BuffClear();
                        OLED_BuffShowString(0,0,"OLED缓存驱\xfd动演示");
                        OLED_BuffShowString(80,2,"--字符");
                        OLED_BuffShowChar(0,4,'1');
                        OLED_BuffShowString(0,6,"6666666");
                        OLED_BuffShow();                        //缓存显示一定要开显示
                        break;
                  
                  case VK_DIGIT_6:
                        OLED_BuffClear();
                        OLED_BuffShowString(0,0,"OLED缓存驱\xfd动演示");
                        OLED_BuffShowString(80,2,"--汉字");
                        OLED_BuffShowGBK(0,4,"秀");
                        OLED_BuffShowString(0,6,"电子DIY小家");   //这一行函数可以自动判断汉字或者字符并显示
                        OLED_BuffShow();                        //缓存显示一定要开显示
                        break;

                  
                  case VK_DIGIT_7:
                        OLED_BuffClear();
                        OLED_BuffShowString(0,0,"OLED缓存驱\xfd动演示");
                        OLED_BuffShowString(80,2,"--点线");
                        OLED_BuffShowPoint(0,40);
                        OLED_BuffShowPoint(64,40);            //点和线的x坐标都是0-127,y坐标0-63
                        OLED_BuffShowLine(20,50,108,50);      //
                        OLED_BuffShow();                        //缓存显示一定要开显示
                        break;                              
                  
                }</font>最后就能完美的运行起来了,运行效果见开头的视频哈。或者这里留下几个截图看完了文章,觉得有用的请在文末点个赞哈哈{:titter:}

国学芯用 发表于 2022-10-17 10:59:25

图文并茂,很详细的讲解,优秀的课代表,好好学习,天天向上
开天斧-STC8H8K64U-直接自带硬件USB仿真,STC8H8K64U代表仿真的天堂

8051爱好者 发表于 2022-10-19 10:18:22

我也拿到了核心板 来不及去买屏   虚拟接口很好用 很方便   第一次用 有惊艳的感觉   椰树牌一直在默默努力啊 赞一个

51单片机爱好者 发表于 2022-10-19 10:23:00


他们的广告真是无处不在,有一说一,不过也是真的好用,虚拟接口,创新应用,很实用!

国学芯用 发表于 2022-10-21 15:13:48

51单片机爱好者 发表于 2022-10-19 10:23
他们的广告真是无处不在,有一说一,不过也是真的好用,虚拟接口,创新应用,很实用! ...
(引用自4楼)

新网站STCAI.COM 必须让每个小伙伴知道
页: [1]
查看完整版本: STC驱动教程系列——CDC驱动虚拟OLED显示汉字字符