STM32开发板动态二维码显示

业务场景需要扫码互动,咨询了小熊派官方,并没有提供案例,之前出厂时屏幕可以显示的二维码只是一个固定图片,显然不适合.到网上找了一些资料,解说的不算完整,不能直接应用。根据这些前人的提醒,自己迁移一份。

准备资料:

硬件:BearPi-IoT开发板,usb数据线一条

软件:STM32CubeMX,Keil uVision5

小熊派提供了完成的开发过程的代码,可以用STM32CubeMX,Keil uVision5进行编辑设计、编译和烧录。

现在缺的就是把字符串变成二维码数据,再把二维码显示到屏幕上。

如何生成二维码数据?这个要靠专家组织提供的类库了。从网上找到了几种QR Encode的C代码,选择了其中一个(在代码中一并提供)。

如何显示在屏幕上?有两种思路,一个是把二维码数据变成图片,使用小熊派提供的LCD_ShowImage来显示,一个是直接把二维码数据打印到屏幕上。

在Windows平台或者非嵌入式的环境,大部分是转换成图片,也都有高级语言环境提供的类库。这个案例我觉得直接输出到屏幕上才符合嵌入式开发理念。

根据观察二维码生成的数据结构,是有数据和行的概念,那么是不是可以按点的形式打印出来?

struct qrcode_bitmap
{
	int line_size;
	int data_size;
	unsigned char *data;
};

LCD正好有一个LCD_Fill函数

void LCD_Fill(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t color);

根据上面的数据结构,通过指针移动得到当前的点,有非0的值就打印黑色,否则白色。

int i, j, color;
unsigned char *pdata = bitmap.data;
for (i = 0; i < bitmap.data_size; i++)
{
    for (j = 0; j < bitmap.data_size; j++)
    {
      color = ((int)pdata[j]) ? BLACK : WHITE;
      LCD_Fill(i, j, i, j, color);
    }
    pdata += bitmap.line_size;
}

在Main方法中调用

LCD_Clear(WHITE); //清屏
display_qr("https://www.baidu.com");

打印出来了,但是太小,一个点对应屏幕上的一个点是不够大的,需要放大线上,把一个点用n个点来显示,需要改进display_ar。先放大8倍,计算x_end,y_end的点位置。

int i, j, color;
int larger = 8;
unsigned char *pdata = bitmap.data;
for (i = 0; i < bitmap.data_size; i++)
{
    for (j = 0; j < bitmap.data_size; j++)
    {
      color = ((int)pdata[j]) ? BLACK : WHITE;
      LCD_Fill(i * larger, j * larger, (i + 1) * larger - 1, (j + 1) * larger - 1, color);
    }
    pdata += bitmap.line_size;
}

二维码像个样子了,而且手机扫码识别也正常。只是还需要美化位置居中才好,稍作修正,设置偏移20,

int i, j, color;
  int larger = 8, offset = 20;
  unsigned char *pdata = bitmap.data;	
  for (i = 0; i < bitmap.data_size; i++)
  {
    for (j = 0; j < bitmap.data_size; j++)
    {
      color = ((int)pdata[j]) ? BLACK : WHITE;
      LCD_Fill(i * larger + offset, j * larger + offset, (i + 1) * larger + offset - 1, (j + 1) * larger + offset - 1, color);
    }
    pdata += bitmap.line_size;
  }

这次像那么回事了。

是不是稳定可靠呢?多拿几个数据看看,显示二维码内容改为display_qr("https://console.huaweicloud.com/mc/?locale=zh-cn&region=cn-north-1#/mc/messages/b8fb4eba5f3445db93ad14cb2e34a536");

这就蹦了?稍微分析一下原因也不难理解,二维码要承载字符串内容,内容越多,越复杂,数据量也越大,data_size大小不固定,前面用了固定的放大倍数和偏移量都无法保证以固定形式正确显示二维码的位置。所以要根据内容大小,计算放大倍数和偏移量。这块屏幕的分辨率是240*240所以...

larger = 240 / bitmap.data_size;
offset =  (240 - larger * bitmap.data_size) / 2;
for (i = 0; i < bitmap.data_size; i++)
{
    for (j = 0; j < bitmap.data_size; j++)
    {
      color = ((int)pdata[j]) ? BLACK : WHITE;
      LCD_Fill(i * larger + offset, j * larger + offset, (i + 1) * larger + offset - 1, (j + 1) * larger + offset - 1, color);
    }
    pdata += bitmap.line_size;
}

代码目录结构

大功告成了,最后附上代码。

经验分享 程序员 微信小程序 职场和发展