Witam
Borykam się z problemem komunikacji kilku procków po sieci RS485 (wykorzystałem układ SN75176. Wszystko jest ok, aż do czasu kiedy dwa procki ze chcą gadać. Wtedy kolejność ramki mi się rozsypuje.
Ramkę mam stworzona w taki sposób:
1 bajt - adres, 1 bajt - dane/rozkaz, 1 bajt suma kontrolna wyliczana z dodania poprzednich dwóch bajtów.
Myślałem nawet wykorzystaniem jakoś timera, aby w razie błędu zaczynał zliczać ramkę od nowa. Ale jak to zapisać gdy korzystam z przerwań na Rx UARTa (program zatrzymuje się na np. raddr = UART_odbierz(); i czeka na znak, a gdy taki nie nadejdzie będzie czekał i czekał, jak temu zaradzić).
Poniżej fragmenty kodów moich programów.
Odbiornik:
Nadajnik:
Biblioteka uart.c:
Dodano po 18 [minuty]:
Myślałem też nad zastosowaniem Watchdoga, ale przy resecie poprzez ten układ wracałbym do początku programu, co nie wchodzi w grę ponieważ steruję zmiennymi a ich stanu nie zapisuję w pamięci EEPROM, więc ten sposób odpada
Borykam się z problemem komunikacji kilku procków po sieci RS485 (wykorzystałem układ SN75176. Wszystko jest ok, aż do czasu kiedy dwa procki ze chcą gadać. Wtedy kolejność ramki mi się rozsypuje.
Ramkę mam stworzona w taki sposób:
1 bajt - adres, 1 bajt - dane/rozkaz, 1 bajt suma kontrolna wyliczana z dodania poprzednich dwóch bajtów.
Myślałem nawet wykorzystaniem jakoś timera, aby w razie błędu zaczynał zliczać ramkę od nowa. Ale jak to zapisać gdy korzystam z przerwań na Rx UARTa (program zatrzymuje się na np. raddr = UART_odbierz(); i czeka na znak, a gdy taki nie nadejdzie będzie czekał i czekał, jak temu zaradzić).
Poniżej fragmenty kodów moich programów.
Odbiornik:
#include <avr/io.h> // dostęp do rejestrów
#include <inttypes.h> //
#include <util/delay.h>
#include <avr/interrupt.h> //obsługa przerwań
#include <uart.h>
#include "definicje.h"
#define addr 41 // adres ustalony jest wg schematu, młodsze bity oznaczają adres, starsze rodzaj - dokładny opis w dokumentacji
volatile int odbior=0;
volatile uint8_t raddr, data, chk;
void piny(void)
{
sbi(DDRC,0);
sbi(PORTC,0);
sbi(DDRC,1);
sbi(PORTC,1);
sbi(DDRD,4);
cbi(PORTD,4); //włączenie odbioru
sbi(DDRC,3);
cbi(PORTC,3); //ustawienie przekaźnika w stanie wyłączony
}
SIGNAL(SIG_UART_RECV)
{
raddr = UART_odbierz();
data = UART_odbierz();
chk = UART_odbierz();
if ((raddr==0x01)&&(data==open))
{
PORTC ^= (1<<LED2);//cbi(PORTC,LED2);
odbior=1;//sbi(PORTC,RELAY);
UART_pakiet(raddr,OK);
}
}
int main(void) // program główny
{
UART_Init(2400); // inicjalizacja portu szeregowego
piny();
sei();
cbi(PORTC,LED1);
while(1) // pętla nieskończona
{
_delay_ms(100);
if (odbior==1)
{
PORTC ^= (1<<RELAY);
odbior=0;
}
}
} Nadajnik:
#include <avr/io.h> // dostęp do rejestrów
#include <inttypes.h> //
#include <util/delay.h>
#include <uart.h>
#include "definicje.h"
#define addr 0x01 // adres ustalony jest wg schematu, młodsze bity oznaczają adres, starsze rodzaj - dokładny opis w dokumentacji
int main(void) // program główny
{
UART_Init(); // inicjalizacja portu szeregowego
DDRC = 0b11110111; // ustawiamy prawie cały port C jako wyjścia
PORTC = 0b11111100; // ustalamy wartości początkowe pinów/podciągamy port
sbi(DDRD,SN); //port D4 jako wyjście
cbi(PORTD,SN); //stan niski (SN ustawiony na odbiór)
unsigned int i = 0;
while(1) // pętla nieskończona
{
while ((bit_is_clear(PINC, PIR))&& (i==0)) // Jeśli na wejściu 3 portu C (PC3) jest stan niski to,
{
//sbi(PORTD,SN);
i = 1;
sbi(PORTC,LED1);
_delay_ms(100);
UART_pakiet(addr,open);
}
if ((!bit_is_clear(PINC, PIR)&&(i==1)))
{
i = 0;
//cbi(PORTC,LED1);
}
}
} Biblioteka uart.c:
#include <avr/io.h>
#include <inttypes.h>
#include <util/delay.h>
#define cbi(sfr, b) (sfr &= ~(1<<b)) // bit 0 na pin portu
#define sbi(sfr, b) (sfr |= (1<<b)) // bit 1 na pin portu
#define GOOD 0xDD
#define ERROR 0x21
#define SN 4
// Definicje funkcji odpowiedzialnych za komunikację po UART-cie
void UART_Init(void)
{
/* Set baud rate */
UBRRH = 0;
UBRRL = 51;
/* Enable receiver and transmitter */
UCSRB = (1<<RXCIE)|(1<<TXEN)|(1<<RXEN);
/* Set frame format: 8data, 1stop bit */
UCSRC = (1<<URSEL)|(3<<UCSZ0);
}
// wysyła znak podany jako parametr na port szeregowy
void UART_wyslij (unsigned char c)
{
/* Wait for empty transmit buffer */
while ( !( UCSRA & _BV(UDRE)) )
;
/* Put data into buffer, sends the data */
UDR = c;
}
// odbiera znak z portu szeregowego i zwraca go jako wartość funkcji
unsigned char UART_odbierz (void)
{
/* Wait for data to be received */
while ( !(UCSRA & (1<<RXC)) )
;
/* Get and return received data from buffer */
return UDR;
}
void UART_pakiet(uint8_t addr, uint8_t data)
{
sbi(PORTD,SN);
_delay_ms(1);
//UART_putchar(SYNC); // Sync
UART_wyslij(addr); // Receiver address
UART_wyslij(data); // Button status
UART_wyslij((addr+data)); // Checksum
_delay_ms(1);
cbi(PORTD,SN);
//_delay_ms(50);
}
void UART_OK(uint8_t addr)
{
UART_pakiet(addr,GOOD);
}
void UART_ERROR(uint8_t addr)
{
UART_pakiet(addr,ERROR);
}
Dodano po 18 [minuty]:
Myślałem też nad zastosowaniem Watchdoga, ale przy resecie poprzez ten układ wracałbym do początku programu, co nie wchodzi w grę ponieważ steruję zmiennymi a ich stanu nie zapisuję w pamięci EEPROM, więc ten sposób odpada