这次咱们来试着一步步的去把握PC与单片机通过RS-232进行通讯和操控。
先说说我硬件的状况。我用的PC是个二手的IBM240小本本,十寸屏,赛扬400,机子很老了。但也有它的长处:1、串口,并口,PS鼠标口、USB口、PCM插槽全有。 调试硬件电路最好仍是用实在串、并口好些,由于用USB转化的串、并口有时会呈现兼容性上的问题,就会增加你调试上的杂乱性。
下图为自己的IBM 240及各种接口图:
下图是PC的巨细比照图
单片机仍是我一步步做出来的那个了,USB-ISP编程线也是我前面秀过,好!现在我放上PC与单片机衔接图:
用本本的长处便是调整便利,接口、器材都在周围,假若是用台式机,你还得钻到桌子底下去插拔那些接口,而现在本本却又没有串、并口了。
言归正传,单片机的RS-232串口通过9针串口线接到本本的串口上,单片机的ISP编程口通过USB-ISP编程器接到本本的USB口。
别的本本要接电源,单片机也要接5V电源,还有千万千要记住,本本是要插上鼠标才玩得转哦!
我将这个一步一步把握串口的通讯与操控分为五步:
1、测验单片机与PC的串口衔接是否正确好用。
2、用VB自己编写的程序替换掉串口调试器软件来接纳单片机发送的数据。
3、把握单片机端怎样发送字符和数值数据。
4、把握PC端程序怎样接纳发送字符和数值型数据。
5、做一个A/D转化(ADC0809)获取数据发送到PC,并在PC上显现实时趋势的比如。
咱们要用到的四个软件:
1、USB接口编程软件:是PC机给单片机进行烧写编程用的
2、串口调试软件:用来测验单片机内串口电路、程序作业是否正常。
3、单片机程序的编程软件KEIL:用于编写单片机内的程序并生成HEX文件。
4、VB6.0:用于编写PC机上的应用程序
先进行第一步作业:
在前面一篇《板子上最一个部件——RS232串口》讲过怎样对单片机上的串口进行调试,咱们仍是先对这个衔接进行测验,咱们首要得承认衔接正确,电路正常,才干进行后边程序编写和调试作业。
依旧是那个最简略的程序,AT89S52从串口不断地发送“hello world!”
#include
#include
void main(void)
{
SCON=0x50; //串口办法1
TMOD=0x20; //守时器1,守时办法为2
PCON=0x80; //设定串口作业办法为1
TCON=0x40; //设守时器1开端计数
TH1=0xfd; //设定波特率为19200
TL1=0xfd; //
TI=1;
TR1=1; //发动守时器
while(1)
{
printf(“hello world!\n”);
}
}
把原先生成好的这个HEX文件用上面讲到的Progisp软件写到AT89S52里。
然后翻开sscom32串口调试器,设定好串标语、波特率和数据位,按下“翻开串口”钮,应该就能收到那个一行行的“hello world!”了。能看到这一行行的文字,阐明电路、衔接和程序都正常了。
假如是乱码,则要将单片机上的复位钮按一下。假如仍是乱码,那一般便是波特率不对,晶振应为11.0592MHZ或串口接触不良,线过长等原因。假如跟本就收不到任何字符,就阐明电路或衔接有毛病,或许程序有问题。那就要好好查查了。
好!现在电路、衔接、程序都能够正常作业。但在串口调试器接纳框里看到接纳到的一行行“hello world!”显现太快,不简略看出它一次一次发送的进程,不便于剖析问题,咱们得给它加点延时。
#include
#include
void delay(void) //界说一个延时子程序
{
unsigned int i;
for (i=65535;i>0;i–);
}
void main(void) //主程序
{
SCON=0x50; //串口办法1
TMOD=0x20; //守时器1,守时办法为2
PCON=0x80; //设定串口作业办法为1
TCON=0x40; //设守时器1开端计数
TH1=0xfd; //设定波特率为19200
TL1=0xfd; //
TI=1;
TR1=1; //发动守时器
while(1)
{
printf(“hello world!\n”); //向串口送出数据
delay(); //调用延时
delay();
}
}
程序写好了,在KEIL里增加上延时句子后,从头生成HEX文件。再用Progisp将它写进AT89S52里,这时,你就能够看到串口调试器现已接纳到大约一秒一次的“Hello world!”了。
在这儿阐明一下,只需像最上面我图上给出的那样把单片机和PC衔接好后,不管你往AT89S52里烧写程序,仍是单片机衔接到PC并向PC串口发送数据,都不必再插拔器材了,只需求在这几个程序间切换作业便能够了。(是不是很便利呢)
这样第一项作业就完结了,承认电路的衔接及单片机程序都作业正常。
下面要进行第二项作业:
意图:用我自己的PC程序把串口调试器软件替换掉。由于我终究要的是接纳单片机上的数据,并将接纳的数据在PC上进行处理、存储,而串口调试器只能接纳固定的内容,你也不无法把收到的数据接纳过来,仅仅能做衔接测验罢了。
我用的是最简略易用的Visual Basic 6.0。详细怎样操作运用,网上有许多教程,也很简略上手。
翻开VB6.0,新建一个工程,也便是要树立一个新的程序。
这是个标准的VB6.0界面,咱们要进行串口的操作需求增加一个串口控件MSCOMM32.OCX,或许你的机子上有,或许没有,没有的在网上搜了下一个装在你c:\winnt\system32\ 。然后你用鼠标右键点击VB界面左边的工具箱,弹出菜单后选部件,或许在上部的主菜单上点“工程”--“部件”,就会弹出如下界面:
在列出的项里找到Microsoft Comm Control 6.0。在前面的小方框里点上钩。留意看下面的提示栏里就告知你这个控件的文件名和地点的目录。点“承认”钮,这时在VB主界面的工具箱里就会多出个小电话的控件图标了:
接下来点击这个控件图标,然后在Form1的窗口上拉出个框(或许双击小电话图标)把图标放到Form1窗口上去。如下图:
假如你的图标放不上去并弹出如下提示框:
就阐明你的VB6.0是简化版,不是正式装置的。解决办法如下:
首要把MSComm32.OCX拷进C:\WINNT\SYSTEM32\ (我的机器一开端并没有这个控件,我去网上下了一个,机器里边有此控件的此步不做!)(注:途径以我机器的winXP体系为例)
然后点击 开端>运转>regsvr32 c:\winnt\system32\mscomm32.ocx 成功后,开端>运转>regedit,进入注册表,找到HKEY_CLASSES_ROOT\Licenses,然后新建一个项,命名为:“4250E830-6AC2-11cf-8ADB-00AA00C00905”,值为:“kjljvjjjoquqmjjjvpqqkqmqykypoqjquoun”。悉数就OK了。
VB6.0设置正常后,我由简入繁地进行程序的编写。在窗体上先放上一个串口控件,一个文本框,一个按钮,一个守时器。如下图:
串口控件是单片机串口和PC串口进行通讯的桥梁;文本框用来显现咱们收到的数据,按钮用来发动这个接纳,守时器用来守时查看每一小段时刻查看是否有串口数据收到。
咱们先对串口控件进行特点设置,Commport是串标语设置,一般设置为1,Settings是对串口的波特率、有无奇偶校验,数据位数,中止位数进行设置,由于我的单片机程序上用的波特率是19200,所以在这儿我只对波特率进行调整,其它都是都用默认值。如下图:
对按钮控键进行设置:仅仅将“Caption”标题特点改为“接纳数据”。
对守时器进行设置,将“Interval”间歇时刻改为400。这样便是每400毫秒查看一次有无数据收到。
对文本框进行设置:将“MultiLine”多行显现设为“True”答应。
控件的特点设置完了,下面咱们为程序写代码,先双击“接纳数据”按钮。会弹出代码窗口,我了如下代码,如图:
上面便是咱们编写的按钮事情代码。写完后咱们在键盘上按“Shift”+“F7”,回到目标窗口。再双击那个守时器控件,界面就切换到守时器的代码窗口,咱们写程序如下图:
现在咱们的这个VB程序就写好了。接着就试着运转一下这个程序,且慢!咱们仍是要先发动串口调试器看看单片机是否还在不断的发送着“hello world!”,承认它仍是在不断地显现着那行“hello world!”,就能够关了串口调试器。然后在VB6.0的主界面点击那个小三角的播映钮。我的程序就运转如下了:
第二项使命完结!我自己接纳了接纳的数据。点菜单的保存这项工程。
第三项使命:把握单片机端怎样发送字符和数值数据。
接下来我要做的是对AT89S52内串行数据的发送进行解和把握,以便咱们能为所欲为地将单片机取得的数值数据或字符数据发送给PC机进行处理或存储。
先来看看本来我写的AT89S52不断发送“hello world!”的那段程序。
#include
#include
void delay(void) //界说一个延时子程序
{
unsigned int i;
for (i=65535;i>0;i–);
}
void main(void) //主程序
{
SCON=0x50; //串口办法1
TMOD=0x20; //守时器1,守时办法为2
PCON=0x80; //设定串口作业办法为1
TCON=0x40; //设守时器1开端计数
TH1=0xfd; //设定波特率为19200
TL1=0xfd; //
TI=1;
TR1=1; //发动守时器
while(1)
{
printf(“hello world!\n”); //向串口送出数据
delay(); //调用延时
delay();
}
}
上面的程序中除了设置串口的句子和延时句子外,担任向串口发送的句子只要一行,即“printf(“helleo world!\n”)”。学习过编程的一般都知道,print句子的作用是输出字符串的,但咱们假如从单片机的A/D模块上取得了数据想发送到PC,应该怎样做呢?尽管你也能够先将这些数据转化成数字字符串,例如咱们从一个8位的A/D模块上取得的数据是个数值从0-255的8位的数值,假如数值是1,那你得先将1这个数值转化成“1”字符对应的代码49(二进制110001,十六进制31H),再用printf句子发送出去。假如值是255,那你得先把它转化成3个字符“2”、“5”、“5”,再用printf发送出去。但这样既杂乱又不标准,“1”是一个字符,“2”、“5”、“5”是三个字符,跟着数值的不同,发送的数据的字节数据也不同,这样可不行。
咱们仍是先蹲蹲马步,了解一下单片机串口发送数据的本质:
上图是串口的发送时序示意图,最上面的TX表明的是单片机串口的发送线,,第二根CLK是内部时钟线,最下面的是发送标志信号TI。
咱们以最常用的串行办法1,即10位异步通讯办法来简略剖析一下。它规则了1位开端位、8位数据位和1位中止位。其间第一位(开端位)和最终一位(中止位)是在你设定好串口的办法,翻开串口后由芯片内串口模块主动刺进的,不必人为加。
当你想通过串口发送数据时,只需求向AT89S52内的一个8位的特别功用寄存器SBUF(99H)送入一个字节你想要发送给PC的数据,它就会主动连同开端位,数据位,中止位一同发生10位串行的电位信号送出。在第10个脉冲后将TX线的电位拉高,一起将标志位TI置1,告知自己的程序发送结束。
接纳方也是以规则好的相同的波特率时钟脉冲为基准,当某一个脉冲到来后检测到RX线上的电位被拉低,就知道对方开端发送数据了,然后从下一个脉冲起计数并在每个脉冲后查看RX线上的电位,若是高电位便记做1,低电位便记做0,如此得到8个位的数据,然后在第10个脉冲后,检测到RX线上的电位为1就知道这帧数据传送结束。(留意:单片机的串行发送口(TX)和PC的接纳口(RX)是通过串行线直接衔接的,所以这两点的信号是相同的)
例如要发送“1”这个字符,代码是49(二进制110001,十六进制31H),串口发送时低位在前,如下图
归纳起来,若想发送数据只需向SBUF送一个字节的数据,然后等TI变为1后,就再发第二个字节依,此类推。
再说说字符和数值的联系,关于电路来说,它不知道什么是字符,什么是数值,仅仅按凹凸电位发送一帧帧的电信号。例如00000000代表0(00H),10101010代表170(AAH),11111111代表255(FF),但关于接纳方PC就有不同了,咱们都知道,电脑下载文本比下载一幅图画的数据量要小得多,原因便是文本仅仅用一个代码来代表一个即将显现的文字图画,而这个文字的图画数据就预先存在自己的电脑里,便是所说的字库。而你下载一幅图画,则需求每一个阵点的数据都得传送,所以数据量很大。西文也是相同的,也是用代码来代表一个需求显现的西文字符图画,这便是ACSII码。这样用一个字节的数(0-255)的规模就能代表一切的西文字符和常用符号了,例如用数值65(十六进制为41H)代表“A”。用数值49(十六进制为31H)代表“1”,我只需向SBUF里输入值65,PC只需以字符办法接纳,就会显现“A”字。假如以数值办法接纳,变量的值便是65。这儿边也包含有一些非字符的功用操控符号。例如13代表回车,10代表换行。
下面咱们就来试试改写一下发送程序:试着用送数值和送字符两种办法发送。同样是“A”“B”“C”“D”四个字符。
#include
#include
void delay(void) //界说一个延时子程序
{
unsigned int i;
for (i=65535;i>0;i–);
}
void main(void) //主程序
{
SCON=0x50; //串口办法1
TMOD=0x20; //守时器1,守时办法为2
PCON=0x80; //设定串口作业办法为1
TCON=0x40; //设守时器1开端计数
TH1=0xfd; //设定波特率为19200
TL1=0xfd; //
TI=1;
TR1=1; //发动守时器
while(1)
{
SBUF=65; //向SBUF内写入65的数值,也便是字符“A”的代码
while(TI==0); //检测TI,当TI=0时,阐明还没发送完,就循环等候。
TI=0; //当TI=1时,就把TI的值置0,以便下一组发送。
SBUF=66; //向SBUF送数值66.即字符“B”的代码
while(TI==0);
TI=0;
SBUF=C; //向SBUF送字符“C”
while(TI==0);
TI=0;
SBUF=D”; //向SBUF送字符“D”
while(TI==0);
TI=0;
delay(); //调用延时
delay();
}
}
将程序编译生成HEX文件后写入AT89S52。翻开我上面用VB6编好那个程序,点击“接纳数据”钮。如下图:
它确实按我料想的执行了。只需是节字数据,不管是数值仍是字符代友都是能够进行发送的。这是C言语的长处。
别的咱们趁便看一下原先用printf函数发送生成HEX和直接写SBUF来成HEX的不同:
上图的提示显现了生成的代码共用了1120个字节。这是用printf函数发送的。
下图是直接写SBUF后的编译提示信息:
哈!直接操作串口缓冲寄存器只用了89个字节。这是直接进行底层操作的优势。
上面的程序发送“A”“B”“C”“D”四个数据,由于没有发送回车符,所以一次次的字符都是接连显现的。咱们再修正一下,把要发送的ABCD这四个数据再加两个代表回车的操控字符数据界说到一个字节数组中变量中,再改用循环的办法来发送,程序如下:
#include
#include
void delay(void) //界说一个延时子程序
{
unsigned int i;
for (i=65535;i>0;i–);
}
void main(void)
{
unsigned char buf[ ]={65,66,C,D,13,10}; //界说一个单字节数组最终两个数值13和10是回车符。
unsigned char i;
SCON=0x50; //串口办法1
TMOD=0x20; //守时器1,守时办法为2
PCON=0x80; //设定串口作业办法为1
TCON=0x40; //设守时器1开端计数
TH1=0xfd; //设定波特率为19200
TL1=0xfd; //
//TI=1;
TR1=1; //发动守时器
while(1)
{
for(i=0;i<6;i++)
{
SBUF=buf[i]; //向串口送出数据
while(TI==0);
TI=0;
}
delay(); //调用延时
delay();
}
}
下面是运转成果:
这样就和原先printf函数输出的作用相同了。
从上面程序咱们知道了,假如咱们想发送丈量的数值数据,能够把用A/D模块取得的丈量数据赋给buf[ ]数组里的变量,然后就能够进行发送处理了。字符直接用上面的发送办法就行了。
这样第三项作业也完结!(啊!累了,要歇歇,歇歇!)
第四步:把握PC端程序怎样接纳发送字符和数值型数据。
接下来咱们来看看PC端的程序怎样正常接纳并处理收到的数据。字符没有问题,由于方才便是显现的字符,但我主要是想看看选用字符办法接纳关于0-255规模内那些非字符数值能否正常接纳和处理。
翻开VB6,调出咱们原先编写的程序,在串口控件的特点中有个InputMode特点,假如是0便是以字符办法接纳,假如是1便是以二进制办法接纳。
原先咱们便是用了缺省的字符办法。为了便于剖析收到的数据,咱们得别离修正一下单片机和PC里的程序,首要不能让单片机不断的发送,而是从PC机先向AT89S52发送一个字符“s”,AT89S52收到并承认是“s”字符后再发送一组数据,发完后停下,等候PC的下次恳求。这样咱们能够精确和稳定地看到这组数据的状况。
VB程序的修正如下:
咱们在Command1+_Click事情的代码里增加了一行MSComm1.Output=”s”,也便是每逢我按下“接纳数据”钮时向AT89S52发送了一个”s”字符,然后清空文本框内容,然后发动守时器子程序Timer1每100毫秒查看一次有无收到数据,收到数据便显现出来。
对AT89S52内的程序做修正,程序循环查看有无收到数据,当的RI=1时便有数据收到,承认收到的数据为字符“s”时,便送出数组内数据。修正程序如下:
#include
void delay(void) //界说一个延时子程序
{
unsigned int i;
for (i=65535;i>0;i–);
}
void main(void)
{
unsigned char buf[]={65,66,C,D,E,F};//界说一个单字节数组
unsigned char i;
SCON=0x50; //串口办法1
TMOD=0x20; //守时器1,守时办法为2
PCON=0x80; //设定串口作业办法为1
TCON=0x40; //设守时器1开端计数
TH1=0xfd; //设定波特率为19200
TL1=0xfd; //
//TI=1;
TR1=1; //发动守时器
while(1)
{ if(RI==1) //假如接纳到数据则进入以下操作
{if(SBUF==s) //假如收到的数据为“s”字符则进入发送操作
{
for(i=0;i<6;i++)//循环发送出数组buf[ ]的6个数据
{
SBUF=buf[i]; //向串口送出数据
while(TI==0);
TI=0;
delay(); //调用延时子程序
}
RI=0;//上面的发送操作结束后将标志RI清0等候PC下次恳求
}
}
}
}
编译、生成HEX文件然后将文件写进AT89S52。咱们运转VB6编写的Scom1程序。
现在我点击“接纳数据”钮后,文本框内一个字符一个字符的顺次显现出“ABCDEF”如下图:
当我再次点击“接纳数据”钮时,文本框先清空,然后再重复上面的显现。到达咱们的要求。PC机每恳求一次,单片机就发送一次数据。
接下来我要做的是让文本框里不再显现“ABCDEF”这几个字符,而是要显现AT89S52发过来的数值,例如我发送65的值,文本框里就显现65,我发送255,文本框就显现255,这样我就能测验出用字符接纳的办法能否将一个字节的值(0-255)都能正确接纳和显现。咱们把那句Text1.Text = Text1.Text + MSComm1.Input 。改成Text1.Text = Text1.Text + str(asc(MSComm1.Input )),便是把原先字符串变量MSComm1.Input先转化成ASCII值,再把这个值显现出来。改完了。咱们运转下试试。
上图显现确实能够正确显现出数值,但这仅仅仅仅有相对应字符几个代码数值,我再来试试,非字符的ASCII值,看是否都能正确收到并显现。先修正AT89S52里咱们原先发送的那些数组buf[ ]里的值,让它们部分不在字符规模里,看能不能正确接纳到显现。咱们将数组unsigned char buf[]={65,66,C,D,E,F};改写为既有字符也有非字符规模的数组unsigned char buf[]={0,1,2,D,254,255};
从上图来看,后两个数据显现不对,254没有显现出来,255显现为63,通过修正AT89S52程序,把0-255的数值都发送一遍,发现大于128的数值简直都不能正确接纳。所以,得出定论:以字符办法接纳数值数据是不可行的!
如下图:
接下来我改动串口控件的InputMode特点,将它的值改为1,即用二进制读取来试试。但二进制办法怎样读取呢,看了许多材料,也试了许屡次,总算弄理解了,本来先要界说一个字节型的可变数组,这样当接纳到数据时把接纳到的一个或多个数值的首地址变量Mscomm1.input赋给这个字节数组名。所以你就能够运用这个字节数组里的变量了。
我先在VB里修正串口控件的InputMode特点,如下图:
然后我要在VB程序里先界说一个单字节Byte类型的数组,将收到的数据变量(Mscomm1.Input)赋给inbuff这个数组名,程序修正如下图:
AT89S52里程序,根本不动,仅仅等候PC机发来恳求字符“s”。收到恳求后,发送0-255的悉数数值。
修正的程序如下:
#include
void delay(void) //界说一个延时子程序
{
unsigned int i;
for (i=15535;i>0;i–);
}
void main(void)
{
unsigned char buf[]={3,4,5,D,255,253};//界说一个单字节数组
unsigned char i;
SCON=0x50; //串口办法1
TMOD=0x20; //守时器1,守时办法为2
PCON=0x80; //设定串口作业办法为1
TCON=0x40; //设守时器1开端计数
TH1=0xfd; //设定波特率为19200
TL1=0xfd; //
//TI=1;
TR1=1; //发动守时器
while(1)
{ if(RI==1) //假如接纳到数据则进入以下操作
{if(SBUF==s) //假如收到的数据为“s”字符则进入发送操作
{for(i=0;i<255;i++)//循环发送出数,这儿做为调试,咱们先发0-255的数值。
{
SBUF=i; //向串口送出数据,这儿不发buf [ ]数组的数据,而是直接发送循环体里的i 值(0-254)。
while(TI==0);
TI=0;
delay(); //调用延时
}
SBUF=255; //上面循环里没有包含255这个值,这儿补发送一次
while(TI==0);
TI=0;
RI=0;//发送结束将收到恳求标志清0等候PC下次恳求
}
}
}
}
显现成果如下:
这样,一切的数值都是能够正确接纳并显现了。
定论:要接纳数值数据,串口控件有必要修正为二进制的接纳特点。即:InputMode=1