以前寫(xiě)的,但是沒(méi)寫(xiě)完,偏偏你要的那部分沒(méi)寫(xiě)。
呵呵~~ 先聲明,沒(méi)調試過(guò)。
僅供參考,有錯誤的地方請指正,謝謝!/////////////////////////******setport.h*******/////////////////////////#ifndef SETPORT_H#define SETPORT_H/********************* int dwBaudRate; //波特率 char bTTY; //串口號 char bDataBit; //數據位 5,6,7,8 char bParity; //奇偶校驗 無(wú)校驗:'N' 偶校驗'E' 奇校驗'O' char bStopBit; //停止位 1,2 char bFctl; //流控制 無(wú)控制:'N' 硬件控制:'H' 軟件控制:'S'**********************///-------------------打開(kāi)串口-------------------//bTTY==0,1,2,3, 對應串口Com1到Com4,成功返回文件描述符,失敗==(-1) extern int PortOpen(char bTTY);//-------------------設置串口-------------------//成功==(0) 失敗==(-1) extern int PortSet(int dwFdcom,int dwBaudRate,char bTTY,char bDataBit,char bParity,char bStopBit,char bFctl);//-------------------關(guān)閉串口-------------------// extern void PortClose(int dwFdcom);//-------------------寫(xiě)串口-------------------//成功返回datalen 失敗==(<0) extern int PortWrite(int dwFdcom,char *cpSendBuf,unsigned int DataLen);//-------------------讀串口-------------------//成功返回datalen 失敗==(-1) extern int PortRead(int dwFdcom,char *cpRecvBuf,unsigned int DataLen,unsigned int dwBaudRate);//-------------------超時(shí)設置-------------------//成功==0 失敗==(<0) extern int PortTimeOut(int dwFdcom, char timeout, int len);#endif//////////////////////////////***********setport.c*******/////////////////////////////#include #include #include #include #include #include #include #include #include #include "setport.h"//-------------------打開(kāi)串口-------------------// extern int PortOpen(char bTTY) { int dwFdcom; unsigned char Ptty[10]="/dev/ttyS"; unsigned char *cpGtty; cpGtty=strcat(Ptty,&bTTY); if(!cpGtty) return -1; else { dwFdcom=open(cpGtty,O_RDWR|O_NOCTTY); } return (dwFdcom); }//-------------------關(guān)閉串口-------------------// extern void PortClose(int dwFdcom) { close(dwFdcom); }//-------------------設置串口-------------------// extern int PortSet(int dwFdcom,int dwBaudRate,char bTTY,char bDataBit,char bParity,char bStopBit,char bFctl) { static int speed_arr[] = {B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300}; static int name_arr[] = {38400, 19200, 9600, 4800, 2400,1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300}; struct termios oldtm_t,newtm_t; int i=0; char *pDatabit; bzero(&oldtm_t,sizeof(oldtm_t)); bzero(&newtm_t,sizeof(newtm_t)); cfmakeraw(&newtm_t); tcgetattr(dwFdcom,&oldtm_t); /*------------設置端口屬性------------*/ for( ; i { if(dwBaudRate==name_arr[i]) { cfsetispeed(&newtm_t,speed_arr[i]); cfsetospeed(&newtm_t,speed_arr[i]); } else return -1; } newtm_t.c_cflag|=CLOCAL; newtm_t.c_cflag|=CREAD; newtm_t.c_cflag &= ~CSIZE; switch(bDataBit) //數據位 { case '5': newtm_t.c_cflag|=CS5; break; case '6': newtm_t.c_cflag|=CS6; break; case '7': newtm_t.c_cflag|=CS7; break; case '8': newtm_t.c_cflag|=CS8; break; default: return -2; } switch(bParity) { case 'N':{ //無(wú)校驗 newtm_t.c_cflag&=~PARENB; newtm_t.c_iflag&= ~INPCK; }break; case 'O':{ //奇校驗 newtm_t.c_cflag |= (PARODD | PARENB); newtm_t.c_iflag |= INPCK; }break; case 'E':{ //偶校驗 newtm_t.c_cflag |= PARENB; newtm_t.c_cflag &= ~PARODD; newtm_t.c_iflag |= INPCK; }break; default: return -3; } //停止位 if(bStopBit=='2') newtm_t.c_cflag|=CSTOPB; //2 else newtm_t.c_cflag&=~CSTOPB; //1 switch(bFctl) //流控制 { case 'N':{ //無(wú)控制 newtm_t.c_cflag &= ~CRTSCTS; newtm_t.c_iflag &= ~(IXON | IXOFF | IXANY ); }break; case 'H':{ //硬件控制 newtm_t.c_cflag |= CRTSCTS; newtm_t.c_iflag &= ~(IXON | IXOFF | IXANY ); }break; case 'S':{ //軟件控制 newtm_t.c_cflag &= ~CRTSCTS; newtm_t.c_iflag |= (IXON | IXOFF | IXANY ); }break; default: return -4; } tcflush(dwFdcom,TCIFLUSH); //端口復位 tcsetattr(dwFdcom,TCSANOW,&newtm_t); //使端口屬性設置生效 return 0; }//-------------------超時(shí)設置-------------------// extern int PortTimeOut(int dwFdcom, char timeout, int len) { struct termios newtm_t; if(tcgetattr(dwFdcom, &newtm_t) != 0) { return (-1); } newtm_t.c_lflag &= ~ICANON; newtm_t.c_cc[VTIME] = timeout; newtm_t.c_cc[VMIN] = len; if(tcsetattr(dwFdcom, TCSANOW, &newtm_t) != 0) { return (-2); } return 0; }////讀寫(xiě)串口用文件讀寫(xiě)方式,read和write兩個(gè)方法,////read是接收數據,write是發(fā)送數據。
從個(gè)人的理解,Linux2。
6內核對中斷處理程序的現在的處理可以分為兩種模式,一種就是上面說(shuō)的老的模式(非共享中斷線(xiàn)),一種屬于使用共享中斷線(xiàn)的新模式,從其使用的注冊中斷處理程序的函數中來(lái)分析,函數原型如下: int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void * dev_id); 參數1:中斷線(xiàn)號 參數2:中斷處理程序函數指針 參數3:標志掩碼(SA_INTERRUPT, SA_SAMPLE_RANDOM, SA_SHIRQ) 參數4:用于參數3為SA_SHIRQ(共享中斷線(xiàn))的時(shí)候,其他為NULL 原來(lái)對于計算機設備比較少的時(shí)候,可能一個(gè)中斷線(xiàn)好可以對應一個(gè)中斷處理程序(非共享中斷線(xiàn)),這時(shí)候參數4為NULL,沒(méi)有任何用,但隨著(zhù)計算機設備的增加,一個(gè)中斷線(xiàn)號對應一個(gè)中斷處理程序已經(jīng)不太現實(shí),這個(gè)時(shí)候就使用了共享的中斷線(xiàn)號,多個(gè)設備使用同一個(gè)中斷線(xiàn)號,同一個(gè)中斷設備線(xiàn)號的所有處理程序鏈接成一個(gè)鏈表,這樣當在共享中斷線(xiàn)號的方式下一個(gè)中斷產(chǎn)生的時(shí)候,就要遍歷其對應的處理程序鏈表,但這個(gè)中斷是由使用同一個(gè)中斷線(xiàn)號的多個(gè)設備中間的一個(gè)產(chǎn)生的,不可能鏈表里面的所有處理程序都調用一遍吧,呵呵,這個(gè)時(shí)候就該第四個(gè)參數派上用場(chǎng)了。 因為多個(gè)設備共享同一個(gè)中斷線(xiàn)號,當中斷產(chǎn)生的時(shí)候到底是那一個(gè)設備產(chǎn)生的中斷呢,這個(gè)就取決于第四個(gè)參數dev_id,這個(gè)參數必須是唯一的,也就是能區分到底是那個(gè)設備產(chǎn)生的中斷,而且從第二個(gè)參數可以看出來(lái),這個(gè)參數被傳入中斷處理程序(第二個(gè)參數),可以這么理解,當中斷產(chǎn)生的時(shí)候,如果是共享的中斷線(xiàn)號,則對應鏈表的所有中斷處理程序都被調用,不過(guò)在每個(gè)中斷處理程序的內部首先檢查(參數信息以及設備硬件的支持)是不是這個(gè)中斷處理程序對應的設備產(chǎn)生的中斷,如果不是,立即返回,如果是,則處理完成,如果鏈表中沒(méi)有一個(gè)是,則說(shuō)明出現錯誤。
下來(lái)說(shuō)說(shuō)中斷處理程序,先看看原型: static irqreturn_t intr_handler(int irq, void * dev_id, struct pt_regs * regs); 參數1:中斷線(xiàn)號 參數2:設備的信息,唯一確定性 參數3:中斷之前的處理器寄存器的信息和狀態(tài) 通過(guò)上面的分析,大概可以看到,參數1(中斷線(xiàn)號)貌似有點(diǎn)多余,因為如果是非共享的中斷線(xiàn),通過(guò)中斷線(xiàn)號直接調用處理程序,將這個(gè)參數傳進(jìn)去好像沒(méi)什么用,如果屬于共享的中斷線(xiàn),則通過(guò)中斷線(xiàn)號直接找到對應的中斷處理程序鏈表,挨個(gè)遍歷,都是一個(gè)中斷線(xiàn)號,傳進(jìn)去也沒(méi)用,該不該調用,通過(guò)第二個(gè)參數來(lái)區分,那為什么要保留這個(gè)參數呢?答案是歷史遺留問(wèn)題,往后可能越來(lái)越?jīng)]用了,至于為什么是歷史遺留問(wèn)題,可能在沒(méi)有第二個(gè)參數的時(shí)候才在第一個(gè)上面做了點(diǎn)手腳,既然第二個(gè)參數已經(jīng)添加進(jìn)去了,第一個(gè)的作用就越來(lái)越少了。 如果是共享的中斷線(xiàn)號,則對應鏈表的所有中斷處理程序都被調用,不過(guò)在每個(gè)中斷處理程序的內部首先檢查(參數信息以及設備硬件的支持)是不是這個(gè)中斷處理程序對應的設備產(chǎn)生的中斷,如果不是,立即返回,如果是,則處理完成,如果鏈表中沒(méi)有一個(gè)是,則說(shuō)明出現錯誤。
Linux混入了mmu內存管理之后,ARM的中斷是怎么樣的呢?和我們在裸板上的中斷有沒(méi)有區別?讓我們從源代碼入手,做一個(gè)粗略的分析:init/main。
c->start_kernel()->trap_init()//-----------------------------------------------1。 trap_init()//glietpletely changes the structure of the visible * memory space。 You will not be able to trace execution through this。
* If you have an enquiry about this, *please* check the linux-arm-kernel * mailing list archives BEFORE sending another post to the list。 */ 。
type __ret, %function__ret: ldr lr, __switch_data mcr p15, 0, r0, c1, c0//將__arm920_setup中設置的r0值,置入cp15協(xié)處理器c1寄存器中 mrc p15, 0, r0, c1, c0, 0 @ read it back。 mov r0, r0//填充armv4中的三級流水線(xiàn):mov r0,r0 對應一個(gè)nop,所以對應2個(gè)nop和一個(gè)mov pc,lr剛好三個(gè)"無(wú)用"操作 mov r0, r0 mov pc, lr//跳轉到__mmap_switched函數 gliethtttp/* * The following fragment of code is executed with the MMU on, and uses * absolute addresses; this is not position independent。
* * r0 = processor control register * r1 = machine ID * r9 = processor ID */ 。align 5__mmap_switched: adr r3, __switch_data + 4 ldmia r3, {r4, r5, r6, r7, r8, sp}@ r2 = compat//2007-07-04 gliethttp//r4 ~ __bss_start//r5 ~ _end//r6 ~ processor_id//r7 ~ __machine_arch_type//r8 ~ cr_alignment//sp ~ (init_task_union)+8192//以下幾步操作對processor_id,__machine_arch_type,cr_alignment賦值gliethttp mov fp, #0 @ Clear BSS (and zero fp)1: cmp r4, r5 //bss區清0 strcc fp, [r4],#4 bcc 1b str r9, [r6] @ Save processor ID str r1, [r7] @ Save machine type#ifdef CONFIG_ALIGNMENT_TRAP orr r0, r0, #2 @ 。
A。#endif bic r2, r0, #2 @ Clear 'A' bit//r2存放 禁用TRAP隊列故障 后的r0值//r8->cr_alignment,cr_no_alignment//所以stmia r8, {r0, r2}后,cr_alignment = r0,cr_no_alignment = r2 stmia r8, {r0, r2} @ Save control register values b SYMBOL_NAME(start_kernel) //進(jìn)入內核C程序//--------------------------------------2。
2 __arm920_proc_info//gliethttp arch/arm/mm/proc-arm920。S。
section "。proc。
info", #alloc, #execinstr 。type __arm920_proc_info,#object__arm920_proc_info://該地址存儲到r10中 。
long 0x41009200 。long 0xff00fff0 。
long 0x00000c1e @ mmuflags b __arm920_setup//add pc, r10, #12 gliethttp將使cpu執行b __arm920_setup跳轉指令 。 long cpu_arch_name 。
long cpu_elf_name 。long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB 。
long cpu_arm920_。
自旋鎖 Linux內核中最常見(jiàn)的鎖是自旋鎖。
一個(gè)自旋鎖就是一個(gè)互斥設備,它只能有兩個(gè)值:"鎖定"和"解鎖"。如果鎖可用,則"鎖定"位被設置,而代碼繼續進(jìn)入臨界區;相反,如果鎖被其他進(jìn)程爭用,則代碼進(jìn)入忙循環(huán)并重復檢查這個(gè)鎖,直到鎖可用為止。
這個(gè)循環(huán)就是自旋鎖的"自旋"。自旋鎖最多只能被一個(gè)可執行的線(xiàn)程持有。
如果一個(gè)執行線(xiàn)程試圖獲得一個(gè)被爭用的自旋鎖,那么該線(xiàn)程就會(huì )一直進(jìn)行忙循環(huán)-旋轉-等待鎖重新可用。注意,同一個(gè)鎖可以用在多個(gè)位置。
缺點(diǎn):一個(gè)被爭用的自旋鎖使得請求它的線(xiàn)程在等待鎖重新可用時(shí)自旋(特別浪費處理器時(shí)間)。 所以,自旋鎖不應該被長(cháng)時(shí)間持有。
當然,可以采用另外的方式處理對鎖的爭用:讓請求線(xiàn)程睡眠,直到鎖重新可用時(shí)在喚醒它。但是,這里有兩次明顯的上下文切換,被阻塞的線(xiàn)程要換入或換出。
因此,持有自旋鎖的時(shí)間最好小于完成兩次上下文切換的耗時(shí)。 注意: 1) 如果禁止內核被搶占,那么在編譯時(shí)自旋鎖會(huì )被完成剔除出內核。
2) Linux內核實(shí)現的自旋鎖是不可遞歸的。小心自加鎖。
3) 調試自旋鎖, 加上配置選項CONFIG_DEBUG_SPINLOCK。 4)自旋鎖可以使用在中斷處理程序中(此處不能使用信號量,因為它們會(huì )導致睡眠),在中斷處理程序中使用自旋鎖時(shí),一定要在獲取鎖之前,首先禁止本地中斷 (在當前處理器上的中斷請求),否則中斷處理程序就會(huì )打斷正持有鎖的內核代碼,有可能試圖去爭用這個(gè)已經(jīng)被持有的自旋鎖。
5) 加鎖是對數據不是對代碼。 6) 所有自旋鎖的等待在本質(zhì)上都是不可中斷的。
1。1。
自旋鎖API介紹自旋鎖實(shí)現與體系結構密切相關(guān),定義在中。在編譯時(shí)對自旋鎖的初始化: spinlock_t my_lock=SPIN_LOCK_UNLOCKED; 或者在運行時(shí): void spin_lock_init(spinlock_t *lock); 進(jìn)入臨界區: spin_lock(&my_lock); /*訪(fǎng)問(wèn)數據*/ spin_unlock(&my_lock); 內核提供禁止中斷同時(shí)請求鎖的接口: spinlock_t my_lock=SPIN_LOCK_UNLOCKED; unsigned long flags; spin_lock_irqsave(&my_lock, flags); /*訪(fǎng)問(wèn)數據*/ spin_unlock_irqrestore(&my_lock, flags);函數spin_lock_irqsave保存了中斷的當前狀態(tài),并禁止了本地中斷,然后在獲取指定的鎖;函數 spin_unlock_irqrestore對指定的鎖解鎖,然后讓中斷恢復到加鎖前的狀態(tài)。
內核提供的自旋鎖的接口: void spin_lock_irq (spinlock_t *lock); void spin_unlock_irq (spinlock_t *lock); void spin_lock_bh (spinlock_t *lock); void spin_unlock_bh (spinlock_t *lock); 如果能夠確保沒(méi)有任何其他代碼禁止本地處理器的中斷,也就是說(shuō),能夠確保在釋放自旋鎖時(shí)應該啟用中斷,這可以使用spin_lock_irq函數,而無(wú)需跟蹤標志。 函數spin_lock_bh在獲得鎖之前禁止軟件中斷,但是會(huì )讓硬件中斷保持打開(kāi)。
以上是我對于這個(gè)問(wèn)題的解答,希望能夠幫到大家。
聲明:本網(wǎng)站尊重并保護知識產(chǎn)權,根據《信息網(wǎng)絡(luò )傳播權保護條例》,如果我們轉載的作品侵犯了您的權利,請在一個(gè)月內通知我們,我們會(huì )及時(shí)刪除。
蜀ICP備2020033479號-4 Copyright ? 2016 學(xué)習?shū)B(niǎo). 頁(yè)面生成時(shí)間:3.307秒