新聞中心
嵌入式Linux串口應(yīng)用全解析:從初學(xué)者到專家

為東豐等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及東豐網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)、東豐網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
嵌入式系統(tǒng)是近年來(lái)極受歡迎的技術(shù),它的特點(diǎn)是體積小巧、功耗低、性能強(qiáng)勁,可以勝任很多嵌入式場(chǎng)景的應(yīng)用。而Linux系統(tǒng)則是最為主流的嵌入式系統(tǒng)之一,因?yàn)樗拈_(kāi)放性、靈活性和強(qiáng)大的社區(qū)支持,Linux系統(tǒng)在嵌入式領(lǐng)域被廣泛應(yīng)用,也是很多嵌入式開(kāi)發(fā)者的首選。
在嵌入式Linux應(yīng)用中,串口是一個(gè)非常關(guān)鍵的組成部分,幾乎所有的嵌入式系統(tǒng)都需要通過(guò)串口與用戶或者上層系統(tǒng)進(jìn)行通信。串口的使用涉及底層硬件和驅(qū)動(dòng)、用戶層協(xié)議和應(yīng)用等多個(gè)方面,難度較大,不同級(jí)別的開(kāi)發(fā)者面對(duì)的問(wèn)題也不同。本篇文章將為讀者全面解析嵌入式Linux串口應(yīng)用,從初學(xué)者到專家,為廣大開(kāi)發(fā)者提供參考和借鑒。
一、串口概覽
串口通信是一種基于異步傳輸?shù)耐ㄐ欧绞?,典型?yīng)用場(chǎng)景是通過(guò)串口連接計(jì)算機(jī)與外部設(shè)備,例如串口終端、單片機(jī)、傳感器等。通常情況下,串口通信通過(guò)一根數(shù)線進(jìn)行數(shù)據(jù)傳輸,可以實(shí)現(xiàn)兩個(gè)設(shè)備之間的數(shù)據(jù)交換和控制信號(hào)的傳輸。串口通信涉及到多個(gè)方面的知識(shí),例如時(shí)序、電氣特性、通信協(xié)議等。
在嵌入式系統(tǒng)中,串口與外部設(shè)備的連接方式通常為TTL電平,信號(hào)包括TX、RX、GND等幾條線。下圖為串口電路的典型實(shí)現(xiàn)方式:

