Newsgroup: it.hobby.robotica
Titolo: Problemi comunicazione RS232 con ATmega8 (un po' lungo...)

Ciao a tutti!
Dopo molto tempo mi rifaccio vivo...
Sto bestemmiando in tutte le lingue conosciute e sconosciute perche' non
riesco a far comunicare un fetentissimo ATmega8 con il mio PC via RS232...
In pratica, ho scritto un piccolo programma in C che manda dei dati alla
seriale, l'ho compilato con avr-gcc e l'ho installato con 湣, poi ho
scritto un fetentissimo programmino in C da far girare sulla mia LinuxBox
per leggere i dati dalla seriale.
Niente da fare! Non riesco a leggere niente di sensato dalla seriale.
La stessa cosa con minicom o con un semplice cat /dev/ttyS0 dopo aver
impostato i giusti parametri di comunicazione con stty...
Qualcuno di voi ha gia' fatto cose del genere e sa darmi una mano?
Questi sono i sorgenti:
ATmega8:
----------------------------
#include <avr/io.h>
#include <stdint.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#define F_CPU 16000000
#define UART_BAUD_RATE 9600  // 9600 Baud
#define UART_UBRR_CALC(BAUD_,FREQ_) ((FREQ_)/((BAUD_)*16L)-1)
void init()
{
  UCSRB |= (1<<TXEN)|(1<<RXEN); //UART TX & RX einschalten
  UCSRC |= (1<<URSEL)|(3<<UCSZ0); //Asynchron 8N1
  UBRRH = (int)(UART_UBRR_CALC(UART_BAUD_RATE,F_CPU)>>8); //Datenrate
einstellen (High-Byte)
  UBRRL = (int)UART_UBRR_CALC(UART_BAUD_RATE,F_CPU); //Datenrate
einstellen (Low-Byte)
}
void TransmitData(char txdata)
{
  while (!(UCSRA & (1<<UDRE)));   //Auf TX-Ready warten
  UDR = txdata; //Daten senden
}
int main(void)
{
  init();
  TransmitData('X');
}
----------------------------
Linux:
----------------------------
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>
#define BAUDRATE B9600
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
void signal_handler_IO (int status);   /* definition of signal handler */
int wait_flag=TRUE;                    /* TRUE while no signal received */
int fd;
main()
{
  int c, res;
  struct termios oldtio,newtio;
  struct sigaction saio;           /* definition of signal action */
  char buf[255];
  /* open the device to be non-blocking (read will return immediatly) */
  fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
  if (fd <0) {perror(MODEMDEVICE); exit(-1); }
  /* install the signal handler before making the device asynchronous */
  saio.sa_handler = signal_handler_IO;
  sigemptyset(&saio.sa_mask);
  saio.sa_flags = 0;
  saio.sa_restorer = NULL;
  sigaction(SIGIO,&saio,NULL);
  /* allow the process to receive SIGIO */
  fcntl(fd, F_SETOWN, getpid());
  /* Make the file descriptor asynchronous (the manual page says only
     O_APPEND and O_NONBLOCK, will work with F_SETFL...) */
  fcntl(fd, F_SETFL, FASYNC);
  tcgetattr(fd,&oldtio); /* save current port settings */
  /* set new port settings for canonical input processing */
  cfsetispeed(&newtio, B9600);
  cfsetospeed(&newtio, B9600);
  newtio.c_cflag |= (CLOCAL | CREAD);
  newtio.c_cflag &= ~PARENB;
  newtio.c_cflag &= ~CSTOPB;
  newtio.c_cflag &= ~CSIZE;
  newtio.c_cflag |= CS8;
  newtio.c_cflag &= ~CRTSCTS;
  newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  tcflush(fd, TCIFLUSH);
  tcsetattr(fd,TCSANOW,&newtio);
  /* loop while waiting for input. normally we would do something
     useful here */
  while (STOP==FALSE)
  {
    usleep(100000);
    /* after receiving SIGIO, wait_flag = FALSE, input is available
 and can be read */
    if (wait_flag==FALSE)
    {
      res = read(fd,buf,255);
      buf[res]=0;
      printf(":%s:%d\n", buf, res);
      wait_flag = TRUE;      /* wait for new input */
    }
  }
  /* restore old port settings */
  tcsetattr(fd,TCSANOW,&oldtio);
}
void signal_handler_IO (int status)
{
  printf("received SIGIO signal.\n");
  wait_flag = FALSE;
}
----------------------------
Idee?
Grazie
Luca Bertoncello
(
luca...@lucabert.de
)
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

> Idee?
Scrivendo i consigli qui sotto credo di avere individuato il problema, 
per cui te lo scrivo subito, ma ti lascio il vecchio messaggio come 
utile check-up finale:
Il problema sembra essere l'ordine in cui imposti il baudrate e attivi 
la seriale.
Come riportato a pagina 149 del datasheet, i registri UBRRH e UCSRC sono 
in realtà mappati allo stesso indirizzo, a seconda del valore del bit 
URSEL il valore viene scritto in un registro o nell'altro. Dato che tu 
hai invertito quei due pezzi di codice andavi a scrivere il valore nel 
registro sbagliato.
La soluzione dovrebbe essere usare il codice in questo modo:
UBRRH = (int)(UART_UBRR_CALC(UART_BAUD_RATE,F_CPU)>>8);
UBRRL = (int)UART_UBRR_CALC(UART_BAUD_RATE,F_CPU);
UCSRB |= (1<<TXEN)|(1<<RXEN);
UCSRC |= (1<<URSEL)|(3<<UCSZ0);
(a proposito: (3<<UCSZ0) è veramente bruttissimo da leggere, meglio 
(1<<UCSZ0)|(1<<UCSZ1))
Fammi sapere se risolvi il problema...
[Inizio vecchia risposta]
Per prima cosa io cercherei di capire se il problema è da parte 
dell'ATmega o del pc.
1) prova a controllare con un un altro pc o terminale se ricevi 
correttamente i caratteri
2) prova a impostare il baudrate prima di attivare l'USART nell'Atmega
3) che cosa usi per convertire i livelli di segnale tra atmega e la 232 
del pc? un max232? è alimentato, i livelli in linea a riposo sono 
normali (+5 all'uscita dell'avr, -12 nel pin RX della porta seriale)?
4) stai usando un clock stabile per l'avr, per esempio un quarzo? oppure 
è l'oscillatore interno o un RC?
[Fine vecchia risposta]
...:::Zmaster:::...

 Fammi sapere se risolvi il problema...
RISOLTO!!! Mille grazie!!!
Ciao
