单片机与PC机的串行通信问题

我是单片机新手
我想做一个单片机与PC串行通信的,要实现的功能是,计算机发送不同数值,单片机连接的4个LED相应亮灭,各位高手,教教单片机程序怎么写比较好!
我用的C8051单片机,我想要单片机端C语言的程序(只要串行通信部分),谢谢大家!

手把手教你用增强型51实验板实现RS232串口通信 《电子制作》2006年8月 站长原创,如需引用请注明出处

上一期,我们已经利用增强型51实验板学会了单片机控制步进电机转动的方法,这一期,我们将一起来学习一下单片机如何与PC机进行通信,一起来完成一个简单的RS232通信实例,我们不做太多的理论,从实例出发,相信能够给大家一个比较通俗、透彻地认识,掌握了它的原理,那你就可以编出任何和PC机进行通信的程序了。
前几期,我们学习和介绍的内容都是以单机的形式,即所有的功能都是在一块增强型51实验板上得以实现。当单片机技术具体应用到工厂、企业及各类工业、民用领域中,它肯定要与外部设置作数据传输,其交互性也使得单片机的应用越来越广泛,我们可以利用它来传数据,传控制命令等等。因此,单片机与PC机的通信是我们学习单片机技术所经历的必要环节,由此,也使我们的学习更具趣味性。
下面我们一起来完成一个用单片机从串行口接收PC机数据,并在数码管上显示出来的实验。
先介绍一下串口通信基本知识。目前较为常用的串口有9针串口(DB9)和25针串口(DB25)。最为简单且常用的是三线制接法,即地、接收数据和发送数据三脚相连,本文只涉及到最为基本的接法,且直接用RS232相连。串口引脚定义如图1所示。

9针串口(DB9) 25针串口(DB25)

针号
功能说明
缩写
针号
功能说明
缩写

1
数据载波检测
DCD
8
数据载波检测
DCD

2
接收数据
RXD
3
接收数据
RXD

3
发送数据
TXD
2
发送数据
TXD

4
数据终端准备
DTR
20
数据终端准备
DTR

5
信号地
GND
7
信号地
GND

6
数据设备准备好
DSR
6
数据准备好
DSR

7
请求发送
RTS
4
请求发送
RTS

8
清除发送
CTS
5
清除发送
CTS

9
振铃指示
DELL
22
振铃指示
DELL

图1 DB9和DB25的常用信号脚说明

我们来看一下本次实验的电路图,如图2所示,即增强型51实验板实现串口通信及数码管显示的电路部分。图2中的4个三极管分别与4个共阳数码管相连,是各个数码管的使能端,分别通过单片机的P2.0,P2.1,P2.2,P2.3来控制,数码管显示的详细工作原理,我们已在前几期杂志中作过介绍,有兴趣的朋友可以去看一下以前几期的内容。图2中MAX232芯片起到RS232与TTL电平转换的作用,我们通过9芯串口与PC机相连。

图2 硬件电路原理图

下面是我们完成本次实验的源程序代码,使用Keil编译软件,将其编译生成HEX文件,然后,通过A51编程器烧入AT89S51芯片即可。
#include "reg51.h"
#include <absacc.h>
unsigned char code tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char dat;

void Init_Com(void)
{
TMOD = 0x20; //定时器工作方式2,初值自动装入
PCON = 0x00; //波特率不增倍
SCON = 0x50; //串行工作方式设定
TH1 = 0xFd; //定时器初值高位
TL1 = 0xFd; //定时器初值低位
TR1 = 1; //启动定时器
}
/*函数功能:LED数码管延时程序*/
void delay(void)
{
int k;
for(k=0;k<600;k++);
}
/*函数功能:LED数码管显示程序*/
void display(int k)
{
P2=0xfe; //位选
P0=tab[k/1000]; //显示千位数字
delay(); //延时
P2=0xfd; //位选
P0=tab[k%1000/100]; //显示百位数字
delay(); //延时
P2=0xfb; //位选
P0=tab[k%100/10]; //显示十位数字
delay(); //延时
P2=0xf7; //位选
P0=tab[k%10]; //显示个位数字
delay(); //延时
P2=0xff; //位选
}
/*函数功能:主程序*/
void main()
{
P2=0xff; //端口初始化,关LED显示
P0=0xff;
Init_Com(); //调用串口初始化程序
while(1) //主循环
{
if ( RI ) //判断是否收到数据
{
dat = SBUF; //接收数据
RI = 0; //软件清除标志位
}
display(dat-48); //显示收到的数据
}
}

