1.簡介

串行端口是實際操作中常用的接口,如Linux使用的debug串行端口。這用于登錄到Linux系統(tǒng)并輸出log。您還可以使用串行端口與外部模塊(如GPS模塊、RS485等)通信。Linux下串行端口使用摘要。希望對大家有幫助。

2.環(huán)境介紹

2.1。硬件

1) NUC972開發(fā)版:

這次需要控制主板背板上的DB9串行端口。

對應(yīng)于NUC972上的PE3和PE2針腳。

2)2條USB到RS232線路,1條debug串行端口UART0用于主板連接,1條串行端口UART1用于主板連接。

2.2。軟件

1)基于之前的《Linux學(xué)習(xí)系列六:操作GPIO》,Linux內(nèi)核配置發(fā)生了變化,生成了新的970uimage,并記錄在主板上。

2) uboot,rootfs使用主板內(nèi)的默認(rèn)值,為了增加micorcom命令,必須使用busybox生成,然后通過USB磁盤導(dǎo)入主板。Busybox特定使用參考《Linux學(xué)習(xí)系列五:Nand Flash根文件系統(tǒng)制作》

3)交叉工具鏈arm_linux_4.8。

3.Busybox生成microcom命令

Microcom命令類似于windows的串行調(diào)試助手,在調(diào)試串行端口時非常有用。默認(rèn)情況下,主板不支持,因此必須使用busybox創(chuàng)建。

1)busybox的使用被遺忘的情況下,請參考《Linux 學(xué)習(xí)系列五:Nand Flash 根文件系統(tǒng)制作》中的詳細(xì)介紹,首先刪除原始~/nuc972/rootfs目錄的內(nèi)容

2)進(jìn)入busybox目錄make menuconfig,輸入/,然后搜索microcom以查找配置的位置

然后進(jìn)入該位置并選擇microcom。

3)編譯make,安裝make install,然后壓縮以生成roo

4)通過u盤進(jìn)入板子,放入根目錄解壓,板子可以支持microcom命令。

4.內(nèi)核配置

1)要使用UART1,內(nèi)核必須配置如下:

Device Drivers -

Character devices -

Serial drivers

[*] nuc970/n9h30uart1支持

保存新的。創(chuàng)建config文件。

2)make uImage,生成新的970uimage文件,單獨下載到主板上即可。

5.UART操作

5.1。命令行操作

我們同時將主板上的兩個串行端口與PC連接起來,通過debug串行端口登錄Linux系統(tǒng),操作UART1,在PC端打開串行調(diào)試助手,選擇UART1對應(yīng)的串行端口,以便通過UART1發(fā)送和接收PC和數(shù)據(jù)。

登錄板

子后,輸入下面指令:

microcom -s 115200 /dev/ttyS1

/dev下的ttyS1對應(yīng)的就是UART1設(shè)備。

microcom 命令后的-s 115200,表示設(shè)置波特率為115200bps。

如果你想了解microcom的詳細(xì)實現(xiàn)機(jī)制,可以到busybox的目錄\miscutils查看microcom.c源代碼即可。

輸入上述命令后,當(dāng)此串口收到數(shù)據(jù)后,就會自動在窗口中顯示出來,如果鍵盤輸入字符,就會自動通過此串口發(fā)送出去。我們可以雙向收發(fā)測試。

注意:

1) micrcom指令退出的方式是Ctrl+x,不是Ctrl+c,如果輸入Ctrl+c,它其實是發(fā)送了0x03字符。

2) 有些工程師喜歡用cat 指令去查看串口就沒有收到數(shù),其實這是不對的,我們做下面這個測試,為了方便起見,我們讓PC端1s一次定時發(fā)送

使用micrcom的話,

microcom -s 115200 /dev/ttyS1

會看到在不斷的接收數(shù)據(jù)

我們Ctrl+x先關(guān)掉microcom,直接輸入

cat /dev/ttyS1

會有什么結(jié)果呢?

什么都沒有收到。

所以千萬不要直接用cat去判斷串口是否有數(shù)據(jù)接收,為什么有時能收到呢,那是因為串口設(shè)備在某個地方被打開(調(diào)用了open函數(shù))了。

