ESPS32 S3 扫码器
条形码(barcode) 是一种通过黑条或者实心方块和空白,按照一定的编码规则排列,便于机器识别的图形标识符。最开始出现的是一维条形码;随后出现了二维条形码,而这种条形码伴随着移动支付的推广,我们的日常生活中无处不在。历史上公认的条形码是诺曼·约瑟夫·伍德兰(NormanJoseph Woodland)和伯纳德·西尔弗 (BernardSilver)发明的。1951年,他们在美国取了条形码的专利授权。而这一切起源于1948年,西尔弗还是费城煤气科技学院的研究生。偶然间他听到当地一家连锁超市的总裁恳请院长发明一种可以在收银台处自动记录商品销售的方法。院长认为这是异想天开。但西尔弗和他的朋友兼研究生同学约伍德兰决心尝试一番,并且相信这会让他们发大财。首先,西尔弗想到可以通过使用紫外线照射使墨绘图形发光的办法来实现。问题是颜料太贵、不稳定且易涂污。接下来,他试着创造一套用来标识的盲点系统。但在将盲点系统标注进货物时困难重重,且经常损害货物。经过几个月的努力,西尔弗决定用莫尔斯电码,这是一套由莫尔斯发明的由点和线组成的符号系统。不久,西尔弗想到可以将莫尔斯电码中的点线设置成粗细不一的条纹。这个想法后来成了各种条码的最基本构想。虽然关于条形码的想法出现的很早,但是由于当时的技术限制,条形码一直无法普及,直到二十世纪六十年代末,随着激光技术的出现和计算机处理能力的进步,条形码的推广和大规模应用才有了技术基础。在1974年6月26日早晨八点零一分,俄亥俄州特洛伊市的马什超市(MarshSupermarkets)通过扫码出售了一包箭牌水果味口香糖。而后,条形码被广泛应用于商品、书籍、邮政等系统中,极大地提升了业务运行效率。条形码的普及让原来要靠手动输入商品价格的超市收银员们摆脱了手腕麻木和“腱鞘炎”的折磨,但新的问题又随之而来:由于容量有限,条形码最多只能记录20个英文数字,日文或者汉字还无法识别。这令很多生产线上的企业严重不满,扫描速度和出错率也为人诟病。90年代,一位任职于DENSOWAVE公司的日本人腾弘原想到,一条码只能横向记录20个数,如果扩大到点阵式平面,记录的信息自然可以增多。然而做码容易,但如何让这个平面码能够高速读取却不简单。腾弘原和另一位同事组成研发小组,开始了新的攻克。方块的二维码有四个直角,他们选定其中三个设置为定位符,然后通过仅剩的一个角的位置来判断二维码内容的方向。这样不管手机从任何方向扫码,都不影响内容的读取。当然,日本人的细节完美主义症也在这上面体现得淋漓尽致。为了避免二维码和其他类似图案相混淆导致识别出错,腾弘原对当时市面上的杂志、海报、纸箱上的图案进行了详尽统计,从而确定二维码定位区的方框使用的黑白区域宽度比为1:1:3:1:1最合适。经过近两年的反复试错,一个能够容纳7000个左右数字,同时还兼具汉字编码能力的小方块码最终问世。相比于过去的条形码,它不仅在信息存储容量上提升了300倍,扫描速度也快了近10倍。1994年,DENSOWAVE公司面向全日本公开了二维码,并取名为“QuickResponse”(快速响应)。尽管DENSOWAVE公司拥有二维码的专利权,但却没有收取专利费,这是研发之初就确定的方针,也是研发者腾弘原的初衷:“希望能有更多人使用二维码”。免费从来都是吸引用户的最好手段。很快,二维码就冲出日本,被应用于全世界各地。这次的作品是一个基于ESP32S3制作的无线条码接收器,基本原理是:用户运行手机上的应用程序,通过摄像头进行条码扫描(一维码和二维码都可以),扫描识别结果会显示在屏幕上,之后通过点击按钮就可以通过蓝牙将结果发送给ESP32S3。最后,ESP32S3 通过自身模拟出来的 USB键盘将内容输入到计算机中。这样,相当于你的手机成为一台“移动扫码器”。首先,设计运行在手机端的APP。使用 AppInventor 来制作,它是一个完全在线开发的Android编程环境,抛弃复杂的代码使用积木式的堆叠法来完成Android程序,用户可以方便快捷的进行开发。这次使用的广州市教育信息中心提供的在线版,网址是 http://app.gzjkw.net/login/。界面空间及介绍如下:
控件用途
列表显示框显示当前扫描到的蓝牙设备。这次的设计中,手机属于提供信息的蓝牙 Server,ESP32 S3 属于从Server获取信息的 Client
水平布局用于并排放置下面两个按钮的控件
按钮1“扫描”按钮,用于启动条码扫描器获取条码
按钮2“发送”按钮,用于将当前的扫描结果发送给 ESP32 S3
标签用于显示当前的扫描结果
条码扫描器调用摄像头实现条码扫描的控件
BluetoothLe1同ESP32S3 进行通讯的蓝牙控件
基本流程是:打开Android程序后,在初始化屏幕时调用BluetoothLE组件开始扫描当前的蓝牙设备,同时设置列表显示框:
如果 BluetoothLE 有扫描发现设备,那就将这个设备的名称加入到列表显示框中,这样列表显示框中列出了当前所有的能被发现的蓝牙设备:
用户可以在列表显示框中通过点击的方式选择连接的设备,选中后BluetoothLE会进行连接:
连接完成后,隐藏列表框,然后BluetoothLE停止扫描
接下来客户可以使用按钮1触发条码扫描器工作
当条码扫描器扫描到条码后,会跳入“扫描结束进行执行”,这里会将扫描结果放置在设置标签1中。
用户点击按钮2后,会连接到 ESP32 S3 上。用一个带有轨迹球的USB键盘来说,前面在列表显示框中的选择动作可以理解成选中了这个USB设备;之后的serviceUUID相当于进一步选中了这个USB设备的键盘端口,进一步characteristicUUID则是读取键盘输入。这里面characteristicUUID对应的ESP32S3 代码是 RX,就是说Android程序负责发送,ESP32S3 接收。
上面没有编写一行代码就完成了了一个 Android 应用程序的编写,打包之后通过二维码直接下载到手机安装之后就可以使用了。接下来介绍这次条码扫描器的硬件设计,电路图如下:
图中的 H1 是烧写接口,具体请参考https://mc.dfrobot.com.cn/thread-312276-1-1.html文章提到的串口小板。就是说,为了体积考虑,这次板子上没有设计烧写的USB转串口部分;右上角是USB公头,用于从计算机取电和USB通讯;左下角是ESP32S3 的最小系统,有兴趣的朋友可以参考 https://mc.dfrobot.com.cn/thread-313475-1-1.html。右侧是用于将5V转为 3.3V 的 AMS1117 芯片。ESP32S3 工作电压为 3.3V。PCB 设计如下:
3D 预览如下:
制作出来的实物如下:
接下来介绍 ESP32 S3 的代码设计。这次的设计只能在 ESP32 S3 上实现,原因是 ESP32 不支持 USB, ESP32 S2 支持 USB,只有 ESP32 S3 同时支持蓝牙和 USB。整体代码相当于:蓝牙接收数据和模拟USB键盘两部分。首先是模拟USB键盘,在文件头部使用对应的库:#include "USB.h"#include "USBHIDKeyboard.h" 再声明一个键盘设备USBHIDKeyboard Keyboard;Setup 中初始化键盘,之后就可以使用Keyboard进行键盘输入了:Keyboard.begin();USB.begin();收到手机通过蓝牙发送的数据之后,在BLECharacteristicCallbacks这个回调函数中进行处理: Keyboard.write((const uint8_t *)rxValue.c_str(),rxValue.length()); uint8_trtn[]={'\r','\n'}; Keyboard.write(rtn,2);直接用 Keyboard.write() 将收到的信息“敲入”计算机中即可。蓝牙部分使用的是 ESP32 自带的蓝牙通讯框架。在文件开头可以看到如下定义:#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"// UART service UUID#define CHARACTERISTIC_UUID_RX"6E400002-B5A3-F393-E0A9-E50E24DCCA9E"#define CHARACTERISTIC_UUID_TX"6E400003-B5A3-F393-E0A9-E50E24DCCA9E"其中的“6E400002-B5A3-F393-E0A9-E50E24DCCA9E”是ESP32S3 蓝牙的接收属性,对于手机来说是发送。
完整代码如下:
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include "USB.h"
#include "USBHIDKeyboard.h"
//声明一个键盘设备
USBHIDKeyboard Keyboard;
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++)
Serial.print(rxValue);
Serial.println();
Serial.println("*********");
Keyboard.write((const uint8_t *)rxValue.c_str(),rxValue.length());
uint8_t rtn[]={'\r','\n'};
Keyboard.write(rtn,2);
}
}
};
void setup() {
Serial.begin(115200);
// 初始化键盘
Keyboard.begin();
USB.begin();
// Create the BLE Device
BLEDevice::init("BarcodeScanner");
// Create the BLE Server
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_READ|BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}
void loop() {
delay(100);
}
电路图和PCB
Arduino 代码
页:
[1]