久久99精品久久久久久琪琪,久久人人爽人人爽人人片亞洲,熟妇人妻无码中文字幕,亚洲精品无码久久久久久久

基于多單片機(jī)的串口擴(kuò)展設(shè)計(jì)論文[5篇材料]

時(shí)間:2019-11-17 01:08:06下載本文作者:會(huì)員上傳
簡(jiǎn)介:寫(xiě)寫(xiě)幫文庫(kù)小編為你整理了多篇相關(guān)的《基于多單片機(jī)的串口擴(kuò)展設(shè)計(jì)論文》,但愿對(duì)你工作學(xué)習(xí)有幫助,當(dāng)然你在寫(xiě)寫(xiě)幫文庫(kù)還可以找到更多《基于多單片機(jī)的串口擴(kuò)展設(shè)計(jì)論文》。

第一篇:基于多單片機(jī)的串口擴(kuò)展設(shè)計(jì)論文

前言

筆者在用單片機(jī)開(kāi)發(fā)一款稱重儀表時(shí),功能較多,對(duì)串口的需求很高。需要的串口數(shù)量多,至少要五個(gè)串口,包括稱重傳感器通信串口,電腦上位機(jī)通信串口,GIM900A 通信串口,大屏幕數(shù)碼管顯示的通信串口,打印模塊的通信串口等。而且對(duì)串口要求穩(wěn)定性高,大部分串口都要求實(shí)時(shí)雙工通信。根據(jù)實(shí)際情況和產(chǎn)品串口需求,采用不用的方法進(jìn)行串口擴(kuò)展,主要用到了模擬串口和多單片機(jī)實(shí)現(xiàn)串口擴(kuò)展。串口擴(kuò)展的一般方法

(1)模擬串口。模擬串口利用其他單片機(jī)引腳模擬串口收發(fā)時(shí)序進(jìn)行串口擴(kuò)展。這種串口擴(kuò)展,缺點(diǎn)比較明顯,通信速率慢,可靠性不高,占用CPU 資源較多。高速雙工通信時(shí)一般不用此方案進(jìn)行串口擴(kuò)展,低速情況下可以考慮。筆者的項(xiàng)目中大屏幕數(shù)碼管顯示就用了這種方案,顯示的時(shí)候只發(fā)不收,單向通信,波特率要求低,最高不過(guò)9600bps。

(2)利用專門(mén)的串口擴(kuò)展芯片處理。串口擴(kuò)展芯片進(jìn)行串口擴(kuò)展,通信穩(wěn)定性高,能達(dá)到一般的串口要求。市場(chǎng)上的串口擴(kuò)展芯片,性能不同,價(jià)格也不一樣,但普遍成本較高,少則二三十元,多則七八十元,不利于產(chǎn)品的成本控制。串口需求較多時(shí),一塊串口擴(kuò)展芯片上串口數(shù)量不足,還需要多塊串口擴(kuò)展芯片級(jí)聯(lián),更增加了成本。

(3)利用多串口單片機(jī)。目前市場(chǎng)上有多串口的單片機(jī),很多低成本單片機(jī)都自帶兩個(gè)串口,比如stc12 多串口系列。用三串口及其以上的單片機(jī)成本更貴。

(4)基于多單片機(jī)的串口擴(kuò)展設(shè)計(jì)。在一定成本要求下,結(jié)合目前單片機(jī)產(chǎn)品自身的優(yōu)勢(shì),利用多單片機(jī)進(jìn)行串口擴(kuò)展,也是一種串口擴(kuò)展的方案。一般c51 系列單片機(jī)自帶雙串口的只要幾元錢(qián),完全可以把單片機(jī)用來(lái)做串口擴(kuò)展,而且有的單片機(jī)自帶spi 通信接口,可以很方便的實(shí)現(xiàn)主從單片機(jī)之間的級(jí)聯(lián)和通信,同時(shí)雙單片機(jī)工作時(shí),可以利用從單片機(jī)處理一定的程序,減輕主單片機(jī)的負(fù)擔(dān),達(dá)到“雙核”效果。基于多單片機(jī)的串口擴(kuò)展設(shè)計(jì)

3.1 串口擴(kuò)展系統(tǒng)框圖

整個(gè)系統(tǒng)由兩塊單片機(jī)構(gòu)成主從結(jié)構(gòu),主機(jī)完成產(chǎn)品的大部分功能,從機(jī)只是進(jìn)行了串口擴(kuò)展,擴(kuò)展出了兩個(gè)雙工硬件串口,如果有需要,也可以分擔(dān)部分主機(jī)的其他功能。兩者之間通過(guò)SPI 硬件接口通信,該硬件SPI 總線是一種全雙工、高速、同步的通信總線,支持主模式和從模式兩種操作模式,主模式中支持高達(dá)3Mbps 的速率,完全可以完成主機(jī)和從機(jī)之間的可靠通信。主機(jī)和從機(jī)的串口通信,和一塊單片機(jī)使用時(shí)的用法一樣,只是先要經(jīng)過(guò)SPI 傳輸。當(dāng)需要向從機(jī)串口發(fā)數(shù)據(jù)時(shí),先要通過(guò)主機(jī)的SPI 通信送給從機(jī),再通過(guò)從機(jī)串口發(fā)給外圍模塊;當(dāng)需要接收從機(jī)串口數(shù)據(jù)時(shí),先從機(jī)接收到串口數(shù)據(jù),從機(jī)再利用SPI 傳輸給主機(jī)。在進(jìn)行軟件開(kāi)發(fā)時(shí),只要定義好主機(jī)和從機(jī)的SPI 通信協(xié)議,即可完成可靠的串口數(shù)據(jù)收發(fā)。

3.2 主機(jī)和從機(jī)之間的SPI 通信

主機(jī)和從機(jī)串口之間需要SPI 通信做橋梁,因此主從機(jī)之間的SPI 通信顯得極其重要,必須要求高速、可靠、實(shí)時(shí),一次SPI 采用中斷完成。主機(jī)部分需要用到常用的四個(gè)函數(shù),即主機(jī)SPI 初始化,SPI 主從機(jī)之間的數(shù)據(jù)交換,向從機(jī)發(fā)送數(shù)據(jù),主機(jī)SPI 中斷接收等。

1)主機(jī)SPI 初始化:

SPDAT=0;

SPCTL=0xfd;

SPSTAT=0xc0;

IE2=IE2 | 0x2;

2)主機(jī)SPI 數(shù)據(jù)交換

SPDAT = dat;

while(!(SPSTAT & SPI_SPIF));

SPSTAT = 0xc0;

return SPDAT;

3)向從機(jī)發(fā)送字符串?dāng)?shù)據(jù)

SPCTL = 0xfd;

IE2=IE2 & 0x01;

SPISS=0;

4)SPI 接收中斷函數(shù)

uchar ucRecvSpi;

SPDAT=SPDAT;

SPSTAT = 0xc0;

ucRecvSpi=SPDAT;

??//SPI 接收到的數(shù)據(jù)處理

?循環(huán)SPI 數(shù)據(jù)交換

發(fā)送字符串

SPISS=1;

SPCTL = 0xec;

IE2=IE2 | 0x3;

從機(jī)部分也需要用到主機(jī)一樣的四個(gè)函數(shù),即從機(jī)SPI 初始化,SPI 主從機(jī)之間的數(shù)據(jù)交換,向主機(jī)發(fā)送數(shù)據(jù),從機(jī)SPI中斷接收等。程序函數(shù)與主機(jī)大部分相同,只有細(xì)微區(qū)別。在從機(jī)SPI 初始化時(shí),SPCTL 控制寄存器初值為0xec。

3.3 擴(kuò)展的串口處理

從機(jī)自帶的兩個(gè)雙工串口即是擴(kuò)展出來(lái)的串口,要實(shí)現(xiàn)收發(fā)數(shù)據(jù),需要用到基本的3 個(gè)函數(shù),即從機(jī)串口初始化,從機(jī)串口向外圍模塊發(fā)送數(shù)據(jù),從機(jī)中斷接收數(shù)據(jù)。串口4 和串口5 函數(shù)類(lèi)似,下面只列舉串口4 的初始化函數(shù)部分。

1)串口1 初始化

TMOD = 0x20;

SCON = 0x5a;

TH1 =TL1=-3;

TR1 = 1;

ES = 1;EA = 1;

2)串口接收中斷

RI = 0;

Buf[i]=SBUF;// 接收串口數(shù)據(jù)存入數(shù)組

if(SBUF==0x0a && Buf[i-2]==0x0d)

接收到結(jié)束符,則向主機(jī)發(fā)送串口數(shù)據(jù)。結(jié)語(yǔ)

