PIC16系列單片機(jī)與PC機(jī)串行通信的軟硬件實(shí)現(xiàn)
互聯(lián)網(wǎng)
摘要: 介紹一種運(yùn)用PIC16F84單片機(jī)實(shí)現(xiàn)與PC機(jī)串行通信的方法,并給出其硬件接口電路及通信源程序,。
Abstract:
Key words :
1 前言
美國Microchip公司的PIC16系列單片機(jī)是一種新型的CMOS工藝的8位單片機(jī),。其中,,PIC16FXX單片機(jī)的程序存儲器為電可擦除閃速存儲器(flash),可多次修改程序,,甚至可以在線編程,。PIC16F83和PIC16F84片內(nèi)數(shù)據(jù)存儲器除RAM外,還有64字節(jié)的EEPROM,,可以當(dāng)作一般的或非易失性的數(shù)據(jù)存儲器使用,,簡單方便。它還具有片內(nèi)上電復(fù)位,、延時(shí)電路,、看門狗電路等。另外,,PIC16系列單片機(jī)功耗極低,,因而是一種非常適合在各種便攜式設(shè)備中使用的高性價(jià)比的單片機(jī),并已經(jīng)得到了越來越廣泛的應(yīng)用,。
但是在許多需要大量計(jì)算的運(yùn)用中,,還必須借助微機(jī)的強(qiáng)大數(shù)據(jù)處理能力,。這樣必須通過通信電路實(shí)現(xiàn)PIC單片機(jī)與微機(jī)間的可靠數(shù)據(jù)傳輸。有的PIC16單片機(jī)內(nèi)并沒有提供串行口,,所以串行通信必須通過自己設(shè)計(jì)的硬件電路和通信軟件來實(shí)現(xiàn),。
下面介紹用查詢法實(shí)現(xiàn)異步串行通訊的方法。同時(shí)給出了用PIC16F84單片機(jī)的兩個(gè)I/O口模擬2線串行口的硬件接口電路,、程序流程框圖,、單片機(jī)內(nèi)通信程序以及微機(jī)內(nèi)的通信程序等。
2 硬件實(shí)現(xiàn)方法與電路
PIC16F84單片機(jī)的程序存儲器由1K×14的閃速(flash)存儲器構(gòu)成,,它只有13條I/O口,,1個(gè)定時(shí)器,為了盡量節(jié)省單片機(jī)的軟硬件資源,,采用下述異步串行通信的實(shí)現(xiàn)方法,。
如圖1所示,PIC16F84在4MHz時(shí)鐘下,,采用半雙工方式,,可實(shí)現(xiàn)9600波特率的異步串行數(shù)據(jù)通信,1位停止位,,8位數(shù)據(jù)位,,無校驗(yàn)位。接收和發(fā)送以低位在先(一般模式),,采用軟件延時(shí),。為節(jié)省篇幅,單片機(jī)內(nèi)的通信程序中未提供任何握手協(xié)議,,用戶可根據(jù)自己的需要在軟件中加入握手方式,。
由于PIC16F84單片機(jī)本身沒有專門的串行口,,這里用其I/O口來模擬串行口的功能,。
PC機(jī)的串行接口是符合EIA RS-232C規(guī)范的外部總線標(biāo)準(zhǔn)接口。RS-232C采用的是負(fù)邏輯,,即邏輯“1”:-5V至-15V,;邏輯“0”:+5V至+15V。而CMOS電平為:邏輯“1”:4.99V,,邏輯“0”:0.01V,;TTL電平的邏輯“1”和“0”則分別為2.4V和0.4V。因此在用RS-232C總線進(jìn)行串行通信時(shí)需外接電路實(shí)現(xiàn)電平轉(zhuǎn)換,。在發(fā)送端用驅(qū)動器將TTL或CMOS電平轉(zhuǎn)換為RS-232C電平,,在接收端用接收器將RS—232C電平再轉(zhuǎn)換為TTL或CMOS電平。
這里選用了MAXIM公司的MAX202E來作電平轉(zhuǎn)換,。MAX202E屬于MAXIM公司的通用串行接收/發(fā)送驅(qū)動器芯片,。其外圍電路簡單,,只需外接四個(gè)0.1μF的電容即可,如圖1所示,。

圖1 接口原理圖
3 PIC16F84單片機(jī)內(nèi)通信程序的設(shè)計(jì)

