STM32开发板(Bearpi)显示动态二维码

举报
神龙居市 发表于 2021/11/01 09:01:32 2021/11/01
【摘要】         业务场景需要扫码互动,咨询了小熊派官方,并没有提供案例,之前出厂时屏幕可以显示的二维码只是一个固定图片,显然不适合。到网上找了一些资料,解说的不算完整,不能直接应用。根据这些前人的提醒,自己迁移一份。准备资料:硬件:BearPi-IoT开发板,USB数据线一条软件:STM32CubeMX,Keil uVision5代码:小熊派基础案例LCD,QRCode生成代码       ...

        业务场景需要扫码互动,咨询了小熊派官方,并没有提供案例,之前出厂时屏幕可以显示的二维码只是一个固定图片,显然不适合。

到网上找了一些资料,解说的不算完整,不能直接应用。根据这些前人的提醒,自己迁移一份。

准备资料

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

软件:STM32CubeMX,Keil uVision5

代码:小熊派基础案例LCD,QRCode生成代码

        小熊派提供了完成的开发过程的代码,可以用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;
}

代码目录结构

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

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。