Android UART串口通訊總結

  • UART串口通訊概念
  • 數據結構
  • termios做用與設置
  • linux下的open/close/read/write 函數使用

UART串口通訊概念

通用異步收發傳輸器(Universal Asynchronous Receiver/Transmitter),一般稱做UART,是一種異步收發傳輸器,UART做爲異步串口通訊協議的一種,工做原理是將傳輸數據的每一個字符一位接一位地傳輸。linux

數據結構

起始位 (邏輯0):表示傳輸字符的開始ios

數據位 :數據位的個數能夠設置爲4,5,6,7,8,構成一個字符。web

奇偶校驗位: 數據位加上奇偶校驗位後,邏輯「1」的數量爲偶數則爲偶校驗。爲奇數則爲奇校驗。在串口通訊中一種簡單的檢錯方式。有四種檢錯方式:偶、奇、高和低。固然沒有校驗位也是能夠的。對於偶和奇校驗的狀況,串口會設置校驗位(數據位後面的一位),用一個值確保傳輸的數據有偶個或者奇個邏輯高位。例如,若是數據是011,那麼對於偶校驗,校驗位爲0,保證邏輯高的位數是偶數個。若是是奇校驗,校驗位爲1,這樣就有3個邏輯高位。高位和低位不是真正的檢查數據,簡單置位邏輯高或者邏輯低校驗。這樣使得接收設備可以知道一個位的狀態,有機會判斷是否有噪聲干擾了通訊或者是否傳輸和接收數據是否不一樣步。數據結構

中止位:它是一幀數據的結束標誌。用於表示單個包的最後一位。典型的值爲1,1.5和2位。因爲數據是在傳輸線上定時的,而且每個設備有其本身的時鐘,極可能在通訊中兩臺設備間出現了小小的不一樣步。所以中止位不單單是表示傳輸的結束,而且提供計算機校訂時鐘同步的機會。適用於中止位的位數越多,不一樣時鐘同步的容忍程度越大,可是數據傳輸率同時也越慢。異步

空閒位:沒有數據傳輸時,爲邏輯「1「svg

傳輸方向:數據從高位(msb)開始傳輸仍是從低位(lsb)開始傳輸函數

這裏寫圖片描述

termios做用與設置

函數描述了用於控制異步通訊端口的通用終端接口。參見Linux API termios描述ui

引用頭文件 spa

#include "termios.h"

結構體:3d

struct termios{
    unsigned short c_iflag;   /* 輸入模式標誌*/
    unsigned short c_oflag;   /* 輸出模式標誌*/
    unsigned short c_cflag;   /* 控制模式標誌*/
    unsigned short c_lflag;   /* 區域模式標誌或本地模式標誌或局部模式*/
    unsigned char  c_line;    /* 行控制line discipline */
    unsigned char  c_cc[NCCS]; /* 控制字符特性*/
};

c_iflag : 控制終端輸入方式

參數 參數說明
IGNBRK 忽略BREAK鍵輸入
BRKINT 若是設置了IGNBRK,BREAK鍵輸入將被忽略
IGNPAR 忽略奇偶校驗錯誤
PARMRK 標識奇偶校驗錯誤
INPCK 容許輸入奇偶校驗
ISTRIP 去除字符的第8個比特
INLCR 將輸入的NL(換行)轉換成CR(回車)
IGNCR 忽略輸入的回車
ICRNL 將輸入的回車轉化成換行(若是IGNCR未設置的狀況下)
IUCLC 將輸入的大寫字符轉換成小寫字符(非POSIX)
IXON 容許輸入時對XON/XOFF流進行控制
IXANY 輸入任何字符將重啓中止的輸出
IXOFF 容許輸入時對XON/XOFF流進行控制
IMAXBEL 當輸入隊列滿的時候開始響鈴
IUTF9 當輸入是UTF8時,可以容許字符擦除在加工模式下正確執行

c_oflag:輸出模式標誌,控制終端輸出方式

參數 參數說明
OPOST 處理後輸出
OLCUC 將輸入的小寫字符轉換成大寫字符(非POSIX)
ONLCR 將輸入的NL(換行)轉換成CR(回車)及NL(換行)
OCRNL 將輸入的CR(回車)轉換成NL(換行)
ONOCR 第一行不輸出回車符
ONLRET 不輸出回車符
OFILL 發送填充字符以延遲終端輸出
OFDEL 以ASCII碼的DEL做爲填充字符,若是未設置該參數,填充字符爲NUL
NLDLY 換行輸出延時,能夠取NL0(不延遲)或NL1(延遲0.1s)
CRDLY 回車延遲,取值範圍爲:CR0、CR一、CR2和 CR3
TABDLY 水平製表符輸出延遲,取值範圍爲:TAB0、TAB一、TAB2和TAB3
BSDLY 空格輸出延遲,能夠取BS0或BS1
VTDLY 垂直製表符輸出延遲,能夠取VT0或VT1
FFDLY 換頁延遲,能夠取FF0或FF1

c_cflag:控制模式標誌,指定終端硬件控制信息

參數 參數說明
CBAUD 波特率(4+1位)(非POSIX)
CBAUDEX 附加波特率(1位)(非POSIX)
CSIZE 數據位長度,取值範圍爲CS五、CS六、CS7或CS8
CSTOPB 設置兩個中止位
CREAD 使用接收器
PARENB 使用奇偶校驗
PARODD 對輸入使用奇偶校驗,對輸出使用偶校驗
HUPCL 關閉設備時掛起
CLOCAL 忽略調制解調器線路狀態
CRTSCTS 使用RTS/CTS流控制

c_lflag:本地模式標誌,控制終端編輯功能

參數 參數說明
ISIG 當輸入INTR、QUIT、SUSP或DSUSP時,產生相應的信號
ICANON 使用標準輸入模式
XCASE 在ICANON和XCASE同時設置的狀況下,終端只使用大寫。
ECHO 顯示輸入字符
ECHOE 若是ICANON同時設置,ERASE將刪除輸入的字符
ECHOK 若是ICANON同時設置,KILL將刪除當前行
ECHONL 若是ICANON同時設置,即便ECHO沒有設置依然顯示換行符
ECHOPRT 若是ECHO和ICANON同時設置,將刪除打印出的字符(非POSIX)
TOSTOP 向後臺輸出發送SIGTTOU信號

c_cc[NCCS]:控制字符,用於保存終端驅動程序中的特殊字符,如輸入結束符等

NCCS 參數說明
VINTR Interrupt字符
VEOL 附加的End-of-file字符
VQUIT Quit字符
VTIME 非規範模式讀取時的超時時間
VERASE Erase字符
VSTOP Stop字符
VKILL Kill字符
VSTART Start字符
VEOF End-of-file字符
VSUSP Suspend字符
VMIN 非規範模式讀取時的最小字符數

注意:控制符VTIME和VMIN之間有複雜的關係。VTIME定義要求等待的時間(百毫米,一般是unsigned char變量),而VMIN定義了要求等待的最小字節數(相比之下,read函數的第三個參數指定了要求讀的最大字節數)。
若是VTIME=0,VMIN=要求等待讀取的最小字節數,read必須在讀取了VMIN個字節的數據或者收到一個信號纔會返回。
若是VTIME=時間量,VMIN=0,無論可否讀取到數據,read也要等待VTIME的時間量。
若是VTIME=時間量,VMIN=要求等待讀取的最小字節數,那麼將從read讀取第一個字節的數據時開始計時,並會在讀取到VMIN個字節或者VTIME時間後返回。
若是VTIME=0,VMIN=0,無論可否讀取到數據,read都會當即返回
​ ​
tcsetattr函數用於設置終端的相關參數。

int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);