圖2 接收子程序框圖 圖3發(fā)送子程序框圖
圖2和圖3分別是串行發(fā)送和接收的子程序流程框圖,。發(fā)送時(shí),通過使數(shù)據(jù)發(fā)送端DX為低電平并保持B秒(9600波特率時(shí)為104μs)來發(fā)送起始位,。隨后每B秒鐘通過置位或清零DX端把數(shù)據(jù)發(fā)送出去,。這里的B是指一位所持續(xù)的時(shí)間(B=1/波特率)。接收時(shí),,數(shù)據(jù)接收端DR大約要每B/2秒(9600波特率時(shí)為52μs)查詢一次以檢測起始位,,如果檢測到起始位,則在大約1.5B秒(9600波特率時(shí)為156μs)后檢測第一位數(shù)據(jù)位,,隨后每B秒鐘檢測一次其它的數(shù)據(jù)位,。
相應(yīng)的源程序如下:
;接收子程序
Rcvr
clrwdt
,;清片內(nèi)看門狗
,;定時(shí)器
btfsc
RA,DR ,;檢測起始位
goto
Rcvr ,;未檢測到起始位
movlw
8 ;檢測到起始位
movwf
R_CNT ,;8位數(shù)據(jù)位
Rnext
call
Delay ,;延時(shí)B/2秒
bcf
STATUS,C ;清進(jìn)位標(biāo)志
rrf
RevReg ,;LSB在先
btfsc
RA,DR ,;該位為0
;還是為1
bsf
RcvReg,,MSB ,;為1
call
Delay ;延時(shí)B/2秒
decfsz
R_CNT
goto
Rnext
retlw0
,;返回
,;發(fā)送子程序
Xmtr
clrwdt
;清片內(nèi)看門狗
,;定時(shí)器
movlw
8 ,;發(fā)送位數(shù)為8
movwf
X_CNT
bcf
RA,DX ,;發(fā)送起始位
Xnext
call
Delay ,;延時(shí)B/2秒
call
Delay ;延時(shí)B/2秒
rrf
XmtReg ;LSB在先
btfsc
STATUS,C ,;檢測將要發(fā)送
,;的數(shù)據(jù)位
bsf
RA,DX ;數(shù)據(jù)位為1
btfss
STATUS,,C
bcf
RA,,DX ;數(shù)據(jù)位為0
decfsz
X_CNT ,;位計(jì)數(shù)為0則
,;發(fā)停止位
goto
Xnext ;位計(jì)數(shù)不為0
,;則發(fā)下一位數(shù)據(jù)位
Xstop
call
Delay ,;延時(shí)B/2秒
call
Delay ;延時(shí)B/2秒
Bsf
RA,DX ,;發(fā)送停止位
Retlw
0 ,;返回
;延時(shí)子程序
Delay
movlw
12 ,;52μS延時(shí)
movwf
DCNT ,;
Dnext
decfsz
DCNT
goto
Dnext ;
retlw 0
,;
4 Win95的串行通信機(jī)制及串口查詢法的原理
常用的DOS系統(tǒng)主要是工作在響應(yīng)中斷方式,。PC機(jī)串行通信程序大多利用其BIOS塊的INT14H中斷,以查詢串口的方式完成異步串行通信,。
Windows系統(tǒng)函數(shù)即包含了通信支持中斷功能,。Win95系統(tǒng)為每個(gè)通信設(shè)備開辟了用戶定義的輸入輸出緩沖區(qū)(即讀/寫緩沖區(qū)),數(shù)據(jù)進(jìn)出通信口均由系統(tǒng)后臺來完成,。應(yīng)用程序只需完成對輸入輸出緩沖區(qū)操作就可以了,。實(shí)際過程是每接收一個(gè)字符就產(chǎn)生一個(gè)低級硬件中斷,Win95系統(tǒng)中的串行驅(qū)動程序就取得了控制權(quán),,并將接收到的字符放入輸入數(shù)據(jù)緩沖區(qū),。然后將控制權(quán)返還正在運(yùn)行的應(yīng)用程序。如果輸入緩沖區(qū)數(shù)據(jù)已滿,,串行驅(qū)動程序用當(dāng)前定義的流控制機(jī)制通知發(fā)送方停止發(fā)送數(shù)據(jù),。隊(duì)列中的數(shù)據(jù)按“先進(jìn)先出”的次序處理。
(1) 按協(xié)議的設(shè)置初始化并打開串口,,這樣做就是通知Windows本應(yīng)用程序需要這個(gè)串口,并封鎖其他應(yīng)用程序使它們不能使用此串口,。
(2) 配置這個(gè)串口,。
(3) 在串口上往返地傳輸數(shù)據(jù),并在傳輸過程中進(jìn)行校驗(yàn),。
(4) 不需要此串口時(shí),,關(guān)閉串口,。即釋放串口以供其它應(yīng)用程序使用。
在這四個(gè)步驟中,,主要的程序代碼集中在第(3)步,。
串口查詢法是一種主要工作在查詢方式下的實(shí)現(xiàn)方法。當(dāng)通信程序工作在“查詢”方式時(shí),,可以不考慮Win95的進(jìn)程和線程的問題,。僅在串口有數(shù)據(jù)時(shí),去讀串口緩沖區(qū)就可以了,,如圖4所示,。這種方法下確定串口讀取的時(shí)機(jī)、握手協(xié)議及軟件糾錯(cuò)的實(shí)現(xiàn)是程序員應(yīng)考慮的主要問題,。

圖4 讀取接收緩沖區(qū)數(shù)據(jù)流程圖

圖5 串口初始化流程
由于這種方法主要工作在查詢方式,。程序員必須完成相當(dāng)一部分通信狀態(tài)的檢測工作,許多細(xì)節(jié)(甚至包括通信過程中的字符屬性的轉(zhuǎn)換)也必須通過程序代碼完成,。這種查詢方法對通信雙方協(xié)議的依賴性尤其大,。雙方通信協(xié)議的約定對程序?qū)崿F(xiàn)的難易程度影響很大。
串口查詢法中,,一般串口初始化的流程如圖5,。
值得注意的一點(diǎn)是,此方法下協(xié)議的約定必須滿足以下條件:即甲方發(fā)送時(shí),,乙方必須在甲方發(fā)送動作之前進(jìn)入循環(huán)接收狀態(tài),,直到接收到字符后通過對串口讀取函數(shù)ReadFile返回值的判斷跳出循環(huán)狀態(tài)。
同時(shí),,一般為了不使系統(tǒng)因循環(huán)等待接收而進(jìn)入“死循環(huán)”狀態(tài),,可以人為設(shè)置讀取串口的循環(huán)次數(shù),一般1000~10000次即可,。
本程序的實(shí)現(xiàn)平臺是VB4,,這是一種極為靈活的高級語言,它可以方便地引入?yún)R編語言的思維,,利用其GoTo轉(zhuǎn)向語句方便地控制程序的流程,,靈活方便。
5 PC機(jī)內(nèi)通信程序的實(shí)例
現(xiàn)約定甲方是PC機(jī),,乙方是單片機(jī)系統(tǒng)(如讀卡器),。通信格式設(shè)置為2400波特率,8位數(shù)據(jù)位,,1位停止位,,無奇偶校驗(yàn)。
下面是一個(gè)約定好通訊協(xié)議的程序?qū)嵗瑓f(xié)議流程如圖6所示,。
以下是甲方(PC機(jī))的幾個(gè)子函數(shù)的程序?qū)嵗?br />

圖6 通信協(xié)議流程
Private Function OpenThePort(cPort as String,,cBaud as String,cParity
as String,,cData as String,,tStops asString)As Boolean ’ 打開串口的子過程
Dim lResult as Long
Dim lHandle as Long
Dim DCB_COMM as DCB
Dim cDCBConfig as String
lHandle = CreateFile(cPort,GENERIC_READ Or GENERIC_WRITE,,
0&,,0&,OPEN_EXISTING,,0&,,0&)
If lHandle = -1 Then ’打開串口失敗
OpenThePort = False
MsgBox “串口可能正被其他應(yīng)用程序占用!”
lResult = CloseHandle(lHandle) ’先關(guān)閉串口后再打開
If lResult = 0 Then
OpenThePort
Exit Function
End If
End If
cDCBConfig.band = 2400 ’設(shè)置DCB
cDCBConfig.parity = None
cDCBConfig.data = 8
cDCBConfig.stop = 1
lResult = BuildCommDCB(cDCBConfig,,DCB_COMM) ’按用戶設(shè)定配置一個(gè)DCB結(jié)構(gòu)
If lResult = 0 Then
OpenThePort = False
MsgBox “無法建立DCB設(shè)備控制塊”
Exit Function
End If
lResult = SetCommState(lHandle,,DCB_Comm) ’實(shí)際設(shè)置一個(gè)串口的DCB
If lResult = 0 Then
OpenThePort = False
MsgBox “無法建立DCB設(shè)備控制塊”
Exit Function
End If
OpenThePort = True
End Function
Private Sub SendHand ( ) ’發(fā)送握手信號的子過程
Dim Nchars As Long
Static Readbuff As String * 1
Static Writebuff As String * 1
Dim lpDCB As DCB
Dim lRet As Long
Dim lHandle As Long
Dim lpOverlapped As OVERLAPPED
Dim RNum As Integer
MsgBox “請把讀卡器插在串口2上!”,,
48,,“提示窗口”
lHandle = OpenThePort(COMM1,2400,None,8,1)
lRet = PurgeComm( lHandle,1 ) ’清輸出緩沖區(qū)
lRet = PurgeComm( lHandle,,0 ) ’清輸入緩沖區(qū)
lRet = GetCommState ( lHandle,,lpDCB ) ’獲得通訊口的狀態(tài)
Shand:
Writebuff$= Chr$(&H8F)
lRet = WriteFile (lHandle,Writebuff$,1,Nchars,lpOverlapped )
’送握手信號入串口緩沖區(qū)
If lRet <= 0 Then
MsgBox “發(fā)送操作出錯(cuò),卡握手信號未發(fā)送成功”,, 16
GoTo Shand ’不成功則重發(fā)
Else
GoTo Qtest
End If
GoTo Shand
Qtest:
Readbuff$ =“ ” ’清除緩沖區(qū)為空
Do While lHandle ’循環(huán)查詢串口
RNum = 0 ’設(shè)置讀串口次數(shù)的指針為0
ReadAgain:
lRet = ReadFile( lHandle,, Readbuff$,1,,Nchars,,lpOverlapped )
If lRet < 0 Then
MsgBox “讀取應(yīng)答信號時(shí)出錯(cuò)”, 16
End If
If lRet = 0 Then
If RNum > 1000 Then ’只讀1000次串口,,以免陷入死循環(huán)
MsgBox
"卡沒有插接好或卡沒有接在串口上!"
GoTo CloseP
End If
RNum = RNum + 1
GoTo ReadAgain
End If
If Hex$(Asc(Readbuff)) <> Hex$(&HFF) Then GoTo Shand
’回送碼不正確則返回繼續(xù)發(fā)送握手信號
Else
Label1.Caption = “握手信號是:”
+Hex$(Asc(Readbuff$))
Msgbox “握手信號正確,,已正確聯(lián)機(jī)”
GoTo CloseP
End If
Loop
CloseP:lRet = CloseHandle( lHandle )
If lRet = 0 Then
MsgBox “串行通訊口關(guān)閉成功”,
48,,“提示窗口”
End If
End Sub
這里要注意的是:當(dāng)PC機(jī)與單片機(jī)系統(tǒng)通信時(shí),,單片機(jī)數(shù)據(jù)存儲區(qū)( RAM )內(nèi)的數(shù)據(jù)是十六進(jìn)制,在信號線上傳輸?shù)氖鞘M(jìn)制數(shù)的ASCII碼的二進(jìn)制形式,;而Windows系統(tǒng)下使用的是ANSI碼,,ANSI碼僅在前126個(gè)與ASCII碼相同。即在Win95下接收到的是十六進(jìn)制數(shù)的ASCII碼的字符串,,可先轉(zhuǎn)換為ANSI碼后再在Win95下還原為十六進(jìn)制數(shù),。
具體為:Code$=Hex$(Asc ( Readbuff$ ) )
另外,,由于32位API函數(shù)參數(shù)的數(shù)據(jù)類型的變化,,所有整形參數(shù)都被換為長整型(Long)以支持32位的處理,,這一點(diǎn)在設(shè)置返回值時(shí)尤其如此。
6 結(jié)束語
以上的軟硬件在我們的實(shí)踐中達(dá)到了較為理想的效果,。通過軟件節(jié)省了硬件的開銷,,并通過在PIC16F84單片機(jī)系統(tǒng)和PC機(jī)雙方的通信軟件內(nèi)增加握手信號,達(dá)到了軟件數(shù)據(jù)校驗(yàn)的目的,,獲得了較高的通信可靠性,。
參 考 文 獻(xiàn)
1 MICROCHIP CO. PIC16/17 MICROCO-NTROLLER DATA BOOK. 1995/1996
2 李東星等. PIC16CXX系列單片機(jī)應(yīng)用設(shè)計(jì). 高奇電子科技公司,1996.10
3 美 Darwin Boyle等. Visual Basic 4 Developer’s Guide. 北京:機(jī)械工
業(yè)出版社,,1997.
美國Microchip公司的PIC16系列單片機(jī)是一種新型的CMOS工藝的8位單片機(jī),。其中,,PIC16FXX單片機(jī)的程序存儲器為電可擦除閃速存儲器(flash),可多次修改程序,,甚至可以在線編程,。PIC16F83和PIC16F84片內(nèi)數(shù)據(jù)存儲器除RAM外,還有64字節(jié)的EEPROM,,可以當(dāng)作一般的或非易失性的數(shù)據(jù)存儲器使用,,簡單方便。它還具有片內(nèi)上電復(fù)位,、延時(shí)電路,、看門狗電路等。另外,,PIC16系列單片機(jī)功耗極低,,因而是一種非常適合在各種便攜式設(shè)備中使用的高性價(jià)比的單片機(jī),并已經(jīng)得到了越來越廣泛的應(yīng)用,。
但是在許多需要大量計(jì)算的運(yùn)用中,,還必須借助微機(jī)的強(qiáng)大數(shù)據(jù)處理能力,。這樣必須通過通信電路實(shí)現(xiàn)PIC單片機(jī)與微機(jī)間的可靠數(shù)據(jù)傳輸。有的PIC16單片機(jī)內(nèi)并沒有提供串行口,,所以串行通信必須通過自己設(shè)計(jì)的硬件電路和通信軟件來實(shí)現(xiàn),。
下面介紹用查詢法實(shí)現(xiàn)異步串行通訊的方法。同時(shí)給出了用PIC16F84單片機(jī)的兩個(gè)I/O口模擬2線串行口的硬件接口電路,、程序流程框圖,、單片機(jī)內(nèi)通信程序以及微機(jī)內(nèi)的通信程序等。
2 硬件實(shí)現(xiàn)方法與電路
PIC16F84單片機(jī)的程序存儲器由1K×14的閃速(flash)存儲器構(gòu)成,,它只有13條I/O口,,1個(gè)定時(shí)器,為了盡量節(jié)省單片機(jī)的軟硬件資源,,采用下述異步串行通信的實(shí)現(xiàn)方法,。
如圖1所示,PIC16F84在4MHz時(shí)鐘下,,采用半雙工方式,,可實(shí)現(xiàn)9600波特率的異步串行數(shù)據(jù)通信,1位停止位,,8位數(shù)據(jù)位,,無校驗(yàn)位。接收和發(fā)送以低位在先(一般模式),,采用軟件延時(shí),。為節(jié)省篇幅,單片機(jī)內(nèi)的通信程序中未提供任何握手協(xié)議,,用戶可根據(jù)自己的需要在軟件中加入握手方式,。
由于PIC16F84單片機(jī)本身沒有專門的串行口,,這里用其I/O口來模擬串行口的功能,。
PC機(jī)的串行接口是符合EIA RS-232C規(guī)范的外部總線標(biāo)準(zhǔn)接口。RS-232C采用的是負(fù)邏輯,,即邏輯“1”:-5V至-15V,;邏輯“0”:+5V至+15V。而CMOS電平為:邏輯“1”:4.99V,,邏輯“0”:0.01V,;TTL電平的邏輯“1”和“0”則分別為2.4V和0.4V。因此在用RS-232C總線進(jìn)行串行通信時(shí)需外接電路實(shí)現(xiàn)電平轉(zhuǎn)換,。在發(fā)送端用驅(qū)動器將TTL或CMOS電平轉(zhuǎn)換為RS-232C電平,,在接收端用接收器將RS—232C電平再轉(zhuǎn)換為TTL或CMOS電平。
這里選用了MAXIM公司的MAX202E來作電平轉(zhuǎn)換,。MAX202E屬于MAXIM公司的通用串行接收/發(fā)送驅(qū)動器芯片,。其外圍電路簡單,,只需外接四個(gè)0.1μF的電容即可,如圖1所示,。

圖1 接口原理圖
3 PIC16F84單片機(jī)內(nèi)通信程序的設(shè)計(jì)

圖2 接收子程序框圖 圖3發(fā)送子程序框圖
圖2和圖3分別是串行發(fā)送和接收的子程序流程框圖,。發(fā)送時(shí),通過使數(shù)據(jù)發(fā)送端DX為低電平并保持B秒(9600波特率時(shí)為104μs)來發(fā)送起始位,。隨后每B秒鐘通過置位或清零DX端把數(shù)據(jù)發(fā)送出去,。這里的B是指一位所持續(xù)的時(shí)間(B=1/波特率)。接收時(shí),,數(shù)據(jù)接收端DR大約要每B/2秒(9600波特率時(shí)為52μs)查詢一次以檢測起始位,,如果檢測到起始位,則在大約1.5B秒(9600波特率時(shí)為156μs)后檢測第一位數(shù)據(jù)位,,隨后每B秒鐘檢測一次其它的數(shù)據(jù)位,。
相應(yīng)的源程序如下:
;接收子程序
Rcvr
clrwdt
,;清片內(nèi)看門狗
,;定時(shí)器
btfsc
RA,DR ,;檢測起始位
goto
Rcvr ,;未檢測到起始位
movlw
8 ;檢測到起始位
movwf
R_CNT ,;8位數(shù)據(jù)位
Rnext
call
Delay ,;延時(shí)B/2秒
bcf
STATUS,C ;清進(jìn)位標(biāo)志
rrf
RevReg ,;LSB在先
btfsc
RA,DR ,;該位為0
;還是為1
bsf
RcvReg,,MSB ,;為1
call
Delay ;延時(shí)B/2秒
decfsz
R_CNT
goto
Rnext
retlw0
,;返回
,;發(fā)送子程序
Xmtr
clrwdt
;清片內(nèi)看門狗
,;定時(shí)器
movlw
8 ,;發(fā)送位數(shù)為8
movwf
X_CNT
bcf
RA,DX ,;發(fā)送起始位
Xnext
call
Delay ,;延時(shí)B/2秒
call
Delay ;延時(shí)B/2秒
rrf
XmtReg ;LSB在先
btfsc
STATUS,C ,;檢測將要發(fā)送
,;的數(shù)據(jù)位
bsf
RA,DX ;數(shù)據(jù)位為1
btfss
STATUS,,C
bcf
RA,,DX ;數(shù)據(jù)位為0
decfsz
X_CNT ,;位計(jì)數(shù)為0則
,;發(fā)停止位
goto
Xnext ;位計(jì)數(shù)不為0
,;則發(fā)下一位數(shù)據(jù)位
Xstop
call
Delay ,;延時(shí)B/2秒
call
Delay ;延時(shí)B/2秒
Bsf
RA,DX ,;發(fā)送停止位
Retlw
0 ,;返回
;延時(shí)子程序
Delay
movlw
12 ,;52μS延時(shí)
movwf
DCNT ,;
Dnext
decfsz
DCNT
goto
Dnext ;
retlw 0
,;
4 Win95的串行通信機(jī)制及串口查詢法的原理
常用的DOS系統(tǒng)主要是工作在響應(yīng)中斷方式,。PC機(jī)串行通信程序大多利用其BIOS塊的INT14H中斷,以查詢串口的方式完成異步串行通信,。
Windows系統(tǒng)函數(shù)即包含了通信支持中斷功能,。Win95系統(tǒng)為每個(gè)通信設(shè)備開辟了用戶定義的輸入輸出緩沖區(qū)(即讀/寫緩沖區(qū)),數(shù)據(jù)進(jìn)出通信口均由系統(tǒng)后臺來完成,。應(yīng)用程序只需完成對輸入輸出緩沖區(qū)操作就可以了,。實(shí)際過程是每接收一個(gè)字符就產(chǎn)生一個(gè)低級硬件中斷,Win95系統(tǒng)中的串行驅(qū)動程序就取得了控制權(quán),,并將接收到的字符放入輸入數(shù)據(jù)緩沖區(qū),。然后將控制權(quán)返還正在運(yùn)行的應(yīng)用程序。如果輸入緩沖區(qū)數(shù)據(jù)已滿,,串行驅(qū)動程序用當(dāng)前定義的流控制機(jī)制通知發(fā)送方停止發(fā)送數(shù)據(jù),。隊(duì)列中的數(shù)據(jù)按“先進(jìn)先出”的次序處理。
(1) 按協(xié)議的設(shè)置初始化并打開串口,,這樣做就是通知Windows本應(yīng)用程序需要這個(gè)串口,并封鎖其他應(yīng)用程序使它們不能使用此串口,。
(2) 配置這個(gè)串口,。
(3) 在串口上往返地傳輸數(shù)據(jù),并在傳輸過程中進(jìn)行校驗(yàn),。
(4) 不需要此串口時(shí),,關(guān)閉串口,。即釋放串口以供其它應(yīng)用程序使用。
在這四個(gè)步驟中,,主要的程序代碼集中在第(3)步,。
串口查詢法是一種主要工作在查詢方式下的實(shí)現(xiàn)方法。當(dāng)通信程序工作在“查詢”方式時(shí),,可以不考慮Win95的進(jìn)程和線程的問題,。僅在串口有數(shù)據(jù)時(shí),去讀串口緩沖區(qū)就可以了,,如圖4所示,。這種方法下確定串口讀取的時(shí)機(jī)、握手協(xié)議及軟件糾錯(cuò)的實(shí)現(xiàn)是程序員應(yīng)考慮的主要問題,。

