夷希微
|
分享:
▲
请问您指的通讯埠是 RS-232 吗? 是的话~请参考以下的资料吧 ^_^ Subject: 在Win32[BCB]下用Serial Port通讯的范例
发信人: vega6385.bbs@cszone.twbbs.org (simayi), 信区: programming 标 题: 在Win32[BCB]下用Serial Port通讯的范例 发信站: 程式设计乐园(CSZone) (Thu Jul 27 21:16:13 2000) 转信站: cis_nctu!news.cis.nctu!freebsd.ntu!news.ntu!CSZone 来 源: octa2.ee.ntu.edu.tw
在Win32[BCB]下用Serial Port通讯的范例 /////////////////////////////////////////////// 下列的程式示范了如何在Win32下 用console mode做Serial Port通讯 关于与之通讯的硬体,请参考松岗 出版的"单晶片8051实务<增修版>" 一书,作者:吴一农,ISBN:957-22-3242-8 硬体线路及8051ASM CODE.请参照 书中第16章的部份.本程式能完全取代 16-19页中的Qbasic程式,达到双向传输的功用. 本程式在BCB5中能顺利编译执行!!
#include <windows.h> #include <stdio.h> #include <conio.h> int main(int argc, char* argv[]) { HANDLE com2_handle ; //RS-232的Com2的handle DCB dcb ; //设定传输参数所需之结构 char buffer[10]; //读取资料所需的缓冲区
DWORD read_bytes = 1 ; //每次读取的byte数
com2_handle = CreateFile( "COM2" ,GENERIC_READ|GENERIC_WRITE , 0, NULL ,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); //开启com2,设为一般读取写入,一般属性,不使用非同步IO
BuildCommDCB( "baud=4800 parity=N data=8 stop=2", &dcb ); //设定传输参数结构的内含值:鲍率:4800,无同位检查,资料位元8,停止位元2
SetCommState( com2_handle , &dcb ); //设定传输参数
COMMTIMEOUTS time_out ; //设定读写逾时参数的结构 time_out.ReadIntervalTimeout = MAXDWORD ; //设为MAXDWORD:如果没有资料供读取,ReadFile函式将立即返回 time_out.ReadTotalTimeoutMultiplier = 0 ; time_out.ReadTotalTimeoutConstant = 0 ; //不使用读取总和时间来判断是否读取逾时 time_out.WriteTotalTimeoutMultiplier = 5 ; time_out.WriteTotalTimeoutConstant = 50 ; //使用写入总和时间来判断是否写入逾时,逾时WriteFile函式将立即返回
SetCommTimeouts( com2_handle , &time_out ) ; //设定com2读写逾时返回
printf("请拨动switch然后接收 或 按数字键0~9传输 或 可以按X结束\n");
while( 1 ) {
ReadFile( com2_handle , buffer , read_bytes ,&read_bytes ,NULL); //由com2读取1byte
//因为ReadFile函式逾时的时候,不仅没读到资料(所以buffer[0]没变动)就返回, //还会把read_bytes内含值改为0,因此read_bytes!= 0时表示有读到资料
if(read_bytes!= 0) { //下面这一段显示四个switch的状态,用1与0表示ON/OFF //方法是有点拙,我也知道用<<和>>很快,可是实作时出了点状况,所以用这个拙方法 int sw1,sw2,sw3,sw4 ; sw1 = (0-buffer[0]-113) / 8 ; sw2 = ((0-buffer[0]-113)- (sw1 * 8)) / 4 ; sw3 = ((0-buffer[0]-113)-(sw1*8)-(sw2*4)) / 2 ; sw4 = ((0-buffer[0]-113)-(sw1*8)-(sw2*4)-(sw3*2)) / 1 ; printf("由COM2得到Switch状态 %d%d%d%d \n", sw1,sw2,sw3,sw4); printf("可以按X结束\n");
} else { read_bytes = 1 ; //因为ReadFile函式逾时的时候,不仅没读到资料(所以buffer[0]没变动)就返回, //还会把read_bytes内含值改为0,所以我们要设回初值,不然下一轮会读不到资料 //(因为内函值为0,表示要读取0byte,所以读不到资料) }
if( kbhit() != 0 ) //如果键盘有被按到,kbhit函式传回值不等于0 { int key ; //存放被按的键的键值 key = getch() ; //把被键值读出来 if( key == 'x' ) { break ; //按下小写x结束本程式 } else { switch( key ) //如果输入数字键0~9,将之传给8051实习板显示出来 { case Ɔ' : WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); printf("传送%c到UART的另一端\n",key); printf("可以按X结束\n"); break ; case Ƈ' : WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); printf("传送%c到UART的另一端\n",key); printf("可以按X结束\n"); break ; case ƈ' : WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); printf("传送%c到UART的另一端\n",key); printf("可以按X结束\n"); break ; case Ɖ' : WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); printf("传送%c到UART的另一端\n",key); printf("可以按X结束\n"); break ; case Ɗ' : WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); printf("传送%c到UART的另一端\n",key); printf("可以按X结束\n"); break ; case Ƌ' : WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); printf("传送%c到UART的另一端\n",key); printf("可以按X结束\n"); break ; case ƌ' : WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); printf("传送%c到UART的另一端\n",key); printf("可以按X结束\n"); break ; case ƍ' : WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); printf("传送%c到UART的另一端\n",key); printf("可以按X结束\n"); break ; case Ǝ' : WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); printf("传送%c到UART的另一端\n",key); printf("可以按X结束\n"); break ; case Ə' : WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); printf("传送%c到UART的另一端\n",key); printf("可以按X结束\n"); break ; default: break ; }
} }
}
CloseHandle( com2_handle ); //关闭com2 return 0;
} /////////////////////////////////// 改写成BCB的版本如下 /////////////////////////////////// //---------------------------------------------------------------------------
#include <vcl.h> #pragma hdrstop
#include "uart_GUI_cpp.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" #include <stdio.h> TForm1 *Form1; HANDLE com2_handle ; //RS-232的Com2的handle DCB dcb ; //设定传输参数所需之结构 char buffer[10]; //读取资料所需的缓冲区 DWORD read_bytes = 1 ; //每次读取的byte数 COMMTIMEOUTS time_out ; //设定读写逾时参数的结构 int key ; //存放被按的键的键值 char temp_string[256]; char temp_string2[256];
//--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender) { Width = 435 ; Height = 300 ; } //---------------------------------------------------------------------------
void __fastcall TForm1::Button11Click(TObject *Sender) { Form1->Close(); } //---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender) {
com2_handle = CreateFile( "COM2" ,GENERIC_READ|GENERIC_WRITE , 0, NULL ,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); //开启com2,设为一般读取写入,一般属性,不使用非同步IO
BuildCommDCB( "baud=4800 parity=N data=8 stop=2", &dcb ); //设定传输参数结构的内含值:鲍率:4800,无同位检查,资料位元8,停止位元2
SetCommState( com2_handle , &dcb ); //设定传输参数
time_out.ReadIntervalTimeout = MAXDWORD ; //设为MAXDWORD:如果没有资料供读取,ReadFile函式将立即返回 time_out.ReadTotalTimeoutMultiplier = 0 ; time_out.ReadTotalTimeoutConstant = 0 ; //不使用读取总和时间来判断是否读取逾时 time_out.WriteTotalTimeoutMultiplier = 5 ; time_out.WriteTotalTimeoutConstant = 50 ; //使用写入总和时间来判断是否写入逾时,逾时WriteFile函式将立即返回
SetCommTimeouts( com2_handle , &time_out ) ; //设定com2读写逾时返回 Memo1->Clear(); Memo2->Clear(); } //---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender) { key = Ƈ' sprintf(temp_string,"%c",key); Memo1->Clear(); Memo1->SetSelTextBuf(temp_string); WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); } //---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender) { key = ƈ' sprintf(temp_string,"%c",key); Memo1->Clear(); Memo1->SetSelTextBuf(temp_string); WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); } //---------------------------------------------------------------------------
void __fastcall TForm1::Button10Click(TObject *Sender) { key = Ɔ' sprintf(temp_string,"%c",key); Memo1->Clear(); Memo1->SetSelTextBuf(temp_string); WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); } //---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender) { key = Ɖ' sprintf(temp_string,"%c",key); Memo1->Clear(); Memo1->SetSelTextBuf(temp_string); WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); } //---------------------------------------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender) { key = Ɗ' sprintf(temp_string,"%c",key); Memo1->Clear(); Memo1->SetSelTextBuf(temp_string); WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); } //---------------------------------------------------------------------------
void __fastcall TForm1::Button5Click(TObject *Sender) { key = Ƌ' sprintf(temp_string,"%c",key); Memo1->Clear(); Memo1->SetSelTextBuf(temp_string); WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); } //---------------------------------------------------------------------------
void __fastcall TForm1::Button6Click(TObject *Sender) { key = ƌ' sprintf(temp_string,"%c",key); Memo1->Clear(); Memo1->SetSelTextBuf(temp_string); WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); } //---------------------------------------------------------------------------
void __fastcall TForm1::Button7Click(TObject *Sender) { key = ƍ' sprintf(temp_string,"%c",key); Memo1->Clear(); Memo1->SetSelTextBuf(temp_string); WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); } //---------------------------------------------------------------------------
void __fastcall TForm1::Button8Click(TObject *Sender) { key = Ǝ' sprintf(temp_string,"%c",key); Memo1->Clear(); Memo1->SetSelTextBuf(temp_string); WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); } //---------------------------------------------------------------------------
void __fastcall TForm1::Button9Click(TObject *Sender) { key = Ə' sprintf(temp_string,"%c",key); Memo1->Clear(); Memo1->SetSelTextBuf(temp_string); WriteFile( com2_handle , &key , read_bytes , &read_bytes ,NULL ); } //---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { CloseHandle( com2_handle ); } //---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender) { Timer1->Enabled = false;
ReadFile( com2_handle , buffer , read_bytes ,&read_bytes ,NULL); //由com2读取1byte
if(read_bytes!= 0) { //下面这一段显示四个switch的状态,用1与0表示ON/OFF //方法是有点拙,我也知道用<<和>>很快,可是实作时出了点状况,所以用这个拙方法 int sw1,sw2,sw3,sw4 ; sw1 = ((0-buffer[0]-113) & 8)/8 ; sw2 = ((0-buffer[0]-113) & 4)/4 ; sw3 = ((0-buffer[0]-113) & 2)/2 ; sw4 = ((0-buffer[0]-113) & 1)/1 ; sprintf(temp_string2,"由COM2得到Switch状态 %d%d%d%d \n", sw1,sw2,sw3,sw4);
Memo2->Clear(); Memo2->SetSelTextBuf(temp_string2); while(read_bytes!= 0)//把缓冲区资料全读完才跳出 { ReadFile( com2_handle , buffer , read_bytes ,&read_bytes ,NULL); //由com2读取1byte sw1 = ((0-buffer[0]-113) & 8)/8 ; sw2 = ((0-buffer[0]-113) & 4)/4 ; sw3 = ((0-buffer[0]-113) & 2)/2 ; sw4 = ((0-buffer[0]-113) & 1)/1 ; sprintf(temp_string2,"由COM2得到Switch状态 %d%d%d%d \n", sw1,sw2,sw3,sw4);
Memo2->Clear(); Memo2->SetSelTextBuf(temp_string2); } read_bytes = 1 ; //因为ReadFile函式逾时的时候,不仅没读到资料(所以buffer[]没变动)就返回, //还会把read_bytes内含值改为0,所以我们要设回初值,不然下一轮会读不到资料 //(因为内函值为0,表示要读取0byte,所以读不到资料) } else { read_bytes = 1 ; //因为ReadFile函式逾时的时候,不仅没读到资料(所以buffer[]没变动)就返回, //还会把read_bytes内含值改为0,所以我们要设回初值,不然下一轮会读不到资料 //(因为内函值为0,表示要读取0byte,所以读不到资料) }
Timer1->Enabled = true; } //---------------------------------------------------------------------------
********************************************* * Simayi司马仲达 simayi@kimo.com.tw ? * * CICQ : 663287 ICQ : 49827636 * * 欢迎大家一起讨论程式设计的问题 * * C/C++ OWL ASM QB都可以讨论喔!! * *********************************************
-- ※ Origin: 程式设计乐园 ◆ From: h117.s170.ts32.hinet.net 另一版本的参考资料如下: 如何使用 Win32 API 存取 RS232 作者 : 郑旭崇
§前言 以往我们在 DOS 作业系统的真实模式下,想要存取 Serial port 可说是件轻而易举的事, 我们可以透过 BIOS 提供的中断服务常式(ISR)对 Serial port 进行存取,或者直接 经由 I/O Port规化 UART 晶片,达到串列通讯的目的.而今在 Windows 作业系统的保 护模式下,欲直接存取 I/O Port 却不是那么简单,而且如果要从低阶 I/O 来控制 Serial port 的话,又会涉及到硬体中断(interrupt)的问题,我们都知道在 Windows 下处理硬体中断也是相当麻烦的.幸好 Windows API 提供了一套通讯函式(Communication Functions) 可以专门用来解决串列通讯的问题.关于 Communication Functions 总共有二十几个, 但实际上如果只想做单纯的传送及接收的话,只须用到五个 Communication Functions. 也就是说,读者只要学会使用这几个 Communication Functions 那么关于串列通讯的问题 便可迎刃而解了. §Win32 API Communication Functions 说明 以下兹对相关的 Win32 API Communication Functions 作简短的介绍. 1.BuildCommDCB 函数原型: BOOL BuildCommDCB( LPCTSTR lpDef, LPDCB lpDCB ). BuildCommDCB 函数是用来填写 DCB 的资料,何谓 DCB 呢? DCB 的全名为 Device Control Block 是一资料结构,里面定义着所有有关串列通讯(Serial Communication)的设定值,DCB 资料结构定义如下: typedef struct _DCB { DWORD DCBlength; // DCB 的大小 (in byte) DWORD BaudRate; // 传输率 (baud rate) bit/秒 DWORD fBinary: 1; // 二进制模式,没有 EOF 检查. DWORD fParity: 1; // 同位元检查 (parity checking) DWORD fOutxCtsFlow:1; // CTS output flow control DWORD fOutxDsrFlow:1; // DSR output flow control DWORD fDtrControl:2; // DTR flow control type DWORD fDsrSensitivity:1; // DSR sensitivity DWORD fTXContinueOnXoff:1; // XOFF continues Tx DWORD fOutX: 1; // XON/XOFF out flow control DWORD fInX: 1; // XON/XOFF in flow control DWORD fErrorChar: 1; // enable error replacement DWORD fNull: 1; // enable null stripping DWORD fRtsControl:2; // RTS flow control DWORD fAbortOnError:1; // abort reads/writes on error DWORD fDummy2:17; // reserved WORD wReserved; // not currently used WORD XonLim; // transmit XON threshold WORD XoffLim; // transmit XOFF threshold BYTE ByteSize; // 每一笔资料的 bit 数, 4-8 BYTE Parity; // 同位元 (0-4) = 无,奇同位,偶同位,mark,space BYTE StopBits; // 停止位元 (0,1,2) = 1, 1.5, 2 char XonChar; // Tx and Rx XON character char XoffChar; // Tx and Rx XOFF character char ErrorChar; // error replacement character char EofChar; // end of input character char EvtChar; // received event character WORD wReserved1; // reserved; do not use } DCB; 这个 DCB Structure 几乎函盖了所有有关串列通讯的参数,提供以后使用 SetCommState API 函数 对硬体进行初始化设定.透过 BuildCommDCB 函数,我们可以最简单的方法来向 DCB Structure 填值,其中 LPCTSTR lpDef 指向一个叫做 device-control string 的位址,而 LPDCB lpDCB 正指向 DCB Structure.我们较感兴趣的是 device-control string,它使用设定串列埠的语 法就跟以往 DOS 时代的 Mode 指令一样,唯一不同的是它的传输率 (baud rate)已经不再限 制于 19200 bit/秒以下,并且最高可达 256000 bit/秒.例如:欲设定 COM2 的 Baud = 57600, 没有同位元,资料 = 8 bit,一个停止位元,可以写成 BuildCommDCB("19200,n,8,1",&dcb). 若涵数执行成功,将传回一个非零的值.若执行失败则传回零. 2.CreatFile 函数原型: HANDLE CreateFile( LPCTSTR lpFileName, // pointer to name of the file DWORD dwDesiredAccess, // access (read-write) mode DWORD dwShareMode, // share mode LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes DWORD dwCreationDistribution, // how to create DWORD dwFlagsAndAttributes, // file attributes HANDLE hTemplateFile // handle to file with attributes to copy ); 这个 Windows API 函数在此是用来开启系统的 Serial Port 并取得一个 HANDLE 代码.以后想要存取 Serial Port 时,只须面对这个 HANDLE 代码即可.当然 CreateFile 函数也可以开启其他类型的档案, 例如 files,pipes,mailslots 等等,有兴趣的朋友可以参考 Borland C++ 或 C++Builder 附加的 Help file 内皆有详尽的说明. 此函数共有七个变数栏位,第一个变数栏位 lpFileName 指向档案名称或装置名称,要当做串列通 讯时, lpFileName 为 "COM1" 或 "COM2".变数 dwDesiredAccess 设定存取型式.常数 GENERIC_READ 代表可读不可写,常数 GENERIC_WRITE 代表可写不可读,GENERIC_READ + GENERIC_WRITE 代表可写亦 可读.变数 dwShareMode 设定共享模式.常数 FILE_SHARE_READ 代表可以同时被多个程式读取,而常数 FILE_SHARE_READ 代表可以同时被多个程式写入,NULL 代表不开放共享.当然在 Serial Port 下 dwShareMode是不能开放共享的. 变数 lpSecurityAttributes 设定保密程度. 变数 dwCreationDistribution 决定档案开启模式.常数 OPEN_EXISTING 代表开启一个已存在的旧档. 常数CREATE_ALWAYS 代表开启新档. 变数 dwFlagsAndAttributes 决定档案属性.在使用 COM Port 时,档案属性必须设为 FILE_ATTRIBUTE_NORMAL. 变数 hTemplateFile 指定档案属性原型. 3.SetCommState 函数原型: BOOL SetCommState( HANDLE hFile, // handle of communications device LPDCB lpDCB // address of device-control block structure ); SetCommState 函数会根据 DCB 资料结构的内容,来设定串列通讯装置,并对硬体重新初始化(initialize). 变数 hFile 存放着执行 CreatFile 函数后所传回的 HANDLE 代码. 变数 lpDCB 指向 DCB 资料结构的位址. 例如 : SetCommState(handle,&dcb) 若涵数执行成功,将传回一个非零的值.若执行失败则传回零. 4.SetupComm 函数原型: BOOL SetupComm( HANDLE hFile, // handle of communications device DWORD dwInQueue, // size of input buffer DWORD dwOutQueue // size of output buffer ); SetupComm 函数主要是用来设定输入资料储列(Queue)与输出资料储列大小. 变数 hFile 一样也是存放着执行 CreatFile 函数后所传回的 HANDLE 代码. 变数 dwInQueue 设定输入资料储列的大小单位为 Byte. 变数 dwOutQueue 设定输出资料储列的大小单位为 Byte. 若涵数执行成功,将传回一个非零的值.若执行失败则传回零. 5.SetCommTimeouts 函数原型: BOOL SetCommTimeouts( HANDLE hFile, // handle of communications device LPCOMMTIMEOUTS lpCommTimeouts // address of communications time-out structure ); 本函数执行的结果,会影响 ReadFile 的读取时间与 WriteFile 的写入时间. 变数 hFile 存放着执行 CreatFile 函数后所传回的 HANDLE 代码. 变数 lpCommTimeouts 指向一个 communications time-out 的资料结构, typedef struct _COMMTIMEOUTS { DWORD ReadIntervalTimeout; DWORD ReadTotalTimeoutMultiplier; DWORD ReadTotalTimeoutConstant; DWORD WriteTotalTimeoutMultiplier; DWORD WriteTotalTimeoutConstant; } COMMTIMEOUTS,*LPCOMMTIMEOUTS; 变数 ReadIntervalTimeout 设定读取第一个字元与第二个字元之间的 time out 时间.单位为毫秒 (msec)当使用 ReadFile 函数从串列埠读取一个字元时,若在 ReadIntervalTimeout 时间内读取第 二个字元,则 ReadFile函数会继续读取下一个字元.若未在 ReadIntervalTimeout 时间内读取第二 个字元,则ReadFile 函数将完成工作也就是跳出 ReadFile 执行下一行叙述.ReadIntervalTimeout 设为 0 表示关闭此功能. 变数 ReadTotalTimeoutMultiplier 视读取的字元数来决定总 time out 时间. 总 time out 时间 = ReadTotalTimeoutMultiplier * 欲读取字元数 + ReadTotalTimeoutConstant. 将 ReadTotalTimeoutMultiplier 设为 0 表示关闭此功能. 变数 ReadTotalTimeoutConstant 为 time out 时间常数.加在 ReadTotalTimeoutMultiplier 之后. 变数 WriteTotalTimeoutMultiplier 与 WriteTotalTimeoutConstant 设定写入串列埠的总 time out 时间.写入串列埠的总 time out 时间 = WriteTotalTimeoutMultiplier * 欲写入之字元数 + WriteTotalTimeoutConstant. 将 WriteTotalTimeoutMultiplier 和 WriteTotalTimeoutConstant 设为 0 表示关闭此功能. 读取串列埠之 time out 设定的恰当与否,将会影响程式的执行效率,如果设定的总 time out 时 间过长,而远端装置又没有回应(No Response)时通常会导致让 User 误判成电脑当机,所以不可以乱设 .一般通常都设成: TimeOut.ReadIntervalTimeout = 0; TimeOut.ReadTotalTimeoutMultiplier = 0; TimeOut.ReadTotalTimeoutConstant = 500; //(总读取 time out 时间 = 0.5 秒) TimeOut.WriteTotalTimeoutMultiplier = 0; TimeOut.WriteTotalTimeoutConstant = 500; //(总写入 time out 时间 = 0.5 秒) 再执行 SetCommTimeouts(handle,&TimeOut) ,即完成了communications time-out 的设定. 若涵数执行成功,将传回一个非零的值.若执行失败则传回零. 最后再将上述的五个 Communication Function 简单地复习一遍. 初始化 COM PORT 的步骤 1.BuildCommDCB : 建立 DCB (Device Control Block). 2.CreatFile : 开启 COM Port 并取得 Handle 代码. 3.SetCommState : 根据 DCB 资料结构的内容,来设定串列通讯装置,并对硬体重新初始化(initialize). 4.SetupComm : 用来设定输入资料储列(Queue)与输入资料储列. 5.SetCommTimeouts :设定 ReadFile 的最大读取时,间与 WriteFile 的最大写入时间. 此时的 Com Port 已可随意存取,欲存取 Com Port 请用 ReadFile() 与 WriteFile() API函数. 从 Com Port 读取一个字元: ReadFile(handle, &lpBuf, 1, &dwRead, NULL); 写一个字元至 Com Port : WriteFile(handle,&WriteBuffer,1,&NoWrite,0); §范例 本次以一个 8051 单板当作远端装置(Remote),透过一条 RS232 传输线与电脑相互沟通做为范例. 在 PC 端使用 Borland C++ Builder ,而在 Remote 8051 端则使用组合语言.由于本文章是以如何使 用 Win32 API 存取 Serial port 为主,所以在 8051 的程式上并没有太复杂的流程与技巧,故不作详 细的说明. 壹、功能: 让游标停留在 "传送的字元" 下的文字方块内,当 User 按下键盘上任一字元时,PC 端送出一个字 元给8051 Remote,8051 Remote 收到此字元后,立即回覆相同的字元给 PC 端,并将此字元显示在 "接收 的字元" 下的文字方块中.若当 User 按下 Read From Remote 时,8051单板收到 "!" 字元,立即传回一 个二进制档(binary file)给 PC,此二进制档的内容是一个16色的 Bitmap File (BMP 档).PC 端在接收 完整个 Bitmap File 后,自动以 C16.BMP 存档.8051 单板的线路图请参照图二. 贰、程式&说明 一、PC (Host) 方面 1.放置如图一所示之控制项. < 1I?@ 2.设定物件属性,见表一. < ai?@ 3.程式码. HANDLE handle; FILE *infile; FILE *outfile; char TxdBuffer; char RxdBuffer; DWORD dwNoByte; DCB dcb; void __fastcall TForm1::FormCreate(TObject *Sender) { Edit1-Text=""; Edit2-Text=""; COMMTIMEOUTS TimeOut; TimeOut.ReadIntervalTimeout = 0; TimeOut.ReadTotalTimeoutMultiplier = 0; TimeOut.ReadTotalTimeoutConstant = 500; //(总读取 time out 时间 = 0.5 秒) TimeOut.WriteTotalTimeoutMultiplier = 0; TimeOut.WriteTotalTimeoutConstant = 500; //(总写入 time out 时间 = 0.5 秒) if (BuildCommDCB("9600,n,8,1",&dcb)){ lbBuildCommDCB-Caption="BuildCommDCB 成功";} else{ lbBuildCommDCB-Caption="BuildCommDCB 失败";} handle=CreateFile("Com1", GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (SetCommState(handle,&dcb)) lbSetCommState-Caption="SetCommState 成功"; else lbSetCommState-Caption="SetCommState 失败"; if (SetupComm(handle,1024,1024)) lbSetupComm-Caption="SetupComm 成功"; else lbSetupComm-Caption="SetupComm 失败"; if (SetCommTimeouts(handle,&TimeOut)) lbSetCommTimeouts-Caption="SetCommTimeouts 成功"; else lbSetCommTimeouts-Caption="SetCommTimeouts 失败"; } //--------------------------------------------------------------------------- void __fastcall TForm1::btnReadClick(TObject *Sender) { TxdBuffer='!' char Name[]={"C16.bmp"}; int a=0; outfile=fopen(Name,"wb"); WriteFile(handle,&TxdBuffer,1,&dwNoByte,0); ReadFile(handle,&RxdBuffer,1,&dwNoByte,NULL); if (dwNoByte == 0 ) {lbStatus-Caption="没有回应 !";return;} a++; fwrite(&RxdBuffer,1,1,outfile); while(dwNoByte != 0) { ReadFile(handle,&RxdBuffer,1,&dwNoByte,NULL); fwrite(&RxdBuffer,1,1,outfile); a++; } fclose(outfile); lbStatus-Caption="共接收了 "+IntToStr(a)+" Bytes"; } //--------------------------------------------------------------------------- void __fastcall TForm1::Edit1KeyPress(TObject *Sender, char &Key) { char lpBuf; char WriteBuffer; char *ptr; DWORD dwWrite; DWORD dwRead; ptr=&Key; WriteBuffer=*ptr; WriteFile(handle,&WriteBuffer,1,&dwWrite,0); ReadFile(handle, &lpBuf, 1, &dwRead, NULL); if (dwRead == 0) { lbStatus-Caption="没有回应 !"; } else {Edit2-Text=Edit2-Text+lpBuf;} } //--------------------------------------------------------------------------- 二、8051 (Remote) 方面 1.硬体如图二所示 <图二 > 2.程式码. ;******************************************************** ;* 使用 RS232 传送 Binrary File For 8051. 作者:郑旭崇 * ;******************************************************** LLCHAR ? ;宣告 Local Label Character = '?' ORG 0H JMP BEGIN ;--------------------------------------------------------------------------- BEGIN: MOV SP,#60H ; MOV SCON,#50H ;Serial Port 传输格式: 9600,N,8,1 MOV TMOD,#20H ; MOV TH1,#0FDH ; SETB TR1 SETB TI MOV DPTR,#Hello ;8051单板一开机,先送出欢迎词给 PC 端. CALL SendStr ; Again: JNB RI,$ ;等待 PC 送字元过来. CLR RI ; MOV A,SBUF ; CJNE A,'!',?10 ;不是 '!' 就将原字元传回 PC 端. CALL SendBinaryFile ;是 '!' 就传回二进制档(Binary File). JMP Again ?10 CALL SendByte JMP Again ;=============================================================================== SendStr: ;送出一字串. ?10 CLR A MOVC A,@A+DPTR ;从 ROM 里面取一个 Byte. CJNE A,0,?20 ; RET ?20 CALL SendByte INC DPTR JMP ?10 RET ;=============================================================================== SendBinaryFile: ;送出二进制档(Binary File). MOV DPTR,#BinData MOV R4,#4 ;准备传送出 200 * 4 = 800 个 Bytes. ?10 MOV R5,#200 ?20 CLR A MOVC A,@A+DPTR ;从 ROM 里面取一个 Byte. CALL SendByte INC DPTR DJNZ R5,?20 DJNZ R4,?10 RET ;=============================================================================== SendByte: ;送出一字元. JNB TI,$ CLR TI MOV SBUF,A RET ;=============================================================================== Hello: DB 'Hello Welcome !',0 BinData: DB 42H,4DH,1EH,03H,00H,00H,00H,00H,00H,00H,76H,00H,00H,00H,28H,00H DB 00H,00H,22H,00H,00H,00H,22H,00H,00H,00H,01H,00H,04H,00H,00H,00H DB 00H,00H,A8H,02H,00H,00H,C4H,0EH,00H,00H,C4H,0EH,00H,00H,00H,00H DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,80H,00H,00H,80H DB 00H,00H,00H,80H,80H,00H,80H,00H,00H,00H,80H,00H,80H,00H,80H,80H DB 00H,00H,C0H,C0H,C0H,00H,80H,80H,80H,00H,00H,00H,FFH,00H,00H,FFH DB 00H,00H,00H,FFH,FFH,00H,FFH,00H,00H,00H,FFH,00H,FFH,00H,FFH,FFH DB 00H,00H,FFH,FFH,FFH,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,AAH,AAH DB AAH,AAH,AAH,AAH,99H,99H,99H,99H,FFH,FFH,FFH,99H,99H,00H,00H,00H DB 00H,00H,AAH,AAH,AAH,AAH,AAH,AAH,99H,99H,99H,99H,FFH,FFH,FFH,99H DB 99H,00H,00H,00H,00H,00H,00H,99H,AAH,AAH,AAH,AAH,AAH,99H,99H,99H DB 99H,FFH,FFH,FFH,99H,99H,00H,00H,00H,00H,00H,99H,AAH,AAH,AAH,AAH DB AAH,99H,99H,99H,99H,FFH,FFH,FFH,99H,99H,00H,00H,00H,00H,00H,00H DB 99H,AAH,99H,99H,AAH,AAH,99H,99H,FFH,FFH,FFH,FFH,99H,00H,00H,00H DB 00H,00H,00H,00H,99H,AAH,99H,99H,AAH,AAH,99H,99H,FFH,FFH,FFH,FFH DB 99H,00H,00H,00H,00H,00H,00H,00H,00H,AAH,99H,99H,99H,AAH,AAH,FFH DB FFH,FFH,FFH,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,AAH,99H,99H DB 99H,AAH,AAH,FFH,FFH,FFH,FFH,00H,00H,00H,00H,00H,00H,00H,00H,00H DB 00H,AAH,99H,99H,99H,AAH,AAH,AAH,AAH,AAH,AAH,AAH,00H,00H,00H,00H DB 00H,00H,00H,00H,00H,AAH,99H,99H,99H,AAH,AAH,AAH,AAH,AAH,AAH,AAH DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,AAH,99H,AAH,AAH,00H,00H DB 00H,FFH,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,AAH,99H DB AAH,AAH,00H,00H,00H,FFH,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H DB 00H,99H,AAH,AAH,AAH,AAH,AAH,FFH,FFH,AAH,FFH,AAH,AAH,00H,00H,00H DB 00H,00H,00H,00H,00H,99H,AAH,AAH,AAH,AAH,AAH,FFH,FFH,AAH,FFH,AAH DB AAH,00H,00H,00H,00H,00H,00H,00H,99H,99H,AAH,AAH,AAH,AAH,FFH,FFH DB 00H,AAH,00H,FFH,AAH,00H,00H,00H,00H,00H,00H,00H,99H,99H,AAH,AAH DB AAH,AAH,FFH,FFH,00H,AAH,00H,FFH,AAH,00H,00H,00H,00H,00H,00H,00H DB 00H,00H,AAH,AAH,AAH,AAH,FFH,FFH,00H,AAH,00H,FFH,AAH,00H,00H,00H DB 00H,00H,00H,00H,00H,00H,AAH,AAH,AAH,AAH,FFH,FFH,00H,AAH,00H,FFH DB AAH,00H,00H,00H,00H,00H,00H,00H,00H,99H,AAH,AAH,AAH,AAH,FFH,FFH DB 00H,AAH,00H,FFH,00H,00H,00H,00H,00H,00H,00H,00H,00H,99H,AAH,AAH DB AAH,AAH,FFH,FFH,00H,AAH,00H,FFH,00H,00H,00H,00H,00H,00H,00H,00H DB 99H,99H,99H,AAH,AAH,AAH,FFH,FFH,FFH,AAH,FFH,FFH,00H,00H,00H,00H DB 00H,00H,00H,00H,99H,99H,99H,AAH,AAH,AAH,FFH,FFH,FFH,AAH,FFH,FFH DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,AAH,AAH,AAH,AAH,FFH DB FFH,AAH,FFH,AAH,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,AAH DB AAH,AAH,AAH,FFH,FFH,AAH,FFH,AAH,00H,00H,00H,00H,00H,00H,00H,00H DB 00H,00H,99H,99H,AAH,AAH,AAH,AAH,AAH,AAH,AAH,00H,00H,00H,00H,00H DB 00H,00H,00H,00H,00H,00H,99H,99H,AAH,AAH,AAH,AAH,AAH,AAH,AAH,00H DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,99H,99H,99H,99H,AAH,AAH,AAH DB AAH,AAH,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,99H,99H,99H DB 99H,AAH,AAH,AAH,AAH,AAH,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H DB 00H,00H,00H,00H,00H,99H,99H,99H,00H,00H,00H,00H,00H,00H,00H,00H DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,99H,99H,99H,00H,00H,00H,00H DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,99H,00H DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H DB 00H,00H,99H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,8BH,D1H END ;----------------------------------------------------------------------------------------- 3.组译程式,在 DOS 提示字元下输入: C:\X8051 REMOTE51 8051 Macro Assembler - Version 4.03a Copyright (C) 1985 by 2500 A.D. Software, Inc. ***** Active Commands ***** Ctrl S = Stop Output Ctrl Q = Start Output Esc C = Stop Assembly Esc T = Terminal Output Esc P = Printer Output Esc D = Disk Output Esc M = Multiple Output Esc N = No Output 2500 A.D. 8051 Macro Assembler - Version 4.03a ------------------------------------------------ Input Filename : REMOTE51.asm Output Filename : REMOTE51.obj Lines Assembled : 116 Assembly Errors : 0 4.连结程式,在 DOS 提示字元下输入: C:\LINK51 -c REMOTE51 -O -X 2500 A.D. Linker Copyright (C) 1985 - Version 4.03a ****************************************************************************** * L O A D M A P * ****************************************************************************** * Section Name Starting Address Ending Address Size * ****************************************************************************** * remote51.obj * * CODE 0000 0383 0384 * ****************************************************************************** Linker Output Filename : remote51.tsk Disk Listing Filename : Symbol Table Filename : Link Errors : 0 Output Format : Executable 参、执行例 请看图三至图五. <1I?T >键入 "Lovely",Remote 8051 回覆 "Lovely" < 1I¥| 按下 Read From Remote 钮,Remote 8051传回一个二进制档(binary file)给 PC,此二 进制档的内容是一个16色的 Bitmap File (BMP 档). <1I?- > C16.BMP 的内容 §结语 看完了本篇文章后,是否对 Win32 API 如何存取 Serial Port 更加了解呢 ? 虽然我用 Borland C++ Builder 来讲解程式,但小弟觉得用何种 Tool 或程式语言的本 身并不重要,重要的是能够摄取文章中的灵魂,进而加以吸收,变成自己的东西,在各种程式语言 或情况下都能运用自如. 读者朋友对于本文章有任何问题或建议,欢迎您 E-mail 给我,小弟的 E-mail是 : pttgood@cm1.hinet.net 当然,读者朋友们想要程式的 Source Code 的话,也可以来信索取. 几个月前我的好友 Tony 的老婆 LCM 生了一个白白胖胖的儿子,他们叫他 "阿肥 ".看到胖嘟嘟 的阿肥和他们俩如此幸福的脸庞,顿时让我觉得人活着就应该感恩惜福,自然就会幸福快乐。 祝福每一位读者健康快乐。
以上资料转载自:http://finetek.myweb.hinet.net/t...2/bcbrs232.htm 大大加油唷 ^_^
此文章被评分,最近评分记录财富:200 (by codeboy) | 理由: 回答的辛苦了~^^ | |
|
|
|