打開串口
和其他的字符設備一樣的,需要先打開相關的設備節點,這次用的串口的設備節點目錄爲/dev/ttySAC3,所以,先打開設備節點並獲取文件句柄
int fd;
char *uart3 = "/dev/ttySAC3";
if((fd = open(uart3,O_CREAT|O_RDWR,0777))<0)
{
printf("open %s failed! \n",uart3);
}
else
{
printf("open %s success! \n",uart3);
}
初始化串口
串口打開之後,需要對其進行初始化,需要初始化的參數包括波特率,數據位,停止位,校驗位,流控等,串口初始化最終會將參數傳遞到內核中,在源碼的arch\arm\include\asm\termios.h頭文件裏,有一個termio結構體的定義
#define NCC 8
struct termio {
unsigned short c_iflag; /* input mode flags 輸入模式標誌*/
unsigned short c_oflag; /* output mode flags 輸出模式標誌*/
unsigned short c_cflag; /* control mode flags 控制模式標誌*/
unsigned short c_lflag; /* local mode flags 本地模式標誌*/
unsigned char c_line; /* line discipline */
unsigned char c_cc[NCC]; /* control characters */
};
函數 tcgetattr 用於讀取當前串口的參數值,在實際應用中,一般用於先確認該串口是否能夠配置,做檢測用。
函數原型爲 int tcgetattr(int fd, struct termios *termios_p)
- fd爲文件句柄
- *termios_p則爲上面的結構體
使用這個函數之前可以先定義一個結構體,用於存儲舊的參數
函數 cfsetispeed 和 cfsetospeed 用於修改串口的波特率,函數 cfgetispeed 和 cfgetospeed 可以用於獲取當前波特率。在實際應用中,這個經常需要用到,例如修改默認的波特率。
函數原型爲int cfsetispeed(struct termios *termios_p, speed_t speed)
和int cfsetospeed(struct termios *termios_p, speed_t speed)
- *termios_p則爲上面的結構體
- speed爲波特率,常用的有B2400,B4800,B9600,B115200等
- 該函數執行成功返回0,失敗返回-1。
獲取當前波特率函數speed_t cfgetispeed
函數原型speed_t cfgetispeed(const struct termios *termios_p)
和speed_t cfgetospeed(const struct termios *termios_p)
- *termios_p則爲上面的結構體
- 返回值爲speed_t
函數 tcflush
函數 tcflush 用於清空串口中沒有完成的輸入或者輸出數據。在接收或者發送數據的時候,串口寄存器會緩存數據,這個函數用於清除這些數據。
函數原型int tcflush(int fd, int queue_selector)
-
fd爲文件句柄
-
queue_selector爲控制tcflush的操作,有三個常用的值
- TCIFLUSH :清除正收到的數據,且不會讀取出來 - TCOFLUSH:清除正在寫入的數據,且不會發送至終端 - TCIOFLUSH:清除所有正在發送的I/O數據
執行成功返回 0,失敗返回-1
函數 tcsetattr
tcsetattr用於設置參數
函數原型int tcsetattr(int fd, int optional_actions,const struct termios *termios_p)
-
fd爲文件句柄
-
optional_actions 參數生效的時間
- TCSANOW:不等數據傳輸完畢就立即改變屬性 - TCSADRAIN:數據傳輸結束後才改變屬性 - TCSAFLUSH:清空緩衝區後才改變屬性
-
termios_p 在舊的參數基礎上修改後的參數
執行成功返回0,失敗返回-1
串口初始化代碼
先定義一個初始化函數
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
定義結構體newtio和oldtio
struct termios newtio, oldtio;
if(tcgetattr(fd, &oldtio) != 0) //讀取當前串口的參數值並保存到oldtio結構體中
{
perror("Setup Serial 1");
return -1;
}
將newtio結構體清0並設置標誌位c_cflag
bzero(&newtio, sizeof(newtio)); //將newtio清零
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
switch (nBits) {
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
}
switch (nEvent){
case 'O':
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'E':
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'N':
newtio.c_cflag &= ~PARENB;
break;
}
switch (nSpeed){
case 2400:
cfsetispeed(&newtio, B2400);
cfsetospeed(&newtio, B2400);
break;
case 4800:
cfsetispeed(&newtio, B4800);
cfsetospeed(&newtio, B4800);
break;
case 9600:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
case 115200:
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
break;
case 460800:
cfsetispeed(&newtio, B460800);
cfsetospeed(&newtio, B460800);
break;
default:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
}
if (nStop == 1) {
newtio.c_cflag &= ~CSTOPB;
}
else if (nStop == 2) {
newtio.c_cflag |= CSTOPB;
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 0;
tcflush(fd, TCIFLUSH);
}
配置相關參數
if((tcsetattr(fd, TCSANOW, &newtio)) != 0 ) //配置參數
{
perror("com set error\n");
return -1;
}
printf("set done\n\r");
return 0;
串口發送
串口發送與文件操作非常類似,使用write函數即可。
write中的三個參數分別爲句柄,傳輸的buffer以及傳輸的長度。
將串口參數配置整合爲一個函數,整體的結構可以顯得更清晰一些
int set_opt(int, int, int, char, int); //文件句柄,波特率,數據位,校驗位,停止位
主函數
if((fd = open(uart3, O_RDWR | O_NOCTTY | O_NDELAY))<0) //打開設備節點
{
printf("open %s failed!\n", uart3);
}
else
{
printf("open %s success\n",uart3);
set_opt(fd, 115200, 8, 'N', 1); //配置相關參數
while(i--){
wr_static = write(fd, buffer, strlen(buffer));
if(wr_static < 0)
printf("write failed\n");
else
{
printf("wr_static is %d\n", wr_static);
}
sleep(1);
}
}
串口接收
串口接收使用read函數,和發送非常相似
int fd;
int nByte;
char *uart3 = "/dev/ttySAC3";
char buffer[512]; //定義一個buffer
char *uart_out = "please input\r\n";
memset(buffer, 0, sizeof(buffer)); //清零緩衝區
if((fd = open(uart3, O_RDWR | O_NOCTTY)) < 0) //打開串口
{
printf("open %s failed \n", uart3);
}
else
{
set_opt(fd,115200,8,'N',1); //配置串口
write(fd, uart_out, strlen(uart_out)); //發送提示
while(1)
{
while((nByte = read(fd, buffer, 512))>0) //循環讀取串口發送過來的數據
{
buffer[nByte+1] = '\0';
write(fd, buffer, strlen(buffer)); //將讀到的數據發送出去
memset(buffer, 0, strlen(buffer)); //清空buffer
nByte = 0;
}
}
}