圖4 讀取接收緩沖區(qū)數(shù)據(jù)流程圖

圖5 串口初始化流程
由于這種方法主要工作在查詢方式,。程序員必須完成相當(dāng)一部分通信狀態(tài)的檢測工作,許多細(xì)節(jié)(甚至包括通信過程中的字符屬性的轉(zhuǎn)換)也必須通過程序代碼完成,。這種查詢方法對通信雙方協(xié)議的依賴性尤其大,。雙方通信協(xié)議的約定對程序?qū)崿F(xiàn)的難易程度影響很大。
串口查詢法中,,一般串口初始化的流程如圖5,。
值得注意的一點(diǎn)是,此方法下協(xié)議的約定必須滿足以下條件:即甲方發(fā)送時(shí),,乙方必須在甲方發(fā)送動作之前進(jìn)入循環(huán)接收狀態(tài),,直到接收到字符后通過對串口讀取函數(shù)ReadFile返回值的判斷跳出循環(huán)狀態(tài)。
同時(shí),,一般為了不使系統(tǒng)因循環(huán)等待接收而進(jìn)入“死循環(huán)”狀態(tài),,可以人為設(shè)置讀取串口的循環(huán)次數(shù),一般1000~10000次即可,。
本程序的實(shí)現(xiàn)平臺是VB4,,這是一種極為靈活的高級語言,它可以方便地引入?yún)R編語言的思維,,利用其GoTo轉(zhuǎn)向語句方便地控制程序的流程,,靈活方便。
5 PC機(jī)內(nèi)通信程序的實(shí)例
現(xiàn)約定甲方是PC機(jī),,乙方是單片機(jī)系統(tǒng)(如讀卡器),。通信格式設(shè)置為2400波特率,8位數(shù)據(jù)位,,1位停止位,,無奇偶校驗(yàn)。
下面是一個(gè)約定好通訊協(xié)議的程序?qū)嵗瑓f(xié)議流程如圖6所示,。
以下是甲方(PC機(jī))的幾個(gè)子函數(shù)的程序?qū)嵗?br />

