天天看點

序列槽開發小小心得

本人新入行,寫的也隻是很膚淺的自己的一點點了解。歡迎批評指正,qq:15065328.email:[email protected]。msn:[email protected]。如果這些經驗能對您有所幫助,我将非常榮幸。歡迎轉載(可能擡舉自己了),但請把以上文字一并保留。謝謝!

項目(先這麼稱呼吧)簡介,簡單的來說就是計算機通過序列槽分别控制4個二極管的亮度。

上位機部分:隻說說我用到的一些函數,和遇到的問題。基本的比如什麼是異步通訊啦之類的就不說了,随便網上一搜能找一籮筐!

下邊是一些函數:

函數名  作用

1.CreateFile 打開序列槽

2.GetCommState  檢測序列槽設定

3.SetCommState 設定序列槽

BuilderCommDCB 用字元串中的值來填充裝置控制塊

GetCommTimeouts 檢測通信逾時設定

SetCommTimeouts 設定通信逾時參數

SetCommMask 設定被監控事件

WaitCommEvent 等待被監控事件發生

WaitForMultipleObjects 等待多個被監測對象的結果

4.WriteFile 發送資料

ReadFile  接收資料

GetOverlappedResult 傳回最後重疊(異步)操作結果

5.PurgeComm 清空序列槽緩沖區,退出所有相關操作

6.ClearCommError 更新序列槽狀态結構體,并清除所有序列槽硬體錯誤

7.CloseHandle  關閉串行口

紅顔色标出來的是我用到的一些函數,因為是最簡單的應用,是以用到的函數也都是最最簡單的一些,都是非常容易了解的。隻是通過計算機向51發送指令是以連ReadFile()都沒用到。省了很多事。。。。。。

1.CreateFile()

功能:打開序列槽裝置

函數原型

HANDLE CreateFile(

LPCTSTR lpFileName, // 序列槽名稱字元串;如: "COM1" 或 "COM2"

DWORD dwDesiredAccess, // 設定讀寫屬性(通路模式 );一般為 GENERIC_READ|GENERIC_WRITE,

DWORD dwShareMode, // 共享模式;"必須"為 0, 即不能共享

LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全屬性;一般為NULL

DWORD dwCreationDistribution, // 建立方式,序列槽設定必須設定此值; 在這裡"必須"為 OPEN_EXISTING

DWORD dwFlagsAndAttributes, // 檔案屬性和标志;在這裡我們設定成FILE_FLAG_OVERLAPPED ,實作異步I/O關于Overlapped I/O模型,自己上網搜了去了解吧,我自己也說不清楚,懵懂的很。

HANDLE hTemplateFile // 臨時檔案的句柄,通常為NULL 

);

說明:

如果調用成功,那麼該函數傳回檔案的句柄,如果調用失敗,則函數傳回INVALID_HANDLE_VALUE。

2.GetCommState()

功能:獲得序列槽狀态

BOOL GetCommState(

HANDLE hFile, // handle of communications device

LPDCB lpDCB // address of device-control block structure

);

3.SetCommState()

功能:設定序列槽狀态 

BOOL SetCommState(

HANDLE hFile, // handle of communications device

LPDCB lpDCB // address of device-control block structure

);

說明:

在打開通信裝置句柄後,常常需要對串行口進行一些初始化工作。這需要通過一個DCB結構來進行。DCB結構包含了諸如波特率、每個字元的資料位數、奇偶校驗和停止位數等資訊。在查詢或配置置串行口的屬性時,都要用DCB結構來作為緩沖區。

調用GetCommState函數可以獲得序列槽的配置,該函數把目前配置填充到一個DCB結構中。一般在用CreateFile打開串行口後,可以調用GetCommState函數來擷取串行口的初始配置。要修改串行口的配置,應該先修改DCB結構,然後再調用SetCommState函數用指定的DCB結構來設定串行口

For example:

DCB dcb;

memset(&dec,0,sizeof(dcb));

if(!GetCommState(HComm,&dcb))//擷取目前DCB配置

 return FALSE;

dcb.BaudRate = CBR_9600;//修改資料傳輸率。。。。這裡還有很多參數可以修改,比如,停止位,有無校驗等等,具體參見dcb結構。

............

if(SetCommState(hComm,&dcb))//設定新參數

......    //錯誤處理

4.WriteFile()

功能:來将資料寫入Serial port.

函數原型:

BOOL WriteFile(

HANDLE hFile, // handle to file to write to

LPCVOID lpBuffer, // 寫如字元串的首位址

DWORD nNumberOfBytesToWrite, // 要寫如字元的個數

LPDWORD lpNumberOfBytesWritten, // 實際寫入位元組數,為一個int型指針

LPOVERLAPPED lpOverlapped // i/o重構結構,我講不清楚,sorry

);

說明:

   ReadFile函數隻要在串行口輸入緩沖區中讀入指定數量的字元,就算完成操作。

而WriteFile函數不但要把指定數量的字元拷入到輸出緩沖中,而且要等這些字元從串行口送出去後才算完成操作。

當ReadFile和WriteFile傳回FALSE時,不一定就是操作失敗,線程應該調用GetLastError函數分析傳回的結果。例如,在重疊操作時如果操作還未完成函數就傳回,那麼函數就傳回FALSE,而且GetLastError函數傳回ERROR_IO_PENDING。如果GetLastError函數傳回ERROR_IO_PENDING,則說明重疊操作還為完成,線程可以等待操作完成。

有兩種等待辦法:一種辦法是用象WaitForSingleObject這樣的等待函數來等待OVERLAPPED結構的hEvent成員,可以規定等待的時間,在等待函數傳回後,調用GetOverlappedResult。

另一種辦法是調用GetOverlappedResult函數等待,如果指定該函數的bWait參數為TRUE,

那麼該函數将等待OVERLAPPED結構的hEvent 事件。GetOverlappedResult可以傳回一個OVERLAPPED結構來報告包括實際傳輸位元組在内的重疊操作結果。

如果規定了讀/寫操作的逾時,那麼當超過規定時間後,hEvent成員會變成有信号的。是以,在逾時發生後,WaitForSingleObject和GetOverlappedResult都會結束等待。WaitForSingleObject的dwMilliseconds參數會規定一個等待逾時,該函數實際等待的時間是兩個逾時的最小值。注意GetOverlappedResult不能設定等待的時限,是以如果hEvent成員無信号,則該函數将一直等待下去

5.PurgeComm()

功能:終止目前正在進行的讀或寫的動作

函數原型:

BOOL PurgeComm(

HANDLE hFile, // handle of communications resource

DWORD dwFlags // action to perform

);

參數說明:

HANDLE hFile,//序列槽名稱字元串

dwFlags 共有四種 flags:

  PURGE_TXABORT: 終止目前正在進行的(背景)寫入動作

  PURGE_RXABORT: 終正目前正在進行的(背景)讀取動作

  PURGE_TXCLEAR: flush 寫入的 buffer

  PURGE_TXCLEAR: flush 讀取的 buffer

調用PurgeComm函數可以終止正在進行的讀寫操作,該函數還會清除輸入或輸出緩沖區中的内容。

6.ClearCommError()

功能: 從字面上的意思看來, 它是用來清除錯誤情況用的, 但是實際上它還可以拿來取得目前通訊裝置的一些資訊.

函數原型:

BOOL ClearCommError(

HANDLE hFile, // handle to communications device

LPDWORD lpErrors, // pointer to variable to receive error codes

LPCOMSTAT lpStat // pointer to buffer for communications status

);

說明:

 在調用ReadFile和WriteFile之前,線程應該調用ClearCommError函數清除錯誤标志。

該函數負責報告指定的錯誤和裝置的目前狀态。

7CloseHandle();

功能:關閉序列槽

BOOL CloseHandle(HANDLE hObject // handle to object to close)

下面是我在bcb裡的一些具體實作:

1.       打開序列槽

void __fastcall TForm1::Button1Click(TObject *Sender)

{

        hCom=CreateFile( "COM2", //檔案名

                         GENERIC_READ|GENERIC_WRITE,//通路模式允許讀寫

                         0, //此項必須是0

                         0,//無安全參數

                         OPEN_EXISTING,//建立方式

                         FILE_FLAG_OVERLAPPED,//異步工作方式

                         0);

        if (hCom==INVALID_HANDLE_VALUE)

        {

                ShowMessage("Can not open the port !");

                CloseHandle(hCom);

                hCom = 0;

                return;

        }

        else ShowMessage("COM2 open success!");

        Button1->Enabled=false;

        CheckBox1->Enabled=true;

        CheckBox2->Enabled=true;

        CheckBox3->Enabled=true;

        CheckBox4->Enabled=true;

        CheckBox5->Enabled=true;

        if(!GetCommState(hCom,&dcb)) //獲得序列槽設定并用它填充dcb結構體

                ShowMessage("GetCommState failed");

        if (!SetupComm(hCom,1024,1024)) //設定輸入輸出緩沖區大小

                ShowMessage("SetupComm failed");

        dcb.BaudRate=9600;

        dcb.fParity=0;

        dcb.Parity=NOPARITY;

        dcb.StopBits=ONESTOPBIT;

        dcb.ByteSize=8;

        if(!SetCommState(hCom,&dcb)) //重新配置序列槽

              ShowMessage("SetCommState failed");

        SetCommMask(hCom,EV_TXEMPTY); //EV_RXCHAR|

        memset(&os,0,sizeof(OVERLAPPED));

        os.hEvent=CreateEvent(NULL,true,false,NULL);

}

2.       發送一個位元組

void sendchar(char ch)

{  DWORD BytesSent=0;

   OverWrite.Offset=0;

   OverWrite.OffsetHigh=0;

   BOOL bResult;

  bResult=WriteFile(hCom,

            &ch,

            1,

            &BytesSent,

            &OverWrite);

  if(bResult) return;

  DWORD dwError=GetLastError();

  if(dwError!=ERROR_IO_PENDING)

  {

    ShowMessage("寫字元錯誤,請确認序列槽以打開!");

    return;

  }

  if(!GetOverlappedResult(hCom,&OverWrite,&BytesSent,TRUE))

  {

     ShowMessage("寫字元錯誤,請确認序列槽以打開!");

     return;

  }

  }      

在與51通訊的過程中,一次有計算機發送兩個資料給單片機,第一個是控制二極管亮度的資料,第二個是選擇控制哪個二極管的資料。為了簡單考慮,每次發送過程調用兩次send函數。下面的是發送子程式:

void send(char channel,int Vdata)

{     PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);

      sendchar(char(Vdata));

      PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);

      sendchar(channel);

      Sleep(10);

 }

上位機的程式就這麼樣了。。。。。

單片機源碼:這是根據上位機的程式來寫的。

#include <reg51.h>

char datax=0;//作為判斷接受的資料為控制信号的标志使用

char receive;

sbit a=P3^2;

sbit b=P3^3;

sbit c=P3^4;

sbit d=P3^5;

sbit e=P3^7;

void initial(void);

void P3con(char x);

void delay(short ms);

void main(void)

{

int i; 

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

  {

    e=0;d=0;c=0;b=0;a=0;P1=0;

    delay(2000);

    a=1;

    b=1;

    c=1;

    d=1;

    e=1;

    P1=0xFF;

    delay(2000);

  }

  initial();//序列槽初始化

  while(1);

}

void initial(void)      //初始化子程式

{

  IP=0x10;//序列槽中斷優先級高

  IE=0x90;//開中斷

  TMOD=0x20;//定時器1 工作模式2

  TH1=253;TL1=253;//設定定時器1初值,波特率為9.6k/s

  SCON=0x50;//串行模式1 8bit異步傳輸

  PCON=0x 7f &PCON;//SMOD=0

  TR1=1;//計時器開

}

void Sinterrupt(void) interrupt 4 using 3 //序列槽中斷響應程式;

{

  if(TI) TI=0;

  else if(RI)

  {   

     RI=0;

     receive=SBUF;

     delay(10);

     SBUF=receive;

     //delay(10);

     //while(!TI);

     //TI=0;

    if(datax==0)                

      {

        P1=receive;                

        datax++;

        return;

      }

    if(datax==1)                 

     {

        P3con(receive);

        datax=0; 

        return;

     }

  }

}

void P3con(char x)   //dac0809的片選信号

{

  switch(x)

 {

  case '1': a=1;delay(2);a=0;break;

  case '2': b=1;delay(2);a=0;break;

  case '3': c=1;delay(2);a=0;break;

  case '4': d=1;delay(2);a=0;break;

  case '5': e=1;delay(2);a=0;break;

  default : break;

  }

}

void delay(int ms)

{

  int i,j;

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

    for (j=0;j<120;j++)

    {}

這裡就不多說了,基本懂得 51c 的都能看懂。

仿真:用的是proteus,序列槽調試助手,虛拟序列槽這三個軟體。

這是虛拟序列槽的軟體。

序列槽開發小小心得

這個,序列槽調試助手

序列槽開發小小心得

具體怎麼用,一摸索就知道了,要說明的是仿真是序列槽調試助手的“序列槽”選擇“COM3”,protues中序列槽要選擇“COM4”,其他比如波特率之類的設定就不廢話了。

序列槽開發小小心得
序列槽開發小小心得

下面這個是仿真的截圖

序列槽開發小小心得

另外注意的是,51的rxd接rs232rxd,txd接txd,這裡,我十分不明白。。。。

序列槽開發小小心得

就這些啦,哈哈,第一次寫點東西,想想以後回來自己看看肯定會笑話自己的,不過,沒什麼,不這樣哪有進步~雖然很稚嫩,但是是自己的~要指導的請聯系我,感激不盡!

繼續閱讀