1. 程式人生 > >linux c/c++串列埠通訊

linux c/c++串列埠通訊

/*串列埠裝置無論是在工控領域,還是在嵌入式裝置領域,應用都非常廣泛。而串列埠程式設計也就顯得必不可少。
偶然的一次機會,需要使用串列埠,而且作業系統還要求是Linux,因此,趁著這次機會,綜合別人的程式碼,
進行了一次整理和封裝。具體的封裝格式為C程式碼,這樣做是為了很好的移植性,使它可以在C和C++環境下,
都可以編譯和使用。程式碼的標頭檔案如下: */

/////////////////////////////////////////////////////////////////////////////// 
//filename:stty.h 
#ifndef __STTY_H__ 
#define __STTY_H__ 

//包含標頭檔案
#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 <pthread.h> 
// 
// 串列埠裝置資訊結構 
typedef struct tty_info_t 

    int fd; // 串列埠裝置ID 
    pthread_mutex_t mt; // 執行緒同步互斥物件 
    char name[24]; // 串列埠裝置名稱,例:"/dev/ttyS0" 
    struct termios ntm; // 新的串列埠裝置選項 
    struct termios otm; // 舊的串列埠裝置選項 
} TTY_INFO; 
// 
// 串列埠操作函式 
TTY_INFO *readyTTY(int id); 
int setTTYSpeed(TTY_INFO *ptty, int speed); 
int setTTYParity(TTY_INFO *ptty,int databits,int parity,int stopbits); 
int cleanTTY(TTY_INFO *ptty); 
int sendnTTY(TTY_INFO *ptty,char *pbuf,int size); 
int recvnTTY(TTY_INFO *ptty,char *pbuf,int size); 
int lockTTY(TTY_INFO *ptty); 
int unlockTTY(TTY_INFO *ptty); 

#endif 


/*從標頭檔案中的函式定義不難看出,函式的功能,使用過程如下: 
(1) 開啟串列埠裝置,呼叫函式setTTYSpeed(); 
(2) 設定串列埠讀寫的波特率,呼叫函式setTTYSpeed(); 
(3) 設定串列埠的屬性,包括停止位、校驗位、資料位等,呼叫函式setTTYParity(); 
(4) 向串列埠寫入資料,呼叫函式sendnTTY(); 
(5) 從串列埠讀出資料,呼叫函式recvnTTY(); 
(6) 操作完成後,需要呼叫函式cleanTTY()來釋放申請的串列埠資訊介面; 
其中,lockTTY()和unlockTTY()是為了能夠在多執行緒中使用。在讀寫操作的前後,需要鎖定和釋放串列埠資源。 
具體的使用方法,在程式碼實現的原檔案中,main()函式中進行了演示。下面就是原始碼檔案: */

//////////////////////////////////////////////////////////////////////////////// 
//stty.c 

#include <stdio.h> 
#include <sys/ioctl.h> 
#include "stty.h" 

/////////////////////////////////////////////////////////////////////////////// 
// 初始化串列埠裝置並進行原有設定的儲存 
TTY_INFO *readyTTY(int id) 

    TTY_INFO *ptty; 
    
    ptty = (TTY_INFO *)malloc(sizeof(TTY_INFO)); 
    if(ptty == NULL) 
        return NULL; 
    memset(ptty,0,sizeof(TTY_INFO)); 
    pthread_mutex_init(&ptty->mt,NULL); 
    sprintf(ptty->name,"/dev/ttyS%d",id); 
    // 
    // 開啟並且設定串列埠 
    ptty->fd = open(ptty->name, O_RDWR | O_NOCTTY |O_NDELAY); 
    if (ptty->fd <0) 
    { 
        free(ptty); 
        return NULL; 
    } 
    // 
    // 取得並且儲存原來的設定 
    tcgetattr(ptty->fd,&ptty->otm); 
    return ptty; 

/////////////////////////////////////////////////////////////////////////////// 
// 清理串列埠裝置資源 
int cleanTTY(TTY_INFO *ptty) 

    // 
    // 關閉開啟的串列埠裝置 
    if(ptty->fd>0) 
    { 
        tcsetattr(ptty->fd,TCSANOW,&ptty->otm); 
        close(ptty->fd); 
        ptty->fd = -1; 
        free(ptty); 
        ptty = NULL; 
    } 
    
    return 0; 


