二维码的标准版本共有40个,从版本1到版本40,每个版本对应不同的尺寸和数据容量。版本越高,二维码的矩阵越大,能存储的信息也越多,但图案也更复杂,需要更高的扫描精度。
二维码版本的基本结构
- 版本计算公式 :每个版本的模块(黑白小方块)数量为
(4 × 版本号 + 17) × (4 × 版本号 + 17)。例如:- 版本1:21 × 21 模块
- 版本2:25 × 25 模块
- 版本40:177 × 177 模块
版本的不同直接影响二维码的容量和应用场景。低版本适合简单数据,如短URL;高版本可用于存储大量文本或图像数据。
数据容量与纠错级别
二维码的容量取决于版本和纠错级别(Error Correction Level),纠错级别有四种:L(低,约7%纠错)、M(中,约15%)、Q(高,约25%)、H(最高,约30%)。纠错允许二维码部分损坏仍可读取。
以下是部分版本在不同纠错级别下的最大数据容量示例(以数字模式为例,实际容量因数据类型而异,如数字、字母、汉字等):
| 版本 | 尺寸 (模块) | L级别容量 (字节) | M级别容量 (字节) | Q级别容量 (字节) | H级别容量 (字节) |
|---|---|---|---|---|---|
| 1 | 21×21 | 41 | 34 | 27 | 17 |
| 2 | 25×25 | 77 | 63 | 48 | 34 |
| 5 | 37×37 | 255 | 202 | 144 | 106 |
| 10 | 57×57 | 652 | 513 | 364 | 288 |
| 20 | 97×97 | 1,953 | 1,589 | 1,153 | 861 |
| 40 | 177×177 | 7,089 | 5,748 | 4,193 | 3,057 |
(数据来源于QR码国际标准ISO/IEC 18004。 实际容量会因编码模式而略有差异,
计算使用的是这个库QR-Code-generator
https://github.com/nayuki/QR-Code-generator/tree/master/c
就用两个文件,qrcodegen.c和qrcodegen.h,导入到keil中。
因为我只想显示设备编号,所以用版本1的就可以
看了一下代码对ram占用很低,自己写的部分就用了两个数组,qrcode和tempBuffer,具体长度由qrcodegen_BUFFER_LEN_FOR_VERSION这个宏根据使用的二维码版本计算,版本1的二维码数组长度就57个字节,所以在我测试的stm32f030c8t6(48mhz,64k的flash,9k的ram)上都能算出来。
需要在keil里勾选C99模式

objectivec
#include "qrcodegen.h"
void printQr(const uint8_t qrcode[]) {
int size = qrcodegen_getSize(qrcode);
int border = 4;
for (int y = -border; y < size + border; y++) {
for (int x = -border; x < size + border; x++) {
vDebug_Printf((qrcodegen_getModule(qrcode, x, y) ? "■■" : " "), stdout);
}
vDebug_Printf("\n", stdout);
}
vDebug_Printf("\n", stdout);
}
uint8_t qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MIN)];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MIN)];
void doBasicDemo(void) {
const char *text = "123teng567"; // User-supplied text
bool ok;
enum qrcodegen_Ecc errCorLvl = qrcodegen_Ecc_LOW; // Error correction level
ok = qrcodegen_encodeText(text, tempBuffer, qrcode, errCorLvl,
qrcodegen_VERSION_MIN, qrcodegen_VERSION_MIN, qrcodegen_Mask_AUTO, true);
if (ok)
printQr(qrcode);
}
printQr函数是把生成通过串口打印出来,当然光打印出来肯定是不行的,要在lcd屏幕上显示就得配合lcd屏幕的画点函数了,这里就不多赘述了。
把从串口助手里打印出来的字符复制到notepad++文本编辑器里,
串口助手打印出来的太乱了

复制在notepad里面,ctrl加滚轮,把文字缩到最小。

手机拿远点用微信就能扫出来了,比较难扫出来,因为字符打印出来的图形并不标准,微信还是比其他扫码工具强的。
下面由ai解释代码:
这段代码是一个使用 qrcodegen 库(一个开源的C语言QR码生成库)的简单演示程序。它展示了如何生成一个包含特定文本的QR码,并以ASCII艺术形式(使用■■表示黑色模块,空格表示白色模块)在控制台打印出来。整个代码分为两个主要函数:printQr(用于打印QR码)和doBasicDemo(用于生成QR码并调用打印函数)。
我会逐部分解释代码,包括整体结构、关键变量、函数逻辑和潜在输出。假设你熟悉基本的C语言概念(如数组、循环和函数);如果不是,我会尽量用通俗语言描述。这段代码是"基本演示"(basic demo),适合初学者理解QR码生成的流程。
- 头文件和依赖(隐含)
虽然代码中没有显式包含头文件,但从函数名可以推断它依赖于qrcodegen.h(qrcodegen库的头文件)。这个库提供QR码生成的核心功能,如编码文本、计算大小和获取模块。
另外,可能需要stdio.h(用于printf)和库中的其他定义(如qrcodegen_getSize、qrcodegen_getModule等)。
vDebug_Printf 似乎是自定义的打印函数(可能是printf的变体,用于调试);在实际代码中,可以替换为标准printf。
- 函数:void printQr(const uint8_t qrcode[])
目的:接收一个已生成的QR码数据数组(qrcode),然后在控制台以文本形式"绘制"QR码。QR码本质上是一个二维网格,黑白模块(像素)组成。
参数:
const uint8_t qrcode[]:一个只读的uint8_t数组,存储QR码的模块数据(每个元素表示一个模块的状态:黑或白)。
逻辑 breakdown:
int size = qrcodegen_getSize(qrcode);:获取QR码的大小(边长)。QR码版本决定大小,例如版本1是21x21模块,最小版本(VERSION_MIN,通常是1)是21模块。
int border = 4;:添加一个4模块宽的白色边框(QR码标准要求至少4模块的安静区,以提高扫描可靠性)。
双重循环:
外循环:for (int y = -border; y < size + border; y++) -- 从上边框(-4)到下边框(size+4),遍历Y轴(行)。
内循环:for (int x = -border; x < size + border; x++) -- 遍历X轴(列)。
对于每个位置(x, y):
调用qrcodegen_getModule(qrcode, x, y):检查该模块是否为黑色(返回true)或白色(false)。
如果黑色,打印"■■"(两个全角方块,模拟一个黑像素);如果白色,打印" "(两个空格)。
每行结束打印"\n"(换行)。
最后添加一个空行"\n",分隔输出。
效果:这会生成一个ASCII艺术风格的QR码,便于在终端查看,而不需要图形库。边框确保QR码不会贴边,提高视觉清晰度。
- 全局变量(缓冲区)
uint8_t qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MIN)];:主缓冲区,用于存储最终生成的QR码数据。大小基于最小版本(VERSION_MIN,通常是1),足够容纳21x21的模块。
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MIN)];:临时缓冲区,用于编码过程中的中间计算(库要求提供两个缓冲区)。
- 函数:void doBasicDemo(void)
目的:演示QR码生成的核心流程:编码文本、设置参数,然后调用printQr打印。
逻辑 breakdown:
const char *text = "123teng567";:用户提供的文本内容。这里是"123teng567" -- 一个简单的字符串。QR码会将这个文本编码成二进制模块。
bool ok;:用于检查编码是否成功。
enum qrcodegen_Ecc errCorLvl = qrcodegen_Ecc_LOW;:设置错误修正级别(Error Correction Level)。选项有LOW(7%纠错)、MEDIUM(15%)、QUARTILE(25%)、HIGH(30%)。LOW是最基本的,生成的QR码最小,但容错低(如果QR码损坏,扫描可能失败)。
ok = qrcodegen_encodeText(text, tempBuffer, qrcode, errCorLvl, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MIN, qrcodegen_Mask_AUTO, true);:
调用库的核心函数qrcodegen_encodeText:将文本编码成QR码。
参数:
text:输入字符串。
tempBuffer:临时缓冲。
qrcode:输出缓冲(最终QR码数据)。
errCorLvl:纠错级别(LOW)。
版本范围:qrcodegen_VERSION_MIN 到 qrcodegen_VERSION_MIN(强制使用最小版本1,21x21大小)。如果文本太长,会失败;实际中可以设为更高版本如40(177x177)。
qrcodegen_Mask_AUTO:掩码模式自动选择(QR码使用掩码来优化模块分布,提高扫描性;AUTO让库挑选最佳)。
true:安静模式(不输出错误信息?库文档中可能是"boostEcl"或其他标志;假设是启用自动提升纠错)。
如果ok为true,编码成功。
if (ok) printQr(qrcode);:如果成功,调用打印函数输出QR码。
整体执行流程
调用doBasicDemo()(假设在main函数中调用)。
生成QR码数据(编码"123teng567")。
如果成功,打印ASCII QR码。