轉載來源:嵌入式系統之初學者點滴 (百度空間)
在這篇文章()中,實現了Linux環境下的串口讀寫操做,程序也運行成功了。可是再進一步測試時發現,若是開機以後直接如上文中所說,分別運行讀程序和寫程序,再用導體同時觸碰串口的二、3針的話。此時將顯示寫入串口成功,可是讀串口數據失敗。
這個奇怪的問題當時之因此沒有被發現出來,是由於在這以前,曾經打開過一次minicom。後來實驗代表,若是打開過一次minicom,哪怕打開又關閉的話,再次運行上文中的串口讀寫程序就沒有問題了。可是重啓機器以後,錯誤又出現了:只要不運行minicom一下,程序讀取老是會有問題。
爲了查找錯誤到底是在什麼地方,分別在剛剛開機、運行過一次本身編寫的串口程序、運行過一次minicom這三種狀況下使用命令
stty -a < /dev/ttyS0查看了COM1的相關參數。而後主要根據本身的讀取程序和minicom對串口的設置差別進行了相應的修改,現將讀取程序的所有貼在下面。通過修改後,該程序運行以後的/dev/ttyS0的環境參數與直接運行minicom後/dev/ttyS0的環境參數徹底相同。
注:程序中紅色部分是與 文中的程序相比加入的主要內容。
/*********************************** read_serial ************************************/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <time.h>
#include <stdlib.h>
#define FALSE -1
#define TRUE 0
void set_speed(int, int);
int set_Parity(int,int,int,int);
int main()
{
int fd,flag,rd_num=0;
struct termios term;
struct timeval timeout;
speed_t baud_rate_i,baud_rate_o;
char recv_buf[20];
fd=open("/dev/ttyS0",O_RDWR|O_NONBLOCK);
if(fd==-1)
printf("can not open the COM1!\n");
else
printf("open COM1 ok!\n");
flag=tcgetattr(fd,&term);
baud_rate_i=cfgetispeed(&term);
baud_rate_o=cfgetospeed(&term);
printf("設置以前的輸入波特率是%d,輸出波特率是%d\n",baud_rate_i,baud_rate_o);
set_speed(fd,1200);
flag=tcgetattr(fd,&term);
baud_rate_i=cfgetispeed(&term);
baud_rate_o=cfgetospeed(&term);
printf("設置以後的輸入波特率是%d,輸出波特率是%d\n",baud_rate_i,baud_rate_o);
if (set_Parity(fd,8,1,'N')== FALSE)
{
printf("Set Parity Error\n");
exit(1);
}
int transfer_started=0;
int i=0;
while(1)
{
rd_num=read(fd,recv_buf,sizeof(recv_buf));
timeout.tv_sec=0;
timeout.tv_usec=200000;
if(rd_num>0)
{
printf("%d(間隔%4.3fs):we can read \"%s\" from the COM1,total:%d characters.\n",++i,timeout.tv_sec+timeout.tv_usec*0.000001,recv_buf,rd_num);
transfer_started=1;
}
else
printf("%d(間隔%4.3fs):read fail! rd_num=%d。本次數據傳輸%s\n",++i,timeout.tv_sec+timeout.tv_usec*0.000001,rd_num,transfer_started==1?"已經結束":"還沒有開始");
// sleep(1); 粗糙定時
select(0,NULL,NULL,NULL,&timeout);/*精肯定時*/
}
}
int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300};
int name_arr[] = {115200, 38400, 19200, 9600, 4800, 2400, 1200, 300};
void set_speed(int fd, int speed){
unsigned int i;
int status;
struct termios Opt;
tcgetattr(fd, &Opt);
for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {
if (speed == name_arr[i]) {
tcflush(fd, TCIOFLUSH);
cfsetispeed(&Opt, speed_arr[i]);
cfsetospeed(&Opt, speed_arr[i]);
status = tcsetattr(fd, TCSANOW, &Opt);
if (status != 0) {
perror("tcsetattr fd1");
return;
}
tcflush(fd,TCIOFLUSH);
}
}
}
/**
*@brief 設置串口數據位,中止位和效驗位
*@param fd 類型 int 打開的串口文件句柄*
*@param databits 類型 int 數據位 取值 爲 7 或者8*
*@param stopbits 類型 int 中止位 取值爲 1 或者2*
*@param parity 類型 int 效驗類型 取值爲N,E,O,,S
*/
int set_Parity(int fd,int databits,int stopbits,int parity)
{
struct termios options;
if ( tcgetattr( fd,&options) != 0)
{
perror("SetupSerial 1");
return(FALSE);
}
options.c_cflag &= ~CSIZE;
switch (databits) /*設置數據位數*/
{
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
fprintf(stderr,"Unsupported data size\n");
return (FALSE);
}
switch (parity)
{
case 'n':
case 'N':
// options.c_cflag &= ~PARENB; /* Clear parity enable */
// options.c_iflag &= ~INPCK; /* Enable parity checking */
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
options.c_oflag &= ~OPOST; /*Output*/
break;
case 'o':
case 'O':
options.c_cflag |= (PARODD | PARENB); /* 設置爲奇效驗*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'e':
case 'E':
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD; /* 轉換爲偶效驗*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's': /*as no parity*/
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
fprintf(stderr,"Unsupported parity\n");
return (FALSE);
}
/* 設置中止位*/
switch (stopbits)
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
fprintf(stderr,"Unsupported stop bits\n");
return (FALSE);
}
/* Set input parity option */
if ((parity != 'n')&&(parity != 'N'))
options.c_iflag |= INPCK;
options.c_cc[VTIME] = 5; // 0.5 seconds
options.c_cc[VMIN] = 1;
options.c_cflag &= ~HUPCL; options.c_iflag &= ~INPCK; options.c_iflag |= IGNBRK; options.c_iflag &= ~ICRNL; options.c_iflag &= ~IXON; options.c_lflag &= ~IEXTEN; options.c_lflag &= ~ECHOK; options.c_lflag &= ~ECHOCTL; options.c_lflag &= ~ECHOKE; options.c_oflag &= ~ONLCR; tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */ if (tcsetattr(fd,TCSANOW,&options) != 0) { perror("SetupSerial 3"); return (FALSE); } return (TRUE); } 這樣的話,讀程序就能夠直接接收到串口過來的數據,而不須要先運行一次minicom了。