我使用的是带有MPLABX/MCC的PIC18f46k42微控制器XC8 2.3。我的目标是使用单个SPI硬件外设与多个设备接口,使用各种GPIO引脚作为芯片选择。我有一个LCD和一个SD卡,它们都需要与MCU通话(obv不同时(。我的问题是当我试图更改SPI硬件配置寄存器以在设备之间切换时。所以我试着减少这个问题,并得出了这个结论:
如果我只使用一个spi配置来驱动屏幕,它就可以工作了。但是,如果我试图关闭那个spi连接,然后重新打开同一个spi连接时,屏幕就不起作用了。我认为问题在于mcc生成的SPI1_Open((。
spi1.h:
#ifndef SPI1_MASTER_H
#define SPI1_MASTER_H
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
/* SPI interfaces */
typedef enum {
SPI1_DEFAULT
} spi1_modes_t;
void SPI1_Initialize(void);
bool SPI1_Open(spi1_modes_t spi1UniqueConfiguration);
void SPI1_Close(void);
uint8_t SPI1_ExchangeByte(uint8_t data);
void SPI1_ExchangeBlock(void *block, size_t blockSize);
void SPI1_WriteBlock(void *block, size_t blockSize);
void SPI1_ReadBlock(void *block, size_t blockSize);
void SPI1_WriteByte(uint8_t byte);
uint8_t SPI1_ReadByte(void);
#endif //SPI1_H
spi1.c:
#include "spi1.h"
#include <xc.h>
typedef struct {
uint8_t con0;
uint8_t con1;
uint8_t con2;
uint8_t baud;
uint8_t operation;
} spi1_configuration_t;
//con0 == SPIxCON0, con1 == SPIxCON1, con2 == SPIxCON2, baud == SPIxBAUD, operation == Master/Slave
static const spi1_configuration_t spi1_configuration[] = {
{ 0x3, 0x60, 0x2, 0x3, 0 }
};
void SPI1_Initialize(void)
{
//EN disabled; LSBF MSb first; MST bus master; BMODE every byte;
SPI1CON0 = 0x03;
//SMP Middle; CKE Active to idle; CKP Idle:High, Active:Low; FST disabled; SSP active high; SDIP active high; SDOP active high;
SPI1CON1 = 0x60;
//SSET disabled; TXR required for a transfer; RXR data is not stored in the FIFO;
SPI1CON2 = 0x02;
//CLKSEL FOSC;
SPI1CLK = 0x00;
//BAUD 3;
SPI1BAUD = 0x03;
TRISCbits.TRISC1 = 0;
}
bool SPI1_Open(spi1_modes_t spi1UniqueConfiguration)
{
if(!SPI1CON0bits.EN)
{
SPI1CON0 = spi1_configuration[spi1UniqueConfiguration].con0;
SPI1CON1 = spi1_configuration[spi1UniqueConfiguration].con1;
SPI1CON2 = spi1_configuration[spi1UniqueConfiguration].con2 | (_SPI1CON2_SPI1RXR_MASK | _SPI1CON2_SPI1TXR_MASK);
SPI1CLK = 0x00;
SPI1BAUD = spi1_configuration[spi1UniqueConfiguration].baud;
TRISCbits.TRISC1 = spi1_configuration[spi1UniqueConfiguration].operation;
SPI1CON0bits.EN = 1;
return true;
}
return false;
}
void SPI1_Close(void)
{
SPI1CON0bits.EN = 0;
}
uint8_t SPI1_ExchangeByte(uint8_t data)
{
SPI1TCNTL = 1;
SPI1TXB = data;
while(!PIR2bits.SPI1RXIF);
return SPI1RXB;
}
void SPI1_ExchangeBlock(void *block, size_t blockSize)
{
uint8_t *data = block;
while(blockSize--)
{
SPI1TCNTL = 1;
SPI1TXB = *data;
while(!PIR2bits.SPI1RXIF);
*data++ = SPI1RXB;
}
}
// Half Duplex SPI Functions
void SPI1_WriteBlock(void *block, size_t blockSize)
{
uint8_t *data = block;
while(blockSize--)
{
SPI1_ExchangeByte(*data++);
}
}
void SPI1_ReadBlock(void *block, size_t blockSize)
{
uint8_t *data = block;
while(blockSize--)
{
*data++ = SPI1_ExchangeByte(0);
}
}
void SPI1_WriteByte(uint8_t byte)
{
SPI1TXB = byte;
}
uint8_t SPI1_ReadByte(void)
{
return SPI1RXB;
}
main.c:
#include "mcc_generated_files/mcc.h"
#include "ST7735.h"
#define led0 PORTAbits.RA7
#define led1 PORTAbits.RA6
#define led2 PORTAbits.RA5
#define led3 PORTAbits.RA4
void main(void)
{
// Initialize the device
SYSTEM_Initialize();
led0 = SPI1_Open(SPI1_DEFAULT);
led0 = SPI1CON0bits.EN;
LCD_RESET = 1;
delay_us(500);
LCD_RESET = 0;
delay_us(500);
LCD_RESET = 1;
delay_us(500);
__delay_ms(1000);
ST7735_initR();
ST7735_fillScreen(ST7735_BLACK);
while (1)
{
// Add your application code
}
}
我也可以包括ST7735.h/ST7735.c中的内容,但我确信它们很好,因为当spi1正常配置时,它们工作得很好。只有当我试图切换spi配置时,这种糟糕的行为才会开始——为了不可避免地在多个设备之间切换,我必须这样做。在上述代码中,SPI默认为EN=0。我可以包含SPI默认为EN=1的版本,并使用SPI1_Close((将其关闭。但是两者的行为相同,此版本稍微简单一些。我非常感谢您的意见。
我自己解决了这个问题。
这就是令人反感的功能:
bool SPI1_Open(spi1_modes_t spi1UniqueConfiguration)
{
if(!SPI1CON0bits.EN)
{
SPI1CON0 = spi1_configuration[spi1UniqueConfiguration].con0;
SPI1CON1 = spi1_configuration[spi1UniqueConfiguration].con1;
SPI1CON2 = spi1_configuration[spi1UniqueConfiguration].con2 | (_SPI1CON2_SPI1RXR_MASK | _SPI1CON2_SPI1TXR_MASK);
SPI1CLK = 0x00;
SPI1BAUD = spi1_configuration[spi1UniqueConfiguration].baud;
TRISCbits.TRISC1 = spi1_configuration[spi1UniqueConfiguration].operation;
SPI1CON0bits.EN = 1;
return true;
}
return false;
}
线路:
SPI1CON2 = spi1_configuration[spi1UniqueConfiguration].con2 | (_SPI1CON2_SPI1RXR_MASK | _SPI1CON2_SPI1TXR_MASK);
应该只是:
SPI1CON2 = spi1_configuration[spi1UniqueConfiguration].con2;
当查看initialize函数时,这一点变得很明显,该函数在默认状态为enable(即SPI1CON0=0x83(时工作:
void SPI1_Initialize(void)
{
//EN disabled; LSBF MSb first; MST bus master; BMODE every byte;
SPI1CON0 = 0x03;
//SMP Middle; CKE Active to idle; CKP Idle:High, Active:Low; FST disabled; SSP active high; SDIP active high; SDOP active high;
SPI1CON1 = 0x60;
//SSET disabled; TXR required for a transfer; RXR data is not stored in the FIFO;
SPI1CON2 = 0x02;
//CLKSEL FOSC;
SPI1CLK = 0x00;
//BAUD 3;
SPI1BAUD = 0x03;
TRISCbits.TRISC1 = 0;
}
这个正确工作的功能不会"被激活";或";带有(_SPI1CON2_SPI1RXR_MASK|_SPI1CONF2_SPI1TXR_MASK(的SPI1CON2。
当测试时,它的行为是正确的。这要归功于奥列格·马祖罗夫,他的评论让我重新检查了mcc生成的代码。虽然mcc生成的代码以前从未让我失败过,但如果您正在使用mcc做任何足够高级的事情,我建议您在假设它正常工作之前仔细检查它。