我正在尝试使用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的之间存在一些同步问题,但是我不知道如何解决这个问题。
答案 0 :(得分:1)
您的代码的主要问题是您要以零结尾的字符串传输简单数组:
char freq_array[] = {0x01, '5', '0', '.', '0', '0', '\r'};
没有零字节可终止字符串。 但是发送功能:
void send_string_SPI(char s[])
...
while (s[i] != 0x00)
...
期望出现一个零字节。 因此,在发送第一个数组时,它将继续在数组范围之外发送许多字节,直到偶尔在内存中的某个地方遇到零字节为止。
在从属代码中,我也看不到data_array
和spi_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
对于客户端和服务器之间的每笔交易,都有一个确认。
例如:
如果客户端向服务器发送了命令,则服务器将确认它确实收到了命令。接下来,服务器将运行命令并将数据发送回客户端。最后,客户端将发送确认信息,确认已获得数据。
此外,以下一些链接可能会为您提供帮助: