51单片机与PC串口通讯

合集下载

51单片机的串口通信程序(C语言)

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单片机串口通信程序。

实验6 单片机与PC机间的串行通信

实验6  单片机与PC机间的串行通信

实验6 单片机与PC机间的串行通信一、实验目的1、掌握电平转换器件RS-232的使用方法;2、掌握Proteus VSM虚拟终端(VITUAL TERMINAL)的使用;3、掌握单片机与PC机间的串行通信软硬件设计方法。

二、实验内容实现利用虚拟终端仿真单片机与PC机间的串行通信。

PC机先发送从键盘输入的数据,单片机接收后回发给PC机。

单片机同时将收到的30~39H间的数据转换成0~9的数字显示,其他字符的数据直接显示为其ASCII码。

单片机和PC机进行通信时,要求使用的波特率、传送的位数等相同。

要能够进行数据传送也必须首先测试双方是否可以可靠通信。

可在PC机和单片机上各编制非常短小的程序,具体可分成PC机串行口发送接收程序、单片机串行口发送程序和单片机串行口发送接收程序。

这三个程序能运行通过,即可证明串行口工作正常。

PC机串行口发送接收程序设置串行口为波特率9600、8位数据、1位停止位、无奇偶校验的简单设置。

从键盘接收的字符可从串行口发送出去,从串行口接收的字符在屏幕上显示。

通过让串行口发送线和接收线短接可测试微机串行口,通过让串行口和单片机系统相接,使用此程序可进一步测试单片机的串行通信状况。

具体程序用BASIC编制,简单易懂。

直接输入即可运行。

程序RS232.三、实验电路原理图图7-1 单片机与PC机间电路原理图四、实验步骤1、在PROTEUS中画好电路原理图。

2、串口模型属性设置串口模型属性设置为:波特率―4800;数据位―8;奇偶校验―无;停止位-1,如图7-2所示。

图7-2 串口模型属性设置3、虚拟终端属性设置PCT代表计算机发送数据,PCR用来监视PC接收到的数据,它们的属性设置完全一样,如图7-3所示。

SCMT和SCMR分别是单片机的数据发送和接收终端,用来监视单片机发送和接收的数据,它们的属性设置也完全一样,如图7-4所示。

单片机和PC机双方的波特率、数据位、停止位和检验位等要确保和串口模型的设置一样,并且同单片机程序中串口的设置一致。

51单片机串口通信程序。。含详细例子

51单片机串口通信程序。。含详细例子

