📄 ex8-7.asm
字号:
$include (STC12C5A.inc) ;包含STC12C5410AD寄存器定义文件
;定义常量,根据MASTER_SLAVE的值,选择下载不同的程序
MASTER_SLAVE EQU 0 ;汇编后的程序代码下载到主单片机中
;MASTER_SLAVE EQU 1 ;汇编后的程序代码下载到从单片机#1中
;MASTER_SLAVE EQU 2 ;汇编后的程序代码下载到从单片机#2中
;定义变量
Slave1_SS EQU P5.1
Slave2_SS EQU P5.2
Flags EQU 20H
SPI_Receive EQU Flags.0 ;SPI 端口收到数据标志位
T0_10MS EQU 30H ;该变量用于保存 10 毫秒计数(T0 中断次数)
SPI_buffer EQU 31H ;该变量用于保存 SPI 端口收到的数据
ORG 0000H
LJMP MAIN
ORG 000BH ;定时器0 中断服务程序入口
LJMP T0_ISR
ORG 004BH ;SPI中断服务程序入口
LJMP SPI_ISR
ORG 0060H
MAIN:
MOV SP, #70H ;设置堆栈指针
;------------ 初始化串口和定时器0------------------------------
MOV SCON, #50H ;0101,0000 8位可变波特率, 无奇偶校验
MOV TMOD, #21H ;T1为自动重装模式,T0为16位定时器模式
MOV TH0, #0C4H
MOV TL0, #00H ;重装数 = 65536-15360 = 50176 = C400H
;晶振频率=18.432MHz时,每10mS中断1次
MOV TH1, #0F6H
MOV TL1, #0F6H
ORL AUXR, #01000000B ;T1 以 1T 的速度计数,是普通8051的12倍
;即波特率 = 4800*12=57600
SETB TR1 ;启动定时器1 开始计数
SETB TR0 ;启动T0
SETB ET0 ;开T0中断
;----------------初始化SPI--------------------------------
IF MASTER_SLAVE == 0 ;主机SPI控制字设置
MOV SPCTL,#11111100B ;0FCH, 忽略 脚, 设为主机
;SSIG=1: 忽略 脚;SPEN=1:允许SPI工作
;DORD=1:先传低位LSB;MSTR=1:设为主机
;CPOL=1:SPI 空闲时SCLK=1,前跳变沿是下降沿,后跳变沿是上升沿。
;CPHA=1:数据由SCLK前跳变沿驱动到SPI口线,SPI模块在后跳变沿采样
;SPR1,SPR0=00:主模式时SPI时钟源选择为fosc/4
ELSE ;从机SPI控制字设置
MOV SPCTL,#01101100B ;6CH, 设为从机, 由 脚决定是否已被选中
;SSIG=0: 由 脚决定主模式或从模式;SPEN=1:允许 SPI 工作
;DORD=1:先传低位 LSB;MSTR=0:设为从机
;CPOL=1:SPI 空闲时 SCLK=1,前跳变沿是下降沿,后跳变沿是上升沿。
;CPHA=1:数据由SCLK前跳变沿驱动到SPI口线,SPI模块在后跳变沿采样
;SPR1,SPR0 = 00:主模式时 SPI 时钟源选择为 fosc/4
ENDIF
MOV SPSTAT,#11000000B ;清0标志位SPIF和WCOL
ORL IE2, #00000010B ;令ESPI(IE2.1)=1,允许SPIF产生中断
MOV Flags, #0 ;清标志字
SETB EA ;开总中断
MOV T0_10MS,#200 ;T0中断计数(10ms×200=2秒)
IF MASTER_SLAVE == 0
CLR Slave1_SS ;选择从单片机 #1 为当前的从单片机
Check_RS232:
JNB RI, Check_SPI ;判断RS-232串口中收到数据否
MOV A, SBUF ;取RS-232串口中收到的数据累加器A
CLR RI
;主单片机将累加器 A 中的数据发送到从机SPI
ANL IE2,#0FDH ;令ESPI(IE2.1)=0,禁止SPIF产生中断
MOV SPDAT, A ;SPI 发送数据
SPI_Wait:
MOV A, SPSTAT ;等待SPIF=1, 即等待SPI发送完毕
ANL A, #80H
JZ SPI_Wait
ORL IE2, #00000010B ;令ESPI(IE2.1)=1,允许SPIF产生中断
LJMP Check_RS232
Check_SPI:
JNB SPI_Receive, Check_RS232 ;判是否收到从机SPI发回数据
;主单片机SPI端口收到新的数据
MOV A, SPI_buffer ;将"从机SPI发回的数据"送到累加器A
CLR SPI_Receive ;清0主单片机SPI端口收到数据标志位
;将累加器 A 中的数据发送到计算机
CLR TI ;清零串口发送中断标志
MOV SBUF, A
RS232_Wait:
JNB TI, RS232_Wait ;等待发送完毕
CLR TI ;清零串口发送中断标志
LJMP Check_RS232
ELSE
Slave_Check_SPI:
JNB SPI_Receive, Slave_Check_SPI ;判收到主 SPI 发回的数据否
;从单片机SPI端口收到新的数据
MOV A, SPI_buffer ;取 "主单片机 SPI 端口发的数据"
CLR SPI_Receive ;清0 从单片机 SPI 端口收到数据标志位
IF MASTER_SLAVE == 2
ADD A, #1 ;如果是从单片机 #2,就把收到的数据加1
ENDIF
MOV SPDAT, A ;将收到数据送 SPDAT, 准备下一次通讯时发回
SJMP Slave_Check_SPI
ENDIF
;-------------- T0中断服务程序 --------------------------------
IF MASTER_SLAVE == 0
T0_ISR:
PUSH PSW ;保存断点现场
PUSH ACC
MOV TH0, #0C4H ;重装时间常数
MOV TL0, #00H
DJNZ T0_10MS,T0_Exit
MOV T0_10MS,#200 ;恢复T0中断计数值
CPL Slave1_SS ;改变当前选择的从单片机
CPL Slave2_SS
T0_Exit:
POP ACC ;恢复断点现场
POP PSW
RETI
ELSE ;从机程序不需要定时器T0
T0_ISR:
RETI
ENDIF
;---------------- SPI中断服务程序 -------------------------------
SPI_ISR: ;SPI中断服务程序
MOV SPSTAT, #11000000B ;0C0H, 清0标志位SPIF和WCOL
MOV A, SPDAT ;保存收到的数据
MOV SPI_buffer, A
SETB SPI_Receive ;设置SPI 端口收到数据标志
RETI
;-----------------------------------------------------------
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -