當前位置:首頁 » 操作系統 » linux串口驅動開發

linux串口驅動開發

發布時間: 2025-05-10 04:55:37

A. linuxusb涓插彛椹卞姩linuxusb涓插彛

濡備綍鍦╨inux涓嬪湪搴旂敤灞傚緱鍒癠SB璁懼囧悕縐頒俊鎮錛

鍏堣幏鍙栦竴涓/dev鐨勫垪琛錛岀劧鍚庡緱鍒版彃鎾浜嬩歡鍚庯紝鍦ㄨ幏鍙栦竴涓嬪綋鍓嶇殑/dev鍒楄〃錛岀劧鍚庡仛涓涓嬫瘮杈僱inux緋葷粺浼氳嚜鍔ㄨ瘑鍒玌SB鎺ュ彛涓轟覆鍙g佺洏sda(閫氬父涓簊da1錛屽彲閫氳繃fdisk-l鍛戒護鏌ヨ)錛屾寕杞藉氨鍙鐢ㄣ備緥錛氭柊寤烘寕杞界洰褰昺kdir/mnt/usb錛屾寕杞絤ount/dev/sda1/mnt/usb錛岀敤瀹屽嵏杞芥寕璧風偣unmount/dev/sda1/mnt/usb銆

濡備綍鏌ョ湅linux涓嬩覆鍙f槸鍚﹀彲鐢?涓插彛鍚嶇О絳夛紵

1銆佹煡鐪嬩覆鍙f槸鍚﹀彲鐢錛屽彲浠ュ逛覆鍙e彂閫佹暟鎹姣斿傚筩om1鍙o紝echolyjie126>/dev/ttyS0

2銆佹煡鐪嬩覆鍙e悕縐頒嬌鐢╨s-l/dev/ttyS*涓鑸鎯呭喌涓嬩覆鍙g殑鍚嶇О鍏ㄩ儴鍦╠ev涓嬮潰錛屽傛灉浣犳病鏈夊栨彃涓插彛鍗$殑璇濋粯璁ゆ槸dev涓嬬殑ttyS*,涓鑸瑃tyS0瀵瑰簲com1錛宼tyS1瀵瑰簲com2錛屽綋鐒朵篃涓嶄竴瀹氭槸蹇呯劧鐨勶紱

3銆佹煡鐪嬩覆鍙i┍鍔錛歝at/proc/tty/drivers/serial

4銆佹煡鐪嬩覆鍙h懼囷細dmesg|grepttyS*

LinuxRS485涓插彛緙栫▼錛

瀵逛簬緙栫▼鏉ヨ達紝娌′粈涔堝尯鍒錛岄氳繃鎺у埗485鐨勪嬌鑳界璇ョ▼搴忓畬鍏ㄥ彲浠ヤ嬌鐢ㄣ傚敮涓鐨勫尯鍒灝辨槸浣犲湪鍙戦佺殑鏃跺欓氳繃紼嬪簭鎶485鐨勬帶鍒惰剼鎷夐珮錛屾帴鏀剁殑鏃跺欐妸浠栨媺浣庡氨鍙浠ヤ簡銆傝嚦浜庣數姘旀柟闈㈢殑鍖哄埆錛歊S232鏄鍏ㄥ弻宸ワ紝鍙浠ュ悓鏃舵敹鍙戱紝RS485鏄鍗婂弻宸ワ紝涓嶈兘鍚屾椂鏀跺彂錛岃繕鏈夌數騫充俊鍙蜂笉涓鏍鳳紝榪欎釜緙栫▼浣犲氨涓嶈佺悊浜嗐

涓婁綅鏈簂abview鎬庝箞閫氳繃涓插彛鎺ユ敹涓嬩綅鏈哄彂鏉ョ殑鏁版嵁騫惰繘琛屽勭悊錛