{ P3_4=0; P3_3=1;
} void RstPro()//编程器复位 {
pw.fpProOver();//直接编程结束 SendData();//通知上位机,表示编程器就绪,可以直接用此函数因为协议号(ComBuf[0])还没被修改,下同 }
void ReadSign()//读特征字 {
} void serial () interrupt 4 using 3 //串口接收中断函数 {
if (RI) { RI = 0 ; ch=SBUF; read_flag= 1 ; //就置位取数标志 }
} main()
{ init_serialcom(); //初始化串口 while ( 1 ) { if (read_flag) //如果取数标志已置位,就将读到的数从串口发出 { read_flag= 0 ; //取数标志清 0 send_char_com(ch); } }
while(RI == 0); RI = 0; c = SBUF; // 从缓冲区中把接收的字符放入 c 中 SBUF = c; // 要发送的字符放入缓冲区 while(TI == 0); TI = 0; } }
4.//////////////// /////////////////////////////////////////////////////////
SendData(); } else break;//等待回应失败 } pw.fpProOver();//操作结束设置为运行状态 ComBuf[0]=0;//通知上位机编程器进入就绪状态 SendData(); }
void Lock()//写锁定位
{
pw.fpLock();
SendData();

51单片机与PC机串口通信的仿真与实现

51单片机与PC机串口通信的仿真与实现

51单片机与PC机串口通信的仿真与实现作者:李健来源:《电脑知识与技术》2018年第32期摘要:介绍了利用几种常见软件实现的51单片机与PC机串口通信的仿真过程,可以在单片机课程的理论教学中加以应用,具有效率高、成本低等优点,有助于教师的教学和学生对知识的掌握和应用。

关键词:51单片机;PC机;串口通信;仿真中图分类号:TP393 文献标识码:A 文章编号:1009-3044(2018)32-0038-02在实际应用中,单片机与PC机间的通信非常普遍[1]。

这时单片机主要完成现场数据采集和设备监控[2],PC机接收单片机发来的数据进行分析、处理,并对结果再次发送单片机进行现场控制等。

笔者在单片机课程的理论教学中,由于课堂上受到条件的约束,采用了纯软件的方法对单片机串口通信进行仿真和演示,便于实现和让学生理解。

下面通过一个实例来介绍51单片机与PC机之间串口通信的仿真与实现过程。

1 所需软件使用到的软件有:VSPD、Proteus、Keil和串口助手[3]。

VSPD是一个虚拟串口小软件,可以虚拟出一对串行接口用于仿真;Proteus是一款流行的单片机仿真软件,用于建立串口通信仿真电路;Keil是用于编写单片机程序的软件;串口助手是用于上位机即PC机的软件,用来向单片机发送数据,或者接收单片机发送来的数据并进行显示。

2 设计与仿真过程预期实现的功能为:PC机通过串口助手向单片机发送一个字节数据,单片机接收到后将数据的二进制形式通过八个数码管的亮灭显示出来,接收的“1”对应的灯亮,接收的“0”对应的灯灭。

同时单片机将接收的数据发回给PC机,PC机将数据在串口助手中再显示出来。

2.1 利用Proteus设计仿真电路如图1所示,在Proteus软件中选用AT89C51单片机、COMPIM、电阻和发光二极管组成仿真电路。

COMPIM在仿真中相当于PC机上配置的RS232标准串行接口,为D型九针插座[4]。

在实际中,单片机和PC机之间需要通过MAX232芯片进行电平转换才能连接,但在仿真图中可以直接将两者的RXD(接收数据)和TXD(发送数据)连接起来进行串行通信。

AT89C51单片机与PC机串行通信的接口实现

AT89C51单片机与PC机串行通信的接口实现

AT89C51单片机与PC机串行通信的接口实现[摘要] 本文介绍了AT89C51单片机与PC机采用RS232C标准进行串行通信的接口实现。

在接口中采用MAX232作电平转换电路,简单的通信协议,PC 机用VB编程,AT89C51单片机采用中断收发方式。

文章给出了相应通信接口电路与程序。

[关键词] 通信协议RS232C 通信接口电路通信接口程序AT89C51是一种带4K字节可编程可擦除只读存储器(FLASH FPEROM)和128字节的存取数据存储器(RAM)的低电压,高性能CMOS8位微处理器。

采用了ATMEL公司的高密度、不容易丢失存储技术,与MCS-51系列的单片机兼容。

具有集成程度高、系统结构简单、价格低廉等优点被广泛应用到控制领域中。

但是在复杂的数据处理、良好的人机交互等方面不能满足需要,常采用PC 机与AT89C51单片机进行通信,AT89C51单片机(下位机)实时采集数据传送给PC机(上位机)处理,然后接收PC机处理的结果,并进行相应的控制的方式来弥补。

本文介绍单片机与PC机进行串行通信的一种接口实现。

一、接口电路的设计(一)接口逻辑电平的转换在PC机系统大都装有异步通信适配器,为标准的RS-232C接口。

RS-232C 为负逻辑,用+3V~+15V表示逻辑“0”, 用-3V~-15V表示逻辑“1”。

AT89C51单片机采用正逻辑TTL电平0和+5V.所以AT89C51与PC机通信时必须进行电平转换。

转换的方法有多种。

常采用MAXIM公司生产的专用的双向电平转换集成电路MAX232。

MAX232引脚排列与外围电路如图1所示。

图1MAX引脚及外围接口图(二)通信接口电路本文采用可靠性高的MAX232作电平转换芯片,选择其中一对发送器与接收器,PC机的串行口与MAX232的电平端口相连,MAX232的逻辑电平端口与单片机的串行口相连,接口电路如图2所示。

图2PC机与AT89C51通信接口图二、通信接口程序(一)通信协议PC机与AT89C51进行通信必须有一定的通信协议,本文采用简单的通信协议。

51单片机与PC机通信

51单片机与PC机通信

《专业综合实习报告》专业:电子信息工程年级:2013级指导教师:学生:目录一:实验项目名称二:前言三:项目内容及要求四:串口通信原理五:设计思路5.1虚拟串口的设置5.2下位机电路和程序设计5.3串口通信仿真六:电路原理框图七:相关硬件及配套软件7.1 AT89C51器件简介7.2 COMPIN简介7.3 MAX232器件简介7.4友善串口调试助手7.5 虚拟串口软件Virtual Serial Port Driver 6.9八:程序设计九:proteus仿真调试十:总结十一:参考文献一:实验项目名称:基于51单片机的单片机与PC机通信二:前言在国内外,以PC机作为上位机,单片机作为下位机的控制系统中,PC机通常以软件界面进行人机交互,以串行通信方式与单片机进行积极交互,而单片机系统根据被控对象配置相应的前向,后向信息通道,工作时作为主控机测对象,作为被控机接受PC机监督,指挥,定期或受命向上位机提供对象及本身的工作状态信息。

目前,随着集成电路集成度的增加,电子计算机向微型化和超微型化方向发展,微型计算机已成为导弹,智能机器人,人类宇宙和太空和太空奥妙复杂系统不可缺少的智能部件。

在一些工业控制中,经常需要以多台单片机作为下位机执行对被控对象的直接控制,以一台PC机为上位机完成复杂的数据处理,组成一种以集中管理、分散控制为特点的集散控制系统。

为了提高系统管理的先进性和安全性,计算机工业自动控制和监测系统越来越多地采用集总分算系统。

较为常见的形式是由一台做管理用的上位主计算机(主机)和一台直接参与控制检测的下位机(单片机)构成的主从式系统,主机和从机之间以通讯的方式来协调工作。

主机的作用一是要向从机发送各种命令及参数:二是要及时收集、整理和分析从机发回的数据,供进一步的决策和报表。

从机被动地接受、执行主机发来的命令,并且根据主机的要求向主机回传相应烦人实时数据,报告其运行状态。

用串行总线技术可以使系统的硬件设计大大简化、系统的体积减小、可靠性提高。

51单片机与串口通信代码

51单片机与串口通信代码

51单片机与串口通信代码串口调试1. 发送:向总线上发命令2. 接收:从总线接收命令,并分析是地址还是数据。

3. 定时发送:从内存中取数并向主机发送.经过调试,以上功能基本实现,目前可以通过上位机对单片机进行实时控制。

程序如下://这是一个单片机C51串口接收(中断)和发送例程,可以用来测试51单片机的中断接收//和查询发送,另外我觉得发送没有必要用中断,因为程序的开销是一样的#i nclude <reg51.h>#i nclude<stdio.h>#i nclude <string.h>#define INBUF_LEN 4 //数据长度unsigned char inbuf1[INBUF_LEN];unsigned char checksum,count3 , flag,temp,ch;bit read_flag=0;sbit cp=P1^1;sbit DIR=P1^2;int i;unsigned int xdata *RAMDATA; /*定义RAM地址指针*/unsigned char a[6] ={0x11,0x22,0x33,0x44,0x55,0x66} ;void init_serialcomm(void){SCON=0x50; //在11.0592MHz下,设置串行口波特率为9600,方式1,并允许接收PCON=0x00;ES=1;TMOD=0x21; //定时器工作于方式2,自动装载方式 TH0=(65536-1000)%256;TL0=(65536-1000)/256;TL1=0xfd;TH1=0xfd;ET0=1;TR0=1;TR1=1;// TI=0;EA=1;// TI=1;RAMDATA=0x1F45;}void serial () interrupt 4 using 3{if(RI){ RI=0;ch=SBUF;TI=1; //置SBUF空switch(ch){case 0x01 :printf("A"); TI=0;break;case 0x02 :printf("B"); TI=0;break;case 0x03 :printf("C"); TI=0;break;case 0x04 :printf("D"); TI=0;break; default :printf("fg"); TI=0;break; }}}//向串口发送一个字符void timer0() interrupt 1 using 3{// char i;flag++;TH0=0x00;TL0=0x00;if(flag==10){// cp=!cp;// for(i=0;i<6;i++)P2=0x25;TI=1;temp=*RAMDATA;printf("%c",temp); TI=0;// RAMDATA--;flag=0;}}//主程序main(){init_serialcomm(); //初始化串口//向6264中送数据{*RAMDATA=0x33;}while(1){*RAMDATA=0x33;;}}调试过程中遇到的问题:1. 发送过程:在发送时必须保证TI=1:即发送缓冲器为空,否则将导致数据发不出去,如果想强制发送可以用:TI=1.具体发送数据:利用printf(“akjdfaklfj”);函数直接发送即可。

PC与51单片机串口通信

PC与51单片机串口通信

PC与51单片机串口通信PC与51单片机串口通信。

包括单片机内运行的程序,及MATLAB调试助手简易程序等!PC与51单片机串口通信串行通信是计算机和外设进行通讯、对外设进行监控并获取由外设采集到的监测数据的一个非常重要的手段。

由于其所用的传输线少,成本低,实现起来方便易行,因而得到广泛的应用。

*****2RC有一个可编程的全双工串行通信接口,可以方便的实现PC机与其之间的串行通信。

一、总体方案系统中采用*****2RC/*****4RD+单片机作为下位机,PC机为上位机,二者通过CH340将PC的USB口转成RS232的串行口接收或上传数据。

单片机部分的程序采用C语言编程,用Keil uVision4编译后产生HEX文件下载到单片机内,从而实现数据收发。

PC端采用一个串口调试助手(sscom4.2)或MATLAB GUI 实现数据的收发。

二、具体方案1、简单通信测试程序本程序为了测试通信方式是否合适,以便于下一步增加程序的内容。

(1)利用STC提供STC-ISP-V4.83软件检查MCU选项MCU Type is: *****4RD+ MCU Firmware Version: 3.2C Chinese:MCU 固件版本号: 3.2CDouble speed / 双倍速: 12T/单倍速振荡放大器增益: full gain 下次下载时P1.0/P1.1 与下载无关内部扩展AUX-RAM: 允许访问(强烈推荐) 下次下载用户应用程序时将数据Flash区擦除: NO 用户软件启动内部看门狗后: 复位关看门狗ALE pin 仍为ALE内部时钟频率:11.0*****M 外部时钟频率:11.0*****M(2)串行口初始参数设定串行口工作方式为方式1(10位异步收发),波特率为9600bps,用定时器1作波特率发生器,选用定时器模式2,其它详见程序及说明。

PC与51单片机串口通信。

包括单片机内运行的程序,及MATLAB调试助手简易程序等!(3)程序功能说明通过串口调试助手,向单片机发送字符,发送字符的末尾需加“!”,让单片机识别数据接收完毕,返回“Wait command!”字符串。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

目录第1章需求分析 ............................................................................................................................ - 1 -1.1课题名称 (1)1.2任务 (1)1.3要求 (1)1.4设计思想 (1)1.5课程设计环境 (1)1.6设备运行环境 (2)1.7我在本实验中完成的任务 (2)第2章概要设计 ............................................................................................................................ - 2 -2.1程序流程图 (2)2.2设计方法及原理 (3)第3章详细设计 ............................................................................................................................ - 3 -3.1电路原理 (3)3.1.1STC89C52芯片 ............................................................................................................. - 3 -3.2串口通信协议 (4)3.3程序设计 (5)3.3.1主程序模块 .................................................................................................................... - 5 -3.3.2串口通讯模块 ................................................................................................................ - 6 -3.3.3控制部分文件 ................................................................................................................ - 8 -3.3.4公共部分模块 .............................................................................................................. - 11 -3.4电路搭建 (12)3.4.1电路原理图 .................................................................................................................. - 12 -第4章上位机关键代码分析 ...................................................................................................... - 12 -4.1打开串口操作 (12)4.2后台线程处理串口程序 (15)4.3程序运行界面 (18)第5章课程设计总结与体会 ...................................................................................................... - 19 -第6章致谢 .................................................................................................................................. - 19 -参考文献........................................................................................................................................... - 19 -第1章需求分析1.1 课题名称故障诊断数据采集通信系统设计与制作。

1.2 任务1、进行协议分析,完成单片机硬件电路原理图设计,在面包板上搭建电路。

2、测试上位机与单片机的通讯状态,实现实验要求部分的功能。

1.3 要求1、单片机能接收并识别上位机的查询请求。

2、单片机能够查询对应接口的状态,并返回接口状态给上位机。

3、能够通过按钮来控制单片机相应接口的状态,相应接口的状态通过LED灯的亮灭状态来表示。

1.4 设计思想根据实验要求,设计数据采集电路,选择合适的元器件,按照原理图,并根据各个元器件的特性以及接口电路结构形式,在面包板上搭接实际电路,搭接完毕之后对电路做优化设计,使电路尽量简洁。

通过与上位机的连接测试,来优化单片机程序的代码,使上位机和下位机能够很协调的工作。

软件编程:使用C语言实现下位机的程序设计。

1.5 课程设计环境1. Windows XP的PC机。

2. Keil uVision3集成开发环境。

3. 串口调试助手3. 单片机最小系统开发板。

4. 面包板和外围器件5. 万用表等辅助工具1.6 设备运行环境由STC89C52单片机和面包板搭建的电路板。

1.7 我在本实验中完成的任务在和小组成员讨论之后,我们小组成员分工合作,我完成的工作是单片机串口的设置及接收上位机的串口数据,并对流数据进行分析。

第2章概要设计2.1 程序流程图2.2 设计方法及原理1、USB转串口模块将USB接口转化为串口后与单片机相连,用来实现单片机与PC机通过串口通讯。

2、初始化单片机串口的设置,使之与上位机的设置相符,具体为通信速率9600B/S,停止位1位,数据位8位。

3、本系统串口数据接收是采用的查询方式,单片机每次循环查询串口是否收到了数据。

4、上位机若连续查询接口状态2次都收不到回复,上位机可以判断与从机失去联系,所有接口状态都置为不正常状态第3章详细设计3.1 电路原理3.1.1STC89C52芯片1、芯片引脚51系列的DIP封装的单片机共有40个外部引脚,其中有P0,P1,P2,P3四组IO口,详细如右图。

2、芯片串口工作原理1、波特率选择波特率(Boud Rate)就是在串口通信中每秒能够发送的位数(bits/second)。

MSC-51串行端口在四种工作模式下有不同的波特率计算方法。

下面以工作模式1为来说明串口通信波特率的选择。

在串行端口工作于模式1,其波特率将由计时/计数器1来产生,通常设置定时器工作于模式2(自动再加模式)。

在此模式下波特率计算公式为:波特率=(1+SMOD)*晶振频率/(384*(256-TH1))其中,SMOD——寄存器PCON的第7位,称为波特率倍增位;TH1——定时器的重载值。

2、SBUF数据缓冲寄存器这是一个可以直接寻址的串行口专用寄存器。

SBUF包含了两个独立的寄存器,一个是发送寄存,另一个是接收寄存器,但它们都共同使用同一个寻址地址-99H。

CPU在读SBUF 时会指到接收寄存器,在写时会指到发送寄存器。

3、SCON串行口控制寄存器通常在芯片或设备中为了监视或控制接口状态,都会引用到接口控制寄存器。

SCON就是51芯片的串行口控制寄存器。

它的寻址地址是98H,是一个可以位寻址的寄存器,作用就是监视和控制51芯片串行口的工作状态。

51芯片的串口可以工作在几个不同的工作模式下,其工作模式的设置就是使用SCON寄存器。

它的各个位的具体定义如下:(MSB)(LSB)串行口控制寄存器SCONSM0、SM1为串行口工作模式设置位,这样两位可以对应进行四种模式的设置。

看表串行口工作模式设置。

3.2 串口通信协议通信协议是通信设备在通信前的约定。

单片机、计算机有了协议这种约定,通信双方才能明白对方的意图,以进行下一步动作。

主机通过轮询方式访问从机,通过发送从机地址呼叫从机,地址相符合的从机把数据发送给主机通信格式:主机发送数据格式:主机每隔5秒钟查询一遍备注: 1从机地址分配:①号:0X01; ②号:0X02; ③号:0x03;④号: 0X04; ⑤号:0X05 ; ⑥号:0X06;⑦号:0X07; ⑧号: 0X08: ⑨号:0X093、数据字节01010101表示检测到故障;01 55 5610101010表示没有检测到故障3.3 程序设计3.3.1主程序模块1、main.c#include <reg52.h>#include <string.h>#include "uart.h"#include "common.h"#include "control.h"UCHAR rstr[TX_PAYLOAD_WIDTH]={0};void main() //接收{uchar t;bool sta;uchar key;InitUart(); //串口初始化InitControl(); //控制端口初始化while(1) //主程序不断的对接收到的数据进行分析{if(RI==1) //检查一下串口中有没有数据(每次一个字节){AppendByte(SBUF); //向协议窗口中增加一个数据RI=0; //清除串口中断t=ProtocolAnalysis(); //进行协议分析if(t!=0){sta=GetSta(t); //查询接口状态SendSta(t,sta); //发送接口状态}UartSend("ENA",3);}//对按钮状态进行查询, 如果有按钮被按下,将对应接口状态改变,然后将对应接口状态发给上位机key=GetKey();if(key!=0) //有键盘按下{ChangeSta(key);// 使用下面两句话接口状态改变之后会立刻通知上位机, 现在上位机采用查询方式来了解接口的状态,故不需要这两句话if(key==3){sta=GetSta(key); //查询接口状态SendSta(key,sta); //发送接口状态}}}}3.3.2串口通讯模块1、Uart.c#include <reg52.h>#include <string.h>#include "uart.h"uint m_nEndIndex; //下一个将要插入数据的下标uchar m_wsBlock[WINDOW_SIZE]; //定义接收缓存区的大小uchar m_wsTemp[WINDOW_SIZE]; //这是一个供数据交换的缓存区void InitUart() //初始化串口工作模式,在使用串口之前必须被调用一次{TMOD = 0x20; // 定时器1工作于8位自动重载模式, 用于产生波特率TH1=(unsigned char)(256 - (XTAL / (32L * 12L * Baudrate)));TL1=(unsigned char)(256 - (XTAL / (32L * 12L * Baudrate))); // 定时器1赋初值SCON = 0x50; //mode1方式,启用接收PCON = 0x00;TR1 = 1; //启用定时器1IE=0x00;//接收数据缓存区初始化部分memset(m_wsBlock,0,WINDOW_SIZE); //将窗口清零m_nEndIndex=0;}//串口接收处理,采用的是中断处理方式,对于发送中断该函数不处理//串口发送函数void UartSend(UCHAR *Data, int Len) //Data为数据指针,len为要发送的数据长度{UCHAR c;int i;for(i=0;i<Len;i++){c=Data[i];SBUF = c; // 要发送的字符放入缓冲区while(TI == 0);TI = 0;}}//第一个参数为接口编号,第二个参数为接口状态,为真接口状态为1,为假接口状态为0 void SendSta(uchar num,bool sta){uchar buf[PROT_LEN]={0};buf[0]=num;if(sta)buf[1]=0xAA; //没有故障elsebuf[1]=0x55; //有故障buf[2]=buf[0]^buf[1]; //按位异或UartSend(buf,3);}// 用于向窗口中插入一个字符,只有这一个函数会修改窗口中的数据void AppendByte(uchar ch){if (WINDOW_SIZE<=0)return;if (m_nEndIndex>=WINDOW_SIZE)//说明窗口已近满了,需要将顶位最前面的字符溢出,后面的所有字符向前移动一位{memcpy(m_wsTemp,m_wsBlock+1,WINDOW_SIZE-1);memcpy(m_wsBlock,m_wsTemp,WINDOW_SIZE-1);m_nEndIndex=WINDOW_SIZE-1;}m_wsBlock[m_nEndIndex]=ch;m_nEndIndex++;}// 用于协议分析,// 返回值为0说明协议分析没有分析到有效请求,不需要状态监测// 为1 说明要对端口1监测// 为2 说明要对端口1监测// 为3 说明要对端口1监测int ProtocolAnalysis(){uchar t;if (m_nEndIndex<PROT_LEN)//接收的长度小于协议长度,直接返回0,不需要分析return 0;if((m_wsBlock[0]=='$')&&(m_wsBlock[2]=='#')){t=m_wsBlock[1];if( (t>0x00)&&(t<0x04) )return t;}return 0;}2.Uart.h#ifndef _UART_H#define _UART_H#include "common.h"#define XTAL 11059200 // CUP 晶振频率#define baudrate 9600#define Baudrate 9600L#define WINDOW_SIZE 3 //定义窗口数据缓存区大小#define TX_PAYLOAD_WIDTH 3 //定义接受数据缓存区的长度#define PROT_LEN 3 //协议长度void InitUart(); //初始化串口工作模式,在使用串口之前必须被调用一次void UartSend(char *Data, int Len);//串口发送.Data为数据指针,len为要发送的数据长度void SendSta(uchar num,bool sta);//第一个参数为接口编号,第二个参数为接口状态,为真接口状态为1,为假接口状态为0 void AppendByte(uchar ch);// 用于向窗口中插入一个字符,只有这一个函数会修改窗口中的数据int ProtocolAnalysis(); // 用于协议分析,#endif3.3.3控制部分文件1、Control.c#include <reg52.h>#include "control.h"sbit key1=P2^0; //按钮状态没有按下时为1sbit key2=P2^1;sbit key3=P2^2;sbit sta1=P2^3; //"!sta0"为1表示正常状态,为0表示异常状态sbit sta2=P2^4;sbit sta3=P2^5;void InitControl() //初始化控制{key1=1;key2=1;key3=1;//开启三盏灯sta1=0;sta2=0;sta3=0;}int GetSta(int t) //得到sta状态{switch (t){case 0x01:return !sta1;;case 0x02:return !sta2;case 0x03:return !sta3;default:return -1;}}int GetKey() //得到按钮的状态{key1=1;if(key1==0){wait(1); //延时10ms消抖if(key1==0) //说明确实被按下{while(key1==0); //等待知道按钮被按下return 1;}}key2=1;if(key2==0){wait(1); //延时10ms消抖if(key2==0) //说明确实被按下{while(key2==0); //等待知道按钮被按下return 2;}}key3=1;if(key3==0){wait(1); //延时10ms消抖if(key3==0) //说明确实被按下{while(key3==0); //等待知道按钮被按下return 3;}}return 0;}void ChangeSta(int t) //改变接口的状态{switch (t){case 0x01:sta1=!sta1;break;case 0x02:sta2=!sta2;break;case 0x03:sta3=!sta3;break;default:break;}}2.Control.h#ifndef _CONTROL_H#define _CONTROL_H#include "common.h"void InitControl(); //初始化控制int GetSta(int t); //得到sta状态int GetKey(); //得到按钮的状态void ChangeSta(int t); //改变接口的状态#endif3.3.4公共部分模块1、Common.c#include <reg52.h>#include <intrins.h>#include "common.h"//用于存放一些公共的函数和宏定义void wait(int n) //延时函数n*10ms;{int i,j;for(i=0;i<n;i++)for(j=0;j<1681;j++);}2、common.h#ifndef _COMMON_H#define _COMMON_H#define UCHAR unsigned char#define uchar unsigned char#define bool unsigned char#define UINT unsigned int#define uint unsigned int#define true 0x01#define false 0x00#define TRUE 0x01#define FALSE 0x00void wait(int n); //延时函数n*10ms #endif3.4 电路搭建3.4.1电路原理图第4章上位机关键代码分析上位机采用的是Windows API编写的串口通讯程序4.1 打开串口操作BOOL CSerialPortEx::InitPort( CWnd* pPortOwner,UINT portnr, // 端口号UINT baud, // 波特率char parity, //检验位UINT databits, //数据位UINT stopbits, //停止位DWORD dwCommEvents,UINT writebuffersize) // {assert(portnr > 0 && portnr < 17);assert(pPortOwner != NULL);if (m_bThreadAlive)//若当前线程或者,则先杀死该线程{do{SetEvent(m_hShutdownEvent);} while (m_bThreadAlive);TRACE("Thread ended\n");}// create events 创建事件if (m_ov.hEvent != NULL) //事件对象已经存在ResetEvent(m_ov.hEvent); //用ResetEvent来手动清除事件对象的通知m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);//事件对象不存在,则创建.默认安全属性,人工重置对象,开始没有信号,匿名事件对象if (m_hWriteEvent != NULL) //同上ResetEvent(m_hWriteEvent);m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);if (m_hShutdownEvent != NULL) //同上ResetEvent(m_hShutdownEvent);m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);// initialize the event objects初始化事件监视对象m_hEventArray[0] = m_hShutdownEvent; // highest prioritym_hEventArray[1] = m_ov.hEvent;m_hEventArray[2] = m_hWriteEvent;//清空list缓存区m_listBuf.clear();// initialize critical section 初始化临界区InitializeCriticalSection(&m_csCommunicationSync); //用来构建一个临界区InitializeCriticalSection(&m_csListSync);// set buffersize for writing and save the ownerm_pOwner = pPortOwner;if (m_szWriteBuffer != NULL)delete [] m_szWriteBuffer; //如果发送缓存区中有数据则释放缓存区m_szWriteBuffer =new BYTE[writebuffersize]; //开辟一个缓存区,长度默认为512个字节m_nPortNr = portnr; //初始化端口号m_nWriteBufferSize = writebuffersize; //初始化数据缓存区大小m_dwCommEvents = dwCommEvents; //初始化串口上待监听的事件BOOL bResult = FALSE;char *szPort = new char[50];char *szBaud = new char[50];EnterCriticalSection(&m_csCommunicationSync);//获得临界区对象的所有权if (m_hComm != NULL){CloseHandle(m_hComm); //如果串口处于打开状态就关闭它m_hComm = NULL;}sprintf(szPort, "COM%d", portnr); //格式化串口号,并存放在szPort中//这里有一个问题,就是1.5个停止位在SetCommState中如何设置sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);//格式化波特率,奇偶检验,数据位,停止位m_hComm = CreateFile(szPort, //串口名称字符串(COM1)GENERIC_READ | GENERIC_WRITE, //读写0, //以独占方式打开NULL, //未设置安全属性OPEN_EXISTING, //串口设备必须设置该值FILE_FLAG_OVERLAPPED, //使用异步IO0); //串口设备这个参数必须设置为0if (m_hComm == INV ALID_HANDLE_V ALUE) //如果打开失败{// port not founddelete [] szPort;delete [] szBaud;return FALSE; //返回FALSE}//打开成功设置下面的值//总超时=时间系数×要求读/写的字符数+ 时间常量m_CommTimeouts.ReadIntervalTimeout = 1000; // 读间隔超时m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000; // 读时间系数m_CommTimeouts.ReadTotalTimeoutConstant = 1000; // 读时间常量m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000; // 写时间系数m_CommTimeouts.WriteTotalTimeoutConstant = 1000; // 写时间常量// configureif (SetCommTimeouts(m_hComm, &m_CommTimeouts)) //设置超时{if (SetCommMask(m_hComm, dwCommEvents))//指定串口上监视的事件集合{if (GetCommState(m_hComm, &m_dcb)){m_dcb.fRtsControl = RTS_CONTROL_ENABLE;// set RTS bit high!if (BuildCommDCB(szBaud, &m_dcb))//用指定的字符串来填充DCB结构{if (SetCommState(m_hComm, &m_dcb)); // normal operation... continueelseProcessErrorMessage("SetCommState()");}elseProcessErrorMessage("BuildCommDCB()");}elseProcessErrorMessage("GetCommState()");}elseProcessErrorMessage("SetCommMask()");}elseProcessErrorMessage("SetCommTimeouts()");delete [] szPort;delete [] szBaud;PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR |PURGE_RXABORT | PURGE_TXABORT);LeaveCriticalSection(&m_csCommunicationSync); //离开临界区TRACE("Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", portnr);return TRUE;}4.2 后台线程处理串口程序UINT CSerialPortEx::CommThread(LPVOID pParam) //串口监视线程的入口函数{CSerialPortEx *port = (CSerialPortEx*)pParam;port->m_bThreadAlive = TRUE;// Misc. variablesDWORD BytesTransfered = 0;DWORD Event = 0;DWORD CommEvent = 0;DWORD dwError = 0;COMSTAT comstat;BOOL bResult = TRUE;BOOL haveError=FALSE;if (port->m_hComm) // check if the port is opened//清空缓冲区PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR |PURGE_RXABORT | PURGE_TXABORT);for (;;){bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);//使用WaitCommEventif (!bResult){switch (dwError = GetLastError()){case ERROR_IO_PENDING:{if(haveError) //说明可能会进入死循环ResetEvent(port->m_hEventArray[1]);//手动将这个事件置为没有信号,防止死循环发生TRACE("表示查询操作转到后台运行\n");break;}case 87:{break;}default:{port->ProcessErrorMessage("WaitCommEvent()");break;}}}else{bResult = ClearCommError(port->m_hComm, &dwError, &comstat);if (comstat.cbInQue == 0) //确定串口中无数据,重新开始循环continue;} // end if bResult// 主监视函数,该函数将阻塞本线程直至等待的某一事件发生TRACE("串口线程正在等待\n");Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);//使用这个函数监视m_hWriteEvent,m_hShutdownEvent,m_ov.hEvent这三个事件TRACE("串口线程等待结束\n");switch (Event){case 0: //关闭{port->m_bThreadAlive = FALSE;::PostMessage(port->m_pOwner->m_hWnd,WM_COMM_THREADEND,(WPARAM) 0,(LPARAM)port->m_nPortNr);AfxEndThread(100); //这个函数彻底杀死线程break;}case 1: // read event{GetCommMask(port->m_hComm, &CommEvent);if (CommEvent & EV_CTS)::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_CTS_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);if (CommEvent & EV_RXFLAG)::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RXFLAG_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);if (CommEvent & EV_BREAK)::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_BREAK_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);if (CommEvent & EV_ERR)::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_ERR_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);if (CommEvent & EV_RING)::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RING_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);if (CommEvent & EV_RXCHAR){ // Receive character event from port.if(!port->m_bBlockRead) //字符读取port->ReceiveChar(port, comstat); //读串口else //块读取{//进行块读取int readlen=0;port->ReadBlock(port,readlen,comstat);if(readlen!=0) //表示串口线肯定没有发生错误haveError=FALSE;else //发生了错误haveError=TRUE;}}break;}case 2: // write event{// Write character event from portport->WriteChar(port); //写串口break;}}} // close forever loopreturn 0;}4.3 程序运行界面第5章课程设计总结与体会本次微机原理与接口的实验课中,我们小组成员紧密的团结在一起,密切讨论,合理的规划好了整个程序流程,合理的分配了任务.在较短的时间内将程序完成了.在与上位机的通讯过程中我们也遇到了很多问题,特别是最开始上位机的告诉发送数据导致下位机没办法及时接收,导致丢失数据.在和上位机组成员的讨论和合作下,通过改变了上位机发送数据的方式,最终我们完成了任务。

相关文档
最新文档