0.96英寸128*64 OLED显示二维码

0.96英寸I2C,OLED 显示屏显示二维码 STM32 SSD1306 RT-Thread

关于

最近手头上有个0.96英寸的 128*64得单色显示屏,突发想法能不能在上面显示二维码,手机扫描出来呢,这样的功能对于拥有这种显示屏的物联网设备肯定大有用处啊。
首先 百度一下,发现还真有人已经实现了这样的功能,CSDN上也有资源,但是这特么的积分也要的太狠吧,我这个穷逼买不起啊,开源给大家看看会屎么?MP啊。

网上找了些资料,发现有开源的库,发现一个库https://github.com/fukuchi/libqrencode 研究了下,表示看的不太明白,放弃。

突然想到 卧槽,我这个用的RT-Thread,不是有在终端打印出二维码的功能么。。。。。
在这里插入图片描述
卧槽。。。。。。什么都⑧说了,开干。

软、硬件环境

首先给大家说明下,我的环境,免得后续出现一系列问题。

  1. 主控MCU ,STM32F103VE;
  2. 显示屏 ,0.96 英寸 128*64 OLED显示屏,控制芯片是SSD1306,接口I2C
  3. 操作系统,众所周知,RT-Thread。
    显示的驱动已经移植好了。只需要可以正常显示字符就可以了。

开启RT-Thread的终端打印二维码功能

利用控制台,开启QRCode
在生成工程之前不要忘记 输入命令 pkgs --update

生成工程 scons --target=mdk5

打开工程,编译。

一切正常的情况下,可以看到下图
在这里插入图片描述
RT-Thread 的这个QrCode的库也是移植这个的https://github.com/ricmoo/QRCode

思路

从源码可以看到如下示例:

