シリアル ポートから 1 文字を送信するたびに 1 文字を返すようにボード (ERC 32 プロセッサ) をプログラムしました。GTKterm を介して文字を送信すると、すべてが正常に機能し、ボードが正しく返されます。文字を送受信するコードを C で書いています。ただし、何らかの方法で失敗するか、一部の実行で機能し、突然機能しなくなります。シリアルポートに関する多くの質問を読みましたが、何が起こっているのかわかりませんでした。
私は3つのアプローチを試みました:
1) 読み取り/書き込みコードのブロック
問題: しばらくは機能していましたが、読み取り機能がブロックされ、バイトを取りませんでした。以下のコード
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sys/types.h>
//Test chars
char d='a',a;
int main()
{
struct termios tio;
struct termios old_tio;
//Open serial port
tty_fd=open("/dev/ttyS1",O_RDWR | O_NOCTTY);
//Just to check, ir returs 3 always
printf("fd: %d\n",tty_fd);
//Get previous configurations
tcgetattr(tty_fd,&old_tio);
cfsetospeed(&tio,B19200); // 19200 baud
cfsetispeed(&tio,B19200);
/*CS8 : 8n1 (8bit,no parity,1 stopbit)
CLOCAL : local connection, no modem contol
CREAD : enable receiving characters*/
tio.c_iflag &= ~(IXON | IXOFF | IXANY);
tio.c_oflag = 0;
tio.c_cflag &= ~PARENB; /* Disables the Parity Enable bit(PARENB),So No Parity */
tio.c_cflag &= ~CSTOPB; /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
tio.c_cflag &= ~CSIZE; /* Clears the mask for setting the data size */
tio.c_cflag |= CS8|CREAD|CLOCAL;
tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //non-cannonical
tio.c_cc[VMIN]=1;
tio.c_cc[VTIME]=0;
tcsetattr(tty_fd,TCSANOW,&tio);
tcflush(tty_fd, TCIFLUSH);
tcflush(tty_fd, TCOFLUSH);
//Write a char and waits for a return char immediately after
bytes_written=write(tty_fd,&d,1);
printf("bytes written:%d\n",bytes_written);
read(tty_fd,&a,1);
printf(" bytes read:%d\n",bytes_read);
tcsetattr(tty_fd,TCSANOW,&old_tio);
close(tty_fd);
return 0;
}
2) スレッド ブロッキング読み取り/書き込みコード
問題: 読み取り関数がブロックされ、1 バイトも取りません。
注: 読み取りスレッドが最初に初期化され、書き込み呼び出しに関係なくポートを「監視」し始めるようにプログラムしました。以下のコード
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <pthread.h>
char a='z';
char read_char='?';
void *read_thread(void *arg)
{
int *tty_fd_ptr= (int*) arg;
int tty_fd = *tty_fd_ptr;
unsigned int bytes_read=0;
//Read until it gets at leats one byte
while(bytes_read<=0)
{
bytes_read=read(tty_fd,&read_char,1);
}
printf("char: %c\n",read_char);
pthread_exit(0);
}
void *test_thread(void *arg)
{
int *tty_fd_ptr= (int*) arg;
int tty_fd = *tty_fd_ptr;
unsigned int bytes_written;
bytes_written=write(tty_fd,&a,1);
printf("Bytes written: %d\n",bytes_written);
pthread_exit(0);
}
int main ()
{
int count;
int tty_fd;
//The port oppening routine and configurations is exactly the same of the
//previous code
//Thread ID
pthread_t tid,tid_2;
//Create attributes
pthread_attr_t attr,attr_2;
pthread_attr_init(&attr);
pthread_create(&tid, &attr,read_thread,&tty_fd);
pthread_attr_init(&attr_2);
pthread_create(&tid_2, &attr_2,test_thread,&tty_fd);
pthread_join(tid,NULL);
pthread_join(tid_2,NULL);
tcsetattr(tty_fd,TCSANOW,&old_tio);
close(tty_fd);
return 0;
}
3) シグナル ハンドラーを使用したノンブロッキング読み取り/書き込みコード
問題: コードでわかるように、メイン ループ (ポート ウォッチャー ループ) の前に書き込み呼び出しを配置しました。ポートへのシグナルハンドラも設定済みです。書き込みますが、何も読み取りません。以下のコード
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sys/types.h>
volatile int STOP=FALSE;
int tty_fd;
int bytes_written=0,bytes_read;
char a='z',c='b';
void signal_handler_IO (int status)
{
printf("Interrupt\n");
wait_flag = FALSE;
}
int main ()
{
struct sigaction saio; /* definition of signal action */
struct termios tio;
struct termios old_tio;
tty_fd=open("/dev/ttyS1",O_RDWR | O_NOCTTY | O_NONBLOCK);
printf("fd: %d\n",tty_fd);
/* 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_status=fcntl(tty_fd, F_SETOWN, getpid());
fcntl_status=fcntl(tty_fd, F_SETFL, FASYNC);
tcgetattr(tty_fd,&old_tio);
cfsetospeed(&tio,B19200); // 19200 baud
cfsetispeed(&tio,B19200);
//cfmakeraw(&tio);
/*CS8 : 8n1 (8bit,no parity,1 stopbit)
CLOCAL : local connection, no modem contol
CREAD : enable receiving characters*/
tio.c_iflag &= ~(IXON | IXOFF | IXANY);
tio.c_oflag=0;
//tio.c_cflag=CS8|CREAD|CLOCAL;
tio.c_cflag &= ~PARENB; /* Disables the Parity Enable bit(PARENB),So No Parity */
tio.c_cflag &= ~CSTOPB; /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
tio.c_cflag &= ~CSIZE; /* Clears the mask for setting the data size */
tio.c_cflag |= CS8|CREAD|CLOCAL;
tio.c_lflag=0;
tio.c_cc[VMIN]=1;
tio.c_cc[VTIME]=0;
tcsetattr(tty_fd,TCSANOW,&tio);
tcflush(tty_fd, TCIFLUSH);
tcflush(tty_fd, TCOFLUSH);
bytes_written=write(tty_fd,&c,1);
printf("bytes written: %d\n",bytes_written);
while (STOP==FALSE)
{
usleep(10000);
/* after receiving SIGIO, wait_flag = FALSE, input is available
and can be read */
if (wait_flag==FALSE)
{
bytes_read=read(tty_fd,&a,1);
printf("bytes read:%d \n",bytes_read);
wait_flag = TRUE; /* wait for new input */
}
}
tcsetattr(tty_fd,TCSANOW,&old_tio);
close(tty_fd);
return 0;
}
私の目標は、転送されるデータが Linux 側で開始され、uart を介してボードに送られ、ボードがデータを取得し、処理してコンピューターに返し、ループが実行されるループ システムのハードウェアを作成することです。何らかの停止条件が満たされるまで再び。複雑さを増す前に、単一の文字ループをテストするためだけに、ボード用の簡単なコードを作成しました。
次の点に注意してください:
-> 1 つの文字で 1 つの書き込み関数を呼び出し、同時に GTKterm を実行する単純なコードを作成すると、GTKterm コンソールでボードの応答を確認できます。
-> コードのブロック バージョンの場合、読み取り関数でコードがブロックされると、ボードをリセットすると、ボードのウェルカム メッセージの最初の文字が表示されます。ボードは必要ありませんが、GTkterm は必要です。
-> ダイレクト Linux マシンでいくつかのコードを試してみたところ、同じ問題が発生し、GTKterm は正常に動作しました。
私が見ていないトリッキーな設定があるかどうかはわかりません。どんな助けでも大歓迎です。
ボード: RTEMS リアルタイム オペレーティング システムでプログラムされている ERC32 チップ (TSC695F)。チップ UART は全二重です。
コンピューター: Windows 7 上の VMware 仮想マシン上の Mandriva Linux。
$ uname -a
Linux localhost.localdomain 2.6.36.2-desktop586-2mnb #1 SMP Wed Dec 22 17:11:08 UTC 2010 i686 i686 i386 GNU/Linux$ cat /etc/*-release
Mandriva Linux リリース 2010.2 (公式) for i586