/////////////////////////////////////////////////////////////////////////////// 
// 設定串列埠通訊速率 
// ptty 引數型別(TTY_INFO *),已經初始化的串列埠裝置資訊結構指標 
// speed 引數型別(int),用來設定串列埠的波特率 
// return 返回值型別(int),函式執行成功返回零值,否則返回大於零的值 
/////////////////////////////////////////////////////////////////////////////// 
int setTTYSpeed(TTY_INFO *ptty, int speed) 

    int i; 
    // 
    // 進行新的串列埠設定,資料位為8位 
    bzero(&ptty->ntm, sizeof(ptty->ntm)); 
    tcgetattr(ptty->fd,&ptty->ntm); 
    ptty->ntm.c_cflag = /*CS8 |*/ CLOCAL | CREAD; 
    
    switch(speed) 
    { 
    case 300: 
        ptty->ntm.c_cflag |= B300; 
        break; 
    case 1200: 
        ptty->ntm.c_cflag |= B1200; 
        break; 
    case 2400: 
        ptty->ntm.c_cflag |= B2400; 
        break; 
    case 4800: 
        ptty->ntm.c_cflag |= B4800; 
        break; 
    case 9600: 
        ptty->ntm.c_cflag |= B9600; 
        break; 
    case 19200: 
        ptty->ntm.c_cflag |= B19200; 
        break; 
    case 38400: 
        ptty->ntm.c_cflag |= B38400; 
        break; 
    case 115200: 
        ptty->ntm.c_cflag |= B115200; 
        break; 
    } 
    ptty->ntm.c_iflag = IGNPAR; 
    ptty->ntm.c_oflag = 0; 
    // 
    // 
    tcflush(ptty->fd, TCIFLUSH); 
    tcsetattr(ptty->fd,TCSANOW,&ptty->ntm); 
    // 
    // 
    return 0; 

// 設定串列埠資料位,停止位和效驗位 
// ptty 引數型別(TTY_INFO *),已經初始化的串列埠裝置資訊結構指標 
// databits 引數型別(int), 資料位,取值為7或者8 
// stopbits 引數型別(int),停止位,取值為1或者2 
// parity 引數型別(int),效驗型別 取值為N,E,O,,S 
// return 返回值型別(int),函式執行成功返回零值,否則返回大於零的值 
/////////////////////////////////////////////////////////////////////////////// 
int setTTYParity(TTY_INFO *ptty,int databits,int parity,int stopbits) 

    // 
    // 取得串列埠設定 
    if( tcgetattr(ptty->fd,&ptty->ntm) != 0) 
    { 
        printf("SetupSerial [%s]\n",ptty->name); 
        return 1; 
    } 
    
    bzero(&ptty->ntm, sizeof(ptty->ntm)); 
    ptty->ntm.c_cflag = CS8 | CLOCAL | CREAD; 
    ptty->ntm.c_iflag = IGNPAR; 
    ptty->ntm.c_oflag = 0; 
    // 
    // 設定串列埠的各種引數 
    ptty->ntm.c_cflag &= ~CSIZE; 
    switch (databits) 
    { //設定資料位數 
    case 7: 
        ptty->ntm.c_cflag |= CS7; 
        break; 
    case 8: 
        ptty->ntm.c_cflag |= CS8; 
        break; 
    default: 
        printf("Unsupported data size\n"); 
        return 5; 
    } 
    // 
    // 
    switch (parity) 
    { // 設定奇偶校驗位數 
    case n: 
    case N: 
        ptty->ntm.c_cflag &= ~PARENB; /* Clear parity enable */ 
        ptty->ntm.c_iflag &= ~INPCK; /* Enable parity checking */ 
        break; 
    case o: 
    case O: 
        ptty->ntm.c_cflag |= (PARODD|PARENB); /* 設定為奇效驗*/ 
        ptty->ntm.c_iflag |= INPCK; /* Disnable parity checking */ 
        break; 
    case e: 
    case E: 
        ptty->ntm.c_cflag |= PARENB; /* Enable parity */ 
        ptty->ntm.c_cflag &= ~PARODD; /* 轉換為偶效驗*/ 
        ptty->ntm.c_iflag |= INPCK; /* Disnable parity checking */ 
        break; 
    case S: 
    case s: /*as no parity*/ 
        ptty->ntm.c_cflag &= ~PARENB; 
        ptty->ntm.c_cflag &= ~CSTOPB; 
        break; 
    default: 
        printf("Unsupported parity\n"); 
        return 2; 
    } 
    // 
    // 設定停止位 
    switch (stopbits) 
    { 
    case 1: 
        ptty->ntm.c_cflag &= ~CSTOPB; 
        break; 
    case 2: 
        ptty->ntm.c_cflag |= CSTOPB; 
        break; 
    default: 
        printf("Unsupported stop bits\n"); 
        return 3; 
    } 
    // 
    // 
    ptty->ntm.c_lflag = 0; 
    ptty->ntm.c_cc[VTIME] = 0; // inter-character timer unused 
    ptty->ntm.c_cc[VMIN] = 1; // blocking read until 1 chars received 
    tcflush(ptty->fd, TCIFLUSH); 
    if (tcsetattr(ptty->fd,TCSANOW,&ptty->ntm) != 0) 
    { 
        printf("SetupSerial \n"); 
        return 4; 
    } 
    
    return 0; 