for (uint8 y = 0; y < qrcode.size; y++) {
    for (uint8 x = 0; x < qrcode.size; x++) {
        if (qrcode_getModule(&qrcode, x, y) {
            Serial.print("**");
        } else {
            Serial.print("  ");
        }
    }
    Serial.print("\n");
}

这个是打印到终端的示例程序,根据代码可以判断,原理是根据生成的点阵,判断点阵的x,y是否为1,然后在再终端打印**或者空格。
函数 qrcode_getModule(&qrcode, x, y),获取指定位置是否有点的,返回1则表示该位置有点,返回0则改位置无点。

那么问题来了,这个得到的二维码的点阵大小是多少?
到刚才那个github项目大佬主页,可以看到
在这里插入图片描述
原来这个点阵和代码里面,定义的#define DEFAULT_QR_VERSION 3
有关,例如定义为4,那么生成的点阵就是 33*33 个点。

那么很简单了,把这些点阵 填充到显示的缓冲,然后不就ojbk了,是不是?
好了开始肝了。
在这里插入图片描述

移植开肝

这里首先我们要搞清楚,这个屏幕显示的原理
屏幕的主控用的是SSD1306:手册
在这里插入图片描述
可以看到点阵的显示扫描方式是,从左到右(也可从右到左),从上到下扫描显示的。每个页纵向8个点,横向127个点。纵向每8个点表示一页,如果是128*64的话就是8页(0~7)。

搞清了显示的原理,那么特么只要填点阵就可以了。
初始化显示屏

    OLED_WR_Byte(0xAE,OLED_CMD);//--display off
	OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
	OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
	OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  
	OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
	OLED_WR_Byte(0x81,OLED_CMD); // contract control
	OLED_WR_Byte(0xFF,OLED_CMD);//--128   
	OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap 
	OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
	OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
	OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
	OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
	OLED_WR_Byte(0x00,OLED_CMD);//
	
	OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
	OLED_WR_Byte(0x80,OLED_CMD);//
	
	OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
	OLED_WR_Byte(0x05,OLED_CMD);//
	
	OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
	OLED_WR_Byte(0xF1,OLED_CMD);//
	
	OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
	OLED_WR_Byte(0x12,OLED_CMD);//
	
	OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
	OLED_WR_Byte(0x30,OLED_CMD);//
	
	OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
	OLED_WR_Byte(0x14,OLED_CMD);//
	
	OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
	
	OLED_Clear();

声明一个显示的二位数组

#define DEFAULT_QR_VERSION 6
#define Xsize  4*DEFAULT_QR_VERSION+17
#define Ysize  (4*DEFAULT_QR_VERSION+17)/8+1
uint8_t qr_code_buff[Ysize][Xsize]={0};  // 显示点阵缓冲

对于显示的点阵,大家可以看如下解释:

                 -------------------------------->X
|       0	    0	2	3	4	.	.	.	.	.	   127
|		0       x	x	x	x	x	.	.	.	.	.	x
|		1       x	x	x	x	x	.	.	.	.	.	x
|		2		x	x	x	x	x	.	.	.	.	.	x
|		.		x	x	x	x	x	.	.	.	.	.	x
|		.		x	x	x	x	x	.	.	.	.	.	x
|		.		x	x	x	x	x	.	.	.	.	.	x
Y		.		x	x	x	x	x	.	.	.	.	.	x
		.		x	x	x	x	x	.	.	.	.	.	x
		7		x	x	x	x	x	.	.	.	.	.	x

       每个X位 表示OLED 的纵向8个点阵的16进制数据

先搞个函数,方便后面操作。下面这个函数可以对上面矩阵任意位置填充一位16进制数。

//根据x,y填充纵向8个点阵的数据
void OLED_Draw_Vertical_Byte(u8 x,u8 y, u8 data)
{
	
	OLED_Set_Pos(x,y);

	OLED_WR_Byte(data,OLED_DATA);
	
}

ojbk!!!
继续下一步
搞个方法,通过生成的二维码的点阵,来对显示的缓存进行相应位置填充,这里大家注意一下细节:
首先 起个函数名,然后第二步确定好传入的参数,可以了。。。。。。。。。。
接下来就像下面这样。。。。。。。。

void OLED_Draw_QRCode(char *qrstr) //绘制 二维码图片    
{

    QRCode qrc;
    uint8_t x, y,z, *qrcodeBytes = (uint8_t *)rt_calloc(1, qrcode_getBufferSize(DEFAULT_QR_VERSION));
    int8_t result;
	  uint8_t num=0;
	
    if (qrcodeBytes)
    {
        result = qrcode_initText(&qrc, qrcodeBytes, DEFAULT_QR_VERSION, ECC_LOW, qrstr);
			  	
        if (result >= 0)
        {
          
				num=qrc.size/8;

					//扫描方式:先每次扫y轴8个点,再扫描整个x轴
				for(x=0;x<qrc.size;x++)   //根据生产的二维码点阵  填充到显示的缓冲矩阵重    先计算到 二维码点阵y坐标的8的整数倍  
				{		
					for(z=0;z<num;z++)  
					{					
						for(y=0;y<8;y++)  //y 坐标每次8个点  
						{
							 if (qrcode_getModule(&qrc, x, 8*z+y))
							 {
									setbit(qr_code_buff[z][x],y);  

							 }
                           else
							 {
								 clrbit(qr_code_buff[z][x],y);  
							 }								 
						}							
			  	}							
				}	
				for(x=0;x<qrc.size;x++)                     //计算填充y轴剩下的 点阵
				{			
                    for(y=0;y<qrc.size%8;y++)
					{
						
						if (qrcode_getModule(&qrc, x, num*8+y))
						{
							setbit(qr_code_buff[num][x],y); 
						}
						else
						{
							clrbit(qr_code_buff[num][x],y); 
						}					
					}				
				}				
				for(y=0;y<Ysize;y++)
				{
				for(x=0;x<Xsize;x++)
				{				
					OLED_Draw_Vertical_Byte(x,y,qr_code_buff[y][x]);		//将计算好点阵 填到屏幕上
				}
				
			}			
        rt_free(qrcodeBytes);
    }
    else
    {
        rt_kprintf("Warning: no memory!\n");
    }
	}
}

好了,到此应该问题不大。。。。。。。。。。。
ojbk!!!!!!!!!!!!!
在这里插入图片描述

开始测试

用RT-Thread 的MSH控制台搞个测试命令

static void qrcode(uint8_t argc, char **argv)
{
   #define DEFAULT_QR_STRING "HELLO WORLD"
      char *qrstr = DEFAULT_QR_STRING;
        if (argc > 1)
        {
            qrstr = argv[1];
        }				
			 OLED_Draw_QRCode(qrstr);
}
MSH_CMD_EXPORT(qrcode, qrcode generator: qrcode [string]);

everthing is OK!!!!!!

放图看下显示效果
在这里插入图片描述
看看大家扫出了什么?

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/ID_TMOD/article/details/108664350