270 likes | 550 Views
6- 3 8051 的串行通讯端口的应用. 例 1. 利用串口方式 0 扩展并行 I/O. 75495 、 75497 是常用的串 / 并、并 / 串转换移位寄存器,利用这些芯片及 8051 的串行端口工作方式 0 ,可方便地扩展并行 I/O 接口. 75495 的原理图. 75497 的原理图. 8051 串行口扩展原理图. 波形图. 编程分析:
E N D
6-3 8051的串行通讯端口的应用 例1. 利用串口方式0扩展并行I/O 75495、75497是常用的串/并、并/串转换移位寄存器,利用这些芯片及8051的串行端口工作方式0,可方便地扩展并行I/O接口
编程分析: 对于高速I/O(如机床位置反馈信号、运动脉冲控制信号等),使用中断处理比较合适,但对于普通I/O(如按钮开关、急停开关、限位开关、继电器、电磁阀等), 并不需要很快的响应速度,反而需要进行滤波处理,对这些信号的处理,一般在主程序中定时扫描即可,扫描周期应≥ 5ms,一般不要超过100ms。 对于本例,对输入输出的读写,用串口中断程序来实现,对这些I/O的逻辑运算和处理,则放在主程序中进行。在I/O处理完成后,通过写SBUF来启动I/O的读写(仅写一次),I/O的刷新由串口不断产生中断来完成。 由于同步串行传输速度快, 也可以采用查询的方式来实现串行端口的读写。
开始 T2中断 初始化 标志定时1 高速处理程序 返回 N 标志定时=1? Y I/O处理程序 标志定时 0 启动I/O刷新 方案1: 利用定时器将主程序分为高速和低速处理2个节拍,利用中断实现I/O的读写,输入输出的刷新在同一节拍完成。程序简单,但响应有延时。
RI中断 TI中断 ASBUF TI 0 Y RAMA 发送完? N P1.0 Y 输入完? 发送数据 N P1.10 REN0 修改接收地址 修改发送地址 P1.0 RI0 RI0 返回 REN1 返回 返回 返回
高速处理程序 N 定时标志=1? T2中断 Y N REN=0? Y 标志定时1 I/O处理程序 P1.10 P1.0 开始 启动刷新OUT 设置地址 REN1 初始化 标志定时 0 返回 方案2: 利用定时器将主程序分为高速和低速处理2个节拍,利用中断实现I/O的读写,输入、输出的刷新分节拍完成。
RI中断 TI中断 ASBUF TI 0 Y RAMA 发送完? N Y 输入完? 发送数据 P1.0 N REN0 修改接收地址 修改发送地址 P1.10 RI0 RI0 返回 返回 返回 返回
开始 T2中断 初始化 标志定时1 高速处理程序 返回 N 标志定时=1? Y 标志定时 0 刷新INPUT I/O处理程序 刷新OUT 方案3: 利用定时器将主程序分为高速和低速处理2个节拍,用查询实现I/O的读写
接收 发送 P1.10 P1.0 P1.11 REN1 Y 发送完? N RI=1? 发送数据 P1.0 RAMASBUF REN0 修改发送地址 返回 Y 输入完? RI0 N TI=1? 修改接收地址 返回 Y RI0
编程: 设单片机晶振频率为12MHz,定时器T2定时时间为5ms,输入缓冲器地址为:20H~21H (X_byte0~1),接收地址寄存器addr_X (30h) , 接收计数器cnt_X(31h); 输出缓冲器地址为:22H~24H(y_byte0~2) ,发送地址寄存器addr_X (32h),发送计数器cnt_Y(33h); • 中断向量: • org 0000h • jmp main • org 0023h • jbc ti, TxD_I • jb ri, RxD_I ; 不能用jbc • reti • org 002bh • ;jmp int_T0 ; 方案2 • clr tf2 • setb T_5ms • reti T2中断程序(方案2): Int_T2: clr tf2 setb T_5ms mov addr_X, #X_byte1 mov cnt_X, #02H clr P1.1 clr p1.0 setb p1.0 reti
写输出子程序: TxD_P: CLR TI ;用jbc指令时可省略 SETB P1.1 ;选择输出 MOV R1, #02H MOV R0, # Y_byte2 ;送输出初始地址 TxD_P1: MOV A, @R0 ;读输出缓冲器 MOV SBUF , A ;发送 TxD_P2: JNB TI, TxD_P2 ;发送完1个字节? DEC R0 ;修改地址 DJNZ R1, TxD_P1 CLR P1.0 ;锁存输出 SETB P1.0 ;锁存输出 CLR P1.1 ;切换到输入 RET
读输入子程序: RxD_P: MOV R0, #X_byte1 ;送输入首地址 MOV R1, #02H ;设置输入个数 CLR P1.1 ;选择输入 CLR P1.0 ;锁存输入端口状态 SETB P1.0 SETB REN ;启动串口接收 RxD_P1: CLR RI RxD_P2: JNB RI, RxD_P2 ;接收完1个字节? MOV A, SBUF ;读输入端口 MOV @R0, A ;缓冲器输入端口状态 DEC R0 ;修改地址 DJNZ R1, RxD_P1 CLR REN ;停止读输入 CLR RI RET
写输出中断程序: TxD_I: CLR TI PUSH ACC ; PSW 00H MOV R0, addr_Y ;送输出地址 DJNZ cnt_Y, END_TI CLR P1.0 SETB P1.0 CLR P1.1 ;方案2无 CLR P1.0 ;方案2无 SETB REN ; 方案2无 POP 00H ; PSW ACC RETI END_TI: MOV A, @R0 ;读输出缓冲器 MOV SBUF , A ;发送 DEC addr_Y ;修改地址 POP 00H ; PSW ACC RETI
读输入中断程序: RxD_I: PUSH ACC ; PSW 00H MOV A, SBUF ;读输入端口 MOV R0, addr_X ;送输入地址 MOV @R0, A ;RAM输入端口状态 DEC addr_X ;修改地址 DJNZ cnt_X, END_RI CLR REN ;停止读输入 CLR RI END_RI: POP 00H ; PSW ACC CLR RI RET
主程序公共部分: main: mov rcap2h, #0ech mov rcap2l, #78h mov th2,#0ech mov tl2, #78h mov t2mod, #00h mov t2con, #04h ;自动装载方式并启动 mov addr_X, #X_byte1 mov cnt_X, #02h mov addr_Y, #Y_byte2 mov cnt_Y, #03h mov Y_byte0, #00h ; 当输出低电平有效时为0ffh mov Y_byte1, #00h ; 当输出低电平有效时为0ffh mov Y_byte2, #00h ; 当输出低电平有效时为0ffh call TxD_P call RxD_P mov ie, #1011xxxxb ; 开中断 Start: call fastP ; 处理高速要求程序
方案2主程序: jnb T_5ms, Start jb REN, start clr T_5ms call PLC_P mov addr_Y, #Y_byte1 mov cnt_Y, #02h mov a, Y_byte2 mov sbuf, a jmp start 方案1主程序: jnb T_5ms, Start clr T_5ms call PLC_P mov addr_X, #X_byte1 mov cnt_X, #02h mov addr_Y, #Y_byte1 mov cnt_Y, #02h mov a, Y_byte2 mov sbuf, a jmp start T2中断程序(方案2): Int_T2: clr tf2 setb T_5ms mov addr_X, #X_byte1 mov cnt_X, #02H clr P1.1 clr p1.0 setb p1.0 reti 方案3主程序: jnb T_5ms,Start clr T_5ms call RxD_P call PLC_P call TxD_P jmp start
读输入子程序: RxD_P: MOV R0, #X_byte1 ;送输入首地址 MOV R1, #02H ;设置输入个数 CLR P1.1 ;选择输入 CLR P1.0 ;锁存输入端口状态 SETB P1.0 setb p1.2 ;准备接收 RxD_P1: mov r2, #08h RxD_P2: mov c, p1.2 ;读入一位 rlc a clr p1.3 ;产生移位时钟 setb p1.3 ;产生移位时钟 djnz r2,RxD_P2 ;接收完一个字节? MOV @R0, A ;缓冲器输入端口状态 DEC R0 ;修改地址 DJNZ R1, RxD_P1 RET ; 132us (12MHz)
写输出子程序: TxD_P: SETB P1.1 ;选择输出 MOV R1, #02H MOV R0, # Y_byte2 ;送输出初始地址 TxD_P1: MOV A, @R0 ;读输出缓冲器 mov r2,#08h TxD_P2: rlc a mov p1.2, c clr p1.3 ;产生移位时钟 setb p1.3;产生移位时钟 djnz r2, TxD_P2 ;发送完1个字节? DEC R0 ;修改地址 DJNZ R1, TxD_P1 CLR P1.0 ;锁存输出 SETB P1.0 ;锁存输出 CLR P1.1 ;切换到输入,安全 RET ; 116us(12MHz)
P1.0 P1.1 8051 SDA SCL 24C256 A2 A1 A0 SDA SCL 24C256 A2 A1 A0 … … [ 1 1 1 ] [ 0 0 0 ] 例2 利用串口方式扩展数据存储器 由于串行通信(如I2C SPI)方式连线少,需要的芯片引脚少,可大大减小PCB板的面积,且芯片价格便宜,采用串行接口的芯片也越来越多(如串行EEPROM、D/A、A/D、温度传感芯片、实时日历时钟等),在单片机系统设计中的应用越来越广泛。 在一些8051系列单片机中,集成了串行接口,但也有一些单片机没有这些接口。由于单片机的I/O口可进行位操作,通过软件用普通I/O端口,很容易就可实现这些串行扩展,本例就以8051的P1口,和串行EEPROM 24C256为例,来说明这种扩展的设计方法。 24C256是一片32Kx8bit。具有3根地址选择线,最多可扩展8片。 24Cxx的内部有16~64byte的页面写缓冲器,每次写数据的个数不能超过页面的大小。也不能跨页面写。
I2wr: clr scl mov r3,#08h I2wr1: rlc a mov sda,c setb scl clr scl djnz r3,I2wr1 setb sda I2wlp0: mov c,sda ; 应答 jc I2wlp0 ; 应答? ret 从24C256的读写时序可以看出,写一个字节用的次数很频繁,用子程序来实现较好。
对EEPROM的读写,数据源应能覆盖所有内部RAM单元,用addr_D来存放数据源的起始地址,用num来存放需要写数据的个数,用addrL addrH来存放写入EEPROM的内部起始地址。 ; 数据源起始地址存放在addr_D单元,数据个数存放在=num ; adrH adrL存放目标起始地址。 w_rom: setb scl setb sda ; 停止 clr sda ; 起始 mov a,#0a0h ; 写命令字 call I2wr mov a,addrH call I2wr mov a,addrL call I2wr mov r0,addr_D mov r2,num wdl31: mov r2,num wdl3: mov r3,#08h mov a,@r0 wdl4: call I2wr inc r0 djnz r2,wdl3 clr sda setb scl ; 停止 setb sda ; 停止 ret
rdl1: mov r3,#08h setb sda rdl2: setb scl mov c,sda rlc a clr scl djnz r3,rdl2 mov @r0,a inc r0 djnz r2,rdl3 clr sda setb scl ; 停止 setb sda ; 停止 ret rdl3: clr sda ; byte end setb scl ; byte end clr scl ; byte end jmp rdl1 R_rom: setb scl setb sda ;停止 clr sda ;起始 mov a,#0a0h call I2wr mov a,adrH call I2wr mov a,adrL call I2wr setb sda setb scl clr sda ; 起始 mov a,#0a1h ; 写读命令 call I2wr mov r0,addr_D mov r2,num