本文中的串口擴(kuò)展方法,實(shí)用性強(qiáng),成本較低,能較好的實(shí)現(xiàn)串口擴(kuò)展,同時(shí)利用多出的單片機(jī),可以為主CPU 分擔(dān)一定的任務(wù),提供一定的硬件資源。

第二篇:?jiǎn)纹瑱C(jī)串口總結(jié)

51單片機(jī)串口總結(jié)

有句話說(shuō)“盡信書(shū)不如無(wú)書(shū)”,要學(xué)好單片機(jī)就要不斷的、大膽的實(shí)驗(yàn),要多懷疑,即使我們的懷疑最終被證明是錯(cuò)誤的那么這也是進(jìn)步(人們認(rèn)識(shí)事物很多情況下來(lái)源于懷疑),當(dāng)懷疑出現(xiàn)時(shí)就要去實(shí)踐。有很多東西如果不通過(guò)實(shí)踐是不可能掌握其中隱藏的奧秘,就拿51單片機(jī)串口通訊這一塊,我認(rèn)為掌握很好了,可以很輕松的實(shí)現(xiàn)數(shù)據(jù)的接收、發(fā)送,但這段時(shí)間當(dāng)我重新學(xué)習(xí)串口時(shí),我才發(fā)現(xiàn)里面還有很多小細(xì)節(jié)從沒(méi)注意,更別說(shuō)研究了。對(duì)于接收發(fā)送程序永遠(yuǎn)是按照別人的模式來(lái)編寫(xiě)程序,并沒(méi)有真真正正的挖掘深層次的內(nèi)容。我身邊太多的人在臨摹別人的程序,當(dāng)然我不反對(duì),但是希望自己多問(wèn)幾個(gè)問(wèn)什么,單純的會(huì)編程是學(xué)不好單片機(jī)的,畢竟單片機(jī)有自己獨(dú)特的硬件結(jié)構(gòu)。

開(kāi)講之前先簡(jiǎn)要說(shuō)一下同步、異步通信:

同步通信:發(fā)送方時(shí)鐘對(duì)接收方時(shí)鐘控制,使雙方達(dá)到完全同步。

異步通信:發(fā)送與接受設(shè)備使用各自的時(shí)鐘控制數(shù)據(jù)的發(fā)送和接受過(guò)程(雖然時(shí)鐘不同,但一般相差不大)。

51單片機(jī)串行口結(jié)構(gòu)

從上圖中我們看到,51單片機(jī)有兩個(gè)物理上獨(dú)立的接收、發(fā)送緩沖器SBUF,它們共用同一個(gè)地址99H,但是請(qǐng)注意:接收緩沖器只能讀而不能寫(xiě),發(fā)送緩沖器只寫(xiě)不讀。單片機(jī)可以同時(shí)實(shí)現(xiàn)數(shù)據(jù)的發(fā)送與接收功能。

特別注意:接收器是雙緩沖結(jié)構(gòu):當(dāng)前一個(gè)字節(jié)從接收緩沖區(qū)取走之前,就已經(jīng)開(kāi)始接收第

二個(gè)字節(jié)(串行輸入至移位寄存器),此時(shí)如果在第二個(gè)字節(jié)接收完畢而前一個(gè)字節(jié)還未被讀走,那么就會(huì)丟失前一個(gè)字節(jié)。

51單片機(jī)串口控制寄存器

關(guān)于51單片機(jī)的控制寄存器各個(gè)位表示的含義在這里我只談SM2。

SM2為多機(jī)控制位,主要用于工作方式2和3,當(dāng)接收機(jī)的SM2=1時(shí),可以利用接收到的RB8來(lái)控制是否激活RI(RB8=0不激活RI,收到的數(shù)據(jù)丟失;RB8=1時(shí)收到的數(shù)據(jù)進(jìn)入SBUF,并激活RI ,進(jìn)而在中斷服務(wù)程序中將數(shù)據(jù)從SBUF中讀走)。當(dāng)SM2=0時(shí),不論收到的RB8為何值都將使接收到的數(shù)據(jù)進(jìn)入SBUF,并激活RI,通過(guò)控制SM2實(shí)現(xiàn)多機(jī)通信。

51單片機(jī)串口通訊方式

51串口通訊方式有3種,方式0、方式

1、方式2與方式3,他們的工作模式不盡相同。首先他們的波特率很容易忽視。方式0與方式2的波特率固定,而方式1和3的波特率由T1的溢出率決定。

方式0的波特率=f/12

系統(tǒng)晶振的12分頻,換句話說(shuō)12M晶振的情況下,其波特率可達(dá)1M,速度是很高的(當(dāng)我們?cè)谶x用串行器件并采用方式0時(shí)需要特別注意器件所能允許的最大時(shí)鐘頻率)。

方式2 =f/64或f/32(當(dāng)SMOD=1時(shí)為f/32,SMOD=0時(shí)為f/64)。

曾經(jīng)我用方式2進(jìn)行MODBUS通信時(shí),總是通訊失敗,我仔細(xì)檢查程序,沒(méi)有發(fā)現(xiàn)邏輯錯(cuò)誤,特別是當(dāng)我參考別人的程序時(shí),發(fā)現(xiàn)很少有人用方式2進(jìn)行MODBUS通訊,所以當(dāng)時(shí)自己妄下結(jié)論51單片機(jī)的串行方式2不可用,直到有一天夜里我突然想起方式2的波特率是固定的,試想晶振11.0592M/32或11.0592M/64怎么也不可能是9600啊,怎么可能通信成功。這才恍然大悟,看來(lái)還是自己太武斷了,沒(méi)有認(rèn)真看書(shū)啊。有時(shí)我們認(rèn)為我們犯這樣的錯(cuò)誤很低級(jí),其實(shí)我們很多次都是因?yàn)檫@樣的小細(xì)節(jié)導(dǎo)致我們整個(gè)系統(tǒng)不正常,正所謂“千里之堤毀于蟻穴”,這些細(xì)節(jié)真的傷不起啊。

方式1、3波特率=(2smod/32)*T1的溢出率,其中TI的溢出率=f/{12*[256-(TH1)]}.關(guān)于3種通訊方式其中有幾點(diǎn)特別容易出錯(cuò):

1、無(wú)論采用哪種通訊方式,數(shù)據(jù)發(fā)送和接受都是低位在先,高位在后。、3種方式作為輸出,由于輸出是CPU主動(dòng)發(fā)送,不會(huì)產(chǎn)生重疊錯(cuò)誤,當(dāng)數(shù)據(jù)寫(xiě)入SBUF后,發(fā)送便啟動(dòng)(通過(guò)單片機(jī)內(nèi)部邏輯控制,與程序無(wú)關(guān)),當(dāng)該字節(jié)發(fā)送結(jié)束(SBUF空),置TI。不要理解為當(dāng)數(shù)據(jù)一寫(xiě)入SBUF就置位TI,如果中斷允許則在中斷中發(fā)送數(shù)據(jù),這就大錯(cuò)特錯(cuò)了。同樣作為輸入,可能會(huì)產(chǎn)生重疊錯(cuò)誤(主要依賴于特定的環(huán)境),當(dāng)一個(gè)字節(jié)的數(shù)據(jù)接收完畢(SBUF滿)置位RI,表示緩沖區(qū)有數(shù)據(jù)提示CPU讀取。

接下來(lái)通過(guò)一些實(shí)驗(yàn)具體說(shuō)明串口通信中需要注意的地方 方式0輸出

方式0主要功能是作為移位寄存器,將數(shù)據(jù)從SBUF中逐位移出,最常見(jiàn)的用法就是外接串入并出的移位寄存器,如74LS164。之前在做這一部分實(shí)驗(yàn)時(shí)總是利用單片機(jī)I/O端口模擬實(shí)現(xiàn),現(xiàn)在想想在串口未被占用的情況下,方式0是最好的實(shí)現(xiàn)方式。

利用串口方式0,向74LS164輸出字符“0”的編碼,程序如下:

該程序采用了中斷方式實(shí)現(xiàn),結(jié)果是通過(guò)74LS164使數(shù)碼管顯示“0”。實(shí)驗(yàn)結(jié)果如下:

這里我說(shuō)明幾點(diǎn): 如果采用查詢方式,并且只發(fā)送一遍,那么程序最后的while(1);不可以省略,否則會(huì)出現(xiàn)數(shù)碼管閃爍的現(xiàn)象(在KEIL環(huán)境下,main()函數(shù)也是作為一個(gè)調(diào)用函數(shù),最后也有返回RET,它不像C中的main()函數(shù),當(dāng)執(zhí)行完畢后就停止,而是重新復(fù)位執(zhí)行,如此反復(fù),這一點(diǎn)要特別注意)

這是查詢方式下不加while(1);的現(xiàn)實(shí)效果 如果采用中斷方式發(fā)送,請(qǐng)記得中斷中清除TI,僅僅是為了解除中斷標(biāo)志,而不是等待發(fā)送結(jié)束,因?yàn)榇藭r(shí)數(shù)據(jù)早已離開(kāi)了SBUF跑到外邊去了。3 74LS164最高25MHZ,采用方式0,沒(méi)有問(wèn)題。

方式0作為輸入模式

以74ls165(最高時(shí)鐘25MHZ)為例,可以滿足要求。

對(duì)應(yīng)結(jié)果如下:

(注意:74ls165線傳送高位,而串口通信低位在先,所以顯示的數(shù)據(jù)和實(shí)際數(shù)據(jù)高低位正好相反

P1.7---P1.0對(duì)應(yīng)D0---D7)。

本程序只接收一次,也許有人會(huì)問(wèn),中斷程序中REN=0,表示什么意思?可不可以改成ES=0?

這個(gè)問(wèn)題很好,首先REN=0表示接收禁止,即不允許串口接收數(shù)據(jù);ES=0是禁止中斷和單片機(jī)是否接收數(shù)據(jù)沒(méi)有關(guān)系,不接收數(shù)據(jù)自然中斷允許也是徒勞,這兩者有很大的區(qū)別。我們?cè)诤芏嘟邮粘绦蛑薪?jīng)常可以看到在判斷RI標(biāo)志后緊跟著清除標(biāo)志位,我想問(wèn)一下,為什么?)

如果我們也按照這種模式改寫(xiě)會(huì)怎樣呢?

實(shí)驗(yàn)結(jié)果如下

兩次結(jié)果差異怎么這么大?為什么會(huì)這樣子?

為了便于理解,也為了說(shuō)明問(wèn)題方便,對(duì)中斷程序做了如下處理:

結(jié)果又變了

是不是感覺(jué)很奇怪,究竟咋回事呢?

首先中斷程序中當(dāng)判斷RI置位標(biāo)志后緊跟著清零是為了接收下一個(gè)字節(jié)的數(shù)據(jù),也為了避免單片機(jī)重復(fù)中斷。

當(dāng)51單片機(jī)串口方式0作輸入時(shí),在REN=1且RI=0的條件下就啟動(dòng)了單片機(jī)串口接收過(guò)程。如果有一個(gè)條件不滿足就不能啟動(dòng)接收過(guò)程,以上出現(xiàn)的錯(cuò)誤正式由于忽略了這個(gè)重要的因素造成的。在RI清零后由于REN仍然為1,單片機(jī)已經(jīng)開(kāi)始接收第二字節(jié)的數(shù)據(jù),由于串口速度很快,RI仍會(huì)置位,而緊接著將REN清零只能阻止單片機(jī)接收數(shù)據(jù),但是卻

不能阻擋第二次中斷。由于只接收了部分外部引腳數(shù)據(jù)(此時(shí)外部引腳為高電平,即邏輯1,其實(shí)單片機(jī)只接收了一位,對(duì)于12M晶振而言,方式0大約8us接收一個(gè)字節(jié)數(shù)據(jù))。相反在RI=0與REN=0之間加上適當(dāng)?shù)难舆t,就可以保證一個(gè)字節(jié)的數(shù)據(jù)全部接收完畢,故此時(shí)我們讀上來(lái)的一個(gè)字節(jié)為0xff。

我在中斷程序中添加了一個(gè)中斷計(jì)數(shù)器(不加延遲),發(fā)現(xiàn)中斷服務(wù)程序的確執(zhí)行了兩次

結(jié)果如下

加上延遲結(jié)果

這就驗(yàn)證了剛才的結(jié)論。

至于說(shuō)可不可以換做ES=0,回答是可以的,盡管同樣可以實(shí)現(xiàn)數(shù)據(jù)的讀取,但是實(shí)質(zhì)不同,當(dāng)禁止中斷后,單片機(jī)仍在接收外部數(shù)據(jù),只是不再請(qǐng)求中斷,自然的不再讀取第2、3。。。字節(jié)的數(shù)據(jù),那么P1將保留第一次中斷時(shí)從SBUF中讀出的數(shù)據(jù)。如果某一時(shí)刻打開(kāi)中斷發(fā)現(xiàn)結(jié)果不正常,如果理解了上面的機(jī)制就不會(huì)覺(jué)得驚訝了。建議:?jiǎn)未谓邮諘r(shí),中斷服務(wù)程序中REN清零放在RI之前。

還有一個(gè)問(wèn)題非常重要:

如果我在中斷服務(wù)程序中不清除RI,會(huì)怎樣?

很少有人會(huì)這樣用,但是經(jīng)常有人忘記了(包括我)。課本上寫(xiě)得很清楚,務(wù)必在中斷中用軟件清除RI,為什么要這樣呢?難道僅僅是為了接收下一次數(shù)據(jù)并且避免單片機(jī)不斷的響應(yīng)中斷?的確如此,如果對(duì)于一個(gè)小系統(tǒng)而言,不清除中斷標(biāo)志,那么單片機(jī)將不停的中斷,影響接下來(lái)任務(wù)的執(zhí)行,系統(tǒng)必然癱瘓,而且不能正常的接收數(shù)據(jù)。總結(jié):方式0作為發(fā)送方,只要向SBUF中寫(xiě)入數(shù)據(jù)就啟動(dòng)了發(fā)送過(guò)程;

方式0在座位接收模式時(shí),REN=

1、RI=0的情況下就已經(jīng)啟動(dòng)了接收過(guò)程。在中斷程序中要注意兩者清零的順序。

還有一種情況要特別注意:?jiǎn)纹瑱C(jī)復(fù)位時(shí)SCON自動(dòng)清零,如果單片機(jī)不工作在方式0,那么如果采用位操作SCON時(shí)也要注意REN=1與SM0、SM1的書(shū)寫(xiě)順序,總之切記方式0啟動(dòng)發(fā)送、接收數(shù)據(jù)的條件。

方式1 方式1為10位異步通信模式。作為輸出和方式0沒(méi)有本質(zhì)的區(qū)別,不同的是數(shù)據(jù)幀的形式,但是對(duì)于接受模式則有點(diǎn)不同,當(dāng)REN=1且RI=0時(shí),單片機(jī)并不啟動(dòng)接收過(guò)程。而是以已選擇波特率的16倍速率采樣RXD引腳的電平,當(dāng)檢測(cè)到輸入引腳發(fā)生1---0負(fù)跳變時(shí),則說(shuō)明起始位有效,才開(kāi)始接受本幀數(shù)據(jù)。方式1模式下 單片機(jī)可以工作在全雙工以及半雙工方式。下面舉兩個(gè)例子

半雙工

主機(jī)發(fā)送某一字符,從機(jī)接收到數(shù)據(jù)后返回?cái)?shù)據(jù)加1的值 比如 主機(jī)發(fā)送“1“,從機(jī)收到后回復(fù)主機(jī)”2“。實(shí)驗(yàn)結(jié)果如下:

方式1工作方式主要注意: 1 波特率可變。數(shù)據(jù)接收以起始位為標(biāo)志,停止位結(jié)束。當(dāng)RI=0且SM2=0或接收到有效停止位時(shí),單片機(jī)將接收到的數(shù)據(jù)移入SBUF中,兩個(gè)條件缺一不可。

方式2和方式3 方式2和3不同的只是波特率,這里以方式3為例

作為輸出模式同方式1沒(méi)有區(qū)別,只是增加了第八位數(shù)據(jù)位,第八位數(shù)據(jù)可以用作校驗(yàn)位或在多機(jī)通信中用作數(shù)據(jù)/地址幀的判別位。

首先我們來(lái)做模擬主從奇偶校驗(yàn)?zāi)J?/p>

主機(jī)發(fā)送一幀數(shù)據(jù),并發(fā)送奇偶校驗(yàn)位,從機(jī)接收數(shù)據(jù)后,判斷數(shù)據(jù)是否正確,如果正

確,接收指示燈亮,并且回送主機(jī)數(shù)據(jù)加1,反之回送0;主機(jī)接收從機(jī)信息,如果校驗(yàn)正確點(diǎn)亮LED指示燈.(從機(jī)、主機(jī)接收數(shù)據(jù)無(wú)論校驗(yàn)正確與否,均顯示接收到的字節(jié)數(shù)據(jù))。奇校驗(yàn)?zāi)J?演示結(jié)果如下:

(注:從接接收不正確,返回0)

主從機(jī)接收正確效果

之前我們已經(jīng)介紹了SM2的具體用法,主要用于多機(jī)通信,將SM2作為數(shù)據(jù)/地址幀 的判別位,在接收地址時(shí)令SM2=1,當(dāng)接收到的第八位數(shù)據(jù)為1時(shí)激活RI產(chǎn)生中斷,然后比較地址,如果地址符合則清除SM2準(zhǔn)備接受數(shù)據(jù)信息,反之不理睬。

特別注意 當(dāng)RI=0且SM2=0(或SM2=1時(shí)接收到第9位數(shù)據(jù)為1)時(shí),單片機(jī)將接收到的數(shù)據(jù)移入SBUF中,兩個(gè)條件缺一不可。

在這里我只舉一個(gè)簡(jiǎn)單的例子 一個(gè)主機(jī),兩個(gè)從機(jī) 起始時(shí),主機(jī)從機(jī)的SM2均置位,所有的從機(jī)等待主機(jī)發(fā)送地址幀,主機(jī)令TB8=1,發(fā)送地址幀。所用的從機(jī)將接受到的地址和自己的地址比較,如果符合,點(diǎn)亮LED指示燈,清除SM2(準(zhǔn)備接受主機(jī)發(fā)送的數(shù)據(jù)幀),并將自己的地址發(fā)送到主機(jī)。主機(jī)接收從機(jī)發(fā)送的地址信息,如果地址符合則數(shù)碼管顯示從機(jī)地址并開(kāi)始準(zhǔn)備發(fā)送數(shù)據(jù),反之發(fā)復(fù)位信號(hào),TB8=1。從機(jī)接收數(shù)據(jù)先判斷RB8,如果RB8=1,則復(fù)位,重新開(kāi)始接收主機(jī)發(fā)送的地址幀,反之通過(guò)P1口外接數(shù)碼管顯示接收到的數(shù)據(jù)。實(shí)驗(yàn)結(jié)果如下:

注意:如果主機(jī)沒(méi)有得到正確的地址,則將按照一定的速率發(fā)送地址幀,直到接收正確的地址為止,該試驗(yàn)主機(jī)向從機(jī)2發(fā)送信息。

另外在這里我補(bǔ)充兩點(diǎn): 我們可以很方便的利用串口通信的工作方式2或3實(shí)現(xiàn)奇偶校驗(yàn),注意技巧,當(dāng)為偶校驗(yàn)時(shí)TB8=P,奇校驗(yàn)時(shí)TB8=~P;

2當(dāng)單片機(jī)利用中斷發(fā)送大量數(shù)據(jù)時(shí),盡量采用中斷發(fā)送,因?yàn)閱纹瑱C(jī)在寫(xiě)入SBUF數(shù)據(jù)后由硬件將數(shù)據(jù)發(fā)送完,在發(fā)送過(guò)程中,單片機(jī)還可以做很多事情,利用中斷發(fā)送數(shù)據(jù)可以提高CPU利用率。尤其在低波特率時(shí)效果更明顯。

第三篇:?jiǎn)纹瑱C(jī)串口通信方式總結(jié)

IIC總線通信協(xié)議————數(shù)據(jù)傳輸高位在前p233 1,起始和停止條件

開(kāi)始信號(hào):SCL為高電平,SDA由高電平向低電平跳變,開(kāi)始傳送數(shù)據(jù)。void start()// 開(kāi)始位 { SDA = 1;

//SDA初始化為高電平“1”

SCL = 1;

//開(kāi)始數(shù)據(jù)傳送時(shí),要求SCL為高電平“1”

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

SDA = 0;

//SDA的下降沿被認(rèn)為是開(kāi)始信號(hào)

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

SCL = 0;

//SCL為低電平時(shí),SDA上數(shù)據(jù)才允許變化(即允許以后的數(shù)據(jù)傳遞)} 結(jié)束信號(hào):SCL為高電平,SDA由低電平向高電平跳變,結(jié)束傳送數(shù)據(jù)。void stop()// 停止位 { SDA = 0;

//SDA初始化為低電平“0”

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

SCL = 1;

//結(jié)束數(shù)據(jù)傳送時(shí),要求SCL為高電平“1”

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

SDA = 1;

//SDA的上升沿被認(rèn)為是結(jié)束信號(hào) }

2,數(shù)據(jù)格式(數(shù)據(jù)輸入)

在IIC總線開(kāi)始信號(hào)后,送出的第一個(gè)字節(jié)數(shù)據(jù)是用來(lái)選擇器件地址和數(shù)據(jù)方向的,其格式為

從器件收到地址型號(hào)后與自己的地址比較,一致則此器件就是主器件要找的器件,并返回ACK(不管是寫(xiě)數(shù)據(jù)還是地址都會(huì)返回)。IIC傳送數(shù)據(jù)時(shí)SCL為低電平時(shí)SDA可改變高低電平,SCL轉(zhuǎn)跳為高時(shí)數(shù)據(jù)輸入(此時(shí)SDA不能跳變),發(fā)送數(shù)據(jù):bit WriteCurrent(unsigned char y){ unsigned char i;bit ack_bit;

//儲(chǔ)存應(yīng)答位

for(i = 0;i < 8;i++)// 循環(huán)移入8個(gè)位

{

SDA =(bit)(y&0x80);

//通過(guò)按位“與”運(yùn)算將最高位數(shù)據(jù)送到S

//因?yàn)閭魉蜁r(shí)高位在前,低位在后

_nop_();

//等待一個(gè)機(jī)器周期

SCL = 1;

//在SCL的上升沿將數(shù)據(jù)寫(xiě)入AT24Cxx

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

SCL = 0;

//將SCL重新置為低電平,以在SCL線形成傳送數(shù)據(jù)所需的8?jìng)€(gè)脈沖

y <<= 1;

//將y中的各二進(jìn)位向左移一位

} SDA = 1;

// 發(fā)送設(shè)備(主機(jī))應(yīng)在時(shí)鐘脈沖的高電平期間(SCL=1)釋放SDA線,//以讓SDA線轉(zhuǎn)由接收設(shè)備(AT24Cxx)控制

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

SCL = 1;

//根據(jù)上述規(guī)定,SCL應(yīng)為高電平

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

_nop_();

//等待一個(gè)機(jī)器周期

ack_bit = SDA;//接受設(shè)備(AT24Cxx)向SDA送低電平,表示已經(jīng)接收到一個(gè)字節(jié)

//若送高電平,表示沒(méi)有接收到,傳送異常

SCL = 0;

//SCL為低電平時(shí),SDA上數(shù)據(jù)才允許變化(即允許以后的數(shù)據(jù)傳遞)

return ack_bit;

// 返回AT24Cxx應(yīng)答位 } 讀數(shù)據(jù):unsigned char ReadData()// 從AT24Cxx移入數(shù)據(jù)到MCU { unsigned char i;unsigned char x;

//儲(chǔ)存從AT24Cxx中讀出的數(shù)據(jù)

for(i = 0;i < 8;i++){

SCL = 1;

//SCL置為高電平

x<<=1;

//將x中的各二進(jìn)位向左移一位

x|=(unsigned char)SDA;//將SDA上的數(shù)據(jù)通過(guò)按位“或“運(yùn)算存入x中

SCL = 0;

//在SCL的下降沿讀出數(shù)據(jù)

} return(x);

//將讀取的數(shù)據(jù)返回 } 發(fā)送數(shù)據(jù)步驟:

oid WriteSet(unsigned char add, unsigned char dat)// 在指定地址addr處寫(xiě)入數(shù)據(jù)WriteCurrent { start();

//開(kāi)始數(shù)據(jù)傳遞

WriteCurrent(OP_WRITE);//選擇要操作的AT24Cxx芯片,并告知要對(duì)其寫(xiě)入數(shù)據(jù)

WriteCurrent(add);

//寫(xiě)入指定地址

WriteCurrent(dat);

//向當(dāng)前地址(上面指定的地址)寫(xiě)入數(shù)據(jù)

stop();

//停止數(shù)據(jù)傳遞

delaynms(4);

//1個(gè)字節(jié)的寫(xiě)入周期為1ms, 最好延時(shí)1ms以上 } 讀數(shù)據(jù)步驟:

/*************************************************** 函數(shù)功能:從AT24Cxx中的當(dāng)前地址讀取數(shù)據(jù) 出口參數(shù):x(儲(chǔ)存讀出的數(shù)據(jù))

***************************************************/ unsigned char ReadCurrent(){ unsigned char x;start();

//開(kāi)始數(shù)據(jù)傳遞

WriteCurrent(OP_READ);

//選擇要操作的AT24Cxx芯片,并告知要讀其數(shù)據(jù)

x=ReadData();

//將讀取的數(shù)據(jù)存入x stop();

//停止數(shù)據(jù)傳遞

return x;

//返回讀取的數(shù)據(jù) } /*************************************************** 函數(shù)功能:從AT24Cxx中的指定地址讀取數(shù)據(jù) 入口參數(shù):set_add 出口參數(shù):x

***************************************************/ unsigned char ReadSet(unsigned char set_add)// 在指定地址讀取 { start();

//開(kāi)始數(shù)據(jù)傳遞

WriteCurrent(OP_WRITE);

//選擇要操作的AT24Cxx芯片,并告知要對(duì)其寫(xiě)入數(shù)據(jù)

WriteCurrent(set_add);

//寫(xiě)入指定地址

return(ReadCurrent());

//從指定地址讀出數(shù)據(jù)并返回 }

單總線協(xié)議————數(shù)據(jù)傳輸?shù)臀辉谇啊穑玻常?1,初始化單總線器件

初始化時(shí)序程序:

函數(shù)功能:將DS18B20傳感器初始化,讀取應(yīng)答信號(hào) 出口參數(shù):flag

***************************************************/ bit Init_DS18B20(void){ bit flag;

//儲(chǔ)存DS18B20是否存在的標(biāo)志,flag=0,表示存在;flag=1,表示不存在

DQ = 1;

//先將數(shù)據(jù)線拉高

for(time=0;time<2;time++)//略微延時(shí)約6微秒

;DQ = 0;

//再將數(shù)據(jù)線從高拉低,要求保持480~960us for(time=0;time<200;time++)//略微延時(shí)約600微秒

;

//以向DS18B20發(fā)出一持續(xù)480~960us的低電平復(fù)位脈沖

DQ = 1;

//釋放數(shù)據(jù)線(將數(shù)據(jù)線拉高)

for(time=0;time<10;time++)

;//延時(shí)約30us(釋放總線后需等待15~60us讓DS18B20輸出存在脈沖)

flag=DQ;

//讓單片機(jī)檢測(cè)是否輸出了存在脈沖(DQ=0表示存在)

for(time=0;time<200;time++)//延時(shí)足夠長(zhǎng)時(shí)間,等待存在脈沖輸出完畢

;return(flag);

//返回檢測(cè)成功標(biāo)志 }

單總線通信協(xié)議中存在兩種寫(xiě)時(shí)隙:寫(xiě)0寫(xiě)1。主機(jī)采用寫(xiě)1時(shí)隙向從機(jī)寫(xiě)入1,而寫(xiě)0時(shí)隙向從機(jī)寫(xiě)入0。所有寫(xiě)時(shí)隙至少要60us,且在兩次獨(dú)立的寫(xiě)時(shí)隙之間至少要1us的恢復(fù)時(shí)間。兩種寫(xiě)時(shí)隙均起始于主機(jī)拉低數(shù)據(jù)總線。產(chǎn)生1時(shí)隙的方式:主機(jī)拉低總線后,接著必須在15us之內(nèi)釋放總線,由上拉電阻將總線拉至高電平;產(chǎn)生寫(xiě)0時(shí)隙的方式為在主機(jī)拉低后,只需要在整個(gè)時(shí)隙間保持低電平即可(至少60us)。在寫(xiě)時(shí)隙開(kāi)始后15~60us期間,單總線器件采樣總電平狀態(tài)。如果在此期間采樣值為高電平,則邏輯1被寫(xiě)入器件;如果為0,寫(xiě)入邏輯0。

下圖為寫(xiě)時(shí)隙(包括1和0)時(shí)序

上圖中黑色實(shí)線代表系統(tǒng)主機(jī)拉低總線,黑色虛線代表上拉電阻將總線拉高。下面是代碼:

WriteOneChar(unsigned char dat){ unsigned char i=0;for(i=0;i<8;i++)

{

DQ =1;

// 先將數(shù)據(jù)線拉高

_nop_();

//等待一個(gè)機(jī)器周期

DQ=0;

//將數(shù)據(jù)線從高拉低時(shí)即啟動(dòng)寫(xiě)時(shí)序

DQ=dat&0x01;

//利用與運(yùn)算取出要寫(xiě)的某位二進(jìn)制數(shù)據(jù),//并將其送到數(shù)據(jù)線上等待DS18B20采樣

for(time=0;time<10;time++)

;//延時(shí)約30us,DS18B20在拉低后的約15~60us期間從數(shù)據(jù)線上采樣

DQ=1;

//釋放數(shù)據(jù)線

for(time=0;time<1;time++)

;//延時(shí)3us,兩個(gè)寫(xiě)時(shí)序間至少需要1us的恢復(fù)期

dat>>=1;

//將dat中的各二進(jìn)制位數(shù)據(jù)右移1位

}

for(time=0;time<4;time++)

;//稍作延時(shí),給硬件一點(diǎn)反應(yīng)時(shí)間 }

對(duì)于讀時(shí)隙,單總線器件僅在主機(jī)發(fā)出讀時(shí)隙時(shí),才向主機(jī)傳輸數(shù)據(jù)。所有主機(jī)發(fā)出讀數(shù)據(jù)命令后,必須馬上產(chǎn)生讀時(shí)隙,以便從機(jī)能夠傳輸數(shù)據(jù)。所有讀時(shí)隙至少需要60us,且在兩次獨(dú)立的讀時(shí)隙之間至少需要1us恢復(fù)時(shí)間。每個(gè)讀時(shí)隙都由主機(jī)發(fā)起,至少拉低總線1us。在主機(jī)發(fā)出讀時(shí)隙后,單總線器件才開(kāi)始在總線上發(fā)送1或0。若從機(jī)發(fā)送1,則保持總線為高電平;若發(fā)出0,則拉低總線。

當(dāng)發(fā)送0時(shí),從機(jī)在讀時(shí)隙結(jié)束后釋放總線,由上拉電阻將總線拉回至空閑高電平狀態(tài)。從機(jī)發(fā)出的數(shù)據(jù)在起始時(shí)隙之后,保持有效時(shí)間15us,因此主機(jī)在讀時(shí)隙期間必須釋放總線,并且在時(shí)隙起始后的15us之內(nèi)采樣總線狀態(tài)。

下圖給出讀時(shí)隙(包括0或1)時(shí)序

圖中黑色實(shí)線代表系統(tǒng)主機(jī)拉低總線,灰色實(shí)線代表總局拉低總線,而黑色的虛線則代表上拉電阻總線拉高。代碼為:

unsigned char ReadOneChar(void){

unsigned char i=0;

unsigned char dat;//儲(chǔ)存讀出的一個(gè)字節(jié)數(shù)據(jù)

for(i=0;i<8;i++)

{

DQ =1;

// 先將數(shù)據(jù)線拉高

_nop_();

//等待一個(gè)機(jī)器周期

DQ = 0;

//單片機(jī)從DS18B20讀書(shū)據(jù)時(shí),將數(shù)據(jù)線從高拉低即啟動(dòng)讀時(shí)序

dat>>=1;

_nop_();

//等待一個(gè)機(jī)器周期

DQ = 1;

//將數(shù)據(jù)線“人為”拉高,為單片機(jī)檢測(cè)DS18B20的輸出電平作準(zhǔn)備

for(time=0;time<2;time++)

;

//延時(shí)約6us,使主機(jī)在15us內(nèi)采樣

if(DQ==1)

dat|=0x80;//如果讀到的數(shù)據(jù)是1,則將1存入dat

else

dat|=0x00;//如果讀到的數(shù)據(jù)是0,則將0存入dat

//將單片機(jī)檢測(cè)到的電平信號(hào)DQ存入r[i]

for(time=0;time<8;time++)

;

//延時(shí)3us,兩個(gè)讀時(shí)序之間必須有大于1us的恢復(fù)期

}

return(dat);

//返回讀出的十進(jìn)制數(shù)據(jù) }

每個(gè)單總線器件內(nèi)部都光刻了一個(gè)全球唯一的64位二進(jìn)制序列碼,用于該單總線器件的識(shí)別

SPI總線協(xié)議

SPI總線有四種工作方式(SP0, SP1, SP2, SP3),其中使用的最為廣泛的是SPI0和SPI3方式。

SPI是一個(gè)環(huán)形總線結(jié)構(gòu),由ss(cs)、sck、sdi、sdo構(gòu)成,其時(shí)序其實(shí)很簡(jiǎn)單,主要是在sck的控制下,兩個(gè)雙向移位寄存器進(jìn)行數(shù)據(jù)交換。

上升沿發(fā)送、下降沿接收、高位先發(fā)送。

上升沿到來(lái)的時(shí)候,sdo上的電平將被發(fā)送到從設(shè)備的寄存器中。

下降沿到來(lái)的時(shí)候,sdi上的電平將被接收到主設(shè)備的寄存器中。讀代碼:

unsigned char ReadCurrent(void){

unsigned char i;unsigned char x=0x00;

//儲(chǔ)存從X5045中讀出的數(shù)據(jù)

SCK=1;

//將SCK置于已知的高電平狀態(tài)

for(i = 0;i < 8;i++){

SCK=1;

//拉高SCK

SCK=0;

//在SCK的下降沿輸出數(shù)據(jù)

x<<=1;//將x中的各二進(jìn)位向左移一位,因?yàn)槭紫茸x出的是字節(jié)的最高位數(shù)據(jù)

x|=(unsigned char)SO;//將SO上的數(shù)據(jù)通過(guò)按位“或“運(yùn)算存入 x

} return(x);

//將讀取的數(shù)據(jù)返回

} 寫(xiě)代碼:

void WriteCurrent(unsigned char dat){

unsigned char i;SCK=0;

//將SCK置于已知的低電平狀態(tài)

for(i = 0;i < 8;i++)// 循環(huán)移入8個(gè)位

{

SI=(bit)(dat&0x80);

//通過(guò)按位“與”運(yùn)算將最高位數(shù)據(jù)送到S

//因?yàn)閭魉蜁r(shí)高位在前,低位在后

SCK=0;

SCK=1;

//在SCK上升沿寫(xiě)入數(shù)據(jù)

dat<<=1;

//將y中的各二進(jìn)位向左移一位,因?yàn)槭紫葘?xiě)入的是字節(jié)的最高位

} } RS232通訊協(xié)議 串行通訊方式3 RS485通訊協(xié)議 串行通訊方式1

第四篇:STC單片機(jī)串口在線燒錄芯片問(wèn)題總結(jié)

STC單片機(jī)串口在線燒錄芯片問(wèn)題總結(jié)

在一個(gè)偶然和朋友聊天中了解了STC單片機(jī)芯片,從此一發(fā)不可收拾。當(dāng)時(shí)我看中STC芯片的一個(gè)主要原因是因?yàn)樗蠥D轉(zhuǎn)換功能和在線燒錄功能。用到現(xiàn)在算起來(lái)也大致有三、四年的時(shí)間了,在此期間用了不少STC不同型號(hào)的芯片。總的來(lái)講這個(gè)芯片還是比較好使的,但在燒錄過(guò)程中也碰到不少麻煩,現(xiàn)在把它羅列如下,以便和同行們一起交流、探討和學(xué)習(xí)。

第一種情況是通過(guò)USB轉(zhuǎn)串口燒錄。曾經(jīng)成功過(guò)一段時(shí)間,但后來(lái)不知道為什么再也燒錄不進(jìn)去了,直到現(xiàn)在也不明白其中的道理。查了一些資料說(shuō)是USB轉(zhuǎn)串口的芯片問(wèn)題,需要專用芯片的USB轉(zhuǎn)串口。我也信了,但從此給我的印象是-------STC單片機(jī)燒錄程序時(shí)是要挑芯片的。

第二種情況是串口燒錄時(shí)有些232芯片不好用,一打聽(tīng)才知道是232芯片不好,不能用國(guó)產(chǎn)的要用進(jìn)口的,我又專門(mén)去買(mǎi)了一批7元多一片的進(jìn)口232芯片,結(jié)果-------沒(méi)有成功過(guò)。不得已只好換回用國(guó)產(chǎn)的,哎!好了,謝天謝地!阿彌多佛!看來(lái)STC芯片串口在線燒錄不但挑USB轉(zhuǎn)串口的芯片,還挑232芯片。

第三種情況是同一批板子、同一批232芯片有些板子能在線燒錄程序,而有些板子卻不能燒錄程序,實(shí)在沒(méi)辦法。還好本次產(chǎn)品是采用PLCC封裝的,只好把不能燒錄的芯片拔到可以燒錄的板子上去燒錄好再拔插回去,說(shuō)到這里有人可能會(huì)懷疑不能燒錄的板子232芯片或外圍電路有問(wèn)題,我當(dāng)時(shí)的直覺(jué)也是這樣的,但是我板子232口只要燒錄好程序,工作時(shí)通訊一切正常,這又作何解釋?不可思議!

第四種情況(也是我偶然發(fā)現(xiàn)的)5v的STC15F104E芯片,有時(shí)候能燒錄,有時(shí)候不能燒錄,不能燒錄的概率在90%以上,真是莫名其妙。摸索了將近一天時(shí)間才發(fā)現(xiàn)串口接上后(板子在沒(méi)有上電的時(shí)候)STC芯片電源腳有約3v電壓,我想想可能是從串口反串回來(lái)的,有這3v電壓的存在,芯片就如同沒(méi)有掉電,所以也就燒錄不進(jìn)去。我就用鑷子把電源到地短接一下,目的是進(jìn)行放電。然后馬上給板子上電,哎~~~成了!并且屢試不爽。有類(lèi)似情況的朋友也不妨一試。哈。。

第五種情況是我有一批板子用的是STC12LE5A60S2 QFP44封裝,在我的筆記本上用串口燒錄成功率為100%,而到我臺(tái)式機(jī)上用串口燒錄時(shí)成功率卻為0%,是我臺(tái)機(jī)的串口有問(wèn)題嗎?非也!臺(tái)機(jī)串口燒錄STC15F104E和其它是好的,但是對(duì)付本批次板卻是無(wú)計(jì)可施,最后無(wú)論我如何絞盡腦汁也不得其解,只好懷疑是板子在設(shè)計(jì)時(shí)有問(wèn)題,但是設(shè)計(jì)有問(wèn)題的板子為什么在筆記本上燒錄又是好的呢?只能說(shuō)-------STC芯片串口在線燒錄不但挑USB轉(zhuǎn)串口的芯片、挑232芯片,還挑電腦。

第六種情況是同一塊板子今天能燒錄進(jìn)去,過(guò)一段時(shí)間又燒錄不進(jìn)去了,再放一段時(shí)間又能燒錄進(jìn)去了。唉~~~看來(lái)STC芯片串口在線燒錄不但挑USB轉(zhuǎn)串口的芯片、挑232芯片、挑電腦,還要看它的心情。

我暈!STC的芯片真的是讓人歡喜讓人憂。

第五篇:linux串口觸摸屏設(shè)計(jì)總結(jié)

Linux serial touch 設(shè)計(jì)總結(jié)

概述:

最近在做嵌入式linux下串口觸摸屏設(shè)計(jì),遇到一些問(wèn)題,經(jīng)過(guò)查找資料和請(qǐng)教同事,總算把問(wèn)題解決了,事后有把linux相關(guān)的內(nèi)核代碼仔細(xì)看了一遍,為了有點(diǎn)成果,特別寫(xiě)了個(gè)總結(jié)。如有任何問(wèn)題請(qǐng)聯(lián)系yxj_5421@163.com,轉(zhuǎn)載請(qǐng)標(biāo)明出處。

系統(tǒng)資源:

Linux:2.6.36

UI:QT+TSLIB 硬件資源不關(guān)心

設(shè)計(jì)方法:

有兩種實(shí)現(xiàn)途徑。

1、是將要使用的串口單獨(dú)拿出來(lái),作為一個(gè)platform總線設(shè)備實(shí)現(xiàn),在嵌入式平臺(tái)mach文件里面,加上串口中斷號(hào)和寄存器首地址,然后將這個(gè)串口注冊(cè)成一個(gè)platform總線設(shè)備。在驅(qū)動(dòng)probe函數(shù)里面需要得到這個(gè)串口中斷號(hào)以及寄存器映射地址,通過(guò)寄存器映射地址設(shè)置串口波特率,數(shù)據(jù)位,停止位等,通過(guò)中斷號(hào)注冊(cè)中斷等,然后調(diào)用input_register_device注冊(cè)一個(gè)input設(shè)備。在中斷里面得到外面觸摸屏的數(shù)據(jù),然后根據(jù)input touch協(xié)議上報(bào)觸摸數(shù)據(jù)。這種方法實(shí)現(xiàn)簡(jiǎn)單明了,不需要和linux的tty,serio等打交道。但是要求知道串口硬件spec,比如寄存器等,而且這個(gè)串口就只能給觸摸屏使用了,不能作為tty使用。因?yàn)槭乔度胧介_(kāi)發(fā),因此很容易知道硬件spec,而且嵌入式平臺(tái)一旦確定,那么這個(gè)串口肯定就是給觸摸屏使用了。因此在嵌入式平臺(tái)上,推薦使用這個(gè)方法。

是將串口作為一個(gè)serio總線設(shè)備,利用linux內(nèi)核提供serio總線驅(qū)動(dòng),通過(guò)設(shè)置對(duì)應(yīng)的串口,調(diào)用serport提供的函數(shù)將串口當(dāng)做serio總線設(shè)備,在驅(qū)動(dòng)里面需要按照serio總線設(shè)備驅(qū)動(dòng)的框架來(lái)實(shí)現(xiàn),這方面的例子linux里面有很多,比如touchright.c,在模塊init函數(shù)里面調(diào)用serio_register_driver注冊(cè)serio總線設(shè)備驅(qū)動(dòng),如果serio總線上對(duì)應(yīng)的serio設(shè)備存在,就調(diào)用connect函數(shù),在這個(gè)函數(shù)里面調(diào)用input_register_device注冊(cè)一個(gè)input設(shè)備。具體驅(qū)動(dòng)不再分析了,很簡(jiǎn)單,相信各位都能看的懂。

至此,兩種方法都實(shí)現(xiàn)了串口觸摸屏的驅(qū)動(dòng),講到這里是不是就完了,非也,本文的重點(diǎn)還在后面,請(qǐng)看下面分析:

第一種方法只要驅(qū)動(dòng)模塊被加載,就會(huì)在/dev/input下面創(chuàng)建一個(gè)eventx節(jié)點(diǎn),tslib就能訪問(wèn)這個(gè)節(jié)點(diǎn),獲得觸摸坐標(biāo),然后送給qt。第二種方法驅(qū)動(dòng)模塊加載后,并沒(méi)有創(chuàng)建eventx節(jié)點(diǎn),也就是說(shuō)connect函數(shù)沒(méi)有被調(diào)用,按照l(shuí)inux驅(qū)動(dòng)模型來(lái)看,就是serio總線上還沒(méi)有對(duì)應(yīng)的serio設(shè)備,因此驅(qū)動(dòng)加載時(shí)沒(méi)有對(duì)應(yīng)的設(shè)備,就不會(huì)調(diào)用connect函數(shù),這時(shí)的串口還是作為一個(gè)linux tty設(shè)備存在。

我遇到的問(wèn)題就是serio驅(qū)動(dòng)加載了,但是沒(méi)有創(chuàng)建eventx節(jié)點(diǎn),查找資料也只有一個(gè)說(shuō)是要把tty設(shè)置成N_MOUSE,然后讀,說(shuō)的不清楚,也不知道怎么實(shí)現(xiàn),經(jīng)過(guò)自己摸索,終于把問(wèn)題解決了。

2、Linux 啟動(dòng)后串口形式: Linux一啟動(dòng)是將串口作為tty來(lái)設(shè)置的。看下的調(diào)用:

start_kernel

init/main.c大家對(duì)這個(gè)函數(shù)不陌生吧,linux啟動(dòng)過(guò)程中重要的一個(gè)函數(shù)

console_init();

drivers/tty/tty_io.c

tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);drivers/tty/tty_idisc.c 給串口注冊(cè)一個(gè)tty鏈路層處理函數(shù)ops。

現(xiàn)在我們需要寫(xiě)一個(gè)上層的應(yīng)用程序,對(duì)這個(gè)tty進(jìn)行設(shè)置,需要設(shè)置波特率,數(shù)據(jù)位,停止位等,最重要的是要將這個(gè)tty設(shè)備設(shè)置成一個(gè)serio總線設(shè)備,然后把它注冊(cè)在serio總線上,請(qǐng)看下面的代碼:

fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);

if(fd < 0){

setline(fd, type->flags, type->speed);ldisc = N_MOUSE;if(ioctl(fd, TIOCSETD, &ldisc)){

} fprintf(stderr, “inputattach: can't set line disciplinen”);return EXIT_FAILURE;

} fprintf(stderr, “inputattach: '%s'-%sn”, device, strerror(errno));return 1;

里面的device就是對(duì)應(yīng)要使用的那個(gè)串口,linux里面一般是/dev/ttyS0,首先是打開(kāi)串口 open(device, O_RDWR | O_NOCTTY | O_NONBLOCK)接著設(shè)置波特率等 setline(fd, CS8, B9600);static void setline(int fd, int flags, int speed){

} struct termios t;tcgetattr(fd, &t);t.c_cflag = flags | CREAD | HUPCL | CLOCAL;t.c_iflag = IGNBRK | IGNPAR;t.c_oflag = 0;t.c_lflag = 0;t.c_cc[VMIN ] = 1;t.c_cc[VTIME] = 0;cfsetispeed(&t, speed);cfsetospeed(&t, speed);tcsetattr(fd, TCSANOW, &t);devt = type->type |(id << 8)|(extra << 16);if(ioctl(fd, SPIOCSTYPE, &devt)){ fprintf(stderr, “inputattach: can't set device typen”);} return EXIT_FAILURE;

read(fd, NULL, 0);

接下來(lái)就是重點(diǎn)了

ldisc = N_MOUSE;if(ioctl(fd, TIOCSETD, &ldisc))

跟蹤代碼到內(nèi)核層ioctl:

long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

drivers/tty/tty_io.c case TIOCSETD: return tiocsetd(tty, p);

drivers/tty/tty_io.c

tty_set_ldisc(tty, ldisc);drivers/tty/tty_idisc.c,ldisc等于N_MOUSE new_ldisc = tty_ldisc_get(ldisc);

ldops = get_ldops(disc);

這段代碼需要得到N_MOUSE的鏈路層,先在tty_ldiscs里面查找是否有N_MOUSE鏈路層的處理函數(shù)ops,如果沒(méi)有,就需要加載serport模塊,看看這個(gè)模塊init函數(shù) retval = tty_register_ldisc(N_MOUSE, &serport_ldisc);注冊(cè)一個(gè)N_MOUSE鏈路層的處理函數(shù)ops 創(chuàng)建一個(gè)新的N_MOUSE鏈路層new_ldisc,接著調(diào)用 tty_ldisc_assign(tty, new_ldisc);

把新的鏈路層放在tty里面 retval = tty_ldisc_open(tty, new_ldisc);打開(kāi)這個(gè)新的鏈路層

至此,已經(jīng)給串口增加了一個(gè)N_MOUSE的鏈路層,并且把鏈路層的處理函數(shù)也注冊(cè)進(jìn)去了。這個(gè)串口當(dāng)前的鏈路層就是N_MOUSE。目前為止串口還只是個(gè)tty設(shè)備,并沒(méi)有注冊(cè)到serio總線上。繼續(xù)看我們的應(yīng)用程序:

devt = type->type |(id << 8)|(extra << 16);if(ioctl(fd, SPIOCSTYPE, &devt)){

fprintf(stderr, “inputattach: can't set device typen”);

return EXIT_FAILURE;} ret = ld->ops->open(tty)

ld->ops就是serport注冊(cè)的serport_ldisc static int serport_ldisc_open(struct tty_struct *tty)drivers/input/serio/serport.c 這個(gè)函數(shù)里面會(huì)創(chuàng)建一個(gè)serport結(jié)構(gòu)體,并初始化

調(diào)用

long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

drivers/tty/tty_io.c retval = ld->ops->ioctl(tty, file, cmd, arg);static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)設(shè)置

serport->id.proto = type & 0x000000ff;serport->id.id

=(type & 0x0000ff00)>> 8;serport->id.extra =(type & 0x00ff0000)>> 16;這里三個(gè)值一定要和serio總線驅(qū)動(dòng)里面對(duì)應(yīng)的值一致,serio總線就是靠它們來(lái)給設(shè)備和驅(qū)動(dòng)建立聯(lián)系的。

調(diào)用

read(fd, NULL, 0);跟蹤代碼到內(nèi)核層tty_read:

static ssize_t tty_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)(ld->ops->read)(tty, file, buf, count)

這個(gè)ld就是tty當(dāng)前的鏈路層結(jié)構(gòu),上面我們已經(jīng)設(shè)置N_MOUSE為tty的當(dāng)前鏈路層,因此ld->ops就是serport注冊(cè)的serport_ldisc static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr)

serio_register_port(serport->serio);

serio_init_port(serio);

serio_queue_event(serio, owner, SERIO_REGISTER_PORT);注冊(cè)一個(gè)serio總線設(shè)備,關(guān)于serio總線,網(wǎng)絡(luò)有很多資料介紹,這里就不說(shuō)了。至此,我們的串口設(shè)備已經(jīng)當(dāng)做serio總線設(shè)備注冊(cè)在serio總線上了,如果相應(yīng)的驅(qū)動(dòng)也在serio總線上,就會(huì)進(jìn)行設(shè)備和驅(qū)動(dòng)的匹配,然后調(diào)用驅(qū)動(dòng)里面的connect函數(shù),在這個(gè)函數(shù)里面就會(huì)創(chuàng)建input節(jié)點(diǎn)。我們的驅(qū)動(dòng)和設(shè)備已經(jīng)運(yùn)行起來(lái)了,現(xiàn)在看看數(shù)據(jù)是如何傳遞的

先看具體串口中斷函數(shù): 我們以altera_uart.c為例: altera_uart_interrupt

altera_uart_rx_chars(pp)

tty_flip_buffer_push(port->state->port.tty);

flush_to_ldisc(&tty->buf.work);

disc->ops->receive_buf(tty, char_buf,flag_buf, count);disc->ops就是serport注冊(cè)的serport_ldisc static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)

