繁体   English   中英

由ISR设置变量的奇怪PIC行为

[英]Odd PIC behavior with variables set by ISR

我在PIC代码中观察到一些奇怪的行为,在该行为中,我将ISR写入的全局变量中的数据连续复制到两个不同的缓冲区中,但是该值似乎只能成功写入两个缓冲区之一。 当我尝试使用不是由ISR编写的其他变量来尝试此操作时,它会正确地复制到两个缓冲区中。

我的设置是使用XC8编译器1.45版的PIC16LF15355。 我将PIC MSSP模块之一配置为SPI接口,以将测量数据写入状态并将状态切换到RF收发器。 我还有另一个远程RF收发器,它通过SPI接口通过PIC16LF15355接收和处理数据。 对于这两个PIC,我将第二个MSSP模块配置为连接到Raspberry Pi的I2C接口,以进行调试。 写入发送端SPI缓冲区的任何数据也将复制到I2C缓冲区,以便可以定期读取以查看正在发送的数据。 同样,将读取到接收端SPI缓冲区中的数据复制到I2C缓冲区中,以便可以定期读取以查看正在接收的内容。

发射端有一个开关输入,该输入通过定时器ISR(以下代码中的timer0_handler)进行去抖动。 该ISR将状态写入sw1State。 当需要传输数据时,会将开关状态和其他测量数据复制到I2C缓冲区中,然后将I2C缓冲区复制到SPI缓冲区中进行传输。 当我定期从Pi采样I2C缓冲区的内容时,可以看到开关状态随着开关的按下而改变。 但是,当我在接收端定期对I2C缓冲区内容进行采样时,我只会看到开关状态默认值(1)。

奇怪的是,如果我更改代码以从未由ISR写入的变量中复制值,则该值会在接收端正确显示。 但是,从I2C缓冲区复制到SPI缓冲区只是一个阵列到另一个阵列的通用副本,所有其他测量数据都会在接收端正确显示。 这两个缓冲区应该相同。 从I2C缓冲区复制到SPI缓冲区写到收发器之间的这段时间里,我的代码中没有任何东西可以修改SPI缓冲区。

下面是该代码的精简副本。 我已经看了好几天了,只是看不出是什么原因造成的。

volatile uint8_t sw1State;            // current switch 1 state
volatile uint8_t sw1TimeExpired;      // true if switch 1 debounce time expired
uint8_t spiOutBuf[13]; // SPI output buffer
uint8_t spiInBuf[13];  // SPI input buffer
uint8_t i2cBuff[13];   // I2C input/output buffer

void interrupt main_ISR( void ) {
    I2C_slave_handler();
    timer0_handler();
    switch_input_handler();
}

int main( void ) {
    ... device initialization code omitted for brevity

    sw1State = 1;
    sw1TimeExpired = 1;

    for ( ; ; )
    {        
        // Read the ADC values and add to the I2C buffer (for debugging).
        for ( uint8_t chan = 0; chan < 9; chan++ )
        {
            i2cBuff[chan + 1] = ADC_read( chan );
        }

        // Read the switch status and add to the I2C buffer.
        i2cBuff[10] = sw1State;

        // Load the write transmit payload command into the SPI buffer.
        spiOutBuf[0] = CMD_W_TX_PAYLOAD;

        // Copy the payload data from the I2C buffer to the SPI buffer.
        for ( uint8_t i = 1; i < 13; i++ )
        {
            spiOutBuf[i] = i2cBuff[i];
        }

        // Write the SPI buffer to the transceiver module payload register.
        writeReadSPI( 13 );

        // Clear the RB4 interrupt-on-change interrupt flag (IRQ change) and 
        // set CE high to initiate the transmit.  Hold CE high until an ack
        // is received or there is an ack timeout.
        IOCBFbits.IOCBF4 = 0;
        CE = 1;
        __delay_us( 130 );    // ensure minimum state change transition time

        ... code here omitted which checks the transceiver status

        __delay_ms( 80 );
    }
}

void switch_input_handler( void ) {
    // Check for switch 1 trigger.
    if ( IOCCFbits.IOCCF6 == 1 )
    {
        IOCCFbits.IOCCF6 = 0;   // clear IOC interrupt

        // Process switch 1 trigger if debounce time has expired.
        if ( sw1TimeExpired == 1 )
        {
            // Toggle between OFF state and ON state.
            if ( sw1State == 1 )
            {
                sw1State = 2;
            }
            else
            {
                sw1State = 1;
            }
            // Load and restart Timer0 with 2-second counter value.
            T0CON0bits.T0EN = 0;
            TMR0H = 0xc2;
            TMR0L = 0xf7;
            T0CON0bits.T0EN = 1;
            sw1TimeExpired = 0;
        }
    }
}

void timer0_handler( void ) {
    if ( PIR0bits.TMR0IF == 1 )
    {
        PIR0bits.TMR0IF = 0;    // clear the interrupt
        T0CON0bits.T0EN = 0;    // disable Timer0

        if ( sw1TimeExpired == 0 )
        {
            sw1TimeExpired = 1; // Note the switch 1 timeout for switch handler.
                                // No state transition here.  This just enables
                                // the next switch interrupt to change state.
        }
    }
}

void I2C_slave_handler( void ) {
   ... code omitted for brevity
}

从代码片段中可以看出,SPI通道正在作为后台任务发送,而I2C通道正在前台(中断处理程序)发送。 这可能会导致竞争状况并解释您遇到的行为。

建议您尝试对两个通道使用单个发送缓冲区,并设置一个变量以指示两个通道何时已成功发送数据。 一旦两个通道都指示已发送数据,则为下一个周期生成新的数据包/缓冲区。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM