C语言编写串口通信程序在裸机下运行
:用C语言程序先输出序列:0.1.2.3.4,然后调用汇编程序输出:5.6.7.8.9。
要求:用两种方法传递参数(1,传值。
2,传址)1,源程序和注释:ZJPRINT.ASM john01.c.MODEL SMALL.CODE PUBLIC _ZJPRINT1 PUBLIC _ZJPRINT2_ZJPRINT1 PROC NEAR PUSH BP MOV BP,SP MOV AL,[BP+4] ADD AL,48;将数字转换成字符 MOV AH,0EH INT 10H;调用BIOS中断 POP BP RET_ZJPRINT1 ENDP_ZJPRINT2 PROC NEAR PUSH BP MOV BP,SP MOV AX,[BP+4] MOV BP,AX;将地址放入基址寄存器 MOV AL,[BP];基址寻址 ADD AL,48;将数字转换成字符 MOV AH,0EH INT 10H;调用BIOS中断 POP BP RET_ZJPRINT2 ENDPEND extern void ZJPRINT1(int num);extern void ZJPRINT2(int *num);main() { int i; printf(\\\ TC output number:\\\ ); for(i=0;i<5;i++) { printf(%d,,i); } printf(\\\ ASM output number(pass value):\\\ ); for(i=5;i<10;i++) { ZJPRINT1(i); printf(,); } printf(\\\ ASM output number(pass address):\\\ ); for(i=5;i<10;i++) { ZJPRINT2(&i); printf(,); } getch(); }2,说明:Tc20中使用汇编语言的方法主要有内嵌汇编、中断函数和汇编函数调用三种方式。
本作业使用的是调用汇编函数的方法。
ZJPRINT.ASM汇编程序通过MASM程序来编译。
在MASM目录下用:MASM ZJPRINT.ASM命令。
john01.c程序在TC目录下用:Tcc –ms –c john01.c来编译。
其中:,-ms表示以small内存模型编译(其它模型:-mt,-mm,-mc,-ml,mh), -c表示compile only。
然后将汇编的目标文件拷贝到TC的目录下。
使用:tlink lib\\\\c0s john01.obj ZJPRINT.obj,john01.exe, ,lib\\\\cs连接生成可执行程序。
以上的c0s.obj和cs.lib不在当前目录中(一般在LIB目录中),连接时,需指明其所在路径。
题目2:PC-PC通讯:实现两个PC机之间的文件的发送和接受。
要求:1,发送文件采用查询方式。
2,接受文件采用中断方式(查询方式),接受后以原文件名存储。
1,硬件连线图计算机上的DB9串口都是针式(公的),所以连接两台计算机的串口电缆两个DB9必须是孔式的(母的)。
简单且常用的是三线制接法,即地、接收数据和发送数据三脚相连。
但是考虑到做一个PC-PC的串口线就干脆做完整一点吧,方便以后其他高级应用也可以使用。
2,双机通信协议,原理关于协议:通过串行端口COM1,完成两台机器传送文件的功能。
串口发送采用查询的方式,即每次发送之前都查询串口的发送状态位(LSR的第5位),当为1 ,表示发送寄存器是空的,那么就可以进行数据发送了。
串口接收采用中断的方式。
接受的时候程序等待接收中断,如果产生了接受中断,中断处理程序就把接收的字符放到一个相应的存储位置,完成接受功能。
文件的发送和接收包括文件名和文件内容的发送和接收。
而这两部分的发送和接收都需要相应的标志来标示,在程序中我简单的定义:发送ZJZJZJZJZJ为开始传送,而$为一个部分传送的完成。
相应的接收就按照上面的定义和顺序来确定接受的是文件名和文件内容。
文件名采用缓冲的方式一次全部接收后再处理,文件内容可能比较大,就采用追加存储的方式。
关于硬件:当端口地址小于256采用直接寻址方式;当端口地址大于256,采用间接寻址方式,端口地址放在DX寄存器中。
对端口操作使用IN和OUT指令。
串口COM1的寄存器地址大于256,所以使用端口操作指令。
使用2400的波特率,数据位8位,停止位1 位,无校验的串口格式。
对于波特率寄存器,根据手册设置波特率寄存器:MSB为00H,LSB为30H。
各端口的地址如下:根据通信中断程序的特点,并结合一般中断处理的编程原则与方法,异步通信中断编程,包括: (1)通信中断初始化 修改中断向量表,使用的串口COM1,接管中断0CH,使新的中断向量指向自行编制的通信中断程序。
修改中使用DOS调用,功能号为25H,35H。
确定8250操作方式,设置中断允许寄存器相应位的允许或禁止(选择中断源类型),并允许中断操作(置MODEM控制寄存器OUT2有效(D3=1))。
确定起止式通信协议,设置通信波特率及数据帧传输格式。
开放通信中断,对8259A-5中断控制器的屏蔽寄存器编程(OCW1),允许中断IRQ4或IRQ3。
(2)通信中断服务程序 进入中断,读取串口接受的字节,存放到变量中。
结束中断处理(通常发中断结束命令EOI到中断控制器),并以IRET返回被中断的通信子程序。
3,程序流程 共有3个程序文件:一个汇编接口程序,一个接收程序,一个发送程序。
在汇编程序中完成寄存器设置,中断向量设置,串口工作方式的设置,中断服务程序的设置,中断控制器的设置。
发送函数:文件john02.c接收函数:文件john03.c汇编接口:文件ZJCOM.asm两个函数公用一个汇编借口,其中发送为查询工作模式,而接收采用中断工作模式。
流程图如下。
4,程序清单 汇编程序代码:文件ZJCOM.asm.MODEL SMALL.CODE COMADDR DW 3F8H ;寄存器地址 COMLCR DW 3FBH COMMCR DW 3FCH COMIER DW 3F9H COMLSR DW 3FDH INTSEG DW ?;保存原来中断向量 INTOFF DW ?;保存原来中断向量 CONTRL DB 00H;中断标示变量 RCVBYT DB ? ;数据存放处 PUBLIC _ZJCOMSET PUBLIC _ZJCOMSND PUBLIC _ZJCOMIST PUBLIC _ZJCOMRCV;#################################################### _ZJCOMSET PROC NEAR MOV DX,COMLCR MOV AL,80H OUT DX,AL ;使能波特率设置 MOV DX,COMADDR MOV AL,30H OUT DX,AL ;设置波特率低8位寄存器 INC DX MOV AL,00H OUT DX,AL ;设置波特率高8位寄存器 MOV DX,COMLCR MOV AL,03H OUT DX,AL ;设置数据8位,停止1位,无奇偶校验 MOV DX,COMMCR MOV AL,00H OUT DX,AL ;设置调制解调器控制寄存器 MOV DX,COMIER MOV AL,00H OUT DX,AL ;关闭中断功能 RET ;这个是不可以少的_ZJCOMSET ENDP;#################################################_ZJCOMSND PROC NEAR ;发送一个字符的函数 PUSH BP MOV BP,SPL1: MOV DX,COMLSR IN AL,DX AND AL,20H ;取出第5位 SUB AL,20H ;检测第5位是否为1,为1可以发送 JNZ L1 MOV DX,COMADDR MOV AL,[BP+4] OUT DX,AL ;发送数据 POP BP RET ;这个是不可以少的_ZJCOMSND ENDP;################################################_ZJCOMIST PROC NEAR ;设置串口接收中断;修改中断向量表 PUSH DS ;下面使用了这个段寄存器 PUSH ES ;所以要先保护 MOV AL,0CH ;指定中断号0CH(即COM1) MOV AH,35H ;调用35H号功能获得中断向量 INT 21H ; MOV INTOFF,BX ;将返回的向量ES:BX MOV BX,ES ;保存在变量中 MOV INTSEG,BX CLI ;修改前关中断 MOV AL,0CH;指定中断号0CH(即COM1) MOV AH,25H;调用25H功能修改中断向量 MOV DX,SEG INTSEV;指向新的中断向量 MOV DS,DX ;DS指向新的段址 MOV DX,OFFSET INTSEV;DX指向偏移量 INT 21H POP ES POP DS;8250重新设置成接受中断 MOV DX,COMMCR MOV AL,08H ;OUT2位置1,打开COM1中断 OUT DX,AL MOV DX,COMIER MOV AL,01H ;只允许接收中断 OUT DX,AL ;8259中断控制器的设置 IN AL,21H ;设置8259中断屏蔽寄存器IMR AND AL,0EFH OUT 21H,AL STI RET _ZJCOMIST ENDP;#################################################_ZJCOMRCV PROC NEAR ;通过中断接受字符 STI ;等待中断LW: MOV AL,CONTRL SUB AL,01H JNZ LW MOV CONTRL,00H MOV AL,RCVBYT CLI RET_ZJCOMRCV ENDP;################################################INTSEV PROC NEAR PUSH CX PUSH DX PUSH SI PUSH DI PUSH DS PUSH ES STI ;开中断 MOV CONTRL,01H ; MOV DX,3F8H IN AL,DX ;读入字节 MOV RCVBYT,AL ; CLI ;关中断 POP ES POP DS POP DI POP SI POP DX POP CX MOV AL,21H OUT 20H,AL IRET;中断返回INTSEV ENDP;################################################END发送文件的源程序:文件john02.c\\\/* Set Com1 ***\\\/\\\/** baud rate: 2400 ***\\\/\\\/** farmat: 8,1,N ***\\\/#include
*\\\/ printf(\\\ Enter file name(enter 0 to exit):); scanf(%s,filename); if( (fp=fopen(filename,r))==NULL ) printf(\\\ File does not exist!!!); } while((fp==NULL) && filename[0]!='0'); printf(get file %s\\\ ,filename); ZJCOMSET(); for(i=0;i<5;i++) { delay(DELAYTIME); ZJCOMSND('Z'); \\\/*开始进行文件名传送的标志*\\\/ delay(DELAYTIME); ZJCOMSND('J'); } printf(\\\ Sending filename!!); for(i=0;filename[i]!=NULL;i++) { ZJCOMSND(filename[i]); delay(DELAYTIME); printf(%c,filename[i]); } delay(DELAYTIME); ZJCOMSND('$'); printf(\\\ Sending filename OK!!); for(i=0;i<5;i++) { delay(DELAYTIME); ZJCOMSND('Z'); \\\/*开始进行文件传送的标志*\\\/ delay(DELAYTIME); ZJCOMSND('J'); } printf(\\\ Sending file!); while( (ch=fgetc(fp)) !=EOF )\\\/*从文件读一字符*\\\/ { printf(.....); delay(DELAYTIME); ZJCOMSND(ch); } delay(DELAYTIME); ZJCOMSND('$'); printf(\\\ Sending OK!); fclose(fp); getch(); exit(0); }接收文件的源程序:文件john03.c\\\/* Set Com1 ***\\\/\\\/** baud rate: 2400 ***\\\/\\\/** farmat: 8,1,N ***\\\/#include stdio.h#include dos.hextern void ZJCOMSET(void);extern void ZJCOMSND(char c);extern char ZJCOMRCV(void);extern void ZJCOMIST(void);int gethead(void) { int i; char ch; for(i=0;i<5;i++) { if((ch=ZJCOMRCV())=='Z') { if((ch=ZJCOMRCV())=='J') ch=ch; else return(0); } else return(0); } return(1); }main(void) { int i; char filename[50]={'t'}; char ch; FILE *fp; ZJCOMSET();\\\/*串口设置*\\\/ ZJCOMIST();\\\/*中断设置*\\\/ printf(\\\ \\\ \\\ Getting file!....\\\ ); if( gethead()!=0 ) { i=0; ch=ZJCOMRCV(); while(ch!='$') { filename[i]=ch; ch=ZJCOMRCV(); i++; } printf(\\\ receive filename OK!\\\ ); } else printf(\\\ receive head error!); if(gethead()!=0) { fp=fopen(filename,w); ch=ZJCOMRCV(); while(ch!=0X24) { fputc(ch,fp); ch=ZJCOMRCV(); } printf(\\\ receive file OK!\\\ ); } fclose(fp); }5,实验总结开始的时候接受老是出错。
后来使用串口调试工具不断地实验,才考虑到可能是发送速度的问题,是发送太快了,而接受来不及,所以丢失信息,导致接收文件失败。
于是我在发送的时候,每个字符都进行一定的延时,这样来保证接受的速度匹配。
等待中断指令HLT来等待接收中断也是不行的。
因为系统的其它中断也有可能触发处理器开始执行程序。
所以我采用的是测试标志字节来判断中断是否发生了。
C语言的文件名也不能太长,否则也出现了不能编译的情况。
串口调试时,准备一个好用的调试工具,如串口调试助手、串口精灵等,有事半功倍之效果;此外还要注意不要带电插拨串口,插拨时至少有一端是断电的,否则串口易损坏。
VB串口自动检测为什么总是无效的端口号8002
Linux下面有设备文件串口装好驱动后 会显示在dev下然后对这个设备文件进行读写即可。
比windows要简单的多。
要用C写一个串口之间通信并显示内容的程序
2. 配置好串口后恢复线程运行 m_pThread->ResumeThread(); \\\/\\\/3. 在 CommProc 中监听事件C\\\/C++ code UINT CommProc(LPVOID pParam) { OVERLAPPED os; DWORD dwMask, dwTrans; memset(&os, 0, sizeof(OVERLAPPED)); os.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL); if(os.hEvent==NULL) { AfxMessageBox(Can't create event object!); return (UINT)-1; } while(m_bConnected) { dwMask=0; if(WaitCommEvent(m_hCom, &dwMask, &os)) \\\/\\\/ 重叠操作 { if(GetLastError()==ERROR_IO_PENDING) \\\/\\\/ 无限等待重叠操作结果 GetOverlappedResult(m_hCom, &os, &dwTrans, TRUE); else { CloseHandle(os.hEvent); return (UINT)-1; } } else { [color=#FF0000]if (dwMask&EV_RXCHAR){ WaitForSingleObject(m_hPostMsgEvent, INFINITE); \\\/* 收到字符,可以通过PostMessage等方法通知主程序*\\\/ 在这里添加代码 }[\\\/color] if (dwMask&EV_TXEMPTY) { WaitForSingleObject(m_hPostMsgEvent, INFINITE); \\\/* 发送字符完毕*\\\/ 在这里添加代码 } } } CloseHandle(os.hEvent); return 0; }------解决方案--------------------------------------------------------用微软串口控件MSCOMM32.OCX,添加之窗体加入窗体,双击打开接收响应函数在窗体初始化部分将串口打开就可以了。