鏂規硶涓鎵句釜浠鍣錛堢ず娉㈠櫒錛宒aq錛夎葷數騫蟲椂搴忚嚜宸辮В鏋愶紝鏂規硶浜屾壘涓猧2c鐨勮漿鎹㈣姱鐗囪漿涓插彛鎴杣sb鎴栬呰姱鐗囨彁渚沝ll錛屾柟娉曚笁鎼炰釜鍗曠墖鏈鴻嚜宸卞啓涓嬩綅鏈鴻В鏋愭椂搴忓啀鐢ㄤ覆鍙d紶鍒扮數鑴戱紝鏂規硶鍥涙壘涓鍙板甫i2c妯″潡鐨勪富鏈虹劧鍚庤皟鐢╳in_api錛圠inux灝變笉鐭ラ亾浜嗭級r

linux鏌ユ壘涓插彛錛

1銆佽懼囧叆鍙 鍙浠ユ煡/dev/ttyS*銆/dev/*uart*錛堜富璁懼囧彿4鎴栬204錛夛紝絎涓涓插彛涓鑸涓簍tyS0銆*uart0絳 USB杞涓插彛璁懼囦竴鑸涓/dev/ttyUSB*(涓昏懼囧彿188)錛岀涓鍙d竴鑸涓簍tyUSB0 2銆佷互涓/dev涓嬪彧鏄涓插彛鐨勫叆鍙o紝鍏蜂綋璁懼囧瓨鍦ㄤ笌鍚﹂渶瑕佹寜鍏抽敭瀛楋紙ttyS銆乼tyUSB銆乽art錛夋煡璇/proc/devices浠ョ『瀹氥 3銆佷覆鍙d負閫氳絝鍙o紝鏈夊氫釜涓插彛璁懼囨椂錛岃佺『瀹氭e湪琚榪炴帴鐨勪覆鍙f槸鍝涓錛岄渶瑕佹嫻嬩竴涓嬶紝濡傦細 cat/dev/ttyS0

B. Linux串口驅動簡介及使用方法linux串口的驅動

Linux 串口驅動簡介
Linux 是一款市場佔有率非常高的操作系統,其架構深受業界歡迎,同時也受到了桌面系統、手機系統以及嵌入式系統的青睞,作為開源系統,市場份額一直都在繼續上漲。
串口驅動對於許多嵌入式設備來說是十分重要的,所以其對Linux的支持同樣十分重要。 Linux內核中有一個串口驅動,可以輕松地將不同的硬體通道做連接,主要包括8253,8250,16550加上8255,16650,16750和16950等幾種。不同硬體的支持受到一定的限制,如16650及其以上就受到hard_seral_port參數設定的限制。
使用 Linux 串口驅動
1. 啟動內核中的串口驅動:在啟動內核時,必須確定計算機使用的串口類型,可以在Kconfig中選擇在make menuconfig時,選擇相應的模塊就可以使能串口設備或者驅動了;
2. 載入必要的模塊及硬體:在編寫makefiile時,必須確保已經編譯好的模塊與硬體相兼容,否則可能會出現無法載入模塊或模塊不能匹配硬體的情況;
3. 編寫驅動程序:有多種方式可以編寫驅動,基於模板的可以採用Driver core方式,可以輕松控制各種設備;也可以從頭開始編寫,從底層實現;
4. 測試串口:最後,測試串口驅動是否正常工作,使用minicom等專業的軟體可以發送指令,測試硬體連接是否正常;
使用Linux驅動串口的好處在於,可以通過修改內核配置和加裝必要的模塊來支持不同的硬體,大大減少用戶的配置時間,而且兼容性更高,可以支持不同的型號的串口硬體,以及不支持的設備也可以輕松支持,確保系統的穩定性。

C. 求教,linux下網口虛擬串口驅動程序

開發虛擬串口驅動程序

虛擬串口就是當本地並沒有對應的串口硬體設備,而為應用層提供串口設備一樣的系統調用介面,以兼容原本使用本地串口的應用軟體的「虛」設備。本文作者給出了一種在Windows平台上實現虛擬串口的方法,由此實現的「串口」具有真實串口完全相同的系統調用介面。
在很多應用中需要用到虛擬串口,如在Modem卡出現之前,已經有了接在計算機串口上的外部Modem,而且各種拔號程序也是通過串口與外部Modem通信的。為了讓已有的拔號程序不做修改,像使用外部Modem一樣使用內置卡,就需要內置卡的驅動程序虛擬一個串口設備。又如當前工業界使用的一些串口伺服器,往往有8個或16個甚至更多的串口,以連接多個串口設備,再通過一個網卡直接連入乙太網。與它在同一網路上的計算機就通過乙太網與串口伺服器上掛接的串口設備通信。為了讓計算機中原來使用本地串口的軟體兼容,就需要在計算機上提供虛擬串口驅動。
虛擬串口的設計關鍵在於,該「串口」實現後必須具有與真實串口完全相同的系統調用介面。要做到這點,從已有的串口設備驅動程序上做修改是最佳捷徑。下文就介紹以Windows NT上的串口驅動程序為基礎,開發可運行於Windows NT、Windows 2000、Windows XP的各個版本虛擬串口驅動程序。
串口驅動中使用的幾個鏈表
由於串口是雙工設備,在一個讀請求發出來還沒有完成之前,同時可以發出寫請求,加上在驅動程序層所有I/O請求都要求非同步完成,即前一個請求尚沒有完成,下一個相同的請求可能又來了。為此,串口驅動程序需要使用多個雙向鏈表數據結構來處理各種IRP(I/O Request Packet,I/O請求包)。當收到一個IRP,先判斷是否可立即完成,可以馬上處理並返回,如果不允許則將IRP插在相應鏈表尾,在適當的時候如設備有空閑時處理,這時往往會產生一個硬體中斷,激發DPC(Deferred Procere Call,暫緩過程調用)過程,由DPC處理函數逐個從鏈表頭取出IRP並試著完成它。串口驅動中有以下幾個鏈表和DPC(在serial.h中有定義):
ReadQueue 和 CompleteReadDpc
用於保存Read IRP的鏈表和用於調度的DPC,與DPC對應的處理函數是SerialCompleteRead,它在read.c文件中,該函數的主要任務就是從ReadQueue中提取下一個IRP,並試著完成它。
WriteQueue 和 CompleteWriteDpc
用於保存Write IRP的鏈表和對應的DPC,與DPC對應的函數是SeriaCompleteWrite,它的實現在write.c中,該函數負責從WriteQueue中提取IRP,並試著完成它。
MaskQueue 和 CommWaitDpc
這一對鏈表用於處理Windows串口驅動的一個特性:事件驅動機制。它允許應用程序預設一個事件標志,而後等待與標志對應事件發生。DPC所調用的函數是SerialCompleteWait,它實現在Waitmask.c文件中,該函數也是試著從MaskQueue中提取IRP並完成它。
PurgeQueue
該鏈表與前面幾個稍有不同,它沒有與之相對應的DPC機制,而是在每次收到Purge請求時從PurgeQueue中逐個提取IRP並試著完成,因某種原因不能完成時則插入鏈表。相應的函數是purge.c文件中的SerialStartPurge。
以上機制是串口驅動程序的重要實現方法,在虛擬串口驅動中需要保留,但不同的是,硬體串口驅動中是ISR(中斷服務程序)根據收、發或MODEM中斷來激發相應的DPC,而在虛擬串口驅動中將因實際情況不同會有不同的激發機制。
DriverEntry的實現
DriverEntry是驅動程序的入口函數,相當於應用程序C語言中的main函數,開發一個虛擬串口驅動首先要修改的就是它。它的函數實體在initunlo.c文件中。只是在虛擬串口驅動中由於不與具體的硬體打交道,就不存在硬體資源分析、硬體初始化、判斷其工作狀態等處理,只需要為虛擬串建立設備對象、符號鏈接和初始化數據結構。一個典型函數實現大體如下:
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
/*填寫DriverObject->MajorFunction[]數組*/
/*建立設備對象*/
/*初始化SERIAL_DEVCIE_EXETENSION數據結構*/
Status = IoCreateDevice(DriverObject, sizeof(SERIAL_DEVICE_EXTENSION), &uniNameString, FILE_DEVICE_SERIAL_PORT, 0,TRUE,&deviceObject);
//初始化所有鏈表
InitializeListHead(&extension->ReadQueue);
InitializeListHead(…);
…;
//初始化所有DPC
KeInitializeDpc(&extension->CompleteReadDpc,SerailCompleteRead,extension);
KeInitializeDpc(…);
/*建立符號鏈接*/
SerialSetupExternalNaming(extension);
return Status;
}
SerialRead和SerialCompleteRead的實現
函數SerailRead和SerialCompleteRead決定了對Read IRP的響應策略,它們都存於read.c中。以串口伺服器要用的虛擬串口為例,當串口伺服器收到來自外部數據時將通過網路發至計算機,計算機則產生相應的網路中斷並進行協議數據處理。網路接收線程緩存新收到的數據並激活CompleteReadDpc,從而SerialCompleteReadIrp得到調用,它再調用CompleteReadIrp對每個IRP進行處理。它們的實現大體如下:
NTSTATUS SerialRead(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
/*此處略去變數聲明和初始化*/
/*提取IRP中相關的數據*/
stack = IoGetCurrentIrpStackLocation(Irp);
ReadLen = stack->Parameters.Read.Length;
/*先看本地緩沖有數據否?有的話先讀取*/
if(Extension->InCounter > 0 )
{ //注意這里要加鎖,以防數據訪問沖突
KeAcquireSpinLock(&Extension->
ReadBufferLock,&lIrql);
FirstRead = (ReadLen>Extension->
InCounter)? Extension->InCounter: ReadLen;
RtlCopyMemory(Irp->AssociatedIrp.
SystemBuffer,Extension->pInBuffer,FirstRead);
Extension->InCounter -= FirstRead;
ReadLen -= FirstRead;
KeReleaseSpinLock(&Extension->
ReadBufferLock,lIrql);//釋放鎖
}
/*是否已讀到足夠數據?是的話則完成該IRP*/
if( 0 == ReadLen)
{
status=STATUS_SUCCESS;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = FirstRead;
IoCompleteRequest(Irp,0);
return status;
}
/*沒有則將IRP插入隊列中,通過網路向串口伺服器發出讀數據請求*/
IoMarkIrpPending(Irp);
InsertWaitList(Extension->ReadQueue,Irp);
status = TdiSendAsync(Extension->ComChannel,pAckPacket,PacketLen(pAckPacket),(PVOID)ReadAckComplete,Irp);
/*返回PENDING,表示該IRP尚沒有完成*/
return STATUS_PENDING;
}
Void CompleteReadIrp(IN PSERIAL_DEVICE_EXTENSION extension,IN PIRP Irp,IN PUCHAR pInData,IN ULONG Length )
{
/*此處略去變數聲明和初始化*/
/*讀取新數據*/
ReadLen = (ReadLen > Length)? Length : ReadLen;
if(ReadLen != 0)
{
RtlCopyMemory(pReadAsync->
pReadBuffer,pInData,ReadLen);
pReadAsync->pReadBuffer += ReadLen;
pReadAsync->ReadAlready += ReadLen;
extension->PerfStats.ReceivedCount +=
ReadLen;
}
else
{
/*因為串口伺服器端只有在已經有了相應的數據或超過時間(此時,Length=0)才會發來應答並激活本DPC過程,所以此時已經超時,為了便於結束本IRP,這里有意改變TotalNeedRead,造成接收完畢的假象*/
pReadAsync->TotalNeedRead =
pReadAsync->ReadAlready;
}
if(pReadAsync->TotalNeedRead == pReadAsync->ReadAlready)
{
/*該IRP是否已經接收完畢,是的話則結束該
IRP*/
EndReadIrp(Irp);
/*從ReadQueue中取下一個IRP*/
}
/*本IRP沒有完成也沒有超時,則繼續等待本DPC下次被激活,注意此時要判斷IRP是否被要求取消*/
}
SerialWrite和SerailCompleteWrite的實現
SerialWrite和SerailCompleteWrite決定了Write IRP的實現。在SerialWrite中調用了網路發送函數TdiSendAsync,當該發送完成後將激活CompleteWriteDpc,調度SerialCompleteWrite函數,而它主要就是取出當前的WriteIRP,設置已經發送的數據數量,調用CompleteWriteIrp做該IRP的進一步處理。它們大體如下:
NTSTATUS SerialWrite(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
/*此處略去變數聲明和初始化*/
/*從IRP中提取有關數據*/
stack=IoGetCurrentIrpStackLocation(Irp);
SendLen = stack->Parameters.Write.Length;
/*為網路發送和非同步操作分配緩沖,在CompleteWrite中全部數據發送完後釋放*/
pWriteAsync = ExAllocatePool(NonPagedPool,
SendLen+PACKET_HEADER_LEN+sizeof(WRITE_ASYNC));
if(pWriteAsync == NULL)
{
//錯誤處理
}
//保存非同步數據

//設置網路發送數據包
BuildDataPacket(pPacket,WRITE,(USHORT)SendLen,pWriteAsync->pWriteBuffer);
/*先將IRP暫時阻塞並插入隊列,在CompleteWrite中完成*/
IoMarkIrpPending(Irp);
InsertWaitList(extension->WriteQueue, Irp);
/*將寫請求和相關數據通過網路發向串口伺服器,由它負責將數據傳到具體串口設備*/
status = TdiSendAsync(Extension->ComChannel,pPacket,PacketLen(pPacket),(PVOID)CompleteWriteIrp,Irp);
//統計數據累加
Extension->PerfStats.TransmittedCount += SendLen;
return STATUS_PENDING;
}

