Linux下用C實現串列埠讀寫
http://hi.baidu.com/weiweisuo1986/item/b33200134ceaac6871d5e81d
之前要做一個和串列埠相關的專案,才認真研究了下串列埠,首先就是要實現串列埠和PC機的通訊。
串列埠的驅動一般不需要我們寫,都是很成熟的驅動,要知道的一點就是你開發板串列埠的名稱,比如ttySAC0,等。所以主要的工作就是程式設計序,實現串列埠的收發,這當然也好理解,就把串列埠當成檔案,對其進行讀寫就可以了。
首先說明下我的編譯環境,Linux使用的版本是2.6.30.4,交叉編譯器使用的是EABI4.3.3。下面是程式程式碼,只有一個檔案:serialport.c!
/**************serialport**************************/
/*************Designed by Suo*********************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
//serial port set function
void setTermios(struct termios *pNewtio, unsigned short uBaudRate)
{
bzero(pNewtio,sizeof(struct termios));
pNewtio->c_cflag = uBaudRate|CS8|CREAD|CLOCAL;
pNewtio->c_iflag = IGNPAR;
pNewtio->c_oflag = 0;
pNewtio->c_lflag = 0;
pNewtio->c_cc[VINTR] = 0;
pNewtio->c_cc[VQUIT] = 0;
pNewtio->c_cc[VERASE] = 0;
pNewtio->c_cc[VKILL] = 0;
pNewtio->c_cc[VEOF] = 4;
pNewtio->c_cc[VTIME] = 5;
pNewtio->c_cc[VMIN] = 0;
pNewtio->c_cc[VSWTC] = 0;
pNewtio->c_cc[VSTART] = 0;
pNewtio->c_cc[VSTOP] = 0;
pNewtio->c_cc[VSUSP] = 0;
pNewtio->c_cc[VEOL] = 0;
pNewtio->c_cc[VREPRINT] = 0;
pNewtio->c_cc[VDISCARD] = 0;
pNewtio->c_cc[VWERASE] = 0;
pNewtio->c_cc[VLNEXT] = 0;
pNewtio->c_cc[VEOL2] = 0;
}
int main(int argc,char **argv)
{
int fd;
int nCount,nTotal;
int i,j,m;
int ReadByte = 0;
struct termios oldtio,newtio;
char *dev = "/dev/tq2440_serial1";
if((argc!=3)||(sscanf(argv[1],"%d",&nTotal)!=1))
{
printf("Usage:COMSend count datat!\n");
return -1;
}
if((fd=open(dev,O_RDWR|O_NOCTTY|O_NDELAY))<0) //open serial COM2
{
printf("Can't open serial port!\n");
return -1;
}
tcgetattr(fd,&oldtio);
setTermios(&newtio,B9600);
tcflush(fd,TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
//Send data
for(i=0;i<nTotal;i++)
{
nCount = write(fd,argv[2],strlen(argv[2]));
printf("send data OK!count=%d\n",nCount);
sleep(1);
}
//receive data
for(j=0;j<20;j++)
{
ReadByte = read(fd,Buffer,512);
if(ReadByte>0)
{
printf("readlength=%d\n",ReadByte);
Buffer[ReadByte]='\0';
printf("%s\n",Buffer);
sleep(3);
}
else printf("Read data failure times=%d\n",j);
}
printf("Receive data finished!\n");
tcsetattr(fd,TCSANOW,&oldtio);
close(fd);
return 0;
}
此程式實現的功能是:執行程式時,輸入要傳送的次數及待發送資料,就向串列埠2傳送資料,如果有資料過了,程式會把接收到的資料顯示在終端上。
相應的Makefile是:
CROSS=arm-linux-
all:shuserial
shuserial:shuserial.c
$(CROSS)gcc -o shuserial shuserial.c
$(CROSS)strip shuserial
clean:
@rm -vf shuserial*.o*~
make出可執行檔案serialport後,就可以在開發板上除錯了。除錯方法:1、把程式用U盤拷到開發板中(當然前提是已啟動Linux系統),我的開發板是Linux2.6.30核心+Qtopia2.2.0。2、連線串列埠,用串列埠線把開發板串列埠2和電腦相連,PC開啟超級終端,設定串列埠COM1屬性為9600波特率,8N1,然後等待接收。3、開啟開發板系統中的終端Terminal,輸入./serialport 10 abcdefghijk ,即可執行此程式,程式向PC串列埠傳送傳送10次“abcdefghijk”,傳送完成後,如果你向超級終端輸入了資料,程式會把資料顯示到Terminal上。
完成了,程式就是這麼簡單,只是實現了簡單的收發功能。
以後用Qt實現此程式……
成功的測試程式:
ReadUart.cpp
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<termios.h>
#include<errno.h>
#include<string.h>
#define TRUE 1
//初始化串列埠
void setTermios(struct termios * pNewtio, int uBaudRate)
{
bzero(pNewtio, sizeof(struct termios));
//8N1
pNewtio->c_cflag = uBaudRate | CS8 | CREAD | CLOCAL;
pNewtio->c_iflag = IGNPAR;
pNewtio->c_oflag = 0;
pNewtio->c_lflag = 0; //non ICANON
pNewtio->c_cc[VINTR] = 0;
pNewtio->c_cc[VQUIT] = 0;
pNewtio->c_cc[VERASE] = 0;
pNewtio->c_cc[VKILL] = 0;
pNewtio->c_cc[VEOF] = 4;
pNewtio->c_cc[VTIME] = 5;
pNewtio->c_cc[VMIN] = 0;
pNewtio->c_cc[VSWTC] = 0;
pNewtio->c_cc[VSTART] = 0;
pNewtio->c_cc[VSTOP] = 0;
pNewtio->c_cc[VSUSP] = 0;
pNewtio->c_cc[VEOL] = 0;
pNewtio->c_cc[VREPRINT] = 0;
pNewtio->c_cc[VDISCARD] = 0;
pNewtio->c_cc[VWERASE] = 0;
pNewtio->c_cc[VLNEXT] = 0;
pNewtio->c_cc[VEOL2] = 0;
}
#define BUFSIZE 512
int main(int argc, char **argv)
{
int fd;
int nread;
int Rlength = BUFSIZE;
int Length = 0;
char buff[BUFSIZE] = {0};
char cMsg[BUFSIZE] = {0};
char *pch = buff;
int i = 0;
struct termios oldtio, newtio;
struct timeval tv;
char *dev =(char *)"/dev/ttyO1";
//char *dev =(char *)"/dev/ttyS1";
fd_set rfds;
if ((fd = open(dev, O_RDWR | O_NOCTTY))<0)
{
printf("err: can't open serial port!\n");
return -1;
}
tcgetattr(fd, &oldtio);
//setTermios(&newtio, B9600);
setTermios(&newtio, B115200);
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newtio);
tv.tv_sec=3;
tv.tv_usec=0;
while (TRUE)
{
//printf("fd is <%d> wait...\n", fd);
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
if (select(1+fd, &rfds, NULL, NULL, &tv)>0)
{
//printf("wait.......\n");
if (FD_ISSET(fd, &rfds))
{
//printf("FD_ISSET...\n");
//nread=read(fd, buff, BUFSIZE);
nread=read(fd, pch, BUFSIZE-Length);
//buff[nread]='\0';
for(i=Length;i<nread+Length;i++)
{
//printf("buff[%d] = <0x%x><%c>.\n", i,buff[i],buff[i]);
printf("%c\n", buff[i]);
}
//printf("\n");
//printf("nread = %d,Length = %d, %s\n",nread,Length, buff);
Length += nread;
if(Length >= BUFSIZE)
{
printf("######Length<%d> is too long.\n", Length);
return -1;
}
//printf("nread is %d...\n", nread);
pch += nread;
}
}
else
{
//memcpy(cMsg,buff,Length);
printf("Uart msg is :\n");
printf("%s\n", buff);
//printf("\n");
memset(buff, 0, BUFSIZE);
pch = buff;
Length = 0;
tv.tv_sec=3;
tv.tv_usec=0;
//sleep(1);
}
}
tcsetattr(fd, TCSANOW, &oldtio);
close(fd);
}
WriteUart.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
//serial port set function
void setTermios(struct termios *pNewtio, unsigned short uBaudRate)
{
bzero(pNewtio,sizeof(struct termios));
pNewtio->c_cflag = uBaudRate|CS8|CREAD|CLOCAL;
pNewtio->c_iflag = IGNPAR;
pNewtio->c_oflag = 0;
pNewtio->c_lflag = 0;
pNewtio->c_cc[VINTR] = 0;
pNewtio->c_cc[VQUIT] = 0;
pNewtio->c_cc[VERASE] = 0;
pNewtio->c_cc[VKILL] = 0;
pNewtio->c_cc[VEOF] = 4;
pNewtio->c_cc[VTIME] = 5;
pNewtio->c_cc[VMIN] = 0;
pNewtio->c_cc[VSWTC] = 0;
pNewtio->c_cc[VSTART] = 0;
pNewtio->c_cc[VSTOP] = 0;
pNewtio->c_cc[VSUSP] = 0;
pNewtio->c_cc[VEOL] = 0;
pNewtio->c_cc[VREPRINT] = 0;
pNewtio->c_cc[VDISCARD] = 0;
pNewtio->c_cc[VWERASE] = 0;
pNewtio->c_cc[VLNEXT] = 0;
pNewtio->c_cc[VEOL2] = 0;
}
int main(int argc,char **argv)
{
int fd;
int nCount = 0, ulen = 0, nTotal = 0;
int i,j,m;
int ReadByte = 0;
char Buffer[512];
struct termios oldtio,newtio;
char *dev = (char*)"/dev/ttyO1";
if((argc!=3)||(sscanf(argv[1],"%d",&nTotal)!=1))
{
printf("Usage:COMSend count datat! ");
return -1;
}
if((fd=open(dev,O_RDWR|O_NOCTTY|O_NDELAY))<0) //open serial COM2
{
printf("Can't open serial port! ");
return -1;
}
tcgetattr(fd,&oldtio);
setTermios(&newtio,B115200); // B9600
//setTermios(&newtio,B57600);
tcflush(fd,TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
//Send data
for(i=0;i<nTotal;i++)
{
nCount = write(fd,argv[2],strlen(argv[2]));
ulen = write(fd, "\r\n",2);
printf("send data OK!count=%d, nTotal=%d, ulen=%d.\n",nCount, nTotal, ulen);
//tcflush(fd,TCIFLUSH);
//tcsetattr(fd,TCSANOW,&newtio);
usleep(500000);
}
/*
//receive data
for(j=0;j<20;j++)
{
ReadByte = read(fd,Buffer,512);
if(ReadByte>0)
{
printf("readlength=%d ",ReadByte);
Buffer[ReadByte]='\0';
printf("%s ",Buffer);
sleep(3);
}
else printf("Read data failure times=%d ",j);
}
printf("Receive data finished! ");
tcsetattr(fd,TCSANOW,&oldtio);
*/
close(fd);
return 0;
}