Direct I/O in DOSBOX for COMM serial communications with QBasic, TBasic or Pbasic

DOSBOX虚拟环境能在WIN10和LINUX平台上支持DOS、WIN3x、Win9x程序运行。串口是当年计算机硬件的标配,经RS232-RS485转换后轻松实现远距离数据通讯,这些当年的程序和设备在今天的DOSBOX下也还是可以使用的。DOS、QuickBasic、TurboBasic、PowerBasic,都曾经陪伴了许多人的青春年华,回味起来既温馨又充实,至今依然很耐人玩味,因此,还是把心得体会写下来。

DOSBOX不仅支持串口,还支持打印口和游戏口。串口和打印口都有Direct I/O能力,游戏口也是如此,而DOSBOX中的程序大多是实模式下运行的,通过Direct I/O即可在串口、并口、游戏口的支持下与外部硬件打交道(其它非标口是不行的)。在QBasic、TBasic、PBasic的On COM(n), On Strig(n)支持下,串口游戏口又都是优于60ms的中断源,合理安排下做中断处理还是比较容易使用的(优先级高的中断会中断优先级低的中断)。反正就是拿它玩的,也不必纠结太多其它什么东西,能用就好。

想让DOSBOX支持串口,要在它的CONF文件中配置一下串口。真实串口要映射成DOSBOX的串口,一般就一对一好了。将serial1       = dummy改成serial1       = directserial realport:COM1,这样真实串口就挂到了DOSBOX的串口serial1,即DOSBOX的COM1口。

[Serial]

serial1       = directserial realport:COM1

串口通讯是既让人兴奋又让人讨厌的东西,无论你在哪个BASIC下常规使用它都有毛病,在数据读取时会出问题,要么缓冲区溢出程序不运行了,要么串口线断线程序死着不动了。研华的STD-DRV能支持四个普通串口,在DOS下调用它的函数比BASIC带的OPEN类的东西好用多了,它是不加密的,移动哪个DOS下都能使用,而用还带C、BASIC、CLIPPER等SAMPLE程序。只是,把它用到DOSBOX下时就不好用了。其实,直接操作串口的状态和数据寄存器就方便了,而且DOSBOX支持这种直接操作。下面是个TuroBasic的实验程序,在其它BASIC下应该也是运行的,这些平台都差不多而且应该是代码兼容的。

ON ERROR GOTO ERRORTRAP1
'TURBOBASIC DOESN'T ALLOW ON_ERROR_ RESUME_NEXT, USE GOTO INSTEAD

CLS
     'SET COM1 BAUD RATE AND MODE
     OUT &H3F8 + 3, &H80
     OUT &H3F8 + 0, &H0C
     OUT &H3F8 + 1, &H00
     OUT &H3F8 + 3, &H03
     OUT &H3F8 + 4, &H00
     OUT &H3F8 + 1, &H00

     ZZZ=32
     DO WHILE INKEY$<>CHR$(27)
     ZZZ = ZZZ + 1

     FOR L = 1 TO 1000
     COMSTATUSOUT = INP(&H3F8 + 5)
     IF (COMSTATUSOUT AND &H20) = &H20 THEN
        OUT &H3F8, ZZZ
        EXIT FOR
     END IF
     NEXT L

     IF ZZZ >= 126 THEN ZZZ = 32

      FOR L = 1 TO 1000
      COMSTATUSIN = INP(&H3F8+5)
      IF (COMSTATUSIN AND 1) <> 0 THEN
          FFF$ = CHR$(INP(&H3F8)): PRINT FFF$+" ";
          EXIT FOR
      END IF
      NEXT L

     LOOP
END

'TURBOBASIC DOESN'T ALLOW ON_ERROR_ RESUME_NEXT, USE A SUBROUTINE INSTEAD
ERRORTRAP1:
      RESUME NEXT

这段程序是寄存器直接发送和接收,然后显示ASCII字符到屏幕上。因为不存在INPUT类的内部等待,和其它封闭起来的毛病,因此,即使是串口线断了,最多是收不到数据,一旦恢复连接则数据又开始接收了,这在与外部硬件实时打交道时可靠多了。如果发送端定义成!nnn#类指令,那收到指令时可按指令行事了,与Adam或NuDam模块类似了,与单片机打交道也可以如此操作。看看它的实际输出吧。

这是将九针串口的2和3脚,TxD和RxD连在一起得到的即时收发反应,正常情况下是稳稳的不丢失字符的。