serio_interrupt(serport->serio, cp[i], ch_flags);

ret = serio->drv->interrupt(serio, data, dfl);drv->interrupt就是我們驅(qū)動(dòng)函數(shù)提供一個(gè)函數(shù),它每次接受一個(gè)字符,在這個(gè)函數(shù)里面,接受到足夠信息后,就能得到觸摸屏坐標(biāo)信息,然后通過(guò)input_report上報(bào)上去。看看數(shù)據(jù)處理流程圖:

總結(jié):

要想讓基于serio總線驅(qū)動(dòng)的串口觸摸屏能正常工作,在linux內(nèi)核需要加載驅(qū)動(dòng)模塊,serport模塊。還需要一個(gè)上層應(yīng)用程序,這個(gè)程序需要進(jìn)行以下工作

1、打開(kāi)你要使用的串口,比如

open(device, O_RDWR | O_NOCTTY | O_NONBLOCK)

device為/dev/ttyS0

2、設(shè)置串口波特率等,和你的串口觸摸屏一致

3、給串口增加一個(gè)N_MOUSE鏈路層

4、設(shè)置你的串口觸摸屏type,id,extra

5、讀串口read(fd, NULL, 0);

下載基于多單片機(jī)的串口擴(kuò)展設(shè)計(jì)論文[5篇材料]word格式文檔
下載基于多單片機(jī)的串口擴(kuò)展設(shè)計(jì)論文[5篇材料].doc
將本文檔下載到自己電腦,方便修改和收藏,請(qǐng)勿使用迅雷等下載。
點(diǎn)此處下載文檔

