对于不带spi串行总线接口的mcs51系列单片机来说,可以使用软件来模拟spi的操作,包括串行时钟、数据输入和数据输出。对于不同的串行接口外围芯片,它们的时钟时序是不同的。对于在sck的上升沿输入(接收)数据和在下降沿输出(发送)数据的器件,一般应将其串行时钟输出口p1.1的初始状态设置为1,而在允许接口后再置p1.1为0。这样,mcu在输出1位sck时钟的同时,将使接口芯片串行左移,从而输出1位数据至mcs51单片机的p1.3口(模拟mcu的miso线),此后再置p1.1为1,使mcs51系列单片机从p1.0(模拟mcu的mosi线)输出1位数据(先为高位)至串行接口芯片。至此,模拟1位数据输入输出便宣告完成。此后再置p1.1为0,模拟下1位数据的输入输出……,依此循环8次,即可完成1次通过spi总线传输8位数据的操作。对于在sck的下降沿输入数据和上升沿输出数据的器件,则应取串行时钟输出的初始状态为0,即在接口芯片允许时,先置p1.1为1,以便外围接口芯片输出1位数据(mcu接收1位数据),之后再置时钟为0,使外围接口芯片接收1位数据(mcu发送1位数据),从而完成1位数据的传送。
图2所示为mcs51系列单片机与存储器x25f008(e2prom)的硬件连接图,图2中,p1.0模拟mcu的数据输出端(mosi),p1.1模拟spi的sck输出端,p1.2模拟spi的从机选择端,p1.3模拟spi的数据输入端(miso)。下面介绍用mcs51单片机的汇编语言模拟spi串行输入、串行输出和串行输入/输出的3个子程序,实际上,这些子程序也适用于在串行时钟的上升沿输入和下降沿输出的其它各种串行外围接口芯片(如a/d转换芯片、网络控制器芯片、led显示驱动芯片等)。对于下降沿输入、上升沿输出的各种串行外围接口芯片,只要改变p1.1的输出电平顺序,即先置p1.1为低电平,之后再次置p1.1为高电平,再置p1.1为低电平……,则这些子程序也同样适用。
3.1 mcu串行输入子程序spiin
从x25f008的spiso线上接收8位数据并放入寄存器r0中的应用子程序如下:
spiin:setb p1.1 ;使p1.1(时钟)输出为1
clr p1.2 ;选择从机
mov r1,#08h ;置循环次数
spiin1:clr p1.1 ;使p1.1(时钟)输出为0
nop ;延时
nop
mov c,p1.3 ;从机输出spiso送进位c
rlc a ;左移至累加器acc
setb p1.1 ;使p1.0(时钟)输出为1
djnz r1,spiin1 ;判断是否循环8次(8位数据)
mov r0,a ;8位数据送r0
ret
3.2 mcu串行输出子程序spiout
将mcs51单片机中r0寄存器的内容传送到x25f008的spisi线上的程序如下:
spiout:setb p1.1 ;使p1.1(时钟)输出为1
clr p1.2 ;选择从机
mov r1,#08h ;置循环次数
mov a,r0 ;8位数据送累加器acc
spiout1:clr p1.1 ;使p1.1(时钟)输出为0
nop ;延时
nop
rlc a ;左移至累加器acc最高位至c
mov p1.0,c ;进位c送从机输入spisi线上
setb p1.1 ;使p1.1(时钟)输出为1
djnz r1,spiout1 ;判是否循环8次(8位数据)
ret
3.3 mcu串行输入/输出子程序spiio
将mcs51单片机r0寄存器的内容传送到x25f008的spisi中,同时从x25f008的spiso接收8位数据的程序如下:
spiio:setb p1.1 ;使p1.1(时钟)输出为1
clr p1.2 ;选择从机
mov r1,#08h ;置循环次数
mov a,r0 ;8位数据送累加器acc
spiio1:clr p1.1 ;使p1.1(时钟)输出为0
nop ;延时
nop
mov c,p1.3 ;从机输出spiso送进位c
rlc a ;左移至累加器acc最高位至c
mov p1.0,c ;进位c送从机输入
setb p1.1 ;使p1.1(时钟)输出为1
djnz r1,spiio1 ;判断是否循环8次(8位数据)
ret