串口通信模块的设计主要利用的芯片是8251和COMPIN管脚,8251芯片的作用是进行串口通信,COMPIN的作用是模拟串口产生信号,这里还用到了虚拟串口,虚拟串口需要下载一个软件名字叫Virtual Serial Port Driver,如果没有串口助手的话还需要下载串口助手,这里我使用的串口助手是stc-isp这两个软件网上可以下载。本文中使用的是异步串行通信方式。
S2,S1 | EP,PEN | L2,L1 | B2,B1 |
---|---|---|---|
00无效 | X0无奇偶校验位 | 00 字符长度为5位 | 01 异步方式 x01 |
01 1个停止位 | 01奇校验 | 01 字符长度为6位 | 10 异步方式 x16 |
10 1.5个停止位 | 11偶校验 | 10 字符长度为6位 | 11 异步方式x64 |
11 字符长度为8位 |
最后一行与频率的设置有关为波特率系数:
收发时钟频率 = 收发波特率 × 波特率系数
2.命令字:
EH | IR | RTS | ER | SBRK | RxE | DTR | TxEN |
---|---|---|---|---|---|---|---|
1 启动搜索字符 | 1 内部复位,使8251A回到方式选择格式 | 1使RTS!引脚输出低电平 | 1使错误标志PE,OE,FE均复位 | 1使TxD线变低,发送空白字符,0正常工作 | 1运行接收0禁止接收 | 1 使DTR!引脚输出低电平 | 1允许发送0禁止发送 |
看起来很复杂使用的时候只需要设置成0001 0101即可,即正常工作,使错误标志复位,允许发送和接收。
3.状态字
DSR | SYNDET/BRKDET | FE | OE | PE | TxE | RxRDY | TxRDY |
---|---|---|---|---|---|---|---|
数据装置准备好 | 同引脚含义 | 帧错误(只用于异步方式) | 溢出错误 | 奇偶错误 | 同引脚含义 | 同引脚含义 | 发送器准备好时为1 |
主要需要使用到的是RxRDY和TxRDY位,输入的时候需要检测RxRDY位是否为高电平如果是表示接受了数据,否则没有。输入的时候还可以对FE和OE进行判断接收到的数据是否正确。
同理输出的时候要检测TxRDY位是否为高电平如果是表示准备好了否则是没有准备好,准备好后才能输出。
对于8251进行编程
1.向控制口连续写入3个全0和再写入40h的目的是为了用软件使8251可靠地复位。
2.先写入方式字4Eh,表示使用一个停止位,无校验,字符长度为8,使用异步方式,波特率系数设置为16。
3.写入命令字15h,表示允许接收和发送数据,并且清除错误标志。
4.最后写入状态字,将RsRDY接收准备完成位清零,TxRDY发送准备完成位置1。
初始化完成之后通过8251输入数据时要读入状态字,判断状态字的第二位即RxRDY为是否为高电平,如果为高电平说明接收数据已经准备好可以输出了,否则继续检测。输出数据和输入输入类似。输入时要检测状态字的最低位即TxRDY位是否为1若为1表示已经准备好了,否则表示没有准备好。输入的时钟信号的设置要根据收发波特率和波特率系数决定。书上给出了公式:
收发时钟频率 = 收发波特率 × 波特率系数
收发波特率为1200,波特率系数为16,收发时钟频率TxC和RxC要设置为19.2KHz,时钟信号CLK的频率书上的介绍是对于异步方式,CLK的频率应该比TxC和RxC大4.5倍,因此CLK的频率至少为86.4KHz。波特率系数设置为1的时候不能正常接收,所以最后设置成16。
这里仿真了一个比较简单的,检测输入的为’a’或‘b’点亮响应的数码管,并将‘a’返回给串口助手。
效果输入’a’:
蓝线数据表示外界向8251发送的数据,红线表示8251接收的数据。
这里串口要设置的和虚拟串口中的相同,因为我虚拟串口中使用的COM2和COM3所以这里也这样使用,反过来使用是一样的。波特率可以选择其他的,这里我选择的1200,要注意对应就行了,还有时钟频率要根据公式设置。
DATAS SEGMENT
;此处输入数据段代码
IOYO equ 0C400h;对应的端口地址
MY8255_A equ IOYO+00H*4
MY8255_B equ IOYO+01H*4
MY8255_C equ IOYO+02H*4
MY8255_MODE equ IOYO+03H*4
MY8251_com equ 0C460h;控制字口
MY8251_data equ 0C440h;数据口,相比控制字口C/D为0
buf1 db 'Receive_a'
length_buf1 equ $-buf1
buf2 db 'Receive_b'
length_buf2 equ $-buf2
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
;此处输入代码段代码
Init:
mov dx,MY8255_mode;设置8255为输出方式
mov al,80h
out dx,al
mov al,00h
mov cx,03h
mov dx,MY8251_com
;写入三个全0和复位控制字的目的是使8251可靠地复位
Out_0:
out dx,al;先向控制口写入三个0
call Revtime
loop out_0;向8251A的控制端口写三个0
mov al,40h;向控制口写入复位字,使D6位等于0
out dx,al
call Revtime
;写入方式字
mov al,01001110B;01表示一个停止位,00表示无检验,11表示字符长度为8,10表示异步方式*16
out dx,al
call Revtime
;写入命令字
mov al,00010101B;允许接收发送数据,清除错误标志
out dx,al
call Revtime
;写入状态字
mov dx,MY8251_com
mov al,00010101B;
out dx,al;清除出错标志,允许发送
Repeating:
;call send
call receive
jmp repeating
Receive proc near
Wait_receive:
mov dx,MY8251_com
in al,dx
test al,02h
jz wait_receive
test al,30h;出错转向出错处理,帧错误和溢出错误
jnz error
mov dx,MY8251_data
in al,dx
mov dx,MY8255_A
out dx,al
cmp al,'a'
je light_a
cmp al,'b'
je light_b
jmp wait_receive
light_a:
mov dx,MY8255_A
mov al,01h
out dx,al
lea di,buf1
mov cx,length_buf1
call send
jmp wait_receive
light_b:
mov dx,MY8255_A
mov al,02h
out dx,al
lea di,buf2
mov cx,length_buf2
call send
jmp wait_receive
Error:
mov dx,MY8255_B
mov al,0ffh
out dx,al
mov dx,MY8251_com
mov al,00010101B;
out dx,al;清除出错标志,允许发送
jmp wait_receive
ret
receive endp
Send proc near
;写入状态字
mov dx,MY8251_com
mov al,00010101B;
out dx,al;清除出错标志,允许发送
Wait_send:
mov dx,MY8251_com
in al,dx
test al,01h;最后一位TxRDY是否为1,为1准备好,否则没有准备好
call Revtime
jz wait_send
mov dx,MY8251_data;发送数据时不用延时
mov al,[di]
out dx,al
inc di
loop Wait_send
ret
send endp
Revtime proc near
push cx
mov cx,02h
D0:
loop d0
pop cx
ret
revtime endp
MOV AH,4CH
INT 21H
CODES ENDS
END START
这里仿真有两个坑:
第一个是不能将波特率系数设置为1,否则接收检测会一直出错至少设置成16。
第二个是如果同时要输入和输出不能虚拟机中自带的Virtual Box检测,不然不能正常通信,单独输入或输出信号时可以使用。
只有单独输出信号的时候连接成:
注意是反接的。