改造一个 USB 亮度计
物理上,人们使用坎德拉/平方米(cd/m2)作为单位,单位投影面积上的发光强度。比如,我们可以使用这个单位来比较不同发光二极管之间的性能差别。在我们日常使用的笔记本电脑上,功耗排在第二位的屏幕,而其中屏幕的功率和亮度有着直接的关系。为此,实验室购买了一个MAVO-MONITORUSB亮度计。它是德国 GMC-Instruments 集团旗下的 GOSSEN Foto-und Lichtmesstechnik Gmbh 有限公司生产的,这是一家专注于官学测量产品研发生产的公司,这款亮度计市场零售价格在1500美元左右。每次测试的时候,需要先将测试头贴在屏幕上,然后在设备的屏幕上度数,然后需要将数值抄写在纸上。这样做很不方便,因此我尝试将其改造为半自动的记录设备。设备提供了一个 USB 端口,从数据手册上了解到,这款设备是通过内置的 FDTI 芯片来实现USB对串口的转接。之前我们介绍过 USB HID设备的读取,相较而言串口和 HID相比,从编程角度来说前者更加方便和通用,资料更加丰富,无论什么编程语言都会支持这一传统设备的编程。但是从客户使用的角度来说,USB串口很可能需要用户安装驱动,虽然Win10内置了很多USB串口芯片的驱动,但是仍然有一些不支持,在使用过程中如果客户使用 Ghost 精简版也会碰到很多问题。而HID设备只需要Application 即可,驱动完全内置。串口通讯需要设置通讯参数,对于这款设备使用的参数为“9600BPS/1 Start bit/ 7 Data bits/ 2 Stopbits/ Even parity/ no Flow control”。接下来用串口工具试验串口设定如下:
*RST恢复设备参数为默认值。运行后设备会重启,但不会影响已存储值。默认设定为:打开自动量程,启用按键输入,屏幕显示打开,存储数据不变,标准采样率(2秒一次),系统时间不受影响。
*IDN?查询设备信息,返回值包括制造商,型号,序列号,硬件版本和Firmware版本。示例如下:输入:*IDN输出:GOSSEN,M 504,31123,02,V 2.04
VERSION?查询命令解释器版本。示例如下:输入:VERSION?输出:VERSION V 1.01(2004)
BEEPER num当后面跟有数字作为参数时,将数字设置为发声时长;没有参数时直接发声。示例如下:设定每次发生时长3秒输入:BEEPER 3 发声一次(如果运行了上面的设定,那么会产生3秒的声音)输入: BEEPER ON
KEYBOARD b启用或者关闭按键输入功能。示例如下:关闭按键输入: KEYBOARD OFF
打开按键输入: KEYBOARD ON
TIME?读取自从上一次校准之后经过的时间示例如下:输入: TIME?输出:00055,02,21
DISPLAY b打开或者关闭屏幕。可选参数为0,1,ON,OFF关闭屏幕输入:DISPLAYOFF打开屏幕输入:DISPLAY1
UNIT:PHOTOMETRICtxt选择测量结果显示的单位。可选参数为LX,FC,CD_M2,FL输入:UNIT:PHOTOMETRIC LX实践显示 CD_M2和FL会报错,提示不支持
PHOTOMETRIC?不加参数时显示当前测量结果。LX:输入:PHOTOMETRIC?输出:289E-02 CD/M2FC:403 E-03 FL1059 E00 FL1870 E-02 FL
RANGE num设定测量范围。测量范围和精度相关,具体可在表格后【Note4】看到
RANGE?查询当前的测量范围输入:RANGE? 输出:1
RANGE:AUTO b打开或者自动量程。参数0,1,ON,OFF 输入:RANGE:AUTOON无输出
RANGE:AUTO?查询当前自动量程是否打开。输入:RANGE:AUTO输出:ON
ECHo b命令回显功能是否启用。参数0,1,ON,OFF在回显打开的情况下,设备在收到主机名后会将命令再次返回主机,这样的方便便于主机确认命令是否正确,但是可能会对处理结果早晨麻烦。例如在回显打开的情况下输入:MEASURE:PHTOT?输出:MEASURE:PHTOT?123E00 LX在回显关闭的情况下输入:MEASURE:PHTOT?输出:123E00LX
DISPLAY:BACKLIGHTb打开或者关闭显示屏幕背光。参数0,1,ON,OFF打开背光输入:DISPLAY:BACKLIGHT ON关闭背光输入:DISPLAY:BACKLIGHT OFF
MEMory:CLEar清除保存的数据。输入:MEMORY:CLEAR输出:100,100
MEMory:FREE?查询当前的存储空间剩余量。输入:MEMORY:CLEAR输出:100,100
MEMory:DATA?查询已经保存的数据。输入:MEMORY:DATA输出:EMPTY
注意:1.上述命令大小写敏感;2.输入命令需要以回车作为结尾;3.上述部分命令有缩写方式,比如:查询当前测量结果的命令“PHOtometric?”可以简写为“PHOT?”,具体建议以手册为准,这里皆使用完整命令。4.命令必须以回车结尾。以 “*IDN”命令为例 ,串口实际发送的十六进制数值如下,需要特别注意结尾处的 0D 0A. 2A 49 44 4E 3F 0D 0A 测量范围和精度=
测量范围Candela/m2(cd/m2)测量范围Candela/m2(ft)分辨率cd/m2分辨率
亮度I0.01...19.990.001… 1.9990.010.001
II0.1...199.90.01… 19.990.10.01
III1 … 19990.1… 199.910.1
IV10… 199901… 1999101
从上面的的知识,我们可以制作一个带有 USB Host 的设备,通过串口命令来控制这个设备,在需要的时候将设备数值发送给 PC 上。经过比较,最终选择了 Teensy 3.6开发板。 这款开发板是PJRC推出的高性能开发板,最高支持180Mhz 的主频。此外接口丰富,自带一个 USB Device 此外还有一个 USB Host,二者可以同时使用。
因此,我们使用板载 USB Host 来连接这个USB亮度计,然后将信息从 USB Device 发送给 PC。为了使用方便,我们使用一个按键进行触发,按下之后USBHost 发送询问命令给设备取得当前读数, USB Device 将自身模拟成一个键盘,直接将读数发给PC。电路设计如下:
可以看到,外围没有元件,只有连接器,U2是 USB 母头,H3 是一个排针用于连接按键。PCB 设计如下:
预览如下:
拿到手的PCB 如下:
下面就是程序设计的过程了,完整代码如下:#include "USBHost_t36.h"
// 通讯参数要求: 9600,Data Bits: 7, Parity:Even, Stop Bits:2
#define USBHOST_SERIAL_7E2 0x1207
// 按键间隔(在间隔以内再次发生的按键都会被忽略)
#define KEYDELAY 2000
// 设置使用 A1 Pin 触发发送
#define PRESSKEY A1
// 发送标志 true-发送 false-不发送
boolean Pressed=false;
// 按键触发时间
unsigned long Elsp;
char *cmdECHOOFF = "ECHO 0"; //关闭命令回显
char *cmdSETUNIT = "UNIT:PHOTOMETRIC LX"; //设定照度返回单位
char *cmdREAD = "MEASURE:PHOTO?";//读取照度
char *cmdVERSION = "VERSION?";//显示版本
USBHost myusb;
USBSerial userial(myusb);
void setup() {
Serial.begin(115200);
// while (!Serial && (millis() < 5000)) ; // wait for Arduino Serial Monitor
// 设置使用 PRESSKEY 触发中断
pinMode(PRESSKEY,INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PRESSKEY), KeyAssert, RISING);
Serial.println("Starting....");
myusb.begin();
userial.begin((uint32_t) 9600,(uint32_t) USBHOST_SERIAL_7E2);
// 打开键盘
Keyboard.begin();
//开始后需要等待设备准备好
delay(5000);
}
byte Status=0;
String revData="";
String HumanReadable="";
void KeyAssert() {
Pressed=true;
}
// 将设备的科学计数法转为常用的表示,结果在 ToStr 中
void SciToStr(String s) {
/*分析设备返回的结果,得到有效数字和小数点位置*/
// 有效数字
int long validNum;
// 小数点位置,就是 E 后面的数值
int zeroPostion;
String sSub;
// Step1. 找到第一个空格,空格之前的就是有效数字
sSub=s.substring(0,s.indexOf(' '));
validNum=sSub.toInt();
// Step2. 将第一个空格之后的字符串切割到另外的字符串中
sSub=s.substring(s.indexOf(' ')+1,s.length());
//Step3. 处理指数位
if (sSub.indexOf('-')!=-1) {
// 有负号,切割从负号到下一个空格
sSub=sSub.substring(sSub.indexOf('-')+1,sSub.indexOf(' '));
zeroPostion=-sSub.toInt();
}
else {
// 没有负号
sSub=sSub.substring(sSub.indexOf('E')+1,sSub.indexOf(' '));
zeroPostion=sSub.toInt();
}
/*分析结束*/
/*根据前面结果,将字符串转为人类易读的字符串*/
String tmp;
// 如果小数位置为正或者为0,只需要在有效数字末尾添加 0 即可
if (zeroPostion>=0) {
HumanReadable=String (validNum);
for (byte i=0;i<zeroPostion;i++) {
HumanReadable=HumanReadable+'0';
}
return;
}
// 如果小数位置小于0 有两种情况:
// 1.在左侧添加组成 0.XYZ 或者 0.0XYZ
// 2.在数字中间加入小数点 X.YZ
if (zeroPostion<0) {
tmp=(String)validNum;
// 处理情况 1
if (abs(zeroPostion)>=tmp.length()) {
HumanReadable="0.";
for (byte i=0;i<abs(zeroPostion)-tmp.length();i++) {
HumanReadable=HumanReadable+"0";
}
HumanReadable=HumanReadable+String(validNum);
return;
}
else {
// 处理情况 2
HumanReadable=tmp;
tmp=HumanReadable.substring(0,HumanReadable.length()-abs(zeroPostion))+'.'+HumanReadable.substring(HumanReadable.length()-abs(zeroPostion));
HumanReadable=tmp;
return;
}
}
}
void loop() {
myusb.Task();
char c;
if (Status==0) {
userial.println(cmdECHOOFF);
Serial.println("Send EchoOff");
delay(500);
Serial.println("Send SETUNIT");
userial.println(cmdSETUNIT);
delay(500);
Status=1;
//if (userial.available()) {Status=1;}
}
if (Status==1) {
userial.println(cmdREAD);
//Serial.println("Read");
delay(100);
while (userial.available()) {
c=userial.read();
//Serial.write(c);
// 有可能收到 0
if (c==0) {continue;}
revData.concat((String)c);
if (c==0x0a) {Status=2;}
delay(2);
}
}
if (Status==2) {
//Serial.print(">"); Serial.print(revData); Serial.println("<");
SciToStr(revData);
Serial.println(HumanReadable);
if ((Pressed)&(millis()>Elsp)) {
Pressed=false;
Keyboard.print(HumanReadable);
Keyboard.press(KEY_DOWN);
Keyboard.release(KEY_DOWN);
Elsp=millis()+KEYDELAY;
}
revData="";
Status=1;
}
}简单的流程介绍:1.对设备发送 ECHO OFF 的命令,设置返回值单位2. 如果有按键按下,那么设置起来标志信息3. 轮询对设备发送读取当前亮度的命令4. 如果按键标志位设置起来,那么就将上一次查询到的当前亮度通过USB接口发送给 PC
Teensy 3.6 开发板提供了非常强大的 USB 支持,自带的例子涵盖了 HIDCDC MSD 以及 Audio,可以非常方便的用在自己的项目中。美中不足的是价格较高(300元左右),如果你的项目对于价格不敏感,或者需要快速实现 USB 相关功能,不妨考虑一下这款开发板。 电路图和 PCB 如下
完整代码如下 zoologist 发表于 2021-1-26 12:27
电路图和 PCB 如下
完整代码如下
好的收到 zoologist 发表于 2021-1-26 12:27
电路图和 PCB 如下
完整代码如下
请问,PCB是用立创EDA设计的吗? 诩 发表于 2021-1-26 22:20
请问,PCB是用立创EDA设计的吗?
是的,立创这个比较方面,我开始用 eagle 后面都是立创 Eda了 66666666666666666666666666666666666 zoologist 发表于 2021-1-27 08:26
是的,立创这个比较方面,我开始用 eagle 后面都是立创 Eda了
好的 #在这里快速回复#谢谢啦
页:
[1]