int recvnTTY(TTY_INFO *ptty,char *pbuf,int size) 

    int ret,left,bytes; 
    
    left = size; 
    
    while(left>0) 
    { 
        ret = 0; 
        bytes = 0; 
        
        pthread_mutex_lock(&ptty->mt); 
        ioctl(ptty->fd, FIONREAD, &bytes); 
        if(bytes>0) 
        { 
            ret = read(ptty->fd,pbuf,left); 
        } 
        pthread_mutex_unlock(&ptty->mt); 
        if(ret >0) 
        { 
            left -= ret; 
            pbuf += ret; 
        } 
        usleep(100); 
    } 
    
    return size - left; 

int sendnTTY(TTY_INFO *ptty,char *pbuf,int size) 

    int ret,nleft; 
    char *ptmp; 
    
    ret = 0; 
    nleft = size; 
    ptmp = pbuf; 
    
    while(nleft>0) 
    { 
        pthread_mutex_lock(&ptty->mt); 
        ret = write(ptty->fd,ptmp,nleft); 
        pthread_mutex_unlock(&ptty->mt); 
        
        if(ret >0) 
        { 
            nleft -= ret; 
            ptmp += ret; 
        } 
        //usleep(100); 
    } 
    
    return size - nleft; 

int lockTTY(TTY_INFO *ptty) 

    if(ptty->fd < 0) 
    { 
        return 1; 
    } 
    
    return flock(ptty->fd,LOCK_EX); 

int unlockTTY(TTY_INFO *ptty) 

    if(ptty->fd < 0) 
    { 
        return 1; 
    } 
    
    return flock(ptty->fd,LOCK_UN); 


#ifdef LEAF_TTY_TEST 
/////////////////////////////////////////////////////////////////////////////// 
// 介面測試 
int main(int argc,char **argv) 

    TTY_INFO *ptty; 
    int nbyte,idx; 
    unsigned char cc[16]; 
    
    ptty = readyTTY(0); 
    if(ptty == NULL) 
    { 
        printf("readyTTY(0) error\n"); 
        return 1; 
    } 
    // 
    // 
    lockTTY(ptty); 
    if(setTTYSpeed(ptty,9600)>0) 
    { 
        printf("setTTYSpeed() error\n"); 
        return -1; 
    } 
    if(setTTYParity(ptty,8,N,1)>0) 
    { 
        printf("setTTYParity() error\n"); 
        return -1; 
    } 
    // 
    idx = 0; 
    while(1) 
    { 
        cc[0] = 0xFA; 
        sendnTTY(ptty,&cc[0],1); 
        nbyte = recvnTTY(ptty,cc,1); 
        printf("%d:%02X\n",idx++,cc[0]); 
    } 
    
    cleanTTY(ptty); 
    

#endif 

相關推薦

LinuxC語言串列通訊

最近在做一個GPS專案,第一部分是將開發板和GPS用串列埠通訊,接受GPS上傳來的資料。Linux下所有的裝置都是以檔案形式儲存的,串列埠也是。整個串列埠通訊的流程圖為:所用到的標頭檔案為:#include<stdio.h>#include<fcntl.h&

C++實現串列通訊上位機軟體

串列埠使用的是RS232匯流排進行通訊,通訊方式是半雙工。有兩種方式可以實現串列埠通訊,一種是通過ActiveX控制元件這種方法程式簡單,但欠靈活。第二個是可以通過呼叫Windows的API函式,本例程通過第二種方式。 一般通過四步來完成通訊(1)開啟串列埠(2)配置串列埠(3)讀寫串列埠(4)

c#的串列通訊簡單例項

---本人是一名小白,最近在做學校有關通訊的專案。在寫這份程式碼之前,查看了許多參考程式碼。如果我有說的不對的地方,還請大家指出來。 工具:串列埠助手、串列埠除錯助手、編譯器(我用的vs2017)//完整程式碼和除錯助手 在文末有連結 一、效果圖 首先給大家放一張效果圖。 二、

基於C#實現串列通訊Demo

https://www.cnblogs.com/Zed-H/p/8651882.html 1.基本概念   2.前端winForm佈局如下(僅僅為了實現功能,佈局略醜)   3.程式碼實現如下 1 nam

windows純C++實現串列通訊

點h檔案 #ifndef _WZSERIALPORT_H #define _WZSERIALPORT_H #include <iostream> using namespace std; /* 作者:歐陽偉 日期:2017-12-14 類名:WZ

ros與下位機通訊常用的c++ boost串列通訊

