本次採用的是125k的rfid讀卡器和標籤,很容易理解的,其實就是一張卡片裡面存了一串數字(這個問題有點像你問乙個藝術家洛必達法則是啥
咦洛必達是啥),然後有個讀卡器,當你把卡片放到讀卡器上時,讀卡器會將卡裡面存的卡號讀取出來,然後放到串列埠傳送緩衝區,等待我們去讀取,那麼問題就是怎麼讀取。
大家都知道。linux下面一切皆檔案,裝置也不例外,上面提到的串列埠就是個裝置檔案,linux裝置檔案一般存放在「/dev/」下,當你ls的時候會發現一大堆什麼ttys0、sda、video....現在筆記本串列埠裝置檔案一般都是ttyusbx(x=0,1,2...)。既然是檔案,那就能開啟嘍,不過它不是被「右鍵->開啟」,而是被「系統呼叫open()」。當然不只是把它開啟就完了,操作串列埠有一系列的系統呼叫。說到系統呼叫,其實就是系統底層給在上層編寫程式的你提供的一些系統級函式。
一些需要的標頭檔案:
[cpp]view plain
copy
#include /*linux系統呼叫*/
#include
#include
#include
#include /*檔案控制*/
#include /*檔案狀態*/
#include /*定義系統型別,像size_t等*/
#include /*出錯碼*/
#include /*終端引數*/
1.開啟串列埠
這裡把open()這個系統呼叫封裝成乙個com_open()函式,可以方便判斷是否開啟成功並列印錯誤資訊。
引數*dev是檔案路徑(上面提到的/dev/ttyusbx),第二個引數告訴它是以什麼方式開啟,常見的有:
o_rdonly 唯讀
o_wronly 只寫
o_rdwr 讀寫
注:上面的三個不能同時出現,即不能這樣寫o_rdonly | o_rdwr,像下面這些是可選的:
o_noctty 如果路徑名指向終端裝置,不要把這個裝置用作控制終端。
o_nonblock 阻塞模式(詳見配置串列埠處)
open()返回值是int型fd檔案描述符,const char *dev)
2.配置串列埠
設定串列埠屬性(類似於約定好雙方通訊協議),即上面提到的配置串列埠,其實主要就是設定termios.h中的termios結構體引數:
[cpp]view plain
copy
typedef struct com_attr /*我自己定義的串列埠屬性結構*/
com_attr;
[cpp]view plain
copy
struct termios /*termios結構,其實終極目的就是把我們自己定義的結構屬性設定到這裡面去*/
可以看到兩個引數,第乙個檔案描述符,告訴它你想在個檔案操作,第二個是我定義的串列埠屬性結構體:
注:由於專案需要,可能有些不必要的引數我就沒有去設定和解釋,詳細可以google一下配置串列埠屬性結構體詳細介紹!
[cpp]view plain
copy
int set_com_attr(int fd, com_attr *attr)
/************************校驗位************************/
switch (attr->parity)
opt.c_cflag &= ~csize; /*無論設定多少校驗位都需要的*/
/*******************資料位*****************/
switch (attr->databits)
opt.c_cflag &= ~cstopb;
/*******************停止位***************/
switch (attr->stopbits)
/*等待時間,阻塞模式下設定的*/
= 0; /*設定超時時間*/
= 1;
opt.c_iflag &= ~(icrnl | inlcr);
opt.c_iflag &= ~(ixon | ixoff | ixany);/*關閉軟體流控(一般都是關閉軟硬流控,我也不知道為啥)*/
tcflush(fd, tcioflush); //刷清緩衝區
if (tcsetattr(fd, tcsanow, &opt)
return true;
} 當以阻塞模式開啟時也可以通過修改結構體termios來改變位非阻塞模式或者通過函式fcntl()函式:
阻塞:fcntl(fd, f_setfl, 0)
對於read,阻塞指當串列埠輸入緩衝區沒有資料的時候,read函式將會阻塞在這裡,直到串列埠輸入緩衝區中有資料可讀取時read讀到了需要的位元組數之後,返回值為讀到的位元組數;對於write,指當串列埠輸出緩衝區滿或剩下的空間小於將要寫入的位元組數,write函式將阻塞在這裡,一直到串列埠輸出緩衝區中剩下的空間大於等於將要寫入的位元組數,執行寫入操作,返回寫入的位元組數。
注:控制符vtime定義要等待的時間t(百毫秒),vmin定義了要等待的最小位元組數n,以下幾種情況:
vtime=0,vmin=n,read必須在讀取了vmin個位元組的資料或者收到乙個訊號才會返回。
vtime=t,vmin=0,不管能否讀取到資料,read也要等待vtime的時間量。
vtime=t,vmin=n,那麼將從read讀取第乙個位元組的資料時開始計時,並會在讀取到vmin個位元組或者vtime時間後返回。
vtime=0,vmin=0,不管能否讀取到資料,read都會立即返回。
非阻塞的定義:fcntl(fd, f_setfl,fndelay)
當串列埠輸入緩衝區沒有資料的時候,read函式立即返回,返回值為0。
[cpp]view plain
copy
void get_com_attr(int fd)
memset(&opt, 0, sizeof(struct termios));
tcgetattr(fd, &opt);
cfmakeraw(&opt);
}
有必要說一下int tcsetattr(int fd, int optional_actions, const struct termios *termios_p)
int tcgetattr(int fd, struct termios *termios_p)
tcgetattr函式用於獲取與終端相關的引數。引數fd為終端的檔案描述符,結果儲存在termios結構體中。
tcsetattr函式用於設定終端的相關引數。引數optional_actions用於控制修改起作用的時間,而結構體termios_p中儲存了要修改的引數;
optional_actions可以取如下的值:
tcsanow:不等資料傳輸完畢就立即改變屬性。
tcsadrain:等待所有資料傳輸結束才改變屬性。
tcsaflush:清空輸入輸出緩衝區才改變屬性。
3.讀取串列埠
這裡也是將read()系統呼叫封裝成com_read(),當我們設定好通訊協議了(串列埠屬性),就可以對串列埠進行讀寫了。
引數一fd就不用說了,第二個引數read_buff從名字看出就是要把資料讀到這個緩衝區中,第三個引數是你想要讀多少位元組,注意是」你想要「,而返回值則是讀到的真正位元組數,當你讀到末尾(假如緩衝區有10個位元組,而你想要讀20個)或者出現異常中斷了讀操作,就會出現返回值ret(return)
!= nbytes。
[cpp]view plain
copy
int com_read(int fd, unsigned char *read_buff, unsigned int nbytes)
ret = read(fd, read_buff, nbytes);
return ret;
} 4.寫入串列埠
道理和寫差不多
[cpp]view plain
copy
int com_write(int fd, byte *write_buff, dword nbytes)
ret = write(fd, write_buff, nbytes);
return ret;
} 5.關閉串列埠
記得每次操作完串列埠要關閉串列埠(當然了,當你操作多個檔案時可別操作錯了檔案描述符,那就gg了)
[cpp]view plain
copy
void com_close(int fd)
close(fd);
} 好了,萬事具備,下面就可以插上裝置刷卡讀卡號啦(注意看清你的裝置ttyusbx中的x是多少啊),具體讀卡號函式就看大家的具體需求啦。
由於博主的專案需求是要將卡號變成乙個字串然後再填充到另乙個字串,然後再巴拉巴拉,可是這個卡號讀出來是一串16進製制資料,所以想了半天決定用型別轉換(不過聽說可以用fprintf)。
linux下c語言 讀取檔案
linux讀取檔案要用到stdio.h檔案,在 usr include下包含大部分的c標頭檔案,sys types.h也位於其中,usr src linu 版本號 存放有你的核心源 在linux下讀檔案也是fopen 檔名 方式 方式有r,w等,下面為一段讀檔案的 cat 7 3.c 1 inclu...
Linux下讀取doc,docx檔案
docx檔案 利用python docx包 test.py coding utf 8 import sys import docx path sys.argv 1 file docx.document path for para in file.paragraphs print para.text ...
linux 下C語言實現 讀取網絡卡速度
這幾天要寫乙個監控之類東東,其中網絡卡一項要計算利用率,那就要取得網絡卡本身速度才能計算出來,本來想用perl實現,但發現網上沒有現成的東東,後來幾經輾轉,最後想起ethtool能取到,就參考了此原始碼,貼出來供大家以後有個思路吧,有時間再轉成perl的 直接編譯命令 gcc p g getnet....