以前寫的,但是沒寫完,偏偏你要的那部分沒寫。
呵呵~~ 先聲明,沒調(diào)試過。
僅供參考,有錯(cuò)誤的地方請(qǐng)指正,謝謝!/////////////////////////******setport.h*******/////////////////////////#ifndef SETPORT_H#define SETPORT_H/********************* int dwBaudRate; //波特率 char bTTY; //串口號(hào) char bDataBit; //數(shù)據(jù)位 5,6,7,8 char bParity; //奇偶校驗(yàn) 無校驗(yàn):'N' 偶校驗(yàn)'E' 奇校驗(yàn)'O' char bStopBit; //停止位 1,2 char bFctl; //流控制 無控制:'N' 硬件控制:'H' 軟件控制:'S'**********************///-------------------打開串口-------------------//bTTY==0,1,2,3, 對(duì)應(yīng)串口Com1到Com4,成功返回文件描述符,失敗==(-1) extern int PortOpen(char bTTY);//-------------------設(shè)置串口-------------------//成功==(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);//-------------------寫串口-------------------//成功返回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í)設(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"//-------------------打開串口-------------------// 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); }//-------------------設(shè)置串口-------------------// 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); /*------------設(shè)置端口屬性------------*/ 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) //數(shù)據(jù)位 { 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':{ //無校驗(yàn) newtm_t.c_cflag&=~PARENB; newtm_t.c_iflag&= ~INPCK; }break; case 'O':{ //奇校驗(yàn) newtm_t.c_cflag |= (PARODD | PARENB); newtm_t.c_iflag |= INPCK; }break; case 'E':{ //偶校驗(yàn) 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':{ //無控制 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); //端口復(fù)位 tcsetattr(dwFdcom,TCSANOW,&newtm_t); //使端口屬性設(shè)置生效 return 0; }//-------------------超時(shí)設(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; }////讀寫串口用文件讀寫方式,read和write兩個(gè)方法,////read是接收數(shù)據(jù),write是發(fā)送數(shù)據(jù)。
從個(gè)人的理解,Linux2。
6內(nèi)核對(duì)中斷處理程序的現(xiàn)在的處理可以分為兩種模式,一種就是上面說的老的模式(非共享中斷線),一種屬于使用共享中斷線的新模式,從其使用的注冊(cè)中斷處理程序的函數(shù)中來分析,函數(shù)原型如下: int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void * dev_id); 參數(shù)1:中斷線號(hào) 參數(shù)2:中斷處理程序函數(shù)指針 參數(shù)3:標(biāo)志掩碼(SA_INTERRUPT, SA_SAMPLE_RANDOM, SA_SHIRQ) 參數(shù)4:用于參數(shù)3為SA_SHIRQ(共享中斷線)的時(shí)候,其他為NULL 原來對(duì)于計(jì)算機(jī)設(shè)備比較少的時(shí)候,可能一個(gè)中斷線好可以對(duì)應(yīng)一個(gè)中斷處理程序(非共享中斷線),這時(shí)候參數(shù)4為NULL,沒有任何用,但隨著計(jì)算機(jī)設(shè)備的增加,一個(gè)中斷線號(hào)對(duì)應(yīng)一個(gè)中斷處理程序已經(jīng)不太現(xiàn)實(shí),這個(gè)時(shí)候就使用了共享的中斷線號(hào),多個(gè)設(shè)備使用同一個(gè)中斷線號(hào),同一個(gè)中斷設(shè)備線號(hào)的所有處理程序鏈接成一個(gè)鏈表,這樣當(dāng)在共享中斷線號(hào)的方式下一個(gè)中斷產(chǎn)生的時(shí)候,就要遍歷其對(duì)應(yīng)的處理程序鏈表,但這個(gè)中斷是由使用同一個(gè)中斷線號(hào)的多個(gè)設(shè)備中間的一個(gè)產(chǎn)生的,不可能鏈表里面的所有處理程序都調(diào)用一遍吧,呵呵,這個(gè)時(shí)候就該第四個(gè)參數(shù)派上用場(chǎng)了。 因?yàn)槎鄠€(gè)設(shè)備共享同一個(gè)中斷線號(hào),當(dāng)中斷產(chǎn)生的時(shí)候到底是那一個(gè)設(shè)備產(chǎn)生的中斷呢,這個(gè)就取決于第四個(gè)參數(shù)dev_id,這個(gè)參數(shù)必須是唯一的,也就是能區(qū)分到底是那個(gè)設(shè)備產(chǎn)生的中斷,而且從第二個(gè)參數(shù)可以看出來,這個(gè)參數(shù)被傳入中斷處理程序(第二個(gè)參數(shù)),可以這么理解,當(dāng)中斷產(chǎn)生的時(shí)候,如果是共享的中斷線號(hào),則對(duì)應(yīng)鏈表的所有中斷處理程序都被調(diào)用,不過在每個(gè)中斷處理程序的內(nèi)部首先檢查(參數(shù)信息以及設(shè)備硬件的支持)是不是這個(gè)中斷處理程序?qū)?yīng)的設(shè)備產(chǎn)生的中斷,如果不是,立即返回,如果是,則處理完成,如果鏈表中沒有一個(gè)是,則說明出現(xiàn)錯(cuò)誤。
下來說說中斷處理程序,先看看原型: static irqreturn_t intr_handler(int irq, void * dev_id, struct pt_regs * regs); 參數(shù)1:中斷線號(hào) 參數(shù)2:設(shè)備的信息,唯一確定性 參數(shù)3:中斷之前的處理器寄存器的信息和狀態(tài) 通過上面的分析,大概可以看到,參數(shù)1(中斷線號(hào))貌似有點(diǎn)多余,因?yàn)槿绻欠枪蚕淼闹袛嗑€,通過中斷線號(hào)直接調(diào)用處理程序,將這個(gè)參數(shù)傳進(jìn)去好像沒什么用,如果屬于共享的中斷線,則通過中斷線號(hào)直接找到對(duì)應(yīng)的中斷處理程序鏈表,挨個(gè)遍歷,都是一個(gè)中斷線號(hào),傳進(jìn)去也沒用,該不該調(diào)用,通過第二個(gè)參數(shù)來區(qū)分,那為什么要保留這個(gè)參數(shù)呢?答案是歷史遺留問題,往后可能越來越?jīng)]用了,至于為什么是歷史遺留問題,可能在沒有第二個(gè)參數(shù)的時(shí)候才在第一個(gè)上面做了點(diǎn)手腳,既然第二個(gè)參數(shù)已經(jīng)添加進(jìn)去了,第一個(gè)的作用就越來越少了。 如果是共享的中斷線號(hào),則對(duì)應(yīng)鏈表的所有中斷處理程序都被調(diào)用,不過在每個(gè)中斷處理程序的內(nèi)部首先檢查(參數(shù)信息以及設(shè)備硬件的支持)是不是這個(gè)中斷處理程序?qū)?yīng)的設(shè)備產(chǎn)生的中斷,如果不是,立即返回,如果是,則處理完成,如果鏈表中沒有一個(gè)是,則說明出現(xiàn)錯(cuò)誤。
Linux混入了mmu內(nèi)存管理之后,ARM的中斷是怎么樣的呢?和我們?cè)诼惆迳系闹袛嘤袥]有區(qū)別?讓我們從源代碼入手,做一個(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中設(shè)置的r0值,置入cp15協(xié)處理器c1寄存器中 mrc p15, 0, r0, c1, c0, 0 @ read it back。 mov r0, r0//填充armv4中的三級(jí)流水線:mov r0,r0 對(duì)應(yīng)一個(gè)nop,所以對(duì)應(yīng)2個(gè)nop和一個(gè)mov pc,lr剛好三個(gè)"無用"操作 mov r0, r0 mov pc, lr//跳轉(zhuǎn)到__mmap_switched函數(shù) 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//以下幾步操作對(duì)processor_id,__machine_arch_type,cr_alignment賦值gliethttp mov fp, #0 @ Clear BSS (and zero fp)1: cmp r4, r5 //bss區(qū)清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隊(duì)列故障 后的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)入內(nèi)核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://該地址存儲(chǔ)到r10中 。
long 0x41009200 。long 0xff00fff0 。
long 0x00000c1e @ mmuflags b __arm920_setup//add pc, r10, #12 gliethttp將使cpu執(zhí)行b __arm920_setup跳轉(zhuǎn)指令 。 long cpu_arch_name 。
long cpu_elf_name 。long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB 。
long cpu_arm920_。
自旋鎖 Linux內(nèi)核中最常見的鎖是自旋鎖。
一個(gè)自旋鎖就是一個(gè)互斥設(shè)備,它只能有兩個(gè)值:"鎖定"和"解鎖"。如果鎖可用,則"鎖定"位被設(shè)置,而代碼繼續(xù)進(jìn)入臨界區(qū);相反,如果鎖被其他進(jìn)程爭(zhēng)用,則代碼進(jìn)入忙循環(huán)并重復(fù)檢查這個(gè)鎖,直到鎖可用為止。
這個(gè)循環(huán)就是自旋鎖的"自旋"。自旋鎖最多只能被一個(gè)可執(zhí)行的線程持有。
如果一個(gè)執(zhí)行線程試圖獲得一個(gè)被爭(zhēng)用的自旋鎖,那么該線程就會(huì)一直進(jìn)行忙循環(huán)-旋轉(zhuǎn)-等待鎖重新可用。注意,同一個(gè)鎖可以用在多個(gè)位置。
缺點(diǎn):一個(gè)被爭(zhēng)用的自旋鎖使得請(qǐng)求它的線程在等待鎖重新可用時(shí)自旋(特別浪費(fèi)處理器時(shí)間)。 所以,自旋鎖不應(yīng)該被長時(shí)間持有。
當(dāng)然,可以采用另外的方式處理對(duì)鎖的爭(zhēng)用:讓請(qǐng)求線程睡眠,直到鎖重新可用時(shí)在喚醒它。但是,這里有兩次明顯的上下文切換,被阻塞的線程要換入或換出。
因此,持有自旋鎖的時(shí)間最好小于完成兩次上下文切換的耗時(shí)。 注意: 1) 如果禁止內(nèi)核被搶占,那么在編譯時(shí)自旋鎖會(huì)被完成剔除出內(nèi)核。
2) Linux內(nèi)核實(shí)現(xiàn)的自旋鎖是不可遞歸的。小心自加鎖。
3) 調(diào)試自旋鎖, 加上配置選項(xiàng)CONFIG_DEBUG_SPINLOCK。 4)自旋鎖可以使用在中斷處理程序中(此處不能使用信號(hào)量,因?yàn)樗鼈儠?huì)導(dǎo)致睡眠),在中斷處理程序中使用自旋鎖時(shí),一定要在獲取鎖之前,首先禁止本地中斷 (在當(dāng)前處理器上的中斷請(qǐng)求),否則中斷處理程序就會(huì)打斷正持有鎖的內(nèi)核代碼,有可能試圖去爭(zhēng)用這個(gè)已經(jīng)被持有的自旋鎖。
5) 加鎖是對(duì)數(shù)據(jù)不是對(duì)代碼。 6) 所有自旋鎖的等待在本質(zhì)上都是不可中斷的。
1。1。
自旋鎖API介紹自旋鎖實(shí)現(xiàn)與體系結(jié)構(gòu)密切相關(guān),定義在中。在編譯時(shí)對(duì)自旋鎖的初始化: spinlock_t my_lock=SPIN_LOCK_UNLOCKED; 或者在運(yùn)行時(shí): void spin_lock_init(spinlock_t *lock); 進(jìn)入臨界區(qū): spin_lock(&my_lock); /*訪問數(shù)據(jù)*/ spin_unlock(&my_lock); 內(nèi)核提供禁止中斷同時(shí)請(qǐng)求鎖的接口: spinlock_t my_lock=SPIN_LOCK_UNLOCKED; unsigned long flags; spin_lock_irqsave(&my_lock, flags); /*訪問數(shù)據(jù)*/ spin_unlock_irqrestore(&my_lock, flags);函數(shù)spin_lock_irqsave保存了中斷的當(dāng)前狀態(tài),并禁止了本地中斷,然后在獲取指定的鎖;函數(shù) spin_unlock_irqrestore對(duì)指定的鎖解鎖,然后讓中斷恢復(fù)到加鎖前的狀態(tài)。
內(nè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); 如果能夠確保沒有任何其他代碼禁止本地處理器的中斷,也就是說,能夠確保在釋放自旋鎖時(shí)應(yīng)該啟用中斷,這可以使用spin_lock_irq函數(shù),而無需跟蹤標(biāo)志。 函數(shù)spin_lock_bh在獲得鎖之前禁止軟件中斷,但是會(huì)讓硬件中斷保持打開。
以上是我對(duì)于這個(gè)問題的解答,希望能夠幫到大家。
聲明:本網(wǎng)站尊重并保護(hù)知識(shí)產(chǎn)權(quán),根據(jù)《信息網(wǎng)絡(luò)傳播權(quán)保護(hù)條例》,如果我們轉(zhuǎn)載的作品侵犯了您的權(quán)利,請(qǐng)?jiān)谝粋€(gè)月內(nèi)通知我們,我們會(huì)及時(shí)刪除。
蜀ICP備2020033479號(hào)-4 Copyright ? 2016 學(xué)習(xí)鳥. 頁面生成時(shí)間:3.307秒