參數fd爲打開的終端文件描述符
參數optional_actions用於控制修改起做用的時間,而結構體termios_p中保存了要修改的參數optional_actions能夠取以下的值:

參數 參數說明
TCSANOW 不等數據傳輸完畢就當即改變屬性。
TCSADRAIN 等待全部數據傳輸結束才改變屬性。
TCSAFLUSH 清空輸入輸出緩衝區才改變屬性。
返回值 參數說明
EBADF 非法的文件描述符。
EINTR tcsetattr函數調用被信號中斷。
EINVAL 參數optional_actions使用了非法值,或參數termios中使用了非法值。
ENCTTY 非終端的文件描述符。

tcgetattr獲取與fd終端關聯的termios

int tcgetattr(int fd, struct termios *termios_p);

tcsetattr從新設置與fd終端關聯的termios

int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);

設置波特率

int cfsetispeed(struct termios *termios_p, speed_t speed); //輸入波特率
int cfsetospeed(struct termios *termios_p, speed_t speed); //輸出波特率

常見配置:
8位數據位、無校驗位:
c_cflag &= ~PARENB;
c_cflag &= ~CSTOPB;
c_cflag &= ~CSIZE;
c_cflag |= CS8;

7位數據位、奇校驗:
c_cflag |= PARENB;
c_cflag |= PARODD;
c_cflag &= ~CSTOPB;
c_cflag &= ~CSIZE;
c_cflag |= CS7;

7位數據位、偶校驗:
c_cflag |= PARENB;
c_cflag &= ~PARODD;
c_cflag &= ~CSTOPB;
c_cflag &= ~CSIZE;
c_cflag |= CS7;

7位數據位、Space校驗:
c_cflag &= ~PARENB;
c_cflag &= ~CSTOPB;
c_cflag &= ~CSIZE;
c_cflag |= CS7;

//8位數據位,無校驗位,波特率115200
char *path = "/dev/ttyHSL1"
termios termios_p;
int fd = open(path, O_RDWR | O_NOCTTY);
tcflush(fd, TCIOFLUSH);
tcgetattr(fd, &termios_p);
termios_p.c_cflag &= ~PARENB;
termios_p.c_cflag &= ~CSTOPB;
termios_p.c_cflag &= ~CSIZE;
termios_p.c_cflag |= CS8;
cfsetispeed(&termios_p, B115200);
cfsetospeed(&termios_p, B115200);
tcsetattr(fd, &termios_p);

linux下的open/close/read/write 函數使用

#include <sys/stat.h> 
#include <fcntl.h> 
int open(const char *path, int oflag, ... ); 

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

#include <unistd.h> 
ssize_t write(int fd, const void *buf, size_t count);   

#include <unistd.h>
int close(int fd);

一個簡單的應用文本讀寫:

#include <stdio.h>
#include <string>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
using namespace std;

struct {
   int fd;
} global_v;

void open_t();
void read_t();
void write_t();
void close_t();

int main(){
   open_t();
   write_t();
   read_t();
   close_t();
   return 0;
}

void open_t(){
    char *file_path = "D:/log.txt";
    int fd = open(file_path, O_RDWR | O_APPEND);
    if(fd > 0){
        global_v.fd = fd;
    }
}

void read_t(){
    if(global_v.fd < 0){
        return;
    }

    int ret = -1;
    char buf[256];
    printf("read_t len = %d\n", sizeof(buf));
    while((ret = read(global_v.fd, &buf, sizeof(buf))) > 0){
        for(int i = 0; i < ret; i ++){
            printf("%c ", buf[i]);
        }
    }
}

void write_t(){
    if(global_v.fd < 0){
        return;
    }

    char *write_buf = "testbuf\n";
    int ret = write(global_v.fd, write_buf, strlen(write_buf));
    printf("write = %d\n", ret); 
}

void close_t(){
    if(global_v.fd < 0){
        return;
    }
    close(global_v.fd);
}