>

二维码显示模块

2017-07-02 by Stavros

做了个小模块, 可以把字符串从PC传到模块上存储, 并以二维码显示出来.

原理图如下, MCU用了48脚的stm32f103, 配1.44寸128x128的TFT屏, 存储么, 24C512和W25Q16各上一片. 其实只要24C512就足够了...

USB接口用了HID协议, 从stm32的官方USB例程改改就行, 好处是PC端不需要装驱动了. 程序太长就不贴上来了.

默认例程收发都是以8字节为单位, 这里先改成64字节, 但是64字节的数据包还是不够长, 所以需要做简单的分包处理. 思路也简单, 把第一字节的最高位和次高位作为首包和尾包的标志位, 接收时如果发现是首包, 就把接收指针指向接收缓冲区的起始位置; 然后把后面的63字节依次从USB端点复制到接收缓冲区, 之后接收指针增加63. 如果发现是尾包, 就设一个"接收完成"的标志变量为真.

主程序这边, 得到完整的数据后再调用libqrencode库, 把字符串转换成二维码显示出来, 最后设置"接收完成"的标志变量为假.

PC端程序用python实现, 因为有pywinusb库, 所以很简单, 贴上来:

import pywinusb.hid as hid
import time

# 从设备接收数据
def sample_handler(data):         
    data = [chr(i) for i in data]
    data = ''.join(data[1:])
    print(data)

# 向设备发送数据
def hid_send(buffer):
    buffer = [i for i in buffer]
    header = 0x80  # 首包标志 
        while len(buffer) > packetsize:
        msg = [0x00] + [header] + buffer[:packetsize]
        print(msg)
        out_report.set_raw_data(msg)
        header = 0x00
        out_report.send()
        print('#')
        buffer = buffer[packetsize:] # buffer向后跳packetsize个位置
    time.sleep(0.1)

    header += 0x40    # 尾包标志
    while len(buffer) < packetsize:
        buffer.append(0)  # 剩余数据不足, 补齐64字节
    msg = [0x00] + [header] + buffer
    out_report.set_raw_data(msg)
    out_report.send()
    print('#')
    time.sleep(0.1)

# 主程序
flt = hid.HidDeviceFilter(vendor_id = 0x8589) # 按vendor_id查找设备
devices = flt.get_devices()
if devices:
    device = devices[0]
    print(device)
else:
    exit()

device.open()

device.set_raw_data_handler(sample_handler)
out_report = device.find_output_reports()[0]

packetsize = 63 # 每次发送63字节

while True:
    str = input().encode('utf8')  # 汉字按utf-8处理
    hid_send(str)

device.close()

之后问题来了, 发现最多只能生成61x61的二维码.

分析原因, 估计是因为libqrencode库返回的qrcode结构体是用malloc分配内存的, 根据我在前面《写了个取剩余可用堆内存的函数》里的分析, arm-none-eabi-gcc里的malloc分配的内存数量上限只能是2的整数次幂; 偏偏libqrencode库内部还多次使用了malloc, 这样20k ram的stm32f103c8一不小心就只能分配到最多4096字节内存了, 如果要生成65x65的二维码就会分配失败.

解决办法只能是换64脚的stm32f103rc或stm32f103re, 它们的内存分别是48k和64k; 128x128的屏幕能显示的最大二维码是125x125, 总共15625个点, 这样只要能成功分配到16k内存就行了, 估计有戏.

附带的好处是, 这俩的flash空间分别有256k和512k, 但是现在程序空间只用了20k多, 这样可以把多余的空间用来存二维码, 24c512和w25q16都可以省掉了.

ps. @Tariel推荐了一个代替*alloc的内存管理库: The BGET Memory Allocator, 也许用它能解决得更漂亮一点.

--------------------更新-------------------------

用bget代替malloc的结果, 可以生成69x69的二维码了... 确实是改善了一点点.