我正在尝试让 2 个 MCU 使用单向 SPI 进行通信,即主设备发送到从设备。在我测试 BF 标志设置的点写入输出缓冲区后,主代码似乎被阻止。
我使用 2 个 PIC16F1503 MCU,其中一个配置为主机,另一个配置为从机。 电路如下图所示。
除了 MSSP 模块细节之外,两个处理器的配置相同
Master 的 SPI 配置为
SPI_init:
clrf INTCON ; Disable all interrupts
banksel TRISC
; set alternative SDO pin
banksel APFCON
bsf APFCON, APFCON_SDOSEL_POSN ; SDO function is on RA4
; complete the rest of SPI setup but don't enable just yet
banksel SSP1STAT
movlw 01000000B
;0------- SMP input data sampled at end of data o/p time
;-1------ CKE xmit occurs on transition from active to idle clock
;--xxxxxx I2C only
movwf SSP1STAT
; set SDO function to alternative RA4 pin
banksel APFCON
bsf APFCON, APFCON_SDOSEL_POSN ; SDO function is on RA4
; set the SPI mode and clock speed
movlw 00110010B
;0------- WCOL write collision bit - no collision
;-0------ SSPOV receive overflow indicator bit - no OF
;--1----- SPEN enable synchronous serial port
;---1---- CKP clock polarity, idle state for clock is high
;----0010 SPI Master mode, Fosc/64
movwf SSP1CON1
; set SS high
banksel LATC
bsf LATC, LATC_LATC3_POSN
call stabilisationWait
return
从机的 SPI 配置是
SPI_init:
clrf INTCON ; Disable all interrupts
banksel TRISC
; set alternative SDO pin, even though we won't be sending any data
banksel APFCON
bsf APFCON, APFCON_SDOSEL_POSN ; SDO function is on RA4
; complete the rest of SPI setup but don't enable just yet
banksel SSP1STAT
movlw 01000000B
;0------- SMP input data sampled at end of data o/p time
;-1------ CKE xmit occurs on transition from active to idle clock
;--xxxxxx I2C only
movwf SSP1STAT
; set SDO function to alternative RA4 pin
banksel APFCON
bsf APFCON, APFCON_SDOSEL_POSN ; SDO function is on RA4
movlw 00110001B
;0------- WCOL write collision bit - no collision
;-0------ SSPOV receive overflow indicator bit - no OF
;--0----- SPEN disable synchronous serial port
;---1---- CKP clock polarity, idle state for clock is high
;----0100 SPI Slave mode, SS enabled
movwf SSP1CON1
; now wait for the SS line to go high, meaning SPI master is ready
banksel PORTC
btfss PORTC, PORTC_RC3_POSN
goto $-1
; now enable SPI
banksel SSP1CON1
bsf SSP1CON1, SSP1CON1_SSPEN_POSN ; enable SPI
call stabilisationWait
return
在主设备中有一个循环,我将一个字节写入 SPI,如下所示。
loop:
movlw 2
call flashLED
call SPI_write
call delay5s
goto loop
SPI_write:
movlw 10101010B
; pull SS low
; banksel LATC
; bcf LATC, LATC_LATC3_POSN
; write the value to SPI transmit buffer
banksel SSP1BUF
movwf SSP1BUF
; wait till BF flag goes high
banksel SSP1STAT
btfss SSP1STAT, SSP1STAT_BF_POSN
goto $-1
; clear the BF flag by reading SSP1BUF
banksel SSP1BUF
movf SSP1BUF, w
; set SS high
; banksel LATC
; bsf LATC, LATC_LATC3_POSN
return
当我运行此程序时,LED 闪烁两次(符合预期),然后程序“挂起”。唯一的阻塞代码是等待 BF 标志变高。
您还会从注释的代码中注意到,我不清楚是否需要显式地操作SS线,或者这是否是由MSSP模块完成的(我怀疑是后者) - 我已经尝试了带/不带的代码SS线设置,问题依然存在。
由于 SPI 没有明确的 ACK,我相信 Slave 代码可能不相关,但是,Slave 中的处理循环在这里供参考。
loop:
; wait for buffer full flag
movlw 1
call flashLED
btfss SSP1STAT, SSP1STAT_BF_POSN
goto $-1
; read the value from the receive buffer
banksel SSP1BUF
movf SSP1BUF, w
movwf bufferValue
goto loop
FWIW,我已成功将 PIC16F1503 配置为驱动 DAC (MCP4091) 的主设备 - 这是单向交互,效果很好。但是,它是用 C 语言编写的,当我将其“翻译”为 ASM 时,它不再起作用。我认为如果我“拥有”主组件和服务器组件,调试会更容易,这就是我将此配置放在一起的原因。
此外,延迟例程工作正常。我已经使用它们很多年了,没有任何问题。
希望有人能够发现我哪里出错了。
根据数据表的以下部分:
数据发送/接收期间对 SSPxBUF 寄存器的任何写入都将被忽略,并且 SSPxCON1 寄存器的写冲突检测位 WCOL 将被置 1。用户软件必须清零 WCOL 位才能成功完成以下对 SSPxBUF 寄存器的写入。
所以在忙等待接收之前,必须确保数据已发送,这样才能得到从机的响应。如果您想在 CPU 忙于等待 BF 标志之前知道移位寄存器是否可用于传输,则需要添加更多代码。
这是 SPI_write 函数的稍微修改版本:
spi1_write:
; wait till transmit buffer to be available if needed
banksel SSP1STAT ; Make sure you are in the SSP registers bank
btfss SSP1STAT, SSP1STAT_BF_POSN ; Make sure there is nothing received in the buffer
goto spi1_send ; Buffer is available for transmission
movf SSP1BUF, W ; There is a received data waiting for handling
movwf ssp1_rx_data ; <- should declare this variable. store the data if needed
spi1_send:
bcf SSP1CON1, SSP1CON1_WCOL_POSN ; Clear the write collision flag before writing to the buffer
movwf SSP1BUF ; Write the data first
btfsc SSP1CON1, SSP1CON1_WCOL_POSN ; Then check whether a write collision has occured
goto spi1_write ; The shift register is still busy, keep checking until the data has been sent
; Now that the data has sent successfully, wait till BF flag goes high
spi1_wait_response:
btfss SSP1STAT, SSP1STAT_BF_POSN
goto spi1_wait_response
; clear the BF flag by reading SSP1BUF
banksel SSP1BUF
movf SSP1BUF, w
return
尝试一下代码,看看是否对您有帮助。
然而,另一方面,delay5s 电话对我来说看起来很可疑。你测试过这个功能吗?也许程序流程挂在那个延迟函数中?