0809的多通道采集
题目描述:1
利用0809设计一个多通道的数据采集卡,要求采样率为500HZ,用8253通道0查询的方式实现采样率的控制(8253A的通道0工作于方式2,当OUT输出变低时启动一次A/D转换,8253的CLK0输出为1MHZ。),采集1000个数据存入内存BUFFER开始的缓冲区。
首先进行计算:
500HZ的采样率,即2ms一次
又因为8253的CLK0的输入为1MHZ
因此1MHZ/500HZ = 2000
所以通道0的初值为2000
因此程序如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48STACK SEGMENT
DB 50 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,SS:STACK
START:
MOV DX,96H ;指向8253的控制口
MOV AL,00110101B ;通道0,先送低字节再送高字节,方式2,BCD码
OUT DX,AL ;初始化8253的通道0完成
MOV DX,90H ;给8253的通道0送初值2000
MOV AL,00H
OUT DX,AL
MOV AX,20H
OUT DX,AL ;8253的通道0初值赋值完毕
LEA DI,BUFFER ;DI指针指向BUFFER
MOV BX,03E8H ;给BX里存放1000
AGAIN PROC NEAR
MOV CX,0008H ;0809通道计数
MOV DX,80H ;DX指向0809的通道0
NEXT:
OUT DX,AL ;启动转换
PUSH DX ;保存当前0809通道地址
MOV DX,8AH ;指向EOC状态口
POLL:
IN AL,DX ;读EOC状态
TEST AL,01H ;测试EOC是否为0(启动开始没)
JNZ POLL ;EOC为1(不为0),继续检验
NO_END:
IN AL,DX ;EOC为0,启动后再次读EOC
TEST AL,01H ;检测EOC是否为0
JZ NO_END ;为0,表示转换未结束,继续等待
POP DX ;为1,转换结束,当前0809通道地址出栈
IN AL,DX ;读转换后数据
MOV [DI],AL ;将读取后的数据存放于DI所指向的地址单元
INC DX ;0809通道指向下一个
INC DI ;指针指向下一个地址单元
DEC BX ;BX减一,数据传输完毕1个
JZ OVER ;如果BX=0,则表示数据已经传输完毕,跳转到结束
LOOP NEXT ;如果BX不等于0,继续循环
JMP AHAIN ;BX不等于0,且一次8通道采集结束,则跳转到一下一个周期
HLT
OVER:
HLT
AGAIN ENDP
CODE ENDS
END START
0809的单通道采集
这题是上题的变种(我怎么感觉都差不多,就删了几句代码)
题目要求:(和上题一样,只是从多通道变成了单通道)1
利用0809设计一个单通道的数据采集卡,要求采样率为500HZ,用8253通道0查询的方式实现采样率的控制(8253A的通道0工作于方式2,当OUT输出变低时启动一次A/D转换,8253的CLK0输出为1MHZ。),采集1000个数据存入内存BUFFER开始的缓冲区。
计算我就不算了,还是上题一样的2000初值
我就默认只用INO这一个通道了
程序如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40CODE SEGMENT
ASSUME CS:CODE
START:
MOV DX,96H ;指向8253的控制口
MOV AL,00110101B ;通道0,先送低字节再送高字节,方式2,BCD码
OUT DX,AL ;初始化8253的通道0完成
MOV DX,90H ;给8253的通道0送初值2000
MOV AL,00H
OUT DX,AL
MOV AX,20H
OUT DX,AL ;8253的通道0初值赋值完毕
LEA DI,BUFFER ;DI指针指向BUFFER
MOV BX,03E8H ;给BX里存放1000
AGAIN PROC NEAR
MOV DX,80H ;DX指向0809的通道0
NEXT:
OUT DX,AL ;启动转换
MOV DX,8AH ;指向EOC状态口
POLL:
IN AL,DX ;读EOC状态
TEST AL,01H ;测试EOC是否为0(启动开始没)
JNZ POLL ;EOC为1(不为0),继续检验
NO_END:
IN AL,DX ;EOC为0,启动后再次读EOC
TEST AL,01H ;检测EOC是否为0
JZ NO_END ;为0,表示转换未结束,继续等待
MOV DX,80H ;指向0809的通道0
IN AL,DX ;读转换后数据
MOV [DI],AL ;将读取后的数据存放于DI所指向的地址单元
INC DI ;指针指向下一个地址单元
DEC BX ;BX减一,数据传输完毕1个
JZ OVER ;如果BX=0,则表示数据已经传输完毕,跳转到结束
JMP AHAIN ;BX不等于0,则跳转到下一次采集
HLT
OVER:
HLT
AGAIN ENDP
CODE ENDS
END START
0809的多通道采集(只循环采集一次)
当然鄙人认为,如果考到多通道,应该不会像第一个例子那样,我估计比较垃圾,不会用1000个数据的要求,只会让你跑一遍8通道即可
所以,又变种了一个题目
题目要求:(和第一题一样,只是从1000个数据变成了跑1遍8通道)1
利用0809设计一个多通道的数据采集卡,要求采样率为500HZ,用8253通道0查询的方式实现采样率的控制(8253A的通道0工作于方式2,当OUT输出变低时启动一次A/D转换,8253的CLK0输出为1MHZ。),8个通道轮流采集一次,并把数据存入内存BUFFER开始的缓冲区。
题目没改,计算不变,还是2000初值
程序如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47#make_COM#
; COM file is loaded at CS:0100h
ORG 100h
STACK SEGMENT
DB 50 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,SS:STACK
START:
MOV DX,96H ;指向8253的控制口
MOV AL,00110101B ;通道0,先送低字节再送高字节,方式2,BCD码
OUT DX,AL ;初始化8253的通道0完成
MOV DX,90H ;给8253的通道0送初值2000
MOV AL,00H
OUT DX,AL
MOV AX,20H
OUT DX,AL ;8253的通道0初值赋值完毕
LEA DI,BUFFER ;DI指针指向BUFFER
AGAIN PROC NEAR
MOV CX,0008H ;0809通道计数
MOV DX,80H ;DX指向0809的通道0
NEXT:
OUT DX,AL ;启动转换
PUSH DX ;保存当前0809通道地址
MOV DX,8AH ;指向EOC状态口
POLL:
IN AL,DX ;读EOC状态
TEST AL,01H ;测试EOC是否为0(启动开始没)
JNZ POLL ;EOC为1(不为0),继续检验
NO_END:
IN AL,DX ;EOC为0,启动后再次读EOC
TEST AL,01H ;检测EOC是否为0
JZ NO_END ;为0,表示转换未结束,继续等待
POP DX ;为1,转换结束,当前0809通道地址出栈
IN AL,DX ;读转换后数据
MOV [DI],AL ;将读取后的数据存放于DI所指向的地址单元
INC DX ;0809通道指向下一个
INC DI ;指针指向下一个地址单元
LOOP NEXT ;如果BX不等于0,继续循环
HLT
AGAIN ENDP
CODE ENDS
END START
0832延时产生梯形波(双缓冲)
0832地址F0H,F1H
延时20ms的梯形波
代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54CODE SEGMENT
ASSUME CS:CODE
START:
MOV DX,F0H ;指向0832的基地址
MOV AL,00H ;下限值
MOV BX,0FFH ;AL上升的时候是从0FF~下一次0FF这么多次,所以保持平衡的时候也要这么多次
MOV CX,16EAH ;为了延时20ms计的数
PING_LOW:
OUT DX,AL ;启动转换
INC DX ;双缓冲,另一个也启动转换
OUT DX,AL
MOV DX,F0H ;指回第一个转换点
INC BX ;增加一次BX
DELAYTIME: ;延时20ms
LOOP DELAYTIME
CMP BX,0FFH
JNZ PING_LOW ;BX没到0FF,继续保持平衡点
UP:
OUT DX,AL ;BX到OFF后,进行上升
INC DX ;双缓冲
OUT DX,AL
MOV DX,F0H
INC AL
MOV CX,16EAH
DELAYTIME:
LOOP DELAYTIME
CMP AL,0FFH ;AL是否达到最大值
JNZ UP
DEC AL ;最大值减1
MOV CX,16EAH
PING_HIGH:
OUT DX,AL
INC DX ;双缓冲
OUT DX,AL
MOV DX,F0H
INC BX
DELAYTIME:
LOOP DELAYTIME
CMP BX,0FFH
JNZ PING_HIGH
DOWN:
OUT DX,AL
INC DX
OUT DX,AL
MOV DX,F0H
DEC AL
MOV CX,16EAH
DELAYTIME:
LOOP DELAYTIME
CMP AL,00H ;AL是否达到最小值
JNZ DOWN
JMP START ;达到就进行新的周期
CODE ENDS
END START
0832延时产生矩形波(单缓冲)
写双缓冲有点麻烦,我就写单缓冲了
还有延时20ms我也不写了,直接CALL DELAYT好了……
程序如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23CODE SEGMENT
ASSUME CS:CODE
START:
MOV AL,0FFH
MOV BX,0FFH
MOV DX,F0H
HIGH:
OUT DX,AL
INC BX
CALL DELAY
CMP BX,0FFH
JNZ HIGH
MOV AL,00H
LOW:
OUT DX,AL
INC BX
CALL DELAY
CMP BX,0FFH
JNZ LOW
MOV AL,0FFH
JMP HIGH
CODE ENDS
END START
8251的发送数据
题目描述:1
某系统用8251A串行发送1000个位于数据段中BUFFER开始的内存单元中的数据,采用异步方式,1个起始位,8个数据位,奇校验,1个停止位,波特率因子为16,发送时钟频率为19200,该8251A的地址为3F0H,3F2H,已知延时宏DELAY_TIME为控制口的写恢复时间,问
1.8251的方式字和命令字各是什么?
2.发送1000个数据大约需要多长时间?
3.编写完整的发送程序实现所要求的任务
先是第一问,易得:方式字:01011110B;命令字:00010001B
然后是第二问:发送一个数据:1+8+1+1=11位
收发波特率=19200/16=1200位/秒
所以时间=11*1000/1200=9.167秒
最后是第三问编程
程序如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36CODE SEGMENT
ASSUME CS:CODE
START:
MOV DX,3F2H ;8251的控制口
MOV AL,00H ;送第一次00
OUT DX,AL
CALL DELAY_TIME
OUT DX,AL ;送第二次00
CALL DELAY_TIME
OUT DX,AL ;送第三次00
CALL DELAY_TIME
MOV AL,40H ;送内部复位命令字,使8251回到方式选择格式
OUT DX,AL
CALL DELAY_TIME
MOV AL,01011110B ;送方式字,一个停止位,奇校验,字符长度为8,异步方式x16
OUT DX,AL
CALL DELAY_TIME
MOV AL,00010001B ;送命令字,错误标志位复位,并且允许发送
OUT DX,AL
CALL DELAY_TIME
LEA DI,BUFFER ;DI指针指向BUFFER首地址
MOV CX,1000 ;计数器,1000个数据
NEXT_T:
IN AL,DX ;读状态字
TEST AL,01H ;测试TxRDY是否为1,即发送器是否准备好
JZ NEXT_T ;没准备好,继续循环
MOV DX,3F0H ;准备好,指向8251的数据口
MOV AL,[DI] ;从BUFFER里取出数据
OUT DX,AL ;发送数据
INC DI ;指针向下移
MOV DX,3F2H ;再指向8251控制口
LOOP NEXT_T ;循环1000次
HLT ;发送结束
CODE ENDS
END START
8251的接受数据
题目描述:1
某系统用8251A串行接收1000个位于数据段中BUFFER开始的内存单元中的数据,采用异步方式,1个起始位,7个数据位,奇校验位,1个停止位,波特率因子为16,波特率为2400,该8251A的地址为80H,81H,已知延时宏DELAY_TIME为控制口的写恢复时间,请编写完整的接收程序实现所要求的任务
和上一题差不多,不再赘述,直接上程序1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40CODE SEGMENT
ASSUME CS:CODE
START:
MOV DX,81H ;8251的控制口
MOV AL,00H ;送第一次00
OUT DX,AL
CALL DELAY_TIME
OUT DX,AL ;送第二次00
CALL DELAY_TIME
OUT DX,AL ;送第三次00
CALL DELAY_TIME
MOV AL,40H ;送内部复位命令字,使8251回到方式选择格式
OUT DX,AL
CALL DELAY_TIME
MOV AL,01011010B ;送方式字,一个停止位,奇校验,字符长度为8,异步方式x16
OUT DX,AL
CALL DELAY_TIME
MOV AL,00010100B ;送命令字,错误标志位复位,并且允许接收
OUT DX,AL
CALL DELAY_TIME
LEA DI,BUFFER ;DI指针指向BUFFER首地址
MOV CX,1000 ;计数器,1000个数据
NEXT_T:
IN AL,DX ;读状态字
TEST AL,02H ;测试RxRDY是否为1,即接收器是否准备好
JZ NEXT_T ;没准备好,继续循环
TEST AL,38H ;准备好,检查是否有错
JNZ ERROR ;有错,转出错处理程序
MOV DX,80H ;无错,指向8251的数据口
IN AL,DX ;接受数据
MOV [DI],AL ;从BUFFER里取出数据
INC DI ;指针向下移
MOV DX,81H ;再指向8251控制口
LOOP NEXT_T ;循环1000次
HLT ;接受结束
ERROR:
HLT
CODE ENDS
END START
8253延时跑马灯的反思
其实写一个延时跑马灯没有什么难度(软延时)
但是连上了8253后好像就变得困难一些了(大神不要喷我)
我今天反思了一下8253的方式0,2,3,分别思考了一下他们的延时
(为什么不思考别的
额,因为本渣觉得他不考~~2333333333)
方式0
方式0的延时比较麻烦,可以求出相应的初值,然后每次都需要重新初始化一次,检测电平,结束后进行跑马灯,然后再重新赋初值
方式2
方式2是可以用于跑马灯或者其他场合延时的,只需要检验OUT的低电平即可,每一次低电平,就是一次延时结束,可以对跑马灯进行左移或者右移。
下面是我随便写的一个基于方式2的延时跑马灯(8255+8253)
我就不写级联了,就写一个初值5000的……1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33CODE SEGMENT
ASSUMT CS:CODE
START:
MOV DX,8255_PORT_CTL
MOV AL,10010000B
OUT DX,AL
MOV AL,00000001B
MOV BL,AL
MOV AL,00100101B
MOV DX,8253_PORT_CTL
OUT DX,AL
MOV DX,8253_PORT_0
MOV AL,50H
OUT DX,AL
RUN:
MOV DX,8255_PORT_A
IN AL,DX
TEST AL,00000001B ;检查是不是低电平,即开始了没有
JNZ RUN ;不是低电平就等待
MOV AL,BL ;是低电平,则移位,让下一个灯亮
MOV DX,8255_PORT_B
OUT DX,AL
ROL AL,1
MOV BL,AL
OVER:
MOV DX,8255_PORT_A
IN AL,DX
TEST AL,00000001B ;检查是不是高电平,即延时结束了没有
JZ OVER ;不是高电平,则继续等待
JMP RUN ;延时结束,进行下一轮程序
CODE ENDS
END START
方式3
和上一个差不多,但是跑马灯程序位置不同1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32CODE SEGMENT
ASSUMT CS:CODE
START:
MOV DX,8255_PORT_CTL
MOV AL,10010000B
OUT DX,AL
MOV AL,00000001B
MOV BL,AL
MOV AL,00100101B
MOV DX,8253_PORT_CTL
OUT DX,AL
MOV DX,8253_PORT_0
MOV AL,50H
OUT DX,AL
RUN:
MOV DX,8255_PORT_A
IN AL,DX
TEST AL,00000001B ;检查是不是低电平,即开始了没有
JNZ RUN ;不是低电平就等待
OVER:
IN AL,DX
TEST AL,00000001B ;检查是不是高电平,即延时结束了没有
JZ OVER ;不是高电平,则继续等待
MOV AL,BL
MOV DX,8255_PORT_B
OUT DX,AL
ROL AL,1
MOV BL,AL
JMP RUN ;延时结束,进行下一轮程序
CODE ENDS
END START
原因分析
方式2大体上和方式3相差不大,但是,方式3产生的是方波,而方式2不是,所以不能用每次检测一个低电平,一个高电平后操作的方式,只能用检测低电平,然后控制8255的方法……大概就是这样,8253的方式问题,还是得看波形~(OUT的波形)
最后猜一个8253能考的题
单独拿来考的话:
1.要么是我之前说的跑马灯……不会的看上面
2.那就是LED灯一灭一亮的周期题了
这种题实在是简单无比……直接级联貌似就解决问题,如果周期小的话,就初始化一个就OK……书上有,不再赘述
8255键盘
8255可以说很常见了,可以单独考,可以和别的一起考
如果8255要单独命题,那么一定是键盘了
现在这个键盘考的也是骚,什么花式都有:
2X2,3X5,4X4……
真的是皮,不过万变不离其中:
总是B口高位是行,低位是列
A口管的就是行
检测有没有键按下,就往A口送0(因为B口共阳极,所以默认都是1)
所以一旦检测到B口的低位有0,就说明有按下的……
然后就是编码什么的了
我感觉懂了后键盘还是比较简单的
总的来说就这么几步:
1.8255初始化
2.检测有没有键按下
3.没有键按下,就开始等待键按下
4.有键按下后就消抖20ms
5.消抖后再检测有没有键按下
6.没有就跳回步骤3,有就进行编码比对
7.逐行给A口送0,检测B口低位,知道有0出现
8.和键盘table比对,比到之后即可。
后记
大概这篇文章算是写完了,陆陆续续,写了很久,今天6月25号了……离微机考试也不过1个星期了,祝我好运吧~~~233333