如何使用SPI正确发送多个字符串

时间:2018-08-02 16:34:19

标签: c avr spi atmega

我正在尝试使用SPI在两个 ATmega 之间进行通信。首先,我为两个ATmega都初始化了SPI。这里ATmega8是 master ,而ATmega32是 slave


主控

主站初始化-ATMEGA8:

#define SPI_ddr             DDRB
#define SPI_port            PORTB
#define PIN_sck             5
#define PIN_mosi            3
#define PIN_ss              2
#define PIN_miso            4

#define SPI_PORT_enable()   (SPI_ddr |= (1 << PIN_sck) | (1 << PIN_mosi) | (1 << PIN_ss))
#define CS_High             SPI_port |= (1 << PIN_ss);
#define CS_Low              SPI_port &= ~(1 << PIN_ss);

void SPI_Init()
{
    SPI_PORT_enable();
    SPI_ddr &= ~(1 << PIN_miso);
    SPCR |= (1 << MSTR) | (1 << SPR0) | (1 << SPR1) | (1 <<SPE);
}

从主机发送数据的功能-ATMEGA8:

void send_char_SPI(char c)
{
    SPDR = c;
    /* Wait for transmission complete */
    while(!(SPSR & (1 << SPIF)));
}

void send_string_SPI(char s[])
{
    int i = 0;
    while (s[i] != 0x00)
    {
        send_char_SPI(s[i]);
        i++;
    }
}

所以现在我有两个字符串要一一发送到从属

char freq_array[] = {0x01, '5', '0', '.', '0', '0', '\r'};
char volt_array[] = {0x02, '2', '9', '1', '.', '4', '\r'};  

主机的主要内容-ATMEGA8:

int main(void)
{
    SPI_Init();
    while (1) 
    {
        CS_Low;
        _delay_ms(10);
        send_string_SPI(volt_array);
        CS_High;
        _delay_ms(1000);

        CS_Low;
        _delay_ms(10);
        send_string_SPI(freq_array);
        CS_High;
        _delay_ms(1000);
    }
}

这是主要问题,当我仅通过SPI向从设备发送一个阵列时,我可以在从设备端获得完美的数据,然后通过UART将其传输到终端。但是,当我同时发送两个数组时,我并没有完美地接收到两个数组。我宁愿大部分时间都收到一个数组,有时又收到另一个数组。我希望 salve 一次接一个接收数组。首先,它将接收第一个数组,然后再次应接收下一个数组。并应同时将其发送到UART。


从属

从站初始化-ATMEGA32:

这里ATmega32正在使用中断接收数据

#define SPI_ddr             DDRB
#define SPI_port            PORTB
#define PIN_sck             7
#define PIN_mosi            5
#define PIN_ss              4
#define PIN_miso            6
#define SPI_PORT_enable()   (SPI_ddr &= ~((1 << PIN_sck) | (1 << PIN_mosi) | (1 << PIN_ss)) )

void SPI_Init()
{
    SPI_PORT_enable();
    SPI_ddr |= (1 << PIN_miso);
    SPCR &= ~(1 << MSTR);
    SPCR |= (1<<SPR0)|(1<<SPR1);       // divide clock by 128
    SPCR |= (1<<SPE);                  // Enable SPI
    SPCR |= (1<<SPIE);

}

从属设备ATMEGA32的ISR:

在这里,我正在检查\r,因为我从 master 发送的每个字符串都以\r结尾。因此,如果得到\r,我将设置spi_data_recieved变量,以便可以在main中对其进行处理(即可以通过UART将接收到的数据发送到终端)。

ISR(SPI_STC_vect)
{
    data_array[data_index] = SPDR;
    if(data_array[data_index] == '\r')
        spi_data_recieved = 1;
    if (data_index > 10)
    {
        data_index = 0;
        Clear_Buffer(data_array, 10);
    }
    else
    {
        data_index++;
    }
}

从站上的UART功能-ATMEGA32:

void Serial_Init(unsigned int baud)
{
    UBRRH = (unsigned char)(baud >> 8);
    UBRRL = (unsigned char)baud;

    UCSRB = (1 << RXEN)  | (1 << TXEN) ;
    UCSRC = (1 << URSEL) | (3 << UCSZ0);

}

void Serial_Transmit(unsigned char data)
{
    UDR = data;
    while ( !( UCSRA & (1 << UDRE) ) );
}

void Serial_Transmit_String(unsigned char *string)
{
    while (*string != 0)
    Serial_Transmit(*string++);
}

从属主机-ATMEGA32:

int main(void)
{
    SPI_Init();
    Serial_Init(103);
    data_index = 0;
    spi_data_recieved = 0;
    sei();
    Serial_Transmit_String((unsigned char*)"TESTING SPI\r\n");
    unsigned char copyBuff[10];
    while (1) 
    {
        if (spi_data_recieved == 1)
        {
            spi_data_recieved = 0;
            strcpy((char*)copyBuff, (char*)data_array);
            Clear_Buffer(data_array, 10);
            data_index = 0;
            switch(copyBuff[0])
            {
                case 0x01: Serial_Transmit_String((unsigned char*)"Frequency: "); break;
                case 0x02: Serial_Transmit_String((unsigned char*)"Bus Voltage: "); break;
                default: Serial_Transmit_String((unsigned char*)"SPI Data: "); break;
            }

            Serial_Transmit_String(copyBuff);
        }

        _delay_ms(10);
    }
}

此设置的预期输出为:

Bus Voltage: 291.4

Frequency: 50.00

Bus Voltage: 291.4

Frequency: 50.00

并以此方式连续

获取的输出为:

SPI Data: 0

Frequency: 50.00

SPI Data: 0

Frequency: 50.00

SPI Data: 0

Frequency: 50.00

在极少数情况下,我可以看到总线电压。

我发现ATmega的之间存在一些同步问题,但是我不知道如何解决这个问题。

2 个答案:

答案 0 :(得分:1)

您的代码的主要问题是您要以零结尾的字符串传输简单数组:

char freq_array[] = {0x01, '5', '0', '.', '0', '0', '\r'};

没有零字节可终止字符串。 但是发送功能:

void send_string_SPI(char s[])
    ...
    while (s[i] != 0x00)
       ...

期望出现一个零字节。 因此,在发送第一个数组时,它将继续在数组范围之外发送许多字节,直到偶尔在内存中的某个地方遇到零字节为止。

在从属代码中,我也看不到data_arrayspi_data_recieved的声明方式。他们是volatile吗? 另外,在ISR中查看Clear_Buffer(data_array, 10);时,我想声明了data_array的长度为10:data_array[10]。 因此,ISR中的data_array[data_index] = SPDR;会写出数组边界,在数组边界的后两个字节,这会损坏RAM的内容。

答案 1 :(得分:0)

尝试在它们之间创建通信协议。

例如,为了上大学,我必须创建一个File Transfer Client/Server which used Vigenere Cipher

对于客户端和服务器之间的每笔交易,都有一个确认。

例如:

如果客户端向服务器发送了命令,则服务器将确认它确实收到了命令。接下来,服务器将运行命令并将数据发送回客户端。最后,客户端将发送确认信息,确认已获得数据。

此外,以下一些链接可能会为您提供帮助: