在 带有128KB缓存的AD7606模拟采集板 后面更新了不带板内缓冲区的C51程序。采集板与计算机之间存在两种实时数据通道:
为了能够利用 STC WiFi下载程序 界面作为接受数据的缓冲界面,这样就需要能够利用ASCII码来高效传输二进制数据。
传统的方式通过C51的printf函数,将二进制转换成ASCII字符串通过串口发送出去,虽然这样有很强的可读性,但是存在着很大的转换效率低下:
因此,最大需要是踹死7个字节来传输一个16bit的数据。传输效率浪费了: η a s c i i = 7 2 \eta _{ascii} = {7 \over 2} ηascii=27
▲ ISP下载软件界面
在网页 What is Base64 Encoding and How does it work? | Base64Encoder 给出了Base64编码的具体方式。它将连续三个字节(24bit)转换成四个6bit组,按照下面的表格找到对应的ASCII码。
▲ Base64编码字符表格
这样的转换效率为 η b a s e 64 = 4 3 \eta _{base64} = {4 \over 3} ηbase64=34
通过Base64的转换比普通的ASCI字符效率提高了:
η Δ = η a s c i i η b a s e 64 = 7 / 2 4 / 3 = 21 8 = 2.625 \eta _\Delta = {{\eta _{ascii} } \over {\eta _{base64} }} = {{7/2} \over {4/3}} = {{21} \over 8} = 2.625 ηΔ=ηbase64ηascii=4/37/2=821=2.625
在实际实现中,将原来的 “62”编码为$+$,修改为$*$,这样在下载程序界面可以避免换行的。整个显示是铺满Mem0界面。
/*
**==============================================================================
** BASE64ASCII.C: -- by Dr. ZhuoQing, 2020-06-04
**
**==============================================================================
*/
//------------------------------------------------------------------------------
#define BASE64ASCII_GLOBALS 1 // Define the global variables
#include "BASE64ASCII.H"
#include "c51basic.H"
//------------------------------------------------------------------------------
void Base64ASCIISendChar(unsigned char ucChar) {
SendChar(ucChar);
}
//------------------------------------------------------------------------------
void Base64ASCIIInit(void) {
g_ucBase64ASCIIBufferPoint = 0;
}
//------------------------------------------------------------------------------
void Base64ASCIIPushByte(unsigned char ucByte) {
g_ucBase64ASCIIBuffer[g_ucBase64ASCIIBufferPoint ++] = ucByte;
if(g_ucBase64ASCIIBufferPoint >= 3) {
Base64ASCIIFlushBuffer();
}
}
unsigned char Base64ASCII6BitChar(unsigned char ucBit) {
if(ucBit < 26) return 'A' + ucBit;
if(ucBit < 52) return (ucBit - 26) + 'a';
if(ucBit < 62) return (ucBit - 52) + '0';
if(ucBit == 62) return '*';
if(ucBit == 63) return '/';
return '=';
}
//------------------------------------------------------------------------------
void Base64ASCIIFlushBuffer(void) {
unsigned char ucDim[4];
unsigned char ucChar, ucNibble;
if(g_ucBase64ASCIIBufferPoint == 0) return;
ucChar = g_ucBase64ASCIIBuffer[0];
ucNibble = ucChar << 4;
ucDim[0] = Base64ASCII6BitChar(ucChar >> 2);
ucChar = g_ucBase64ASCIIBuffer[1];
ucDim[1] = Base64ASCII6BitChar((ucNibble & 0x30) | (ucChar >> 4));
ucNibble = (ucChar & 0xf) << 2;
ucChar = g_ucBase64ASCIIBuffer[2];
ucDim[2] = Base64ASCII6BitChar(ucNibble | (ucChar >> 6));
ucDim[3] = Base64ASCII6BitChar(ucChar & 0x3f);
if(g_ucBase64ASCIIBufferPoint == 1) {
ucDim[2] = '=';
ucDim[3] = '=';
} else if(g_ucBase64ASCIIBufferPoint == 2) {
ucDim[3] = '=';
}
Base64ASCIISendChar(ucDim[0]);
Base64ASCIISendChar(ucDim[1]);
Base64ASCIISendChar(ucDim[2]);
Base64ASCIISendChar(ucDim[3]);
g_ucBase64ASCIIBufferPoint = 0;
}
//==============================================================================
// END OF THE FILE : BASE64ASCII.C
//------------------------------------------------------------------------------
/*
**==============================================================================
** BASE64ASCII.H: -- by Dr. ZhuoQing, 2020-06-04
**
** Description:
**
**==============================================================================
*/
#ifndef __BASE64ASCII__
#define __BASE64ASCII__
//------------------------------------------------------------------------------
#ifdef BASE64ASCII_GLOBALS
#define BASE64ASCII_EXT
#else
#define BASE64ASCII_EXT extern
#endif // BASE64ASCII_GLOBALS
//------------------------------------------------------------------------------
//==============================================================================
void Base64ASCIISendChar(unsigned char ucChar);
//------------------------------------------------------------------------------
void Base64ASCIIInit(void);
BASE64ASCII_EXT unsigned char g_ucBase64ASCIIBuffer[3];
BASE64ASCII_EXT unsigned char g_ucBase64ASCIIBufferPoint;
void Base64ASCIIPushByte(unsigned char ucByte);
void Base64ASCIIFlushBuffer(void);
unsigned char Base64ASCII6BitChar(unsigned char ucbit);
//==============================================================================
// END OF THE FILE : BASE64ASCII.H
//------------------------------------------------------------------------------
#endif // __BASE64ASCII__
def Base64Ascii2Bit(ascii):
ascii = int(ascii)
if ascii >= ord('A') and ascii <= ord('Z'): return ascii - ord('A')
if ascii >= ord('a') and ascii <= ord('z'): return ascii - ord('a') + 26
if ascii >= ord('0') and ascii <= ord('9'): return ascii - ord('0') + 52
if ascii == ord('*'): return 62
if ascii == ord('/'): return 63
return 0
def Base64Ascii2Byte(fourb):
data = bytearray()
bits0 = Base64Ascii2Bit(fourb[0])
bits1 = Base64Ascii2Bit(fourb[1])
bits2 = Base64Ascii2Bit(fourb[2])
bits3 = Base64Ascii2Bit(fourb[3])
data.append(bits0 * 4 + int(bits1 / 16))
data.append((bits1 & 0xf) * 16 + int(bits2 / 4))
data.append((bits2 & 0x3) * 64 + bits3)
if fourb[2] == ord('=') and fourb[3] == ord('='):
data = data[0:1]
return data
if fourb[3] == ord('='):
return data[0:2]
return data
def Base64Ascii2Data(ascii):
data = bytearray()
length = len(ascii)
for i in range(int(length / 4)):
bytedata = Base64Ascii2Byte(ascii[i*4:i*4+4])
if len(bytedata) > 0:
data.extend(bytedata)
valdim = [x*256+y for x,y in zip(data[0::2], data[1::2])]
valdim = [(d & 0x7fff) - (d & 0x8000) for d in valdim]
return valdim
经过测试,在 带有128KB缓存的AD7606模拟采集板 上,对八个通道进行周期为1毫秒的采集,实际上传速率为 16kByte/s。再乘以编码增益 η b a s e 64 = 4 3 \eta _{base64} = {4 \over 3} ηbase64=34,则实际上传速率为:21.3kByte/秒.
▲ 通过AD7606采集板采集到的两个通道的信号波形
#------------------------------------------------------------
stm32cmd('ad5v')
stm32cmd('CLEAR')
stm32cmd('adascii 1000 8 1')
val = stm32val()[10]
while True:
time.sleep(.2)
valnew = stm32val()[10]
if valnew == val: break
val = valnew
tspbeep(1200, 200)
stm32cmd("COPY")
time.sleep(.5)
pastestr = bytes(clipboard.paste(), 'utf-8')
data = Base64Ascii2Data(pastestr)
plt.plot(data[0::8], label='Channel1')
plt.plot(data[1::8], label='Channel2')
plt.xlabel("sample")
plt.ylabel("Voltage(V)")
plt.legend(loc='upper right')
plt.grid(True)
plt.show()
通过Base64编码,将原来的3个字节的数据编码成4个字节的ASCII字符,可以在适合ASCII存储显示的界面完成二进制数据的传递。这大大提高数据的传输效率。
//==============================================================================
// PROCESS THE DEBUG BUFFER
//------------------------------------------------------------------------------
void SerialDebugProcessBuffer(void) {
unsigned int nNumber, nChannel, nWaitTime, i, j;
int nData[8];
unsigned int nNum;
SerialDebugBuffer2Argument();
if(g_ucSDANumber == 0) return;
if(strcmp("hello", (char *)STD_ARG[0]) == 0)
printf("%s is ready !\r\n", VERSION_STRING);
else IFARG0("ad") {
sscanf(SDA(1), "%d", &nNumber);
sscanf(SDA(2), "%d", &nChannel);
sscanf(SDA(3), "%d", &nWaitTime);
g_ucWaitMS = 0;
for(i = 0; i < nNumber; i ++) {
while(g_ucWaitMS != nWaitTime);
g_ucWaitMS = 0;
AD7606Convert();
AD7606ReadData(nData, 4);
for(j = 0; j < nChannel; j ++) {
nNum = nData[j];
SendChar((unsigned char)(nNum >> 8));
SendChar((unsigned char)nNumber);
}
}
}
else IFARG0("adtext") {
sscanf(SDA(1), "%d", &nNumber);
sscanf(SDA(2), "%d", &nChannel);
sscanf(SDA(3), "%d", &nWaitTime);
g_ucWaitMS = 0;
for(i = 0; i < nNumber; i ++) {
while(g_ucWaitMS != nWaitTime);
g_ucWaitMS = 0;
AD7606Convert();
AD7606ReadData(nData, 4);
for(j = 0; j < nChannel; j ++) {
nNum = nData[j];
printf("%d ", nNum);
}
}
} else IFARG0("adascii") {
sscanf(SDA(1), "%d", &nNumber);
sscanf(SDA(2), "%d", &nChannel);
sscanf(SDA(3), "%d", &nWaitTime);
g_ucWaitMS = 0;
Base64ASCIIInit();
for(i = 0; i < nNumber; i ++) {
while(g_ucWaitMS != nWaitTime);
g_ucWaitMS = 0;
AD7606Convert();
AD7606ReadData(nData, 4);
for(j = 0; j < nChannel; j ++) {
nNum = nData[j];
Base64ASCIIPushByte((unsigned char)(nNum >> 8));
Base64ASCIIPushByte((unsigned char)nNum);
}
}
Base64ASCIIFlushBuffer();
} else IFARG0("ad5v") {
OFF(AD7606_RANGE);
} else IFARG0("ad10v") {
ON(AD7606_RANGE);
}
else printf("Error command : %s !\r\n", STD_ARG[0]);
}
C51工程文件:C51\STC\Tools\AD7606\Sample8G1KNoBuffer\Sample8G1KNoBuffer.uvproj ↩︎