AT89S52之串行异步通信笔记
SRF
中断入口地址
- 中断源
- 外中断
- 外部中断0 INT0(P3.2)
- 外部中断1 INT1(P3.3)
- 电平方式触发
- 低电平
- 脉冲方式触发
- 脉冲后延的负跳
- 内中断
- 定时中断
- 串行中断
- 外中断
中断允许控制寄存器
- EA中断允许总控制位
- ES串行中断允许控制位
- ET2、ET1、ET0、EX1、EX0
- AT89S52有两个定时/计数器T1,T2
- T1,T2各有四种工作方式
定时器/计数器工作方式寄存器TMOD
- 工作方式
顾 12M的晶振对于一个正道周期为1/12us ,一个机器周期为1us
方式1位16位寄存器,顾最大65536个数 从0-65535-0变化
所以,你要想定时1us,因为它溢出中断,所以FF FF 执行完+1 后溢出 置位TF0 并 触发中断 定时器恢复为0
定时器/计数器控制寄存器TCON
-
溢出TF:查询方式,软件清零;中断方式,硬件自动清零。
-
允许TR:启动停止
串行控制口寄存器SCON
- 串行口工作方式
- REN控制是否允许接受。当REN=1时,允许接收,当REN=0
- 方式0,8位移位寄存器方式,典型应用串口驱动数码管
- 方式1,10位异步通信方式,通信的帧格式为1个起始位0,8个数据位,最后是停止位1
- 方式2,11位方式,通信的帧格式为1个起始位0,9个数据位,第九位作为奇偶校验位或者多机通讯是的地址数据标识位,最后是停止位1,共11个二进制位。
串行口工作方式选择:
电源控制寄存器PCON
- 波特率加倍
定时器T1的溢出率:
定时器T1的波特率的计算公式:
- 串行口传输方式为方式0和方式2的波特率不灵活:
- 串行口传输方式为方式1或者方式3时的波特率灵活,其计算公式:
常用波特率:
汇编使用定时器1工作在方式1【10位数据帧格式】(无奇偶校验位)发送接受(双向,允许接受,REN=1),配置波特率为9600bit/s,
①设置定时器1工作方式2:
MOV TMOD, #20H ;M1,M2为10,T1为定时方式2
②设置定时器1的初始值:
MOV TL1, #0FDH ;TL1为8位定时/计数
MOV TH1, #0FDH ;TH1为自动装载的初值,波特率为9600bit/s
②启动定时器1工作(TCON):
SETB TR1 ;启动定时器
④设置串行口工作方式:
MOV SCON, #50H ;串行口工作在方式1
⑥设置波特串加倍位为不加倍
SMOD:MOV PCON,#00H
⑥开中断开关IE:
SETB ES;
SETB EA;
实验现象
未发送完SBUF里的数据时,SCON 寄存器里TI位为0
当发送完SBUF里的数据时,SCON 寄存器里TI位由硬件自动置1,并进入中断
注意事项:
当确认程序配置的波特率无误,但是利用串口调试助手接受到数据和实际单片机发送的数据不吻合时可按下面检查
- 查看芯片的晶振,检查配置的波特率是否误差较大(>1%),利用单片机小精灵查看
- 查看自己使用的串口调试助手的跳线帽,STC89C52单片机输出的串口信号是0-3.3V电平,跳线帽应短接3.3端而不是5V端。
- 当下载完程序后应先进行复位操作再进行串口调试,查看数据。
AT89S52之汇编实现串行通信-只发送数据
;中断方式,硬件自动清除定时器1中断,即清除TF1标志位
;数据从TXD端输出,当数据写入发送缓冲器SBUF后,启动发送器发送。当发送完一帧数据后,置中断标志TI为1。T1为串行控制寄存器里的
/**
**AT89S52之汇编实现串行通信-只发送数据
**备注:波特率为4800bit/s,波特率误差为0.16%,采用定时器1工作在方式2(自动装载初值),采用串口传输方式1(10位数据帧格式)
*/
ORG 0000H
LJMP MAIN
ORG 001BH;定时器1中断
LJMP IT1P
ORG 0023H;串行传输中断
LJMP SEND
ORG 0100H
MAIN:
MOV TMOD, #20H ;M1,M2为10,T1为定时方式2
MOV TL1, #0F3H ;TL1为8位定时/计数
MOV TH1, #0F3H ;TH1为自动装载的初值,波特率为4800bit/s
MOV SCON,#50H ;串口工作方式1 10位数据格式
;SETB ET1 ;允许定时器1中断,有病吧,你开TM定时器1中断干哈????
SETB EA ;允许总中断
SETB ES ;允许串行传输中断ES,传输完成触发中断
MOV PCON,#80H;波特率加倍,减小波特率误差 0.16%
SETB TR1 ;启动定时器
LOOP:MOV A,#99H
MOV SBUF,A
CONT:
INC DPTR
LJMP $
//WAIT:JBC TI,CONT ;判断发送结束否,必须要有个等待发送完毕的过程,发送完毕才能进行下一次的发送
//SJMP WAIT
IT1P:
INC DPTR
RETI ;中断服务程序的返回必须用RETI,用RET则CPU不会清除中断,造成下次无法进入中断
SEND:
CLR TI;TI的位地址是99H,存在于字节地址为98H的SCON第二位里
MOV A,#66H
MOV SBUF,A
RETI
END
2018-12-2日更新 汇编实现数据收发
;中断方式,硬件自动清除定时器1中断,即清除TF1标志位
;数据从TXD端输出,当数据写入发送缓冲器SBUF后,启动发送器发送。当发送完一帧数据后,置中断标志TI为1。T1为串行控制寄存器里的
/**
**AT89S52之汇编实现串行通信-只发送数据
**备注:波特率为4800bit/s,波特率误差为0.16%,采用定时器1工作在方式2(自动装载初值),采用串口传输方式1(10位数据帧格式)
*/
//定时延迟之类的必须大于一个机器周期
;=================================================================================================================
ORG 0000H
LJMP MAIN
ORG 000BH ;定时器0中断
LJMP Timer0Interrupt
ORG 001BH ;定时器1中断
LJMP Timer1Interrupt
ORG 0023H ;串行传输中断
LJMP UARTInterrupt
ORG 0100H
MOV SP,#60H
;=================================================================================================================
;=================================================================================================================
MAIN:
LCALL InitTimer0 ;定时器0初始化
LCALL InitUART ;串口初始化
MOV A,#99H
MOV SBUF,A
CONT:
INC DPTR
LJMP $
;=================================================================================================================
;定时器0中断服务函数
Timer0Interrupt:;定时器中断里赋定时初值,其定时是时间不能小于本中断里所以程序语句执行时间,否则定时器会一直中断????;或者最后清除中断,但是一定要清除,否则会一直进入中断,无法执行其他程序和进入其他中断
PUSH DPH
PUSH DPL
PUSH ACC
MOV TH0,#00H ;
MOV TL0,#01H
;========================
CPL P2.7
//延迟1s
MOV R2,#01H
LCALL DELAY1S
;========================
POP ACC
POP DPL
POP DPH
CLR TF0
RETI
;=================================================================================================================
;定时器1中断服务函数
Timer1Interrupt:
PUSH DPH
PUSH DPL
PUSH ACC
MOV TH0,#0FFH
MOV TL0,#0FFH
;========================
;add your code here!
;========================
POP ACC
POP DPL
POP DPH
CLR TF1
RETI
UARTInterrupt:
JB RI,IsUART_Receive ;RI为1则转移
CLR TI ;TI的位地址是99H,存在于字节地址为98H的SCON第二位里
CPL P2.6
MOV R2,#01H
LCALL DELAY1S
MOV A,#99H
MOV SBUF,A
RETI ;中断服务程序的返回必须用RETI,用RET则CPU不会清除中断,造成下次无法进入中断
;=================================================================================================================
InitTimer0:
MOV TMOD,#01H ;工作方式1,16位计数器
MOV TH0,#00H
MOV TL0,#01H
SETB ET0 ;开定时器T0中断
SETB EA ;开总中断
SETB TR0 ;启动定时器
RET
;=================================================================================================================
/*
InitTimer1:
MOV TMOD,#20H ;M1,M2为10,T1为定时方式2
MOV TL1, #0F3H ;TL1为8位定时/计数
MOV TH1, #0F3H ;TH1为自动装载的初值,波特率为4800bit/s
MOV SCON,#50H ;串口工作方式1 10位数据格式
MOV TMOD,#01H
MOV TH0,#0FFH
MOV TL0,#0FFH
SETB EA ;开总中断
SETB ET0 ;开定时器T0中断
SETB TR0 ;启动定时器
RET
*/
;=================================================================================================================
InitUART:
MOV TMOD,#20H ;M1,M2为10,T1为定时方式2
MOV TL1, #0F3H ;TL1为8位定时/计数
MOV TH1, #0F3H ;TH1为自动装载的初值,波特率为4800bit/s
MOV SCON,#50H ;串口工作方式1 10位数据格式
;SETB ET1 ;关定时器1中断,定时器1会自动装载初值,无需中断
SETB EA ;开总中断
SETB ES ;开串行传输中断ES,传输完成触发中断
MOV PCON,#80H ;波特率加倍,波特率误差为 0.16%
SETB TR1 ;启动定时器
RET
;=================================================================================================================
IsUART_Receive: ;发送中断里先查询是否接受
CLR RI
PUSH ACC
MOV A,SBUF
;========================
CPL P2.0
MOV R2,#01H
LCALL DELAY1S
;========================
POP ACC
RETI
DELAY1S: ;误差 0us
START:
MOV R7,#38H
DL1:
MOV R6,#0E2H
DL0:
MOV R5,#26H
DJNZ R5,$
DJNZ R6,DL0
DJNZ R7,DL1
NOP
DJNZ R2,START
RET
END