比如你讓microcom指令在后臺執(zhí)行

microcom -s 115200 /dev/ttyS1 &

這時再使用cat指令就可以顯示數(shù)據(jù)了。

5.2.C語言串口編程

我們看下在C代碼里如何操作串口,下面是一個例子:

//-------------------------------------------------- // Copyright (c) Topsemic //-------------------------------------------------- #include <; #include <; #include <uni; #include <; #include <asm; #include <memory.h> #define DEV_NAME "/dev/ttyS1" int main (int argc, char *argv[]) { int fd; int len, i,ret; char buf[] = "Hello TopSemic! \n"; fd = open(DEV_NAME, O_RDWR | O_NOCTTY); if(fd < 0) { perror(DEV_NAME); return -1; } len = write(fd, buf, sizeof(buf)); if (len < 0) { printf("write data error \n"); } memset(buf,0x00,sizeof(buf)); len = read(fd, buf, sizeof(buf)); if (len < 0) { printf("read error \n"); return -1; } printf("%s", buf); return(0); }

將它編譯后放到板子里,注意上述代碼沒有設(shè)置串口波特率,默認(rèn)值是9600,需要在串口調(diào)試助手中正確配置,運(yùn)行一下我們先看看效果:

交叉驗證下,我們把UART1的波特率設(shè)置為115200后,結(jié)果如下,可以看到是無法正確接收到數(shù)據(jù)的。

上述程序工作過程是串口先發(fā)送一串?dāng)?shù)據(jù),然后一直停在read函數(shù)處不動,直到接收到數(shù)據(jù)后返回退出。此時串口工作在阻塞模式下。所謂阻塞和非阻塞的含義如下:

阻塞:

對于read,指當(dāng)串口輸入緩存區(qū)沒有數(shù)據(jù)的時候,read函數(shù)將會阻塞在這里,直到串口輸入緩存區(qū)中有數(shù)據(jù)可讀取,read讀到了需要的字節(jié)數(shù)之后,返回值為讀到的字節(jié)數(shù);

對于write,指當(dāng)串口輸出緩沖區(qū)滿,或剩下的空間小于將要寫入的字節(jié)數(shù),則write將阻塞,一直到串口輸出緩沖區(qū)中剩下的空間大于等于將要寫入的字節(jié)數(shù),執(zhí)行寫入操作,返回寫入的字節(jié)數(shù)。

非阻塞:

對于read,指當(dāng)串口輸入緩沖區(qū)沒有數(shù)據(jù)的時候,read函數(shù)立即返回,返回值為-1。

對于write,指當(dāng)串口輸出緩沖區(qū)滿,或剩下的空間小于將要寫入的字節(jié)數(shù),則write將進(jìn)行寫操作,寫入當(dāng)前串口輸出緩沖區(qū)剩下空間允許的字節(jié)數(shù),然后返回寫入的字節(jié)數(shù)。

在打開串口文件時,打開模式加上O_NDELAY可以以非阻塞方式打開串口;反之,不加上O_NDEAY,默認(rèn)以阻塞方式打開串口。上述第一例子中沒有加O_NDEAY標(biāo)志,所以工作在阻塞模式下,下面再看個例子,我們加上O_NDEAY

#include <; #include <; #include <uni; #include <; #include <asm; #include <memory.h> #define DEV_NAME "/dev/ttyS1" int main (int argc, char *argv[]) { int fd; int len, i,ret; char buf[] = "Hello TopSemic! \n"; fd = open(DEV_NAME, O_RDWR | O_NOCTTY|O_NDELAY); if(fd < 0) { perror(DEV_NAME); return -1; } len = write(fd, buf, sizeof(buf)); if (len < 0) { printf("write data error \n"); } while(1) { memset(buf,0x00,sizeof(buf)); len = read(fd, buf, sizeof(buf)); printf("len:%d \n",len); if(len>0) printf("%s", buf); usleep(100000); } }

這時程序運(yùn)行結(jié)果如下,在串口接收不到數(shù)據(jù)時,read函數(shù)立即返回,返回值是-1,當(dāng)接收到數(shù)據(jù)后,返回值是接收到數(shù)據(jù)值長度。