(執行串之前請先安裝串列埠驅動minicom) 一.首先移植c++ boost 庫: 1. 先去 Boost官網 下載最新的Boost版本, 我下載的是boost_1_63_0版本, 解壓     tar -xvf archive_name.tar.gz. 2. 進入

C#實現串列通訊

        .NET提供了SerialPort類進行串列埠通訊。 串列埠主要有以下幾個引數:  1.串列埠名稱(PortName)  2.波特率(BaudRate) 3.資料位(DataBits) 4.奇偶效應(Parity)  5.停止位(StopBits)         使用很簡單

C#中串列通訊筆記

1、設定相應的控制元件,並命名 2、開啟串列埠按鈕事件程式碼(  其中全域性變數private SerialPort ComDevice = new SerialPort();)注:SerialPort需要使用using System.IO.Ports;  private

C++編寫串列通訊程式

宣告:本部落格的內容主要是本人學習其他串列埠通訊部落格之後的總結,主要參考的部落格地址如下: 串列埠通訊一般分為同步和非同步兩種方式,本部落格主要講述非同步通訊程式的編寫,其程式設計步驟主要分為四步驟: 一、開啟串列埠  Win32系統把檔案的概念進

C#製作串列通訊助手

介面:程式碼:using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.

C# winform 串列通訊時檢測電腦可用串列並顯示

單擊同一個按鈕實現顯示“全部串列埠”和“可用串列埠”想切換 #region 全部串列埠和可用串列埠切換 private void button1_Click(object sende

linux下的串列通訊

2> 把串列埠線的一端短接(用金屬把2,3號腳連通),用萬用表測另一端的2,3號如果正常的話會有嘀嘀的短接報警聲。二、linux下串列埠的基本操作 1、串列埠的操作 1.1開啟:fd = open("/dev/ttySAC1", O_RDWR | O_NOCTTY | O_NDELAY);       

linux c/c++串列通訊

/*串列埠裝置無論是在工控領域,還是在嵌入式裝置領域,應用都非常廣泛。而串列埠程式設計也就顯得必不可少。 偶然的一次機會,需要使用串列埠,而且作業系統還要求是Linux,因此,趁著這次機會,綜合別人的程式碼, 進行了一次整理和封裝。具體的封裝格式為C程式碼,這樣做是為了很好的

Linux C開發之用modbus實現串列通訊

    想要讀取串列埠資料,modbus是一個很好用的第三方庫。該庫適用於windows和Linux,支援RTP、RTU等協議,基於Linux的開發較難一些,是我前段時間主要的研究方向。http://www.modbus.org/是modbus的主頁,有興趣的朋友可以檢視一

Linux C串列程式設計

轉自:https://blog.csdn.net/herghost/article/details/51251760   如何找到串列埠裝置號 串列埠之開啟操作 串列埠之初始化 串列埠之傳送 串列埠之接收 如何找到串列埠裝置號

C語言RL78 serial bootloader和C#語言bootloader PC端串列通訊程式

            瞭解更多關於bootloader 的C語言實現,請加我QQ: 1273623966 (驗證資訊請填 bootloader),歡迎諮詢或定製bootloader(線上升級程式)。   前段時間完成的hyperboot_rl78, 是專門為Renesas 16-bit微控制器RL78 通

C語言實現串列通訊知識點整理(四)】關於執行緒和程序

轉載:https://www.cnblogs.com/fuchongjundream/p/3829508.html 因為在外部檔案中呼叫結構體沒有用extern修飾,導致獲取不到正確的值,一直糾結線上程上。現在大概總結執行緒和程序的特點: 概念 1、程序(process) 狹義定義:

C語言實現串列通訊知識點整理(三)】串列開啟、設定資料成功後進行資料讀寫

int OpenDev(char *Dev) { int fd = open(Dev,O_RDWR | O_NOCTTY | O_NONBLOCK); if(-1 == fd) { perror("Can't Open Serial Port"); return -1;

C語言實現串列通訊知識點整理(二)】遇到的問題整理(待續....)

1.c編譯錯誤--error:stray \357 in program UTF-8編碼問題。UTF-8編碼有BOM和無BOM格式。BOM,ByteOrderMark(位元組標記順序),表明使用UTF8來進行編碼。UTF-8的BOM通常為3個位元組EF BB BF。轉換成對應的字元檢視,就是‘\

C語言實現串列通訊知識點整理(一)】執行緒、開啟串列、設定波特率、設定校驗位、互斥鎖等實現基本的通訊

  部分程式碼借鑑地址:https://blog.csdn.net/wangqingchuan92/article/details/73497354/ 謝謝! 1.建立執行緒線上程內進行串列埠之間的收發 void CREAT_pthread(void) { pthr