新聞中心
引言

UART是一種常用的串行通信接口,常用于單片機(jī)和外圍設(shè)備之間進(jìn)行數(shù)據(jù)傳輸。Linux系統(tǒng)下提供了豐富的串口通信工具和庫函數(shù),可以非常方便地進(jìn)行串口通信測試和開發(fā)。本文將介紹Linux系統(tǒng)下的UART測試程序,詳細(xì)講解其原理、實現(xiàn)和使用方法。
一、UART簡介
UART(Universal Asynchronous Receiver/Tranitter)是一個通用異步串行接口,它可以支持異步傳輸和少量同步傳輸。在UART串口通信中,數(shù)據(jù)以字節(jié)為單位通過串行通信線路進(jìn)行傳輸,通信線路包括一條單向數(shù)據(jù)線(TX)和一條單向接收線(RX),同時還有一個以上的控制線(如CTS、RTS等)。
在UART通信中,數(shù)據(jù)傳輸是以一定波特率進(jìn)行的。波特率表示傳輸速率,即單位時間內(nèi)傳輸?shù)谋忍財?shù)。例如,對于波特率為9600 bps的UART串口通信,每秒可以傳輸9600個比特(即9600/8=1200個字節(jié))的數(shù)據(jù)。波特率越高,傳輸速度越快,但是傳輸距離越短,誤碼率越高。
二、UART測試程序原理
Linux系統(tǒng)下提供了多種測試UART串口通信的工具和庫函數(shù),例如minicom、stty、termios等。這些工具和庫函數(shù)都是基于系統(tǒng)調(diào)用函數(shù)編寫的,主要目的是為了方便用戶進(jìn)行串口通信的測試和開發(fā)。而本文將介紹一種基于C語言的UART測試程序,它可以直接調(diào)用串口設(shè)備文件的讀寫函數(shù)進(jìn)行數(shù)據(jù)的收發(fā)。具體原理如下:
1. 打開串口設(shè)備文件
在Linux系統(tǒng)下,每個串口都會被表示為一個設(shè)備文件,例如/dev/ttyS0、/dev/ttyS1等。在UART測試程序中,首先需要打開指定的串口設(shè)備文件,以便后續(xù)進(jìn)行數(shù)據(jù)的讀寫。
2. 設(shè)置串口參數(shù)
在進(jìn)行串口通信時,需要設(shè)置一些參數(shù),如波特率、數(shù)據(jù)位、校驗位、停止位等。通過串口控制寄存器,可以對這些參數(shù)進(jìn)行設(shè)置。在UART測試程序中,可以通過調(diào)用tcgetattr和tcsetattr等函數(shù)設(shè)置指定的串口參數(shù)。
3. 發(fā)送數(shù)據(jù)
在UART測試程序中,可以通過調(diào)用write函數(shù)向串口發(fā)送數(shù)據(jù)。write函數(shù)會將指定的數(shù)據(jù)寫入串口設(shè)備文件,發(fā)送給外部設(shè)備。
4. 接收數(shù)據(jù)
在UART測試程序中,可以通過調(diào)用read函數(shù)從串口接收數(shù)據(jù)。read函數(shù)會從串口設(shè)備文件中讀取數(shù)據(jù),存儲到緩沖區(qū)中,供后續(xù)進(jìn)行處理。
5. 關(guān)閉串口設(shè)備文件
在串口通信完成后,需要關(guān)閉打開的串口設(shè)備文件,以便下次進(jìn)行訪問。
三、UART測試程序?qū)崿F(xiàn)
基于上述原理,可以編寫C語言程序?qū)崿F(xiàn)UART測試功能。下面給出一段完整的UART測試程序代碼:
#include
#include
#include
#include
#include
int set_interface_attribs (int fd, int speed, int parity)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
perror (“error %s from tcgetattr”);
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for miatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn’t block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
perror (“error %s from tcsetattr”);
return -1;
}
return 0;
}
void set_blocking (int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
perror (“error %s from tggetattr”);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
perror (“error %s setting term attributes”);
}
int mn()
{
char buf[256];
int fd = open(“/dev/ttyS0”, O_RDWR | O_NOCTTY | O_SYNC);
if (fd
{
perror(“error opening”);
return -1;
}
set_interface_attribs(fd, B9600, 0); // set speed to 9600 bps, 8n1 (no parity)
set_blocking(fd, 0); // set no blocking
write(fd, “hello\n”, 6); // send 6 character greeting
usleep ((6 + 25) * 100); // sleep enough to tranit the 6 plus
// receive 25: approx 100 uS per char tranit
int n = read(fd, buf, sizeof buf); // read up to 100 characters if ready to read
printf(“received %d bytes: %s\n”, n, buf);
close(fd);
return 0;
}
本段代碼中,首先通過調(diào)用open函數(shù)打開指定的串口設(shè)備文件(/dev/ttyS0),然后通過tcgetattr和tcsetattr函數(shù)設(shè)置串口參數(shù)(波特率為9600,數(shù)據(jù)位為8位,校驗位為無,停止位為1位)。通過write函數(shù)向串口發(fā)送一條數(shù)據(jù)“hello\n”,并通過read函數(shù)從串口接收數(shù)據(jù),存儲到buf緩沖區(qū)中。
在進(jìn)行編譯時,需要將此代碼保存為uart_test.c文件,并通過gcc命令進(jìn)行編譯:
$ gcc uart_test.c -o uart_test
四、UART測試程序使用方法
在Linux系統(tǒng)上,進(jìn)行UART測試時需要先連接好串口線,將串口設(shè)備連接到計算機(jī)上。然后,執(zhí)行上述編譯好的uart_test程序即可進(jìn)行測試。如果測試通過,可以在終端上看到接收到的數(shù)據(jù)。
需要注意的是,在Linux系統(tǒng)下,串口設(shè)備文件的權(quán)限可能需要進(jìn)行修改才能進(jìn)行讀寫操作。可以通過chmod命令進(jìn)行修改,例如:
$ sudo chmod 666 /dev/ttyS0
這條命令將/dev/ttyS0串口設(shè)備文件的權(quán)限設(shè)置為666,即所有用戶都有讀寫權(quán)限。
結(jié)論
相關(guān)問題拓展閱讀:
- linux下uart的文件節(jié)點(diǎn)是怎樣創(chuàng)建的
- 如何在S3C2440上linux操作系統(tǒng)下將串口的波特率提高以致921600
linux下uart的文件節(jié)點(diǎn)是怎樣創(chuàng)建的
(1)試驗?zāi)康?掌握通過文件系統(tǒng)操作UART設(shè)備的方爛槐法.
(2)在linux中,所有設(shè)備都是以文件的形式被打開并進(jìn)行讀/寫慎橘操作的,本饑孝友試驗中使用POSIX兼容的文件操作接口函數(shù)對底層設(shè)備進(jìn)行操作.其中,POSIX是Portable Operating System Interface for UNIX的首字母縮寫,是一套IEEE和ISO標(biāo)準(zhǔn).
如何在S3C2440上linux操作系統(tǒng)下將串口的波特率提高以致921600
就是把串口的波特率提上去,硬件環(huán)境呢,就是采用飛凌的TE2440-II(比較古老了,大家勿噴)操作系統(tǒng)是linux2.6.28,大家都知道,正常情況下,Linux下串口波特率更高到115200,因為我們特殊需要的原因,需要把波特率提高到至少460800,當(dāng)然最理想的結(jié)果就是波特率達(dá)到921600,大的背景就是這個樣子了。
然后先考究硬件,看看在硬件上到底能不能滿足我們的要求,主控芯片S3C2440,在UART一章說在系統(tǒng)時鐘下,波特率更高可達(dá)115200,然后注釋中說如果Pclk達(dá)到60M,可以實現(xiàn)921600,我就按他說的,將主頻提高,順便將pclk提高到了60M,發(fā)現(xiàn)921600根本實現(xiàn)不了,230400波特率雖然能通,但是錯誤率很高,根本無法用,然后我又嘗試著將Pclk提高到了70M,通過這種飲鴆止渴的方式,波特率可以提高到230400并且穩(wěn)定傳輸,但是更高的波特率則無法實現(xiàn),而Pclk不能無限提高,因為我們開發(fā)板還連接了觸摸屏,在Pclk70M的情況下,觸摸屏經(jīng)常重啟,說明這個方案不可行,所以就pass掉了,下面簡單說一下我怎么更改的系統(tǒng)時鐘Fclk,Hclk,Pclk。這三個時鐘的關(guān)系以及計算方法我就不贅述了,我主要參考博客
進(jìn)行修改
1)首先找到bootloader中 INC文件夾下的Option.inc文件,打開以后,找到如下代碼段,這段代碼就是主頻400M時對應(yīng)的M,P和S值設(shè)置,需要更改主頻的話虛野更改其中相應(yīng)的數(shù)值幾個(后來我發(fā)現(xiàn),其實這個地方不改也行,因為最終起作用的是第二步)
CLKDIV_VAL EQU5
;1:4:8
M_MDIV EQU
127 ;127
M_PDIV EQU
2 ;2
M_SDIV EQU
1 ; 2440A
|
M_SDIV EQU
0 ; 2440X
>
>
2)找到u2440mon.c,然后在main()函數(shù)中找到如下代碼,修改case2中的mpll_val = (92flags & UPF_SPD_MASK) == UPF_SPD_CUST)
quot = port->custom_divisor;
else
quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
/* check to see if we need to change clock source */
if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
s3c24xx_serial_setsource(port, clksrc);
if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
clk_disable(ourport->baudclk);
ourport->baudclk = NULL;
}
clk_enable(clk);
ourport->clksrc = clksrc;
ourport->baudclk = clk;
}
其中,uart_get_baud_rate()函數(shù)用于計算出上位機(jī)程序到設(shè)置的波特率的值,經(jīng)我調(diào)試得知,上位機(jī)波特率從2400到921600都可以被準(zhǔn)確的計算出來;所以這個函數(shù)跳過,然后看最后那個if語句,這個語句的作用是產(chǎn)看目前的時鐘源是否與設(shè)置的時鐘源相同,如果不相同,則按照設(shè)置的時鐘源進(jìn)行更改,這里面還涉及l(fā)inux下的關(guān)于管理時鐘的一個結(jié)構(gòu)體clk結(jié)構(gòu)體,參照博客
以及
我找到了linux下的mach-dk2440.c這個文件,這個文件中定義了串口所用的clk結(jié)構(gòu)體,這也是linux系統(tǒng)啟動時對串口的初始化配置結(jié)構(gòu)體都在這,但是我更改過這個地方,讓他初始化配置是選擇fclk作為串口的時鐘源,但是我發(fā)現(xiàn)這并沒有效果,所以繼續(xù)尋找中。
這樣就剩下一個函數(shù)可以考慮了,s3c24xx_serial_getclk(),進(jìn)入這個函數(shù)你會發(fā)現(xiàn),這個函數(shù)是對串口時鐘及波特率一個全面的配置,進(jìn)入這個函數(shù)中,就有個結(jié)構(gòu)體tmp_clksrc,這個結(jié)構(gòu)體很關(guān)鍵,他的內(nèi)容如下:
static struct s3c24xx_uart_clksrc tmp_clksrc = {
.name = “pclk”,
.min_baud
= 0,
.max_baud
= 0,
.divisor
= 1,
};
從這個名字中就可以看出,它把串口的時鐘源內(nèi)定成為了pclk,這也是罪魁禍?zhǔn)祝钱?dāng)我把name更改為fclk時,整個系統(tǒng)就無法啟動了,包括前面說的更改mach-dk2440.c中初始化配置,也是無法啟動,后來在配置串口是做了一個判斷,當(dāng)波特率低于202300時,才有系統(tǒng)源配置不變,當(dāng)波特率高于202300時,不在采用tmp_clksrc這個結(jié)構(gòu)體,而是采用我自己定義的一個結(jié)構(gòu)體,當(dāng)然就是把name改成fclk,發(fā)現(xiàn)雖然只是能夠更改 里面部分參數(shù)的時鐘源,而正在的時鐘源還是pclk,說明我的更改根本么有生效,由于這個linux調(diào)用太龐雜了,我就抱著試試看的態(tài)度,也是沒有辦法的辦法,在配置完串口時鐘的代碼之后,添加了如下幾行代碼,直接更改S3C2440的寄存器,我知道這樣做是很不“道德”的,而且很容易引起系統(tǒng)混亂,但是我只是這么試試,沒想到還真的有用。
在 samsung.c文件中添加
if (baud >=)
{
printk(“baud >[email protected]\n”);
__raw_writel(0x1fc5,S3C24XX_VA_UART0 + S3C2410_UCON);
__raw_writel(0x0fc5,S3C24XX_VA_UART1 + S3C2410_UCON);
__raw_writel(0x8fc5,S3C24XX_VA_UART2 + S3C2410_UCON);
__raw_writel(32,S3C24XX_VA_UART0 + S3C2410_UCON+0x24);//保證控制臺的波特率還是115200用于顯示
__raw_writel(3,S3C24XX_VA_UART1 + S3C2410_UCON+0x24);//921600
//__raw_writel(3,S3C24XX_VA_UART1 + S3C2410_UCON+0x24);
}
上面這段代碼經(jīng)我多次試驗得到的,因為一開始用的系統(tǒng)主時鐘fclk為400M,這樣算出來UBRDIV1分頻應(yīng)該為3,但是這樣的話錯誤率比較高,還是導(dǎo)致無法傳輸,至此我終于明白手冊上為什么說pclk在60M 可以實現(xiàn)921600了,因為用60M時鐘計算的話,分頻UBRDIV1為3.069,最接近整數(shù)3,所以在這個錯誤率下可以實現(xiàn)921600的波特率傳輸,所以我將系統(tǒng)時鐘fclk設(shè)置為420M,其中MDIV=97,PDIV=1,SDIV=1,而ucon0=0x1fc5,ucon1=0x0fc5,ucon2=0x8fc5,這樣n=1+6=7,所以串口的時鐘源為fclk/n=60M,可以得到精確的921600波特率,所以實現(xiàn)我剛開始的目標(biāo),其實要實現(xiàn)其他的波特率也可以,比如460800,計算后主時鐘fclk(盡量算出的分頻UBRDIV1最貼近整數(shù)),然后就可以實現(xiàn)了。
在這還有個小想法,提高串口波特率,還可以使用USB轉(zhuǎn)串口,因為USB轉(zhuǎn)串口可以實現(xiàn)921600,而linux中以及集成了USB轉(zhuǎn)串口的驅(qū)動,只需要在調(diào)用串口的那個open函數(shù)中改為調(diào)用USB轉(zhuǎn)串口的節(jié)點(diǎn)即可,當(dāng)然,這個方案我沒有試,因為我們就一個USB口,而且還被占用了,所以希望有需要的朋友可以試一下。
用 stty 命令 (使用前請確認(rèn)你的終端設(shè)備確實支持這個速率), 比如
stty# 設(shè)置 baud rate 到
stty speed # 查看當(dāng)前終端 baud rate
# 如果不是設(shè)置當(dāng)洞銷前終端段游,則用下面的命令納燃游設(shè)置指定終端設(shè)備
stty -F /dev/
88、四時田園雜興范大成
88、四時田園雜興 范大成
linux uart測試程序的介紹就聊到這里吧,感謝你花時間閱讀本站內(nèi)容,更多關(guān)于linux uart測試程序,Linux系統(tǒng)下的UART測試程序詳解,linux下uart的文件節(jié)點(diǎn)是怎樣創(chuàng)建的,如何在S3C2440上linux操作系統(tǒng)下將串口的波特率提高以致921600的信息別忘了在本站進(jìn)行查找喔。
創(chuàng)新互聯(lián)服務(wù)器托管擁有成都T3+級標(biāo)準(zhǔn)機(jī)房資源,具備完善的安防設(shè)施、三線及BGP網(wǎng)絡(luò)接入帶寬達(dá)10T,機(jī)柜接入千兆交換機(jī),能夠有效保證服務(wù)器托管業(yè)務(wù)安全、可靠、穩(wěn)定、高效運(yùn)行;創(chuàng)新互聯(lián)專注于成都服務(wù)器托管租用十余年,得到成都等地區(qū)行業(yè)客戶的一致認(rèn)可。
分享文章:Linux系統(tǒng)下的UART測試程序詳解(linuxuart測試程序)
瀏覽路徑:http://fisionsoft.com.cn/article/cdeocgc.html


咨詢
建站咨詢