從上圖中可以看出,串口通信的最小單元是字節(jié),包括起始位、數(shù)據(jù)位、校驗(yàn)位和停止位。在Linux系統(tǒng)中,串口通信可以通過(guò)底層驅(qū)動(dòng)和用戶層程序兩種方式實(shí)現(xiàn),具體實(shí)現(xiàn)方式會(huì)在后面的章節(jié)中詳解。
二、串口驅(qū)動(dòng)
Linux系統(tǒng)中的串口驅(qū)動(dòng)一般是由CPU提供的內(nèi)部UART芯片控制的,對(duì)于不同的CPU架構(gòu)和不同的驅(qū)動(dòng)實(shí)現(xiàn)方式,串口驅(qū)動(dòng)的底層實(shí)現(xiàn)也不盡相同。本文將重點(diǎn)介紹在ARM架構(gòu)下的嵌入式Linux串口驅(qū)動(dòng)實(shí)現(xiàn)。
2.1、總線和設(shè)備
在Linux系統(tǒng)中,驅(qū)動(dòng)程序通常被視為設(shè)備,設(shè)備又入到某些總線上,以便與其他設(shè)備或者操作系統(tǒng)內(nèi)核進(jìn)行通信。串口通信的底層驅(qū)動(dòng)涉及到和總線的交互,特別是在多個(gè)設(shè)備共用同一總線時(shí),對(duì)于驅(qū)動(dòng)程序的管理和調(diào)度是非常重要的。
Linux系統(tǒng)中有很多種總線和設(shè)備,只需在內(nèi)核中注冊(cè)一個(gè)新設(shè)備,就可以支持這個(gè)設(shè)備作用于相應(yīng)的總線上,然后操作系統(tǒng)就可以自動(dòng)發(fā)現(xiàn)、管理和使用該設(shè)備。注冊(cè)設(shè)備的過(guò)程是動(dòng)態(tài)的,可以在操作系統(tǒng)運(yùn)行時(shí)完成。
2.2、串口芯片與驅(qū)動(dòng)
在ARM架構(gòu)下,嵌入式系統(tǒng)中通常會(huì)用到一些內(nèi)部UART串口控制器,這些控制器需要一個(gè)相應(yīng)的驅(qū)動(dòng)程序進(jìn)行配置、控制和數(shù)據(jù)傳輸。串口驅(qū)動(dòng)程序通常被編譯為模塊(又稱驅(qū)動(dòng)模塊),在特定的時(shí)候需要被內(nèi)核加載進(jìn)來(lái)。
串口通信在硬件上的實(shí)現(xiàn)是非常復(fù)雜和多樣化的,不同的芯片和控制器有不同的數(shù)據(jù)結(jié)構(gòu)和寄存器配置,因此對(duì)應(yīng)的驅(qū)動(dòng)程序也有區(qū)別。通常情況下,驅(qū)動(dòng)程序需要進(jìn)行一些基本操作,例如設(shè)備注冊(cè)、初始化、讀寫操作、中斷處理等。
在Linux系統(tǒng)下,我們可以通過(guò)內(nèi)核源碼樹(shù)的drivers/tty/serial/目錄查看當(dāng)前系統(tǒng)支持的串口驅(qū)動(dòng)程序,這里列出一些常用的驅(qū)動(dòng)程序名稱:
“`
● 8250 – 最簡(jiǎn)單的串口驅(qū)動(dòng),支持大多數(shù)x86系統(tǒng)
● 8250_pci – 支持通過(guò)PCI總線連接的8250串口
● 8250_pnp – 支持ISA PnP總線的8250串口
● dz – DECstation串口驅(qū)動(dòng)
● clps711x – 對(duì)于Cirrus Logic 711x處理器的串口驅(qū)動(dòng)
● fsl-imx-uart – 用于Freescale i.MX系列Soc的驅(qū)動(dòng)
● max3100 – 驅(qū)動(dòng)Maxim的MAX3100多串口UART
“`
對(duì)于不同種類的驅(qū)動(dòng)程序,需要傳遞相應(yīng)的數(shù)據(jù)結(jié)構(gòu)和參數(shù),對(duì)應(yīng)的信息一般寫在一個(gè)包含驅(qū)動(dòng)程序信息的數(shù)據(jù)結(jié)構(gòu)中,例如tty_driver結(jié)構(gòu)體。
2.3、串口驅(qū)動(dòng)編寫
編寫嵌入式Linux串口驅(qū)動(dòng),需要按照特定的規(guī)范進(jìn)行實(shí)現(xiàn),這里介紹一下嵌入式系統(tǒng)中Linux串口驅(qū)動(dòng)程序的編寫流程:
1. 新建一個(gè).c文件,作為驅(qū)動(dòng)程序的源文件。
2. 在文件頭部引入Linux內(nèi)核頭文件、驅(qū)動(dòng)程序頭文件等。
3. 在文件中定義驅(qū)動(dòng)程序的關(guān)鍵結(jié)構(gòu)體,例如tty_driver、tty_port等。
4. 聲明一些必要的版本信息、完整與半口通信能力。
5. 定義驅(qū)動(dòng)程序接口,例如模塊加載和卸載、設(shè)備注冊(cè)和卸載等函數(shù)。
6. 定義串口處理函數(shù)。
7. 注冊(cè)串口驅(qū)動(dòng)程序,將驅(qū)動(dòng)程序添加到驅(qū)動(dòng)程序鏈表中。
如下代碼是一個(gè)簡(jiǎn)單的串口驅(qū)動(dòng)示例,實(shí)現(xiàn)了從串口讀取輸入的字符,并將其打印輸出:
“`
#include
#include
#include
#include
#include
#include
#include
#define DRIVER_NAME “my_serial”
static struct tty_driver *serial_driver;
static struct tty_port tty_port;
static dev_t dev_id;
static struct class *my_class;
static int my_serial_dev_init(struct tty_port *port)
{
return 0;
}
static int my_serial_dev_open(struct tty_struct *tty, struct file *file)
{
return tty_port_open(&tty_port, tty, file);
}
static ssize_t my_serial_dev_write(struct tty_struct *tty, const unsigned char *buf, size_t count)
{
return tty_write_room(&tty_port) – count;
}
static void my_serial_dev_close(struct tty_struct *tty, struct file *file)
{
tty_port_close(&tty_port, tty, file);
}
static inline void my_serial_output_byte(struct tty_struct *tty, unsigned char ch)
{
return;
}
static int my_serial_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
return tty_standard_install(tty, old_termios);
}
static const struct tty_operations my_serial_ops = {
.open = my_serial_dev_open,
.close = my_serial_dev_close,
.write = my_serial_dev_write,
.set_termios = my_serial_set_termios,
.output = my_serial_output_byte,
};
static int my_serial_probe(struct platform_device *pdv)
{
int ret;
ret = alloc_chrdev_region(&dev_id, 0, 1, DRIVER_NAME);
if (ret) {
printk(“Can not get major number.\n”);
return ret;
}
my_class = class_create(THIS_MODULE, DRIVER_NAME);
if (IS_ERR(my_class)) {
printk(“Class create fled.”);
unregister_chrdev_region(dev_id, 1);
return PTR_ERR(my_class);
}
serial_driver = alloc_tty_driver(1);
if (!serial_driver) {
printk(“Can’t alloc driver.\n”);
class_destroy(my_class);
unregister_chrdev_region(dev_id, 1);
return -ENOMEM;
}
serial_driver->owner = THIS_MODULE;
serial_driver->driver_name = DRIVER_NAME;
serial_driver->name = “ttyMyS0”;
serial_driver->major = MAJOR(dev_id);
serial_driver->minor_start = 0;
serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
serial_driver->subtype = SERIAL_TYPE_NORMAL;
serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(serial_driver, &my_serial_ops);
ret = tty_register_driver(serial_driver);
if (ret) {
printk(“Can not register driver.\n”);
tty_unregister_driver(serial_driver);
class_destroy(my_class);
unregister_chrdev_region(dev_id, 1);
return ret;
}
ret = tty_port_init(&tty_port);
if (ret) {
printk(“Can not init port.\n”);
tty_unregister_driver(serial_driver);
class_destroy(my_class);
unregister_chrdev_region(dev_id, 1);
return ret;
}
ret = tty_port_register_device(&tty_port, serial_driver, 0, NULL);
if (ret) {
printk(“Can not register device.\n”);
tty_port_destroy(&tty_port);
tty_unregister_driver(serial_driver);
class_destroy(my_class);
unregister_chrdev_region(dev_id, 1);
return ret;
}
printk(“Serial device is attached successfully.\n”);
return 0;
}
static int my_serial_remove(struct platform_device *pdv)
{
tty_unregister_driver(serial_driver);
class_destroy(my_class);
unregister_chrdev_region(dev_id, 1);
return 0;
}
static struct platform_driver my_serial_platform_driver = {
.probe = my_serial_probe,
.remove = my_serial_remove,
.driver = {
.name = “my_serial”,
.owner = THIS_MODULE,
},
};
static int __init my_serial_init(void)
{
return platform_driver_register(&my_serial_platform_driver);
}
static void __exit my_serial_exit(void)
{
platform_driver_unregister(&my_serial_platform_driver);
}
module_init(my_serial_init);
module_exit(my_serial_exit);
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“Your Name”);
MODULE_DESCRIPTION(“My Serial Driver”);
MODULE_ALIAS(“my_serial”);
“`
在上述驅(qū)動(dòng)程序中,主要的結(jié)構(gòu)體有:
● tty_driver:定義了串口驅(qū)動(dòng)程序的一些屬性,例如tty_ops等。
● tty_port:串口端口的結(jié)構(gòu)體,包含了串口的一些控制信息。
● tty_struct:串口的數(shù)據(jù)結(jié)構(gòu),指向從用戶空間調(diào)用驅(qū)動(dòng)的附加參數(shù)。
驅(qū)動(dòng)程序中的核心函數(shù)包括:
● my_serial_dev_init:初始化串口設(shè)備端口,設(shè)置相關(guān)中斷服務(wù)程序。
● my_serial_dev_open:打開(kāi)串口設(shè)備,這里使用了tty_port_open。
● my_serial_dev_close:關(guān)閉串口設(shè)備,這里使用了tty_port_close。
● my_serial_dev_write:向串口設(shè)備寫數(shù)據(jù),這里使用了tty_write_room。
● my_serial_output_byte:輸出一個(gè)字節(jié)到串口,由tty_sub_internal()調(diào)用。
● my_serial_set_termios:設(shè)置terminal區(qū)設(shè)置的串口參數(shù),這里使用tty_standard_install。
● my_serial_probe:驅(qū)動(dòng)的探測(cè)函數(shù),注冊(cè)字符設(shè)備和tty結(jié)構(gòu),初始化和設(shè)置串口的參數(shù)和中斷服務(wù)程序。
● my_serial_remove:驅(qū)動(dòng)的銷毀函數(shù),注銷字符設(shè)備等等。
本節(jié)介紹了嵌入式Linux系統(tǒng)中串口驅(qū)動(dòng)的基本實(shí)現(xiàn)流程,涉及到很多領(lǐng)域的知識(shí),包括設(shè)備驅(qū)動(dòng)、總線結(jié)構(gòu)、數(shù)據(jù)結(jié)構(gòu)等等。對(duì)于初學(xué)者來(lái)說(shuō),這一部分的內(nèi)容可能會(huì)比較晦澀,但是掌握這些基礎(chǔ)知識(shí)對(duì)于理解上層串口應(yīng)用和調(diào)試都有很大的幫助。
三、串口應(yīng)用
在嵌入式Linux系統(tǒng)中,除了底層的串口硬件驅(qū)動(dòng)外,還需要一些上層的應(yīng)用程序來(lái)實(shí)現(xiàn)串口通信的功能。Linux系統(tǒng)中最常用的上層串口應(yīng)用程序是minicom、picocom等,它們提供了完整的串口設(shè)置、字符輸入和數(shù)據(jù)讀取和顯示等功能。在本節(jié)中,我們將主要介紹如何使用Linux系統(tǒng)中的串口應(yīng)用程序。
3.1、串口環(huán)境配置
在使用上層串口應(yīng)用程序之前,需要先進(jìn)行一些配置工作。首先要確認(rèn)系統(tǒng)中是否已經(jīng)安裝了相關(guān)的串口應(yīng)用程序(例如minicom等),如果沒(méi)有安裝則需要先進(jìn)行安裝,配置好對(duì)應(yīng)的串口驅(qū)動(dòng),可以在Linux系統(tǒng)下使用以下命令查看系統(tǒng)中當(dāng)前支持的串口:
“`
$ dmesg|grep tty
[ 0.000000] Kernel command line: console=ttyS2,115200n8 root=/dev/mmcblk0p2 rootfstype=ext4 rootwt
[ 0.230496] ff180000.serial: ttyS0 at MMIO 0xff180000 (irq = 21, base_baud = 7500000) is a M
[ 0.231688] console [ttyS0] enabled
[ 0.238301] m_serial 78b6000.serial: m_serial: detected port #0
[ 0.238341] m_serial 78b6000.serial: uartclk = 19202300
[ 0.238389] 78b6000.serial: ttyS1 at MMIO 0x78b6000 (irq = 128, base_baud = 115200) is a M
[ 0.238425] m_serial: driver initialized
[ 0.245754] m_serial 7874000.serial: m_serial: detected port #1
[ 0.245790] m_serial 7874000.serial: uartclk = 19202300
[ 0.245834] 7874000.serial: ttyS2 at MMIO 0x7874000 (irq = 129, base_baud = 115200) is a M
“`
在本例中,系統(tǒng)中支持三個(gè)串口ttyS0、ttyS1和ttyS2,其中ttyS2口被配置為控制臺(tái)。接下來(lái),我們需要確認(rèn)串口的一些基礎(chǔ)參數(shù),例如波特率、停止位、數(shù)據(jù)位和奇偶校驗(yàn)等。這些參數(shù)需要和通訊設(shè)備的參數(shù)相配合,正確設(shè)置后才能進(jìn)行數(shù)據(jù)傳輸。
我們可以通過(guò)以下命令修改串口的默認(rèn)設(shè)置:
“`
$sudo stty -F /dev/ttyS0 9600 -parenb cs8 -cstopb
“`
此命令表示將串口的波特率設(shè)置為9600,不使用奇偶校驗(yàn)位,數(shù)據(jù)位為8,停止位為1,可以根據(jù)需要進(jìn)行修改。
3.2、使用串口應(yīng)用
在配置好串口環(huán)境后,我們可以使用Linux系統(tǒng)中的minicom等串口應(yīng)用來(lái)進(jìn)行數(shù)據(jù)交互和調(diào)試。minicom是一個(gè)輕量級(jí)的串口通信程序,功能較為全面,可以很方便地進(jìn)行數(shù)據(jù)讀取和字符輸入等操作,使用該程序時(shí)需要注意以下幾個(gè)步驟:
1. 首先確認(rèn)已正確配置串口相關(guān)參數(shù),例如波特率、數(shù)據(jù)位、停止位等。
2. 打開(kāi)終端,輸入以下命令打開(kāi)minicom程序:
“`
$ sudo minicom -s
“`
該命令表示使用minicom程序,并打開(kāi)設(shè)置界面。
3. 在設(shè)置界面中選擇Serial Port Configuration選項(xiàng),配置好串口相關(guān)參數(shù),例如波特率、數(shù)據(jù)位、停止位等。
4. 在前面的界面中選擇Exit選項(xiàng),此時(shí)將會(huì)自動(dòng)連接串口設(shè)備,并打開(kāi)一個(gè)終端窗口進(jìn)行數(shù)據(jù)輸入。
成都網(wǎng)站建設(shè)公司-創(chuàng)新互聯(lián),建站經(jīng)驗(yàn)豐富以策略為先導(dǎo)10多年以來(lái)專注數(shù)字化網(wǎng)站建設(shè),提供企業(yè)網(wǎng)站建設(shè),高端網(wǎng)站設(shè)計(jì),響應(yīng)式網(wǎng)站制作,設(shè)計(jì)師量身打造品牌風(fēng)格,熱線:028-86922220嵌入式linux怎樣用串口傳送文件
那個(gè)當(dāng)然要看了。就看那個(gè)基礎(chǔ)版的,基礎(chǔ)的東西要學(xué),如果你不看你就搞不定一些系統(tǒng)管理的東西:比如說(shuō):環(huán)境變量,系統(tǒng)故障,一些文件目錄的權(quán)限啊,不同軟件包的安裝之類的……
這些最基礎(chǔ)的東西沒(méi)有學(xué)好,就別說(shuō)你還嵌入式linux了,萬(wàn)一進(jìn)不了系統(tǒng),空賀慎你拍渣就干瞪眼了..
而且嵌入式linux當(dāng)然是建立在linux之上,你連這個(gè)平臺(tái)都沒(méi)有玩轉(zhuǎn),還怎么談開(kāi)發(fā)。。
所以,靜下心來(lái),基斗敬礎(chǔ)的東西要學(xué)好,嵌入式很難的,學(xué)的東西又多,路還長(zhǎng)的。。。
嵌入式linux 串口的介紹就聊到這里吧,感謝你花時(shí)間閱讀本站內(nèi)容,更多關(guān)于嵌入式linux 串口,嵌入式Linux串口應(yīng)用全解析:從初學(xué)者到專家,嵌入式linux怎樣用串口傳送文件的信息別忘了在本站進(jìn)行查找喔。
創(chuàng)新互聯(lián)【028-86922220】值得信賴的成都網(wǎng)站建設(shè)公司。多年持續(xù)為眾多企業(yè)提供成都網(wǎng)站建設(shè),成都品牌建站設(shè)計(jì),成都高端網(wǎng)站制作開(kāi)發(fā),SEO優(yōu)化排名推廣服務(wù),全網(wǎng)營(yíng)銷讓企業(yè)網(wǎng)站產(chǎn)生價(jià)值。
分享題目:嵌入式Linux串口應(yīng)用全解析:從初學(xué)者到專家(嵌入式linux串口)
標(biāo)題路徑:http://fisionsoft.com.cn/article/djgocpp.html


咨詢
建站咨詢