我们来一起分析一下程序代码,main主程序首先将P2口和P0口全部输出高电平,即数据管不显示任何内容,Init_Com函数用来初始化串口设置,如波特率设置,工作方式的设置,这些都是程序运行的一切初始化设置。然后,我们看到了一个while(1)语句,该语句的作用是产生死循环,即单片机上电复位后,我们就不断地去接收由PC机发过来的串口数据,同时将接收到的数据放在dat 这个变量中,每接收完一次数据,我们需要执行RI = 0这条语句,用来清除串口数据接收标志位,现在我们已经收到了PC机传过来的数据了,余下的任务就是要将数字通过数码管显示出来,我想大家看了我们前几期的介绍,已经并不陌生数码管的使用了,在这里,我们也写得非常简洁,通过display这个函数将数字显示出来,因为我们收到的是字符型的ASCII码数据,如数字“0”的ASCII码值是48,所以,我们要显示“0”的话,还需要将其值减去48后才是真正要显示的数据。数码管我们采用动态扫描法进行显示,delay函数的作用是产生一定时间的延时,对于人眼来说是分辨不出来的,在display的函数体内,我们先将数据装载到P0口,如我们在程序开始时定义的:unsigned char code tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}语句,意思相当于:数字“0”对应的数码管段码值为“0xc0”, 数字“1”对应的数码管段码值为“0xf9”, 数字“2”对应的数码管段码值为“0xa4”……以此类推,最后通过数码管的使能端来显示各位数码管的值。至此,整个程序的功能就轻松地实现了我们所需要的功能,看到这里相信你现在对串行通信感到并不是原来想的那么深奥了吧。

现在我们已经将程序写好,并烧入了单片机芯片,下面我们要做的就是用串口线将增强型51实验板和PC机相连起来,同时给实验板接上电源,然后就是通过PC机软件来发数据了,要在PC机上向串口发送数据一定要借助相应软件,打开光盘内附带的串口调试软件,它设置方便、灵活,界面简洁明。因为我们得告诉实验板来显示哪些数字,程序的功能是发送“1”、“2”、“3”......“8”、“9”、“0”等字符,增强型51实验板收到数据后通过数码管显示出来,所以我们得在软件发送区内填上我们所需要发送的数字,如图3所示。

图3

串口调试软件中,设置参数如下:串口:COM1;波特率:9600;校验位:无;数据位:8位;停止位:1位;发送内容:5
当我们点击“手动发送”按钮后,我们可以看到增强型51实验板上的数码管已显示数字“5”的字样,如图4所示。当然,我们也可以选择“自动发送”,即每隔一定的时间,由软件自动发送“发送缓冲区”内的数据,时间周期可以在软件界面中设置。

图4

现在,你已经可以自由发挥来接收PC机发过来的数据了,只要发挥你的想象力,定义好PC机和单片机两端的数据通信协议,你可以做出任何通过电脑来对单片机进行控制的程序,实现各种各样的数据传输,远程控制功能,比如通过PC机来控制液晶显示、控制步进电机的转动、控制蜂鸣器奏乐等等,您也可以将本期所讲的知识与前几期所讲的关联起来,完成功能更多,更实用的具体应用实例。因此,到本期的学习,我们已经可以将单片机与PC相连,借助PC机强大而灵活的功能,就可以为我们解决各类实际生产及应用型问题提供了方便。这一期的内容我们就介绍到这里,增强型51实验板更多的学习内容,我们将在以后几期陆续为大家作介绍,祝大家学习顺利。

详见: http://www.hificat.com/dpj_step/rs232.asp

参考资料:http://www.hificat.com/

温馨提示:答案为网友推荐,仅供参考
第1个回答  2008-06-21
#define COM1 0
#define DATA_READY 0x0100
#define TRUE 1
#define FALSE 0

#define SETTINGS ( 0xE0 | 0x00 | 0x00 | 0x03)

void main()
{
int in, out, status, DONE = FALSE;
int a;
a=1;
bioscom(0, SETTINGS, COM1);
cprintf("... BIOSCOM [ESC] to exit ...\n");
while (!DONE)
{
status = bioscom(3, 0, COM1);
if (status & DATA_READY)
if ((out = bioscom(2, 0, COM1) & 0xFF) != 0)
{
printf("\nsuccess");
putch(out);
}
printf("\nout=%x",bioscom(2,0,COM1));
a=bioscom(2,0,COM1)&0x00ff;
printf("a=%x",a);
if (kbhit())
{
if ((in = getch()) == '\x1B')
DONE = TRUE;
bioscom(1, in, COM1);
}
}
return 0;
}
第2个回答  2020-04-26
双方都能发能收,硬件及协议应该没问题了,那么这是特意这么安排的,不然单片机连续发你就看不清数据了。
相似回答