除了如此操作之外,DOSBOX还可借助PCAP或SLIRP联网,不过是有局限的。毕竟DOSBOX不是基于虚拟网卡结构的,它没有虚拟网上就只能寄生在物理网卡,从底层收发数据,就是CAP抓包数据或叫截获数据,这网联得好像不怎么正道似的,但却是能联接上网的。

另外就是共享数据,DOSBOX和主机WINx用的是相同的文件系统,通过对文件系统的加解锁就可以将砂箱DOSBOX中的数据文件共享给主机程序读取。DOSBOX对文件加锁,写完数据关闭文件,释放文件锁;主机程序加锁文件,读取数据,并释放文件锁。这种方法做大数据交换还算方便吧,怎么也比串口收发数据方便,如果Mount的是Ramdisk那还可以不停的读写操作提高数据交换的即时性。

总之,DOS虽然老,但在64位Win10和Linux上还是能用的。相比Mono和Wine, DOSBOX轻便多了,不用建一堆Windows的目录结构和注册表。Watcom c/c++带上Pmode/W,DOSBOX下的DOS也能保护模式编程,上Win3x和Win9x也挺好玩的。

上述基于DOSBOX的串口通讯,也可以在QUICK BASIC下用On Com(1) gosub的中断方式实现。下面的代码编译:

BC nonam6.bas /w /v /x

Link nonam6

最终产生nonam.exe

ON ERROR GOTO ERRORTRAP1
'TURBOBASIC DOESN'T ALLOW ON_ERROR_ RESUME_NEXT, USE GOTO INSTEAD

ON COM(1) GOSUB COMTRAP1
COM(1) ON

OPEN "COM1:9600,N,8,1,CD0,CS0,DS0,BIN" FOR RANDOM AS #1

CLS
ERRORID = 0

START:
     ZZZ = 32
     SDATAID = 0
     DO WHILE INKEY$ <> CHR$(27)
        TBUFFERID = INP(&H3F8 + 5) AND &H20
        IF ERRORID = 1 THEN
                'RECOVERED FROM AN ERROR, UNCONDITIONAL SEND
                SDATAID = 1
                ERRORID = 0
                ZZZ = ZZZ + 1
                IF ZZZ >= 126 THEN ZZZ = 32
                PRINT #1, ZZZ
        ELSEIF SDATAID = 0 AND TBUFFERID = 32 THEN
                SDATAID = 1
                ZZZ = ZZZ + 1
                IF ZZZ >= 126 THEN ZZZ = 32
                PRINT #1, ZZZ
        END IF
     LOOP
CLOSE #1
END

COMTRAP1:
      COM(1) OFF
      INPUT #1, COMDATA
      PRINT CHR$(COMDATA) + " ";
      SDATAID = 0
      COM(1) ON
      RETURN

'TURBOBASIC DOESN'T ALLOW ON_ERROR_ RESUME_NEXT, USE A SUBROUTINE INSTEAD
ERRORTRAP1:
      'CLOSE COMPORT AND REOPEN THE PORT
      COM(1) OFF
      CLOSE #1
      OPEN "COM1:9600,N,8,1,CD0,CS0,DS0,BIN" FOR RANDOM AS #1
      COM(1) ON
      ERRORID = 1       'FLAG - RETURN FROM AN ERROR
      RESUME START

上述程序运行时,将串口2、3针短路,得到如下屏幕

上述程序稍做改变,发送由单字符改为字符串,比如 $AAB,每次发送一个ASC(串),收端也做判断,以$开始并以CHR$(13)结尾的作为一个指令串辨识,然后依指令串定义去做相应的执行。上面中断方式的QBASIC程序若是在PBASIC上运行,去掉串口打开时字符串中的,PB不使用这个参数,否则编译出错:BAD FILENAME。

下面是收发指令方式的测试,因为其它BASIC不支持SUB或FUNCTION类的子过程,就用带标号的原始GOSUB和RETURN方式了,可以尽量保持在不同BASIC下的编译运行,但所附的这个例子是在QBASIC 7下编译运行的。

某些模块使用类似的指令,所以,就参照它们的指令写法。键盘上按键 1、2、3、4,分别发出不同的字符串指令,而中断方式的子过程返加收到的指令并附加了一些字符,这些字符的地方可以是数据采集卡的高8位和低8位转换值的合成结果,如此便完成了收指令并按指令返回数据采集结果的测试,测试条件是串口的2、3脚短接。程序如下:

CLS
DIM COMSTRING(20) AS STRING
CPOS = 1

ON ERROR GOTO ERRORTRAP1
ON COM(1) GOSUB COMTRAP1
OPEN "COM1:9600,N,8,1,CD0,CS0,DS0,RS,BIN" FOR RANDOM AS #1
COM(1) ON

        COMMANDSET = 0
        PRINT
        PRINT "Press key 1, 2, 3, and 4 on the keyboard, and see..."
        PRINT "Press ESC to exit"
        PRINT

        DO
        KEYIN$ = INKEY$
        IF KEYIN$ = CHR$(27) THEN EXIT DO
        IF KEYIN$ = "1" THEN
                INSTRUCT$ = "$AAB" + CHR$(13)
                GOSUB SENDOUT                 'SEND OUT A COMMAND
           ELSEIF KEYIN$ = "2" THEN
                INSTRUCT$ = "$AAC" + CHR$(13)
                GOSUB SENDOUT                 'SEND OUT A COMMAND
           ELSEIF KEYIN$ = "3" THEN
                INSTRUCT$ = "$AAD" + CHR$(13)
                GOSUB SENDOUT                 'SEND OUT A COMMAND
           ELSEIF KEYIN$ = "4" THEN
                INSTRUCT$ = "$AAE" + CHR$(13)
                GOSUB SENDOUT                 'SEND OUT A COMMAND
        END IF
        LOOP
        END
 
SENDOUT:
        COMIN$ = LTRIM$(RTRIM$(INSTRUCT$))
        'PRINT COMIN$           'TO SEE WHATS IN

    IF COMIN$ <> "" THEN
      FOR NN = 1 TO LEN(COMIN$)
          PRINT #1, ASC(MID$(COMIN$, NN, 1))
      NEXT NN
    END IF
    RETURN

COMTRAP1:
      COM(1) OFF
      INPUT #1, COMDATA

      IF COMDATA = ASC("$") THEN
                COMSTRING(1) = CHR$(COMDATA)
                CPOS = 1
         ELSEIF COMDATA <> 13 THEN
                CPOS = CPOS + 1
                IF CPOS > 20 THEN CPOS = 20
                COMSTRING(CPOS) = CHR$(COMDATA)
         ELSE
                'A FULL STRING OF COMMAND IDENTIFIED
                LOCALCOMMAND$ = ""
                FOR OO = 1 TO CPOS
                    LOCALCOMMAND$ = LOCALCOMMAND$ + COMSTRING(OO)
                NEXT OO
                    '*******************************************
                    'CHECK LOCALCOMMAND$ VS COMMAND TABLE OF ICP
                    IF LOCALCOMMAND$ = "$AAB" THEN
                                PRINT "IT IS $AAB, I WILL SEND BACK ACQUIRED DATA"
                        ELSEIF LOCALCOMMAND$ = "$AAC" THEN
                                PRINT "IT IS $AAC, I WILL SEND BACK ACQUIRED DATA"
                        ELSEIF LOCALCOMMAND$ = "$AAD" THEN
                                PRINT "IT IS $AAD, I WILL SEND BACK ACQUIRED DATA"
                        ELSEIF LOCALCOMMAND$ = "$AAE" THEN
                                PRINT "IT IS $AAE, I WILL SEND BACK ACQUIRED DATA"
                    END IF
                    '*******************************************
      END IF

      COM(1) ON
      RETURN


'TURBOBASIC DOESN'T ALLOW ON_ERROR_ RESUME_NEXT, USE A SUBROUTINE INSTEAD
ERRORTRAP1:
      'CLOSE COMPORT AND REOPEN THE PORT
      COM(1) STOP: COM(1) OFF
      CLOSE #1
      OPEN "COM1:9600,N,8,1,CD0,CS0,DS0,RS,BIN" FOR RANDOM AS #1
      PRINT #1, ZZZ: INPUT #1, COMDATA
      COM(1) ON
      RESUME NEXT

上面的程序都是基于串口2、3脚直接短接测试的。将指令发送程序和接受应答程序分开运行在两台机器上的话,大致是这个样子的。

发送程序

CLS
DIM COMSTRING(20) AS STRING
BRATE$ = RTRIM$(LTRIM$(COMMAND$))
IF BRATE$ = "" THEN BRATE$ = "9600"
CPOS = 1
DATASET = 0

ON ERROR GOTO ERRORTRAP1
ON COM(1) GOSUB COMTRAP1
OPEN "COM1:" + BRATE$ + ",N,8,1,CD0,CS0,DS0,RS" FOR RANDOM AS #1
COM(1) ON

START:
        CLS
        DATASET = 0
        PRINT
        PRINT "Press key 1, 2, 3, and 4 on the keyboard, and see..."
        PRINT "Press ESC to exit"
        PRINT

        DO
        KEYIN$ = INKEY$
        IF KEYIN$ = CHR$(27) THEN EXIT DO
                IF DATASET = 0 THEN
                        DATASET = 1
                        INSTRUCT$ = "$AAB" + CHR$(13)
                        TBUFFERID = INP(&H3F8 + 5) AND &H20
                        IF TBUFFERID = 32 THEN
                           GOSUB SENDOUT                 'SEND OUT A COMMAND
                        END IF
                END IF

'        IF KEYIN$ = "1" THEN
'                INSTRUCT$ = "$AAB" + CHR$(13)
'                GOSUB SENDOUT                 'SEND OUT A COMMAND
'           ELSEIF KEYIN$ = "2" THEN
'                INSTRUCT$ = "$AAC" + CHR$(13)
'                GOSUB SENDOUT                 'SEND OUT A COMMAND
'           ELSEIF KEYIN$ = "3" THEN
'                INSTRUCT$ = "$AAD" + CHR$(13)
'                GOSUB SENDOUT                 'SEND OUT A COMMAND
'           ELSEIF KEYIN$ = "4" THEN
'                INSTRUCT$ = "$AAE" + CHR$(13)
'                GOSUB SENDOUT                 'SEND OUT A COMMAND
'        END IF
        LOOP
        END
 
SENDOUT:
        COMIN$ = LTRIM$(RTRIM$(INSTRUCT$))
        'PRINT COMIN$           'TO SEE WHATS IN

    IF COMIN$ <> "" THEN
      FOR NN = 1 TO LEN(COMIN$)
          PRINT #1, ASC(MID$(COMIN$, NN, 1))
      NEXT NN
    END IF
    RETURN

COMTRAP1:
      COM(1) OFF
      INPUT #1, COMDATA

      IF COMDATA = ASC("!") THEN
                COMSTRING(1) = CHR$(COMDATA)
                CPOS = 1
         ELSEIF COMDATA <> 13 THEN
                CPOS = CPOS + 1
                IF CPOS > 20 THEN CPOS = 20
                COMSTRING(CPOS) = CHR$(COMDATA)
         ELSE
                'A FULL STRING OF COMMAND IDENTIFIED
                LOCALCOMMAND$ = ""
                FOR OO = 1 TO CPOS
                    LOCALCOMMAND$ = LOCALCOMMAND$ + COMSTRING(OO)
                NEXT OO
                    '*******************************************
                    'PRINT ACCEPTED DATA
                    PRINT LOCALCOMMAND$ + " ";
                    DATASET = 0
                    '*******************************************
      END IF

      COM(1) ON
      RETURN


'TURBOBASIC DOESN'T ALLOW ON_ERROR_ RESUME_NEXT, USE A SUBROUTINE INSTEAD
ERRORTRAP1:
      'CLOSE COMPORT AND REOPEN THE PORT
      COM(1) STOP: COM(1) OFF
      CLOSE #1
      OPEN "COM1:" + BRATE$ + ",N,8,1,CD0,CS0,DS0,RS" FOR RANDOM AS #1
      PRINT #1, ZZZ: INPUT #1, COMDATA
      COM(1) ON
      RESUME START

接收程序

CLS
DIM COMSTRING(20) AS STRING
BRATE$ = RTRIM$(LTRIM$(COMMAND$))
IF BRATE$ = "" THEN BRATE$ = "9600"
CPOS = 1

PORTDO = &H378
PORTDI = &H379

ON ERROR GOTO ERRORTRAP1
ON COM(1) GOSUB COMTRAP1
OPEN "COM1:" + BRATE$ + ",N,8,1,CD0,CS0,DS0,RS" FOR RANDOM AS #1
COM(1) ON

START:
        CLS
        MIDPOS = (80 - LEN("DATA ACQUISITION KERNEL")) / 2
        LOCATE 11, MIDPOS: PRINT "DAQSBC VER1.0"
        LOCATE 12, MIDPOS: PRINT "DATA ACQUISITION KERNEL"
        LOCATE 13, MIDPOS: PRINT "DATE:" + DATE$
        LOCATE 14, MIDPOS: PRINT "TIME:" + TIME$ + "..."

        DO WHILE INKEY$ <> CHR$(27)
                LOCATE 13, MIDPOS: PRINT "DATE:" + DATE$
                LOCATE 14, MIDPOS: PRINT "TIME:" + TIME$ + "..."

                '****************************************
                '* SELET ADC ADDRESS                    *
                '* ACQUIRE HIGHER BITS, THEN LOWER BITS *
                '* ACQUIRE DI                           *
                '****************************************
        LOOP
        END

'        DO
'        KEYIN$ = INKEY$
'        IF KEYIN$ = CHR$(27) THEN EXIT DO
'        IF KEYIN$ = "1" THEN
'                INSTRUCT$ = "$AAB" + CHR$(13)
'                GOSUB SENDOUT                 'SEND OUT A COMMAND
'           ELSEIF KEYIN$ = "2" THEN
'                INSTRUCT$ = "$AAC" + CHR$(13)
'                GOSUB SENDOUT                 'SEND OUT A COMMAND
'           ELSEIF KEYIN$ = "3" THEN
'                INSTRUCT$ = "$AAD" + CHR$(13)
'                GOSUB SENDOUT                 'SEND OUT A COMMAND
'           ELSEIF KEYIN$ = "4" THEN
'                INSTRUCT$ = "$AAE" + CHR$(13)
'                GOSUB SENDOUT                 'SEND OUT A COMMAND
'        END IF
'        LOOP
'        END
'
'SENDOUT:
'        COMIN$ = LTRIM$(RTRIM$(INSTRUCT$))
'        'PRINT COMIN$           'TO SEE WHATS IN
'
'    IF COMIN$ <> "" THEN
'      FOR NN = 1 TO LEN(COMIN$)
'          PRINT #1, ASC(MID$(COMIN$, NN, 1))
'      NEXT NN
'    END IF
'    RETURN

COMTRAP1:
      COM(1) OFF
      INPUT #1, COMDATA

      IF COMDATA = ASC("$") THEN
                COMSTRING(1) = CHR$(COMDATA)
                CPOS = 1
         ELSEIF COMDATA <> 13 THEN
                CPOS = CPOS + 1
                IF CPOS > 20 THEN CPOS = 20
                COMSTRING(CPOS) = CHR$(COMDATA)
         ELSE
                'A FULL STRING OF COMMAND IDENTIFIED
                LOCALCOMMAND$ = ""
                FOR OO = 1 TO CPOS
                    LOCALCOMMAND$ = LOCALCOMMAND$ + COMSTRING(OO)
                NEXT OO
                    '*******************************************
                    
                    IF LOCALCOMMAND$ = "$AAB" THEN
                                 '******************************
                                 OUTVAL = INP(PORTDI) + VAL(RIGHT$(TIME$, 1))
                                 OUTSTRING$ = STR$(OUTVAL)
                                 PRINT #1, ASC("!")
                                 'SEND ASCII CHARACTERS FOR PORT VALUE ACQUIRED
                                 FOR PP = 1 TO LEN(OUTSTRING$)
                                        PRINT #1, ASC(MID$(OUTSTRING$, PP, 1))
                                 NEXT PP
                                 PRINT #1, 13
                                 '******************************
                    END IF

      END IF

      COM(1) ON
      RETURN


'TURBOBASIC DOESN'T ALLOW ON_ERROR_ RESUME_NEXT, USE A SUBROUTINE INSTEAD
ERRORTRAP1:
      'CLOSE COMPORT AND REOPEN THE PORT
      COM(1) STOP: COM(1) OFF
      CLOSE #1
      OPEN "COM1:" + BRATE$ + ",N,8,1,CD0,CS0,DS0,RS" FOR RANDOM AS #1
      PRINT #1, ZZZ: INPUT #1, COMDATA
      COM(1) ON
      RESUME START

发送与应答指令可以根据自己的喜好定义,应答程序可以安装在SBC板子的CF/IDE卡上或DOM电子盘上,采集量可是DI、计数或ADC,输出量可是DO或DAC,或是直接使用串行总线模组(或单片机串口通讯,功能与上述应答程序是类同的)。

DOSBOX 文件方式的数据交换

DOSBOX是可以多份考贝同时运行的,两个DOSBOX中的程序可通过文件锁方式同时操作同一数据文件,比竟它们是基于同一平台的文件,操作系统会管理好文件锁,这也是DOSBOX完备的能力。不仅两个DOSBOX程序能同时操作同一文件,DOSBOX砂箱中的文件还可以和主平台的程序进行文件操作。下图是两个DOSBOX中的不同程序操作同一数据文件的情形。

写文件操作程序 - DOSBOX1

CLS
ON ERROR RESUME NEXT
ON TIMER(1) GOSUB TIMERTRAP
TIMER ON

WHILE INKEY$ <> CHR$(27): WEND
END

TIMERTRAP:
OUTSTRING$ = TIME$
OPEN "FSHARE.TXT" FOR OUTPUT SHARED AS #1
     WRITE #1, OUTSTRING$
CLOSE #1
PRINT "SENT TIMESTAMP: " + OUTSTRING$
RETURN

读文件操作程序 - DOSBOX2

CLS
ON ERROR RESUME NEXT
ON TIMER(1) GOSUB TIMERTRAP
TIMER ON

WHILE INKEY$ <> CHR$(27): WEND
END

TIMERTRAP:
OPEN "FSHARE.TXT" FOR INPUT SHARED AS #1
     INPUT #1, ACCEPTSTRING$
CLOSE #1
     PRINT "RECEIVED TIMESTAMP: " + ACCEPTSTRING$
RETURN

打开文件时加上SHARED就解决文件锁问题,如果加上ON ERROR除错就更好了,实际应用时宜判断一下错误代号,比笼统的RESUME要更精准。

上面的程序是用TIMER读写的,改一下让它在LOOP中不断更新,速度就不一样了。

FSHARE.BAS

CLS
ON ERROR RESUME NEXT

WHILE INKEY$ <> CHR$(27)
        OUTSTRING$ = STR$(ABS(1000 * RND(1)))
        OPEN "FSHARE.TXT" FOR OUTPUT SHARED AS #1
                WRITE #1, OUTSTRING$
        CLOSE #1
        PRINT "SENT DATA: " + OUTSTRING$
WEND
END

SHAREF.BAS

CLS
ON ERROR RESUME NEXT

WHILE INKEY$ <> CHR$(27)
        OPEN "FSHARE.TXT" FOR INPUT SHARED AS #1
                INPUT #1, ACCEPTSTRING$
        CLOSE #1
        PRINT "RECEIVED DATA: " + ACCEPTSTRING$
WEND
END

对如此反复读写的磁盘耐受问题

现在的硬盘都有足够的缓冲,这一点数据磁盘是不发生物理机械动作的。更好的方法是使用固态电子盘,或是RAM虚拟盘,就不会有机械性磁盘动作了。

小结:

使用DOSBOX砂箱的好处有许多,比如:

1. 不需要注册表注册,直接考贝到WINDOWS10就能运行它,而砂箱里的DOS、WIN3x、WIN9x也就随时可运行了,是软件虚拟化的硬件,因此,没有硬件冲突。

2. 它是跨平台的,可以在各种LINUX、BSD、UNIX下运行,这也意味着,砂箱里的程序都可以在其它平台上依托于砂箱而运行。

3. 现在已经打通了砂箱与外界的联系,包括串口和文件共享,自己的程序也就不再被外界孤立隔离。

即然在DOSBOX砂箱DOS下的QBASIC能通过串口与外部设备交换数据,那砂箱里WINx16下的VB3或其它比如DELPHI 2又如何呢?

我们在砂箱里用VB3编写一个串口交互程序,形同下图。

 在砂箱的WIN3.2环境下的VB3中运行它

通过串口发送给外部设备并由外部设备的数据清楚顺畅不间断地显示在列表框中,说明在砂箱里,不论是DOS程序还是WINx16程序,都能完成基于串口的数据交互。

WINx16独立在WINx64平台上运行

砂箱里的VB3程序,可以直接编译成EXE文件,通常情况下它必须有基于DOSBOX的WIN3.x环境才能运行,而实际上,我们可以另辟蹊径,甩掉不必要的砂箱,让程序直接在WINx64平台上运行。下图显示的非常清楚,背景是WIN10x64界面,前台程序PROJECT1.EXE就是VB3编译的WINx16程序,完全不需要砂箱支持。

 但是,一定是有背景程序负责在WIN3.2和WIN64之间翻译,否则肯定会因兼容性问题报错的。背景支持程序就是OTVDM,它是一个独立的EXE文件,直接运行它即会在WIN64平台安装好支持,一旦安装好就不需要再干涉它了,启动计算机它自动做无名英雄,用户是感觉不到它存在的,老旧WIN3.2程序直接双击就行了。

Rx、Tx、GND三线串口是各类单片机的最基本配备,也是各类PC主板卡必配的通讯口,是计算机最方便的通讯口,还是很有必要用好的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值