大家可能注意到,上述代碼沒有關(guān)于串口的參數(shù)配置,比如波特率、校驗位、數(shù)據(jù)位、停止位的設(shè)置,實際應(yīng)用中很可能是要修改這些參數(shù)的,最常見的就是修改波特率,下面例子在上面的基礎(chǔ)上修改如下:

#include <; #include <; #include <uni; #include <; #include <asm; #include <memory.h> #include <; #define DEV_NAME "/dev/ttyS1" static struct termios newtios,oldtios; /*termianal settings */ static int saved_portfd=-1; /*serial port fd */ static void reset_tty_atexit(void) { if(saved_portfd != -1) { tcsetattr(saved_portfd,TCSANOW,&oldtios); } } /*cheanup signal handler */ static void reset_tty_handler(int signal) { if(saved_portfd != -1) { tcsetattr(saved_portfd,TCSANOW,&oldtios); } _exit(EXIT_FAILURE); } static set_port_attr (int portfd,int baudrate) { struct sigaction sa; /*get serial port parnms,save away */ tcgetattr(portfd,&newtios); memcpy(&oldtios,&newtios,sizeof newtios); /* configure new values */ cfmakeraw(&newtios); /*see man page */ new |=IGNPAR; /*ignore parity on input */ new &= ~(OPOST | ONLCR | OLCUC | OCRNL | ONOCR | ONLRET | OFILL); new[VMIN]=1; /* block until 1 char received */ new[VTIME]=0; /*no inter-character timer */ switch(baudrate) { case 9600: cfsetispeed(&newtios,B9600); cfsetospeed(&newtios,B9600); break; case 19200: cfsetispeed(&newtios,B19200); cfsetospeed(&newtios,B19200); break; case 38400: cfsetispeed(&newtios,B38400); cfsetospeed(&newtios,B38400); break; case 115200: cfsetispeed(&newtios,B115200); cfsetospeed(&newtios,B115200); break; } /* register cleanup stuff */ atexit(reset_tty_atexit); memset(&sa,0,sizeof sa); = reset_tty_handler; sigaction(SIGHUP,&sa,NULL); sigaction(SIGINT,&sa,NULL); sigaction(SIGPIPE,&sa,NULL); sigaction(SIGTERM,&sa,NULL); /*apply modified termios */ saved_portfd=portfd; tcflush(portfd,TCIFLUSH); tcsetattr(portfd,TCSADRAIN,&newtios); return portfd; } int main (int argc, char *argv[]) { int fd; int len, i,ret; char buf[] = "Hello TopSemic! \n"; fd = open(DEV_NAME, O_RDWR | O_NOCTTY|O_NDELAY); if(fd < 0) { perror(DEV_NAME); return -1; } set_port_attr (fd,115200); len = write(fd, buf, sizeof(buf)); if (len < 0) { printf("write data error \n"); } while(1) { memset(buf,0x00,sizeof(buf)); len = read(fd, buf, sizeof(buf)); printf("len:%d \n",len); if(len>0) printf("%s", buf); usleep(100000); } return 0; }

這時我們把波特率修改為115200了,大家可以驗證下,只有把uart1對應(yīng)串口波特率設(shè)置為115200時才可以正確收發(fā)。

6.結(jié)束語

本篇為大家介紹了Linux下UART的使用,如果實現(xiàn)收發(fā)數(shù)據(jù),如何配置波特率等參數(shù),以及如何使用microcom 命令調(diào)試等。

1.《【板子串口怎么連接電腦】嵌入式Linux系列7篇:使用串口》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識,僅代表作者本人觀點,與本網(wǎng)站無關(guān),侵刪請聯(lián)系頁腳下方聯(lián)系方式。

2.《【板子串口怎么連接電腦】嵌入式Linux系列7篇:使用串口》僅供讀者參考,本網(wǎng)站未對該內(nèi)容進(jìn)行證實,對其原創(chuàng)性、真實性、完整性、及時性不作任何保證。

3.文章轉(zhuǎn)載時請保留本站內(nèi)容來源地址,http://f99ss.com/why/2993958.html