圖6 通信協(xié)議流程
Private Function OpenThePort(cPort as String,,cBaud as String,cParity
as String,,cData as String,,tStops asString)As Boolean ’ 打開串口的子過程
Dim lResult as Long
Dim lHandle as Long
Dim DCB_COMM as DCB
Dim cDCBConfig as String
lHandle = CreateFile(cPort,GENERIC_READ Or GENERIC_WRITE,,
0&,,0&,OPEN_EXISTING,,0&,,0&)
If lHandle = -1 Then ’打開串口失敗
OpenThePort = False
MsgBox “串口可能正被其他應(yīng)用程序占用!”
lResult = CloseHandle(lHandle) ’先關(guān)閉串口后再打開
If lResult = 0 Then
OpenThePort
Exit Function
End If
End If
cDCBConfig.band = 2400 ’設(shè)置DCB
cDCBConfig.parity = None
cDCBConfig.data = 8
cDCBConfig.stop = 1
lResult = BuildCommDCB(cDCBConfig,,DCB_COMM) ’按用戶設(shè)定配置一個(gè)DCB結(jié)構(gòu)
If lResult = 0 Then
OpenThePort = False
MsgBox “無法建立DCB設(shè)備控制塊”
Exit Function
End If
lResult = SetCommState(lHandle,,DCB_Comm) ’實(shí)際設(shè)置一個(gè)串口的DCB
If lResult = 0 Then
OpenThePort = False
MsgBox “無法建立DCB設(shè)備控制塊”
Exit Function
End If
OpenThePort = True
End Function
Private Sub SendHand ( ) ’發(fā)送握手信號的子過程
Dim Nchars As Long
Static Readbuff As String * 1
Static Writebuff As String * 1
Dim lpDCB As DCB
Dim lRet As Long
Dim lHandle As Long
Dim lpOverlapped As OVERLAPPED
Dim RNum As Integer
MsgBox “請把讀卡器插在串口2上!”,,
48,,“提示窗口”
lHandle = OpenThePort(COMM1,2400,None,8,1)
lRet = PurgeComm( lHandle,1 ) ’清輸出緩沖區(qū)
lRet = PurgeComm( lHandle,,0 ) ’清輸入緩沖區(qū)
lRet = GetCommState ( lHandle,,lpDCB ) ’獲得通訊口的狀態(tài)
Shand:
Writebuff$= Chr$(&H8F)
lRet = WriteFile (lHandle,Writebuff$,1,Nchars,lpOverlapped )
’送握手信號入串口緩沖區(qū)
If lRet <= 0 Then
MsgBox “發(fā)送操作出錯(cuò),卡握手信號未發(fā)送成功”,, 16
GoTo Shand ’不成功則重發(fā)
Else
GoTo Qtest
End If
GoTo Shand
Qtest:
Readbuff$ =“ ” ’清除緩沖區(qū)為空
Do While lHandle ’循環(huán)查詢串口
RNum = 0 ’設(shè)置讀串口次數(shù)的指針為0
ReadAgain:
lRet = ReadFile( lHandle,, Readbuff$,1,,Nchars,,lpOverlapped )
If lRet < 0 Then
MsgBox “讀取應(yīng)答信號時(shí)出錯(cuò)”, 16
End If
If lRet = 0 Then
If RNum > 1000 Then ’只讀1000次串口,,以免陷入死循環(huán)
MsgBox
"卡沒有插接好或卡沒有接在串口上!"
GoTo CloseP
End If
RNum = RNum + 1
GoTo ReadAgain
End If
If Hex$(Asc(Readbuff)) <> Hex$(&HFF) Then GoTo Shand
’回送碼不正確則返回繼續(xù)發(fā)送握手信號
Else
Label1.Caption = “握手信號是:”
+Hex$(Asc(Readbuff$))
Msgbox “握手信號正確,,已正確聯(lián)機(jī)”
GoTo CloseP
End If
Loop
CloseP:lRet = CloseHandle( lHandle )
If lRet = 0 Then
MsgBox “串行通訊口關(guān)閉成功”,
48,,“提示窗口”
End If
End Sub
這里要注意的是:當(dāng)PC機(jī)與單片機(jī)系統(tǒng)通信時(shí),,單片機(jī)數(shù)據(jù)存儲區(qū)( RAM )內(nèi)的數(shù)據(jù)是十六進(jìn)制,在信號線上傳輸?shù)氖鞘M(jìn)制數(shù)的ASCII碼的二進(jìn)制形式,;而Windows系統(tǒng)下使用的是ANSI碼,,ANSI碼僅在前126個(gè)與ASCII碼相同。即在Win95下接收到的是十六進(jìn)制數(shù)的ASCII碼的字符串,,可先轉(zhuǎn)換為ANSI碼后再在Win95下還原為十六進(jìn)制數(shù),。
具體為:Code$=Hex$(Asc ( Readbuff$ ) )
另外,,由于32位API函數(shù)參數(shù)的數(shù)據(jù)類型的變化,,所有整形參數(shù)都被換為長整型(Long)以支持32位的處理,,這一點(diǎn)在設(shè)置返回值時(shí)尤其如此。
6 結(jié)束語
以上的軟硬件在我們的實(shí)踐中達(dá)到了較為理想的效果,。通過軟件節(jié)省了硬件的開銷,,并通過在PIC16F84單片機(jī)系統(tǒng)和PC機(jī)雙方的通信軟件內(nèi)增加握手信號,達(dá)到了軟件數(shù)據(jù)校驗(yàn)的目的,,獲得了較高的通信可靠性,。
參 考 文 獻(xiàn)
1 MICROCHIP CO. PIC16/17 MICROCO-NTROLLER DATA BOOK. 1995/1996
2 李東星等. PIC16CXX系列單片機(jī)應(yīng)用設(shè)計(jì). 高奇電子科技公司,1996.10
3 美 Darwin Boyle等. Visual Basic 4 Developer’s Guide. 北京:機(jī)械工
業(yè)出版社,,1997.
此內(nèi)容為AET網(wǎng)站原創(chuàng),,未經(jīng)授權(quán)禁止轉(zhuǎn)載。