文檔為doc格式


聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn)自行上傳,本網(wǎng)站不擁有所有權(quán),未作人工編輯處理,也不承擔(dān)相關(guān)法律責(zé)任。如果您發(fā)現(xiàn)有涉嫌版權(quán)的內(nèi)容,歡迎發(fā)送郵件至:645879355@qq.com 進(jìn)行舉報(bào),并提供相關(guān)證據(jù),工作人員會(huì)在5個(gè)工作日內(nèi)聯(lián)系你,一經(jīng)查實(shí),本站將立刻刪除涉嫌侵權(quán)內(nèi)容。

相關(guān)范文推薦

    單片機(jī)課程論文設(shè)計(jì)-電子鐘課程設(shè)計(jì)

    單片機(jī)課程論文設(shè)計(jì) ——電子鐘 一 課程設(shè)計(jì)的主要內(nèi)容 1 設(shè)計(jì)思想 1.1硬件設(shè)計(jì)思想 1.1.1電路設(shè)計(jì)思想 電路原理圖見(jiàn)圖1,由動(dòng)態(tài)數(shù)碼顯示組成時(shí)、分、秒的顯示。把“單片機(jī)......

    51單片機(jī)論文

    課程設(shè)計(jì)報(bào)告 課程設(shè)計(jì)名稱:智能控制避障小車(chē) 學(xué)生姓名: 班 級(jí): 學(xué) 號(hào): 成 績(jī): 指導(dǎo)教師: 開(kāi)課時(shí)間:2016-2017學(xué)年第 一學(xué)期 I 獨(dú) 創(chuàng) 聲 明 本人聲明所呈交的課程設(shè)計(jì)是本人在導(dǎo)......

    單片機(jī)課程設(shè)計(jì)論文

    目錄題目:巡回檢測(cè)報(bào)警控制系統(tǒng)第一章 實(shí)驗(yàn)任務(wù)及要求............1功能描述................2元件選擇....... ................2第二章系統(tǒng)總體設(shè)計(jì)方案................3......

    基于單片機(jī)的時(shí)鐘控制器設(shè)計(jì)論文

    單片機(jī)原理與應(yīng)用技術(shù)課程設(shè)計(jì)報(bào)告 基于單片機(jī)控制的時(shí)鐘控制器 專業(yè)班級(jí): _電氣XX班_ __ 姓名:__ ___XXX__ ___ 時(shí) 間:2013/11/25~12/15 指導(dǎo)教師: XXXX XXX 2013年12月11日......

    單片機(jī)設(shè)計(jì)心得

    四周的畢業(yè)設(shè)計(jì)結(jié)束了,在這次的畢業(yè)設(shè)計(jì)中不僅檢驗(yàn)了我所學(xué)習(xí)的知識(shí),也培養(yǎng)了我如何去把握一件事情,如何去做一件事情,又如何完成一件事情。在設(shè)計(jì)過(guò)程中,與同學(xué)分工設(shè)計(jì),和同學(xué)們......

    單片機(jī)導(dǎo)游應(yīng)用論文

    文 章來(lái)源蓮山 課件 w w w.5Y k J.Com 7 凌陽(yáng)單片機(jī)在電子導(dǎo)游器中的應(yīng)用是小柯論文網(wǎng)通過(guò)網(wǎng)絡(luò)搜集,并由本站工作人員整理后發(fā)布的,凌陽(yáng)單片機(jī)在電子導(dǎo)游器中的應(yīng)用是篇質(zhì)量較......

    素質(zhì)擴(kuò)展策劃書(shū)(精選多篇)

    素 質(zhì) 擴(kuò) 展 策 劃 書(shū) 一、 活動(dòng)目的: 為了加強(qiáng)新老校區(qū)學(xué)生會(huì)的交流,增強(qiáng)學(xué)生會(huì)內(nèi)部的凝聚力,培養(yǎng)隊(duì)員們的團(tuán)隊(duì)意識(shí)和協(xié)作能力,創(chuàng)造集體和諧。 二、 活動(dòng)主題: 溝通 友誼 團(tuán)結(jié)......

    擴(kuò)展型課文教學(xué)設(shè)計(jì)

    Unit 3 Travel journal I.Teaching aims and demands: 1.Skill goals: Describe a journey. Revise means of transportation. The Present Progressive Tense expresses f......

主站蜘蛛池模板: 极品人妻少妇一区二区三区| 国产av激情无码久久| 精品国产肉丝袜久久首页| 性视频播放免费视频| 国产精品无码永久免费888| 精品国内自产拍在线播放观看| 中文字幕一区二区三区久久网站| 午夜伦情电午夜伦情电影| 亚洲一区二区三区波多野结衣| 久久精品www人人爽人人| 人妻熟女久久久久久久| A级毛片无码久久精品免费| 色爱无码av综合区| 丰满的人妻hd高清日本| 大地资源网第二页免费观看| 性xxxx视频播放免费| 人妻精品丝袜一区二区无码av| 免费a级毛片无码免费视| 日韩精品成人av在线观看| 日本另类αv欧美另类aⅴ| 国产精品综合av一区二区| 婷婷综合缴情亚洲狠狠小说| 久久久久波多野结衣高潮| 久久人妻无码一区二区| 亚洲 自拍 另类 欧美 综合| 亚洲中文字幕久久久一区| 亚洲午夜久久久久久久久电影网| 国产手机精品一区二区| 欧美乱码精品一区二区三区| 中文字幕无码一区二区免费| 午夜自产精品一区二区三区| 亚洲国产精品成人无码区| 亚洲色欲综合一区二区三区| 激情 小说 亚洲 图片 伦| √天堂资源地址在线官网| 成人在线免费视频| 丰满爆乳一区二区三区| 国产午夜精品一区二区三区嫩草| 麻豆av一区二区三区久久| 亚洲 小说 欧美 另类 社区| 无码人妻黑人中文字幕|