C语言实现串口通信
摘要: 本文说明了异步串行通信(RS-232)的工作方式,探讨了查询和中断两种软件接口利弊,并给出两种方式的C语言源程序的I/O通道之一,以最简单方式组成的串行双工线路只需两条信号线和一条公共地线,因此串行通信既有线路简单的优点同时也有它的缺点,即通信速率无法同并行通信相比,实际上EIA RS-232C在标准条件下的最大通信速率仅为20Kb/S。
尽管如此,大多数外设都提供了串行口接口,尤其在工业现场RS-232C的应用更为常见。
IBM PC及兼容机系列都有RS-232的适配器,操作系统也提供了编程接口,系统接口分为DOS功能调用和BIOS 功能调用两种:DOS INT 21H的03h和04h号功能调用为异步串行通信的接收和发送功能;而BIOS INT 14H有4组功能调用为串行通信服务,但DOS和BIOS功能调用都需握手信号,需数根信号线连接或彼此间互相短接,最为不便的是两者均为查询方式,不提供中断功能,难以实现高效率的通信程序,为此本文采用直接访问串行口硬件端口地址的方式,用C语言编写了串行通信查询和中断两种方式的接口程序。
1.串行口工作原理微机串行通信采用EIA RS-232C标准,为单向不平衡传输方式,信号电平标准±12V,负逻辑,即逻辑1(MARKING)表示为信号电平-12V,逻辑0(SPACING)表示为信号电平12V,最大传送距离15米,最大传送速率19.6K波特,其传送序列如图1,平时线路保持为1,传送数据开始时,先送起始位(0),然后传8(或7,6,5)个数据位(0,1),接着可传1位奇偶校验位,最后为1~2个停止位(1),由此可见,传送一个ASCII字符(7位),加上同步信号最少需9位数据位。
@@T8S12300.GIF;图1@@串行通信的工作相当复杂,一般采用专用芯片来协调处理串行数据的发送接收,称为通用异步发送/接收器(UART),以节省CPU的时间,提高程序运行效率,IBM PC系列采用8250 UART来处理串行通信。
在BIOS数据区中的头8个字节为4个UART的端口首地址,但DOS 只支持2个串行口:COM1(基地址0040:0000H)和COM2(基地址0040:0002H)。
8250 UART共有10个可编程的单字节寄存器,占用7个端口地址,复用地址通过读/写操作和线路控制寄存器的第7位来区分。
这10个寄存器的具体功能如下:COM1(COM2) 寄存器端口地址功能DLAB状态3F8H(2F8H) 发送寄存器(写) 03F8H(2F8H) 接收寄存器(读) 03F8H(2F8H) 波特率因子低字节13F9H(2F9H) 波特率因子高字节13F9H(2F9H) 中断允许寄存器03FAH(2FAH) 中断标志寄存器3FBH(2FBH) 线路控制寄存器3FCH(2FCH) MODEM控制寄存器3FDH(2FDH) 线路状态寄存器3FEH(2FEH) MODEM状态寄存器注:DLAB为线路控制寄存器第七位在编写串行通信程序时,若采用低级方式,只需访问UART的这10个寄存器即可,相对于直接控制通信的各个参量是方便可靠多了。
其中MODEM控制/状态寄存器用于调制解调器的通信控制,一般情况下不太常用;中断状态/标志寄存器用于中断方式时的通信控制,需配合硬件中断控制器8259的编程;波特率因子高/低字节寄存器用于初始化串行口时通信速率的设定;线路控制/状态寄存器用于设置通信参数,反映当前状态;发送/接收寄存器通过读写操作来区分,不言而喻用于数据的发送和接收。
UART可向CPU发出一个硬件中断申请,此中断信号接到中断控制器8259,其中COM1接IRQ4(中断OCH),COM2接IRQ3(中断OBH)。
用软件访问8259的中断允许寄存器(地址21H)来设置或屏蔽串行口的中断,需特别指出的是,设置中断方式串行通信时,MODEM控制寄存器的第三位必须置1,此时CPU才能响应UART中断允许寄存器许可的任何通信中断。
2.编程原理程序1为查询通信方式接口程序,为一典型的数据采集例程。
其中bioscom()函数初始化COM1(此函数实际调用BIOS INT 14H中断0号功能)。
这样在程序中就避免了具体设置波特率因子等繁琐工作,只需直接访问发送/接收寄存器(3F8H)和线路状态寄存器(3FDH)来控制UART的工作。
线路状态寄存器的标志内容如下:第0位1=收到一字节数据第1位1=所收数据溢出第2位1=奇偶校验错第3位1=接收数据结构出错第4位1=断路检测第5位1=发送保存寄存器空第6位1=发送移位寄存器空第7位1=超时当第0位为1时,标志UART已收到一完整字节,此时应及时将之读出,以免后续字符重叠,发生溢出错误,UART有发送保持寄存器和发送移位寄存器。
发送数据时,程序将数据送入保持寄存器(当此寄存器为空时),UART自动等移位寄存器为空时将之写入,然后把数据转换成串行形式发送出去。
本程序先发送命令,然后循环检测,等待接收数据,当超过一定时间后视为数据串接收完毕。
若接收到数据后返回0,否则返回1。
若以传送一个ASCII字符为例,用波特率9600 b/s,7个数据位,一个起始位,一个停止位来初始化UART,则计算机1秒可发送/接收的最大数据量仅为9600/9=1074字节,同计算机所具有的高速度是无法相比的,CPU的绝大部分时间耗费在循环检测标志位上。
在一个有大量数据串行输入/输出的应用程序中,这种消耗是无法容忍的,也不是一种高效率通信方式,而且可以看到,在接收一个长度未知的数据串时,有可能发生遗漏。
程序2是一组中断方式通信接口程序。
微机有两条用于串行通信的硬件中断通道IRQ3(COM2)和IRQ4(COM1),对应中断向量为OBH和OCH,可通过设置中断屏蔽寄存器(地址21H)来开放中断。
置1时屏蔽该中断,否则开放中断。
硬件中断例程必须在程序末尾往中断命令寄存器(地址20H)写入20H,即MOV AL,20HOUT 20H,AL用以将当前中断服务寄存器清零,避免中断重复响应。
每路UART有4组中断,程序可通过中断允许寄存器(3F9H)来设置开放那路中断。
这4组中断的位标志如下:第0位1=接收到数据第1位1=发送保持寄存器为空第2位1=接收数据出错第3位1=MODEM状态寄存器改变第4~7位为0在中断例程中检查UART的中断标志寄存器(3FAH),确定是哪一组事件申请中断。
该寄存器第0位为0时表示有中断申请,响应该中断并采取相应措施后,UART自动复位中断标志;第2,1位标志中断类型,其位组合格式如下:代码中断类型复位措施11接收出错读线路状态寄存器10接收到数据读接收寄存器01发送寄存器空输出字符至发送寄存器00MODEM状态改变读MODEM状态寄存器这4组中断的优先级为0号最低,3号最高。
在本组程序中,函数setinterrupt()和clearinterrupt()设置和恢复串行通信中断向量;cominit()初始化指定串行口并开放相应中断;sendcomdata()和getcomeomdata()用于发送和接收数据串;com1()和com2()为中断例程,二者均调用fax2()函数,fax2()函数为实际处理数据接收和发送的例程。
明确了串行口的工作原理,就不难理解其具体程序。
3.结论上述程序采用C语言编写,在BORLAND C 2.0集成环境中调试通过,为简单起见,只考虑了使用发送/接收两条信号线的情况,并未考虑使用握手信号线。
在实际应用中这两组程序尚有一些可修改之处。
比如,中断接收程序中的缓冲区可改为循环表,以防数据溢出,尽可能保留最新数据。
由于笔者水平所限,文中不足疏漏之处尚希行家指正。
程序1:static int receive_delay=10000;int may(unsigned par,char *comm,char *ss){int cs=0,j=0;char *p;bioscom(0,par,0); //com1loop:p=comm;inportb(0x3f8); //resetdo{ while((inportb(0x3f8 5)&0x20)==0); outportb(0x3f8,*p ); }while(*p); //send commandos=0;j=0;do{ if((inportb(0x3fd)&0x01)==0)if(os〉receive_delay) break;else { cs ;continue; } ss[j ]=inportb(0x3f8); cs=0;}while(l);ss[j]=\0;if(j) return 0;else return 1;程序2:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <bios.h>#inolude <dos.h>#define maxsize 4096#define SEND 2#define RECEIVE 1#define COM1 0#define COM2 1static unsigned char Hardinterrupt=0;struct ComInterrupt{int portadd;int intbit;char buf[maxsize],*comm;int bufh,recount,sendcount;}com[2]={{0x3f8,0x0c,,,0,0,0},{0x2f8,0x0b,,,0,0,0} };void static interrupt (*old_com[2])(void);vold interrupt coml(vold);void interrupt com2(void);void fax2(int comnum);void setinterrupt(int comnum);void clearinterrupt(int comnum);void cominit(int comnum, int para, int interruptmark); void sendcomdata (int comnum,char *command);int getcomdata (int comnum, char *buf);void interrupt com1(void){fax2(0);}void interrupt com2(void){fax2(1);}// set cominterrupt, comnum 0=com1, 1=com2void setinterrupt (int comnum){old_com[comnum]=getvect(com[comnum].intbit); if (!oomnum)setvect(com[comnum].intbit,coml); //com1elsesetvect(com[comnum].intbit,com2); //com2//set hard intHardinterrupt = inportb(0x21);if(comnum)outportb(0x21,Hardinterrupt&0xf7); //com2 ,0 elseoutportb(0x21,Hardinterrupt&0xef); //com1 0,}void clear interrupt(int comnum){if(comnum)outportb(0x21,Hardinterrupt | 0x08); //COM2 elseoutportb(0x21,Hardinterrupt|0x10); //COM1 setvect(com[comnum].intbit,old_com[comnum]); for( i=0;i<maxsize;i ) com[comnum].buf=\0;com[comnum].sendcount=com[comnum].recount=com[comnum].bufh=0; outportb(com[comnum].portadd 1,0);outportb(com[comnum].por tadd 4,0x0);}void fax2(int i)//i=o,com1; i=1, com2{ unsigned char mark;mark=inport(com.portadd 2);do{if(mark&0x4)// receive data{ if (com.bufh==maxsize)com.bufh=0; com.buf[com.bufh ]=inportb(com.portadd); com[i].recount ;}else if(mark&0x2)// send command{ if(*m)outportb(com.portadd,*m );com,sendcount ;}elseoutportb(com.portadd 1,1);}}while ((mark=inport([1]. portadd 2))!=1);outportb(ox20,0x20); //hard int return}// interruptmark 1= reoeive, 2=send, 3=rec&send void comint(int com, char para, int interruptmark) {bioscom(0, par, com);//open com interruptoutportbv (com[comnum]. portadd 4,0x8;outportb (com[comnum].portadd 1,interruptmark);}void sendcomdata(int comnum,char * command){ unsigned char interruptmark;com[comnum],comm=command;com[comnum],sendcount=0;//set send interruptinterruptmark=inportb (com[comnum].portadd_1); outportb (com[comnum].portadd 1.(interruptmark|2)); }//get com_receivedate and clear com_receivebuf,int getcomdata (int comnum, char * buf){ int result=com[comnum]. recount,i:if(buf)strncpy(buf,com[comnum].buf,com [comnum].bufh);buf[com[comnum].bufh]=\0;com[comnum].recount=com [comnum].bufh=0; retun(result);}。
51单片机的串口通信程序(C语言)
51单片机的串口通信程序(C语言) 51单片机的串口通信程序(C语言)在嵌入式系统中,串口通信是一种常见的数据传输方式,也是单片机与外部设备进行通信的重要手段之一。
本文将介绍使用C语言编写51单片机的串口通信程序。
1. 硬件准备在开始编写串口通信程序之前,需要准备好相应的硬件设备。
首先,我们需要一块51单片机开发板,内置了串口通信功能。
另外,我们还需要连接一个与单片机通信的外部设备,例如计算机或其他单片机。
2. 引入头文件在C语言中,我们需要引入相应的头文件来使用串口通信相关的函数。
在51单片机中,我们需要引入reg51.h头文件,以便使用单片机的寄存器操作相关函数。
同时,我们还需要引入头文件来定义串口通信的相关寄存器。
3. 配置串口参数在使用串口通信之前,我们需要配置串口的参数,例如波特率、数据位、停止位等。
这些参数的配置需要根据实际需要进行调整。
在51单片机中,我们可以通过写入相应的寄存器来配置串口参数。
4. 初始化串口在配置完串口参数之后,我们需要初始化串口,以便开始进行数据的发送和接收。
初始化串口的过程包括打开串口、设置中断等。
5. 数据发送在串口通信中,数据的发送通常分为两种方式:阻塞发送和非阻塞发送。
阻塞发送是指程序在发送完数据之后才会继续执行下面的代码,而非阻塞发送是指程序在发送数据的同时可以继续执行其他代码。
6. 数据接收数据的接收与数据的发送类似,同样有阻塞接收和非阻塞接收两种方式。
在接收数据时,需要不断地检测是否有数据到达,并及时进行处理。
7. 中断处理在串口通信中,中断是一种常见的处理方式。
通过使用中断,可以及时地响应串口数据的到达或者发送完成等事件,提高程序的处理效率。
8. 串口通信实例下面是一个简单的串口通信实例,用于在51单片机与计算机之间进行数据的传输。
```c#include <reg51.h>#include <stdio.h>#define BAUDRATE 9600#define FOSC 11059200void UART_init(){TMOD = 0x20; // 设置定时器1为模式2SCON = 0x50; // 设置串口为模式1,允许接收TH1 = 256 - FOSC / 12 / 32 / BAUDRATE; // 计算波特率定时器重载值TR1 = 1; // 启动定时器1EA = 1; // 允许中断ES = 1; // 允许串口中断}void UART_send_byte(unsigned char byte){SBUF = byte;while (!TI); // 等待发送完成TI = 0; // 清除发送完成标志位}unsigned char UART_receive_byte(){while (!RI); // 等待接收完成RI = 0; // 清除接收完成标志位return SBUF;}void UART_send_string(char *s){while (*s){UART_send_byte(*s);s++;}}void main(){UART_init();UART_send_string("Hello, World!"); while (1){unsigned char data = UART_receive_byte();// 对接收到的数据进行处理}}```总结:通过以上步骤,我们可以编写出简单的51单片机串口通信程序。
C语言串口通信-源代码
C语言串口通信-源代码#include<tdio.h>#include<do.h>#include<conio.h>#include<tring.h>#defineCOM2320某2f8#defineCOMINT0某0b#defineMa某BufLen500#definePort82590某20#defineEofInt0某20taticcharintvectnum;taticunignedcharmakb;taticunignedcharBuffer[Ma某BufLen];taticintCharInBuf,CircIn,CircOut;taticvoid(interruptfar某OldAyncInt)();taticvoidinterruptfarAyncInt(void);unignedcharData,unignedcharStop,unignedcharParity){ unignedcharHigh,Low;intf;intvectnum=IntVectNum;CharInBuf=0;CircIn=0;CircOut=0;diable();OldAyncInt=getvect(IntVectNum);etvect(IntVectNum,Ay ncInt);enable();makb=inp(Port8259+1);if(IntVectNum==0某0c)outp(Port8259+1,makb&0某ef);eleoutp(Port8259+1,makb&0某f7);}taticvoidinterruptfarAyncInt(void){diable();if(CharInBuf<Ma某BufLen)if(CircIn<Ma某BufLen-1)CircIn++;eleCircIn=0;if(CircIn==CircOut)CircOut++;eleCharInBuf++;enable();outp(Port8259,EofInt);}voidRetore(void)etvect(intvectnum,OldAyncInt);outp(Port8259+1,makb);}intGetCharInBuf(unignedchar某Char) {intFlag;Flag=-1;if(CharInBuf>0){(某Char)=Buffer[CircOut];if(CircOut<Ma某BufLen-1)CircOut++; eleCircOut=0;CharInBuf--;Flag=0;}returnFlag;}intSendChar(unignedcharChar)return0;}main(){inti,c;unignedcharInChar;Init_COM(COM232,COMINT,1200,8,1,0); while(1){if(kbhit()){if((InChar=getch())==27)break; elewhile(SendChar(InChar));}if(GetCharInBuf(&InChar)==0)printf("%c",InChar);}Retore();}接收程序:#include<do.h>#include<ftream.h>#include<conio.h>#include<tdio.h>#include<tdlib.h>#include<math.h>#defineR某D0//接收voidInt(){unignedcharkey,key2;if(peek(0某40,port某2)==0){e某it(1);}ele{};Getportaddr(port);//得到串口地址SerInit(SER_BAUD_9600,SER_PARITY_EVEN|SER_BITS_8|SER_STOP_1) ;//初始化串口,设置波特率等SerOpen();do{if(kbhit()){key2=getch();if(key2==27){break;}};key=getb();if(key!=0某ff){printf("%某\t",key);FILE某fp;fp=fopen("C:\\Receivedata.dat","ab");//可选择接收数据的存放文件路径和文件名if(fp==NULL)printf("Fileopenerror!");//fputc(key,fp);fwrite(&key,izeof(unignedchar),1,fp);fcloe(fp);}}while(key2!=27);SerCloe();//printf("%dcharhabeenreceived\n",incount); //printf("%dcharhabeenended\n",outcount);//printf("\num=%d\n",um);}{printf("PleaeinputthereceiveCOMnum:(1~4)\n"); Cloe_Serial(intport_bae){outp(port_bae+SER_MCR,0);outp(port_bae+SER_IER,0);outp(PIC_IMR,old_int_mak);if(port_bae==COM_1){_do_etvect(INT_SER_PORT_0,Old_Ir);}ele{_do_etvect(INT_SER_PORT_1,Old_Ir);}}/某-------------发送应用----------------某/ voidmain(intargc,char某argv[]){charch,pre;intdone=0;FILE某fp;argc=2;if(argc<2){printf("\nUage:diplayfilename.wav!!!");//e某it(1);}if((fp=fopen(argv[1],"r+b"))==NULL){printf("cannotopenthefile\n");//e某it(0);}feek(fp,0,SEEK_SET);Open_Serial(COM_1,SER_BAUD_9600,SER_PARITY_EVEN|SER_STOP_1);printf("preanykeytobeginending");getch();//Serial_Write('');//该语句可用于发送单个字符while(!done&&ch!=EOF)//发送文件开始{ch=fgetc(fp);SER_BITS_8|//if(ch==EOF)Serial_Write(27);Serial_Write(ch);delay(30);if( kbhit()){pre=getch();if(pre==27){Serial_Write(27);done=1;}}}Cloe _Serial(COM_1);fcloe(fp);}下面介绍最重要的MFC:CWnd:窗口,它是大多数“看得见的东西”的父类(Window里几乎所有看得见的东西都是一个窗口,大窗口里有许多小窗口),比如视图CView、框架窗口CFrameWnd、工具条CToolBar、对话框CDialog、按钮CButton,etc;一个例外是菜单(CMenu)不是从窗口派生的。
c语言怎么写串口通信编程 -回复
c语言怎么写串口通信编程 -回复在C语言中进行串口通信编程,你需要了解串口的基本原理以及相关的函数和库。
串口通信是一种通过串行数据传输进行通信的方式,常用于嵌入式系统中与外部设备进行数据交互。
本文将以步骤的形式来介绍如何在C语言中进行串口通信编程。
步骤一:了解串口的基本原理在开始串口通信编程之前,你需要了解串口的基本原理。
串口是通过发送和接收数据位的序列来进行通信的。
串口通信需要考虑的一些参数包括波特率(即数据传输速率)、数据位数、校验位和停止位等。
波特率指的是每秒钟传输的位数,可以是常用的9600、19200、38400等。
步骤二:选择合适的串口库在C语言中,你可以选择使用合适的串口库来简化串口通信的编程工作。
常见的串口库包括Windows系统中的WinAPI、Linux系统中的termios库等。
选择库的时候,需根据你所使用的操作系统和开发环境进行选择。
步骤三:打开串口在开始使用串口进行通信之前,需要先打开串口。
使用串口库的函数,可以根据需要选择打开特定的串口,一般通过指定串口名称或者端口号来进行打开。
打开串口的函数可能返回一个文件描述符或者句柄,用于后续的读写操作。
步骤四:配置串口参数打开串口之后,需要进行串口参数的配置。
这包括波特率、数据位数、校验位和停止位等参数的设置。
一般通过调用相应的函数,将需要设置的参数传递给串口库,以完成参数的配置。
步骤五:读取串口数据配置完串口参数后,你可以开始读取串口数据。
通过调用读取函数,你可以从串口接收缓冲区中获取数据,并进一步进行处理。
读取函数可能会阻塞程序执行,直到有数据可读取为止。
步骤六:发送串口数据与读取串口数据相对应的是发送串口数据。
通过调用相应的发送函数,你可以将你要发送的数据写入串口发送缓冲区,等待发送。
发送函数可能会阻塞程序执行,直到数据成功发送。
步骤七:关闭串口在程序结束时,需要关闭已经打开的串口。
通过调用相应的函数,可以完成串口的关闭。
用c语言实现串口读写程序
用c语言实现串口读写程序一、前言串口通信是一种常见的通信方式,它可以实现单片机与计算机之间的数据传输。
在嵌入式系统中,使用串口通信可以方便地进行调试和数据传输。
本文将介绍如何使用C语言实现串口读写程序。
二、硬件准备在进行串口通信之前,需要准备好相应的硬件设备。
一般来说,需要一台计算机和一个串口转USB模块(或者直接使用带有串口接口的计算机)。
同时,在单片机端也需要连接一个串口模块。
三、C语言编程实现1. 打开串口在C语言中,可以通过打开文件的方式来打开串口设备。
下面是一个示例代码:```#include <stdio.h>#include <fcntl.h>#include <termios.h>int open_serial_port(const char *device_path, int baud_rate) {int fd;struct termios options;fd = open(device_path, O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) {perror("open_serial_port: Unable to open device");return -1;}fcntl(fd, F_SETFL, 0);tcgetattr(fd, &options);cfsetispeed(&options, baud_rate);cfsetospeed(&options, baud_rate);options.c_cflag |= (CLOCAL | CREAD);options.c_cflag &= ~PARENB;options.c_cflag &= ~CSTOPB;options.c_cflag &= ~CSIZE;options.c_cflag |= CS8;options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);options.c_oflag &= ~OPOST;tcsetattr(fd, TCSANOW, &options);return fd;}```在上述代码中,open_serial_port函数用来打开串口设备,并设置相应的参数。
C语言实现串口通信
C语言实现串口通信在使用系统调用函数进行串口通信之前,需要打开串口设备并设置相关参数。
打开串口设备可以使用open(函数,设置串口参数可以使用termios结构体和tcsetattr(函数。
以下是一个简单的串口通信接收数据的示例代码:```c#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#include <termios.h>int mainint fd; // 串口设备文件描述符char buff[255]; // 存储接收到的数据int len; // 接收到的数据长度//打开串口设备fd = open("/dev/ttyS0", O_RDONLY);if (fd < 0)perror("Failed to open serial port");return -1;}//设置串口参数struct termios options;tcgetattr(fd, &options);cfsetspeed(&options, B1200); // 设置波特率为1200 tcsetattr(fd, TCSANOW, &options);//接收数据while (1)len = read(fd, buff, sizeof(buff)); // 从串口读取数据if (len > 0)buff[len] = '\0'; // 将接收到的数据转为字符串printf("Received data: %s\n", buff);}}//关闭串口设备close(fd);return 0;```这段代码首先通过open(函数打开串口设备文件"/dev/ttyS0",然后使用tcgetattr(函数获取当前设置的串口参数,接着使用cfsetspeed(函数设置波特率为1200,最后使用tcsetattr(函数将设置好的串口参数写回。
[电子工程] 单片机C语言之串口通信协议(代码分享)
现实生活中,我们总是要与人打交道,互通有无。
单片机也一样,需要跟各种设备交互。
例如汽车的显示仪表需要知道汽车的转速及电动机的运行参数,那么显示仪表就需要从汽车的底层控制器取得数据。
而这个数据的获得过程就是一个通信过程。
类似的例子还有控制器通常是单片机或者PLC与变频器的通信。
通信的双方需要遵守一套既定的规则也称为协议,这就好比我们人之间的对话,需要在双方都遵守一套语言语法规则才有可能达成对话。
通信协议又分为硬件层协议和软件层协议。
硬件层协议主要规范了物理上的连线,传输电平信号及传输的秩序等硬件性质的内容。
常用的硬件协议有串口,IIC,SPI,RS485,CAN和USB。
软件层协议则更侧重上层应用的规范,比如modbus协议。
好了,那这里我们就着重介绍51单片机的串口通信协议,以下简称串口。
串口的6个特征如下。
(1)、物理上的连线至少3根,分别是Tx数据发送线,Rx数据接收线,GND共用地线。
(2)、0与1的约定。
RS232电平,约定﹣5V至﹣25V之间的电压信号为1,﹢5V至﹢25V之间的电压信号为0 。
TTL电平,约定5V的电压信号为1,0V电压信号为0 。
CMOS电平,约定3.3V的电压信号为1,0V电压信号为0 。
其中,CMOS电平一般用于ARM芯片中。
(3)、发送秩序。
低位先发。
(4)、波特率。
收发双方共同约定的一个数据位(0或1)在数据传输线上维持的时间。
也可理解为每秒可以传输的位数。
常用的波特率有300bit/s, 600bit/s, 2400bit/s, 4800bit/s, 9600bit/s。
(5)、通信的起始信号。
发送方在没有发送数据时,应该将Tx置1 。
当需发送时,先将Tx置0,并且保持1位的时间。
接受方不断地侦测Rx,如果发现Rx常时间变高后,突然被拉低(置为0),则视为发送方将要发送数据,迅速启动自己的定时器,从而保证了收发双方定时器同步定时。
(6)、停止信号。
发送方发送完最后一个有效位时,必须再将Tx保持1位的时间,即为停止位。
51单片机的串口通信程序(C语言)
#include <reg52.h>#include<intrins.h>#include <stdio.h>#include <math.h>#define uchar unsigned char#define uint unsigned intsbit Key1 = P2^3;sbit Key2 = P2^2;sbit Key3 = P2^1;sbit Key4 = P2^0;sbit BELL = P3^6;sbit CONNECT = P3^7;unsigned int Key1_flag = 0;unsigned int Key2_flag = 0;unsigned int Key3_flag = 0;unsigned int Key4_flag = 0;unsigned char b;unsigned char code Num[21]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00, 0x10,0x89};unsigned char code Disdigit[4] = {0x7F,0xBF,0xDF,0xEF};unsigned char Disbuf[4];void delayms(uint t){uint i;while(t--){/* 对于11.0592M时钟,约延时1ms */for (i=0;i<125;i++){}}}//-----------------------------------------------------void SendData(uchar Dat){uchar i=0;SBUF = Dat;while (1){if(TI){TI=0;break;}}}void ScanKey(){if(Key1 == 0){delayms(100); if(Key1 == 0){Key1_flag = 1; Key2_flag = 0; Key3_flag = 0;Key4_flag = 0;Key1 = 1;}else;}if(Key2 == 0){delayms(100);if(Key2 == 0){Key2_flag = 1; Key1_flag = 0; Key3_flag = 0;Key4_flag = 0;Key2 = 1;}else;}if(Key3 == 0){delayms(50);if(Key3 == 0){Key3_flag = 1; Key1_flag = 0; Key2_flag = 0;Key4_flag = 0;Key3 = 1;}else;}if(Key4 == 0){delayms(50);if(Key4 == 0){Key4_flag = 1;Key1_flag = 0;Key2_flag = 0;Key3_flag = 0;Key4 = 1;}else;}else;}void KeyProc(){if(Key1_flag){TR1 = 1;SendData(0x55);Key1_flag = 0; }else if(Key2_flag){TR1 = 1;SendData(0x11); Key2_flag = 0;}else if(Key3_flag) {P1=0xff;BELL = 0;CONNECT = 1;Key3_flag = 0;}else if(Key4_flag){CONNECT = 0;BELL = 1;Key4_flag = 0;}else;}void Initdisplay(void){Disbuf[0] = 1;Disbuf[1] = 2;Disbuf[2] = 3;Disbuf[3] = 4;}void Display() //显示{unsigned int i = 0;unsigned int temp,count;temp = Disdigit[count]; P2 =temp;temp = Disbuf[count];temp = Num[temp];P0 =temp;count++;if (count==4)count=0;}void time0() interrupt 1 using 2 {Display();TH0 = (65535 - 2000)/256;TL0 = (65535 - 2000)%256;}void main(){Initdisplay();TMOD = 0x21;TH0 = (65535 - 2000)/256;TL0 = (65535 - 2000)%256;TR0 = 1;ET0 = 1;TH1 = 0xFD; //11.0592MTL1 = 0xFD;PCON&=0x80;TR1 = 1;ET1 = 1;SCON = 0x40; //串口方式REN = 1;PT1 = 0;PT0 = 1;EA = 1;while(1){ScanKey();KeyProc();if(RI){Disbuf[0] = 0;Disbuf[1] = 20;Disbuf[2] = SBUF>>4;Disbuf[3] = SBUF&0x0f;RI = 0;}else;}}51单片机串口通信C语言程序2**************************************************************; 平凡单片机工作室;ckss.asm;功能:反复向主机送AA和55两个数;主机使用一个串口调试软件设置19200,n,8,1***************************************************************/#include "reg51.h"#define uchar unsigned char#define uint unsigned int//延时程序//////////////////由Delay参数确定延迟时间*/void mDelay(unsigned int Delay){ unsigned int i;for(;Delay>0;Delay--){ for(i=0;i<124;i++){;}}}//////////////////// 主程序////////////////////void main(){ uchar OutDat; //定义输出变量TMOD=0x20; //TMOD=0TH1=0xf3; //12MHZ ,BPS:4800,N,8,1TL1=0xf3;PCON=0x80; //方式一TR1=1; //?????????????????????????????SCON=0x40; //串口通信控制寄存器模式一OutDat=0xaa; //向串口发送固定数据值for(;;) //循环程序{SBUF=OutDat;//发送数据for(;;){ if(TI) //发送中断位当发送停止位时置1,表示发送完成break;}mDelay(500);TI=0; //清零中断位OutDat=~OutDat; //显示内容按位取反}}。
c语言串口编程实例
c语言串口编程实例摘要:1.串口编程基础2.C 语言串口编程步骤3.C 语言串口编程实例4.实例详解5.总结正文:一、串口编程基础串口编程是指通过计算机串行接口进行数据通信的编程方式。
串口(Serial Port)是一种计算机硬件接口,可以通过串行通信传输数据。
与并行通信相比,串行通信只需一条数据线,传输速度较慢,但具有线路简单、成本低的优点。
因此,串口编程在电子设备、计算机外设、通信设备等领域有广泛的应用。
二、C 语言串口编程步骤1.包含头文件:在使用C 语言进行串口编程时,首先需要包含头文件`<reg52.h>`或`<intrins.h>`。
2.配置串口:配置串口包括设置波特率、数据位、停止位、奇偶校验等参数。
3.初始化串口:初始化串口主要是初始化串口硬件,如配置UART(通用异步收发器)等。
4.打开串口:打开串口是指使能串口通信功能,以便数据传输。
5.读写串口:通过`in`和`out`语句实现数据的输入输出。
6.关闭串口:在数据传输完成后,需要关闭串口以节省资源。
7.串口通信:通过循环寄存器、缓存寄存器或FIFO(先进先出)等方法实现数据的收发。
三、C 语言串口编程实例以下是一个简单的C 语言串口编程实例,该实例通过串口发送数据“Hello, World!”:```c#include <reg52.h>#include <intrins.h>sbit UART_TXD = P3^1; // 配置UART TXD 引脚void init_uart(); // 初始化UART 函数void send_data(unsigned char dat); // 发送数据函数void main(){init_uart(); // 初始化UARTsend_data("H"); // 发送字符"H"send_data("e"); // 发送字符"e"send_data("l"); // 发送字符"l"send_data("l"); // 发送字符"o"send_data(" "); // 发送空格send_data("W"); // 发送字符"W"send_data("o"); // 发送字符"r"send_data("r"); // 发送字符"l"send_data("d"); // 发送字符"d"while(1); // 循环等待}void init_uart() // 初始化UART 函数{TMOD = 0x20; // 设置定时器1 为工作状态TH1 = 0xfd; // 设置定时器1 的计数值TL1 = 0xfd; // 设置定时器1 的计数值TR1 = 1; // 使能定时器1SCON = 0x40; // 设置串口工作状态ES = 0; // 开总中断EA = 1; // 开总中断允许}void send_data(unsigned char dat) // 发送数据函数{SBUF = dat; // 将数据存入缓存寄存器while(!TI); // 等待发送缓存清空TI = 0; // 清空发送缓存}```四、实例详解1.配置串口:通过设置UART TXD 引脚为P3.1,确定波特率、数据位、停止位和奇偶校验等参数。
一个c语言的串口通信程序范例
#include 〈stdio.h>#include <dos。
h>#include <conio。
h〉#include <string。
h〉#define COM232 0x2f8#define COMINT 0x0b#define MaxBufLen 500#define Port8259 0x20#define EofInt 0x20static int comportaddr;static char intvectnum;static unsigned char maskb;static unsigned char Buffer[MaxBufLen];static int CharsInBuf,CircIn,CircOut;static void (interrupt far *OldAsyncInt)();static void interrupt far AsyncInt(void);void Init_COM(int ComPortAddr, unsigned char IntVectNum, int Baud, unsigned char Data, unsigned char Stop, unsigned char Parity){unsigned char High,Low;int f;comportaddr=ComPortAddr;intvectnum=IntVectNum;CharsInBuf=0;CircIn=0;CircOut=0;f=(Baud/100);f=1152/f; High=f/256;Low=f-High*256;outp(ComPortAddr+3,0x80);outp(ComPortAddr,Low);outp(ComPortAddr+1,High);Data=(Data-5)|((Stop-1)*4);if(Parity==2) Data=Data|0x18;else if(Parity==1) Data=Data|0x8;outp(ComPortAddr+3,Data);outp(ComPortAddr+4,0x0a);outp(ComPortAddr+1,0x01);disable();OldAsyncInt=getvect( IntVectNum ); setvect( IntVectNum, AsyncInt );enable();maskb=inp(Port8259+1);if(IntVectNum==0x0c)outp(Port8259+1,maskb&0xef); else outp(Port8259+1,maskb&0xf7);}static void interrupt far AsyncInt(void){disable();if(CharsInBuf<MaxBufLen)Buffer[CircIn]=inp(comportaddr);if(CircIn〈MaxBufLen-1) CircIn++;else CircIn=0;if(CircIn==CircOut) CircOut++;else CharsInBuf++;enable();outp(Port8259,EofInt);}void Restore(void){setvect(intvectnum,OldAsyncInt);outp(Port8259+1,maskb);}int GetCharInBuf(unsigned char *Char)int Flag;Flag=—1;if(CharsInBuf>0){(*Char)=Buffer[CircOut];if(CircOut<MaxBufLen—1)CircOut++;else CircOut=0;CharsInBuf—-;Flag=0;}return Flag;}int SendChar(unsigned char Char){if((inp(comportaddr+5)&0x20)==0) return —1; outp(comportaddr,Char);return 0;}main(){int i,c;unsigned char InChar;Init_COM(COM232,COMINT,1200,8,1,0); while(1){if(kbhit()){if((InChar=getch())==27)break;else while(SendChar(InChar));}if(GetCharInBuf(&InChar)==0)printf("%c",InChar);}Restore();}。
C语言串口通信-源代码
#include <stdio.h>#include <dos.h>#include <conio.h>#include <string.h>#define COM232 0x2f8#define COMINT 0x0b#define MaxBufLen 500#define Port8259 0x20#define EofInt 0x20static int comportaddr;static char intvectnum;static unsigned char maskb;static unsigned char Buffer[MaxBufLen];static int CharsInBuf,CircIn,CircOut;static void (interrupt far *OldAsyncInt)();static void interrupt far AsyncInt(void);void Init_COM(int ComPortAddr, unsigned char IntVectNum, int Baud, unsigned char Data, unsigned char Stop, unsigned char Parity) {unsigned char High,Low;int f;comportaddr=ComPortAddr;intvectnum=IntVectNum;CharsInBuf=0;CircIn=0;CircOut=0;f=(Baud/100);f=1152/f; High=f/256;Low=f-High*256;outp(ComPortAddr+3,0x80);outp(ComPortAddr,Low);outp(ComPortAddr+1,High);Data=(Data-5)|((Stop-1)*4);if(Parity==2) Data=Data|0x18;else if(Parity==1) Data=Data|0x8;outp(ComPortAddr+3,Data);outp(ComPortAddr+4,0x0a);outp(ComPortAddr+1,0x01);disable();OldAsyncInt=getvect( IntVectNum );setvect( IntVectNum, AsyncInt );enable();maskb=inp(Port8259+1);if(IntVectNum==0x0c)outp(Port8259+1,maskb&0xef); else outp(Port8259+1,maskb&0xf7);}static void interrupt far AsyncInt(void){disable();if(CharsInBuf<MaxBufLen)Buffer[CircIn]=inp(comportaddr);if(CircIn<MaxBufLen-1) CircIn++;else CircIn=0;if(CircIn==CircOut) CircOut++;else CharsInBuf++;enable();outp(Port8259,EofInt);}void Restore(void){setvect(intvectnum,OldAsyncInt);outp(Port8259+1,maskb);}int GetCharInBuf(unsigned char *Char){int Flag;Flag=-1;if(CharsInBuf>0){(*Char)=Buffer[CircOut];if(CircOut<MaxBufLen-1)CircOut++;else CircOut=0;CharsInBuf--;Flag=0;}return Flag;}int SendChar(unsigned char Char){if((inp(comportaddr+5)&0x20)==0) return -1; outp(comportaddr,Char);return 0;}main(){int i,c;unsigned char InChar;Init_COM(COM232,COMINT,1200,8,1,0);while(1){if(kbhit()){if((InChar=getch())==27)break;else while(SendChar(InChar));}if(GetCharInBuf(&InChar)==0)printf("%c",InChar);}Restore();}接收程序:#include <dos.h>#include <fstream.h>#include <conio.h>#include <stdio.h>#include <stdlib.h>#include <math.h>#define RXD 0 //接收#define TXD 0 //发送#define LSB 0 //波特率调节低8位#define MSB 1 //波特率调节高8位#define IER 1 // 中断起用寄存器#define IIR 2 //中断标识寄存器#define LCR 3 //线路控制寄存器#define MCR 4 //调制解调器控制寄存器#define LSR 5 //线路状态寄存器#define MSR 6 //调制解调器状态寄存器#define IERV 1#define OUT2 0x08#define ERTS 2#define EDTR 1#define EMPTY 0X20#define READY 0X30#define ICREG 0X20#define IMASKREG 0X21#define EOI 0X20#define WAITCOUNT 5000#define BUFFLEN 2048 //用于存储字符的数组的界#define ALTE 0X12#define ALTQ 0X10#define SER_BAUD_1200 96#define SER_BAUD_2400 48#define SER_BAUD_9600 0x0C#define SER_BAUD_19200 6#define SER_STOP_1 0 /*/ 1 stop bit per character*/#define SER_STOP_2 4 /*/ 2 stop bits per character*/#define SER_BITS_5 0 /*/ send 5 bit characters*/#define SER_BITS_6 1 /*/ send 6 bit characters*/#define SER_BITS_7 2 /*/ send 7 bit characters*/#define SER_BITS_8 3 /*/ send 8 bit characters*/#define SER_PARITY_NONE 0 /*/ no parity*/#define SER_PARITY_ODD 8 /*/ odd parity*/#define SER_PARITY_EVEN 24 /*/ even parity*/int port;int ComNum;unsigned portaddr;unsigned portf;unsigned int baudtable[]={0x180,0xc0,0x60,0x30,0x18,0x0c,0x06};unsigned char paritytable[]={0x08,0x18,0x00,0x28,0x38};unsigned char buffer[BUFFLEN];//recv bufint buffin=0;int buffout=0;int incount=0;int outcount=0;void interrupt(*vect_com)(...);void putb(unsigned char ch)//write a char to the recvbuf 将中断得到的数据写到缓冲区{int temp;temp=buffin;if(++buffin==BUFFLEN)buffin=0;if(buffin!=buffout){buffer[buffin]=ch;// printf("bufferin[%d]=%c",buffer[buffin]);// getch();}elsebuffin=temp;};unsigned char getb()//read a char from the recvbuf{if(buffout!=buffin){if(++buffout==BUFFLEN)buffout=0;//printf("bufferout[%d]=%c",buffout,buffer[buffout]);return(buffer[buffout]);}elsereturn(0xff);};/*unsigned char sender( unsigned char ch){outportb(portaddr2+TXD,ch);printf("\nsender outportdata=%c\n",ch);outcount++;return(1);};*/void interrupt receiver(...){unsigned char ch;ch=inportb(portaddr+RXD);putb(ch);incount++; //记录接收了多少个数据。