NTSTATUS CompleteWriteIrp(IN PDEVICE_OBJECT deviceobject,IN PIRP pIrp,IN PVOID context)
{
/*此處略去變數聲明和初始化*/
SendLen=pWriteAsync->TotalNeedWrite - pWriteAsync->WroteAlready;
if(SendLen == 0)//全部數據發送完畢
{
EndWaitWriteIrp(pWriteIrp,STATUS_SUCCESS,
pWriteAsync->WroteAlready,pWriteAsync);
//從WriteQueue中取下一個IRP;
}
else //發送剩餘數據
{
if(pWriteIrp->Cancel)
{
//IRP被要求取消,完成WriteIrp
EndWaitWriteIrp(pWriteIrp,STATUS_CANCELLED,
pWriteAsync->WroteAlready,pWriteAsync);
return STATUS_CANCELED;
}
else
{
//再次設置網路數據包並發送
BuildDataPacket(…);
status = TdiSendAsync(…);
//統計數據累加
Extension->PerfStats.TransmittedCount +=
SendLen;
return STATUS_MORE_PROCESSING_REQUIRED;
}
}
}
其他幾個介面函數的實現
除Read/Write外,SerialUnload、SerialCreateOpen、 SerialClose、SerialCleanup、SerailFlush等調用介面是硬體相關性比較弱的介面函數,基本不要修改,直接刪除原來操作硬體的部分即可。復雜一點就是SerialIoControl,該介面函數包含有大量設置、讀取串口硬體狀態的處理,可建立一個本地數據結構隨時保存虛擬串口的當前硬體狀態。同時為了保證串口伺服器端的真實串口狀態和上層軟體要求的一致,需要將所有設置請求通過網路發送到伺服器端,由它負責改變真實硬體的狀態。

熱點內容
飛騰伺服器什麼時候上市 發布:2025-05-10 08:08:18 瀏覽:275
安卓和蘋果平板如何用一個賬號 發布:2025-05-10 08:06:02 瀏覽:184
java學完 發布:2025-05-10 07:49:35 瀏覽:457
蟹怎麼存儲 發布:2025-05-10 07:45:14 瀏覽:534
天諭文件夾 發布:2025-05-10 07:39:31 瀏覽:652
數據處理演算法 發布:2025-05-10 07:35:00 瀏覽:883
遍歷ftp的目錄 發布:2025-05-10 07:35:00 瀏覽:667
資料庫宿舍管理系統 發布:2025-05-10 07:24:23 瀏覽:869
c語言遍歷二維數組 發布:2025-05-10 07:17:49 瀏覽:623
sql合並兩列 發布:2025-05-10 07:07:01 瀏覽:822