微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

PIC18

如何解决PIC18

我正在将PIC18f46k42单片机XC8 2.3与MPLABX / MCC一起使用。我的目标是使用单个SPI硬件外设与使用各种GPIO引脚作为芯片选择的多个设备接口。我有一个LCD和SD卡,都需要与MCU通讯(不能同时观察)。我的问题是当我尝试更改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;

这在查看初始化函数时变得很明显,该函数在默认状态为启用(即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 | _SPI1CON2_SPI1TXR_MASK)的SPI1CON2。

经过测试,此行为正确。感谢Oleg Mazurov,他的评论使我重新检查了mcc生成的代码。尽管mcc生成的代码从未使我失败过,但是如果您使用mcc做了足够高级的事情,我建议您在仔细检查其内容之前,先对其进行仔细检查。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。