串口通信的例子

时间:2024-03-03 18:28:57

实验:

1.实现现象:下载程序后打开串口调试助手,将波特率设置为4800,选择发送的数据就可以显示
            在串口助手上。
2.实验数据发送过程:数据从上位机(PC机)发送至下位机(51单片机),再从51单片机发送至上位机显示

操作:

1.使用Keil软件编写好程序,并编译成 *.hex文件

2.给51单片机上电(用USB先将单片机和PC机连接),将 *.hex文件烧录到 51单片机

3.打开串口助手 sscom32.exe,设置如下:

4.输入要发送的数据“串口通信例子”,点击“发送”,显示结果:

Keil代码:

/**************************************************************************************
*		              串口通信实验												  *
实现现象:下载程序后打开串口调试助手,将波特率设置为4800,选择发送的数据就可以显示
			在串口助手上。
实验数据发送过程:数据从上位机(PC机)发送至下位机(51单片机),再从51单片机发送至上位机显示
注意事项:无。																				  
***************************************************************************************/

#include <reg52.h>

#define u16 unsigned int
#define u8  unsigned char
	
/*******************************************************************************
* 函数名         :usartInit()
* 函数功能		   :设置串口,串口初始化
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void usartInit()
{
	/* 步骤:
	1、确定T1的工作方式(编程TMOD寄存器);
	2、计算T1的初值,装载TH1、TL1;
	3、启动T1(编程TCON中的TR1位);
	4、确定串行口控制(编程SCON寄存器);
	5、串行口在中断方式工作时,要进行中断设置(编程IE、IP寄存器)。
	*/
	
	/*
	SCON:特殊功能寄存器。用以设定串行口的工作方式、接收/发送控制以及设置状态标志。
	8位数据位:SM0,SM1,SM2,REN,TB8,RB8,TI,RI
	SM0和SM1为工作方式选择位:有00,01,10,11四种组合,分别对应方式1-4,各种方式的用途和特点查资料
		选择方式1,所以SM0=0,SM1=1
	SM2:多机通信控制位,这里设置成0,(不论收到的RB8为0和1,均可以使收到的数据进入SBUF,并激活RI)
	REN:允许串行接收位。0为禁止接收,1为允许接收。这里设置成1。
	TB8:可以用作数据的奇偶校验位,或在多机通信中,作为地址帧/数据帧的标志位。这里不用,设置成0
	RB8:作为奇偶校验位或地址帧/数据帧的标志位。在方式1时,若SM2=0,则RB8是接收到的停止位。这里不用,设置成0
	TI:发送中断标志位。在方式0时,当串行发送第8位数据结束时,或在其它方式,串行发送停止位的开始时,由内部硬件使TI置1,
			向CPU发中断申请。在中断服务程序中,必须用软件将其清0,取消此中断申请。
	RI:接收中断标志位。在方式0时,当串行接收第8位数据结束时,或在其它方式,串行接收停止位的中间时,由内部硬件使RI置1,
			向CPU发中断申请。也必须在中断服务程序中,用软件将其清0,取消此中断申请。
	所以,数据位是:01010000,转成十六进制是0X50
	*/
	SCON=0X50;			// 设置为工作方式1
	
    /*
    选择为定时器0模式,工作方式1,仅用TR0打开启动。
    TMOD:8位,字节地址89H,各个位分别是:GATE C/T非 M1 M0 GATE C/T非 M1 M0,依次为高4位和低四位
    GATE是门控位,为零时,TR0或TR1为1时,定时计数器就会工作
    CT非:定时/计数模式选择,0为定时模式,1为计数模式
    M1M0:工作方式设置位。00、01、10、11,对应方式0-方式3,一般使用方式1或方式2,这里使用方式2,
	低四位用于T0,高四位用于T1,这里用T1,
	所以,数据位是:00100000,转成十六进制是:0X20
    */
	TMOD=0X20;			// 设置计数器工作方式2
	
	/*
	PCON:PCON中只有一位SMOD与串行口工作有关。用于设置波特率是否倍增,8位数据位
	当SMOD=1时,波特率提高一倍。复位时,SMOD=0,这里设置成倍增。
	所以,数据位是10000000,转成十六进制是:0X80
	*/
	PCON=0X80;			// 波特率加倍
	
	/*
	TH0/TL0用于控制T0定时多久或计数达到多少再进入中断。
	TH1/TL1用于控制T1定时多久或计数达到多少再进入中断。
	他们值用软件计算,也可以通过公式计算出来。
	波特率4800,定时器方式选择方式2,晶振频率为12MHz,SMOD=1,计算结果是:F3H
	TH1:0XF3
	TL1:0XF3
	*/
	TH1=0XF3;			// 计数器初始值设置,注意波特率是4800的
	TL1=0XF3;
	
	/*
	下面三个变量查看定时/计数器中断那一章有解释。
	*/
	ES=1;				// 打开接收中断
	EA=1;				// 打开总中断
	TR1=1;				// 打开计数器
}


/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	usartInit();  	// 串口初始化
	while(1);		
}

/*******************************************************************************
* 函数名         : usart() interrupt 4
* 函数功能		  : 串口通信中断函数,串口通信的中断号是4
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void usart() interrupt 4
{
	u8 receiveData;		// 用于接收数据的变量

	/*
	SBUF:接收、发送缓冲器
	*/
	receiveData=SBUF;	// 出去接收到的数据
	RI = 0;				// 清除接收中断标志位
	// ***************** 到这里,表示数据从上位机发送到下位机完成
	
	// ***************** 以下是,数据从下位机发送到上位机显示的过程
	SBUF=receiveData;	// 将接收到的数据放入到发送寄存器
	/* 
	TI:发送中断标志位。
	在方式0时,当串行发送第8位数据结束时,或在其它方式,串行发送停止位的开始时,
	由内部硬件使TI置1,向CPU发中断申请。在中断服务程序中,必须用软件将其清0,取消此中断申请
	当数据发送完成时,TI=1(由内部硬件自动完成设置),!TI=0,跳出while循环,否则一直在发送数据
	*/
	while(!TI);			// 等待发送数据完成,
	TI=0;				// 清除发送完成标志位,这里内部硬件不会自动清除,必须手动(软件)清除
}

 

扩展实验:

1. 发送1,控制LED灯的显示,发送2,控制蜂鸣器,发送3,控制数码管,,,,,,

2. Java和51单片机的通信,点击网页上按钮,控制51单片机的动作

 

************************* 下面是发送数字1时,蜂鸣器响,但是程序还没有完善,只有一个功能,而且发送了一次之后,不能第二次发送数据了

/**************************************************************************************
*		              串口通信实验												  *
实现现象:下载程序后打开串口调试助手,将波特率设置为4800,选择发送的数据就可以显示
			在串口助手上。
实验数据发送过程:数据从上位机(PC机)发送至下位机(51单片机),再从51单片机发送至上位机显示
注意事项:无。																				  
***************************************************************************************/

#include <reg52.h>
#include <intrins.h>

#define u16 unsigned int
#define u8  unsigned char
	
u8 receiveData;		// 用于接收数据的变量
	
/*******************************************************************************
* 函数名         :usartInit()
* 函数功能		   :设置串口,串口初始化
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void usartInit()
{
	/* 步骤:
	1、确定T1的工作方式(编程TMOD寄存器);
	2、计算T1的初值,装载TH1、TL1;
	3、启动T1(编程TCON中的TR1位);
	4、确定串行口控制(编程SCON寄存器);
	5、串行口在中断方式工作时,要进行中断设置(编程IE、IP寄存器)。
	*/
	
	/*
	SCON:特殊功能寄存器。用以设定串行口的工作方式、接收/发送控制以及设置状态标志。
	8位数据位:SM0,SM1,SM2,REN,TB8,RB8,TI,RI
	SM0和SM1为工作方式选择位:有00,01,10,11四种组合,分别对应方式1-4,各种方式的用途和特点查资料
		选择方式1,所以SM0=0,SM1=1
	SM2:多机通信控制位,这里设置成0,(不论收到的RB8为0和1,均可以使收到的数据进入SBUF,并激活RI)
	REN:允许串行接收位。0为禁止接收,1为允许接收。这里设置成1。
	TB8:可以用作数据的奇偶校验位,或在多机通信中,作为地址帧/数据帧的标志位。这里不用,设置成0
	RB8:作为奇偶校验位或地址帧/数据帧的标志位。在方式1时,若SM2=0,则RB8是接收到的停止位。这里不用,设置成0
	TI:发送中断标志位。在方式0时,当串行发送第8位数据结束时,或在其它方式,串行发送停止位的开始时,由内部硬件使TI置1,
			向CPU发中断申请。在中断服务程序中,必须用软件将其清0,取消此中断申请。
	RI:接收中断标志位。在方式0时,当串行接收第8位数据结束时,或在其它方式,串行接收停止位的中间时,由内部硬件使RI置1,
			向CPU发中断申请。也必须在中断服务程序中,用软件将其清0,取消此中断申请。
	所以,数据位是:01010000,转成十六进制是0X50
	*/
	SCON=0X50;			// 设置为工作方式1
	
    /*
    选择为定时器0模式,工作方式1,仅用TR0打开启动。
    TMOD:8位,字节地址89H,各个位分别是:GATE C/T非 M1 M0 GATE C/T非 M1 M0,依次为高4位和低四位
    GATE是门控位,为零时,TR0或TR1为1时,定时计数器就会工作
    CT非:定时/计数模式选择,0为定时模式,1为计数模式
    M1M0:工作方式设置位。00、01、10、11,对应方式0-方式3,一般使用方式1或方式2,这里使用方式2,
	低四位用于T0,高四位用于T1,这里用T1,
	所以,数据位是:00100000,转成十六进制是:0X20
    */
	TMOD=0X20;			// 设置计数器工作方式2
	
	/*
	PCON:PCON中只有一位SMOD与串行口工作有关。用于设置波特率是否倍增,8位数据位
	当SMOD=1时,波特率提高一倍。复位时,SMOD=0,这里设置成倍增。
	所以,数据位是10000000,转成十六进制是:0X80
	*/
	PCON=0X80;			// 波特率加倍
	
	/*
	TH0/TL0用于控制T0定时多久或计数达到多少再进入中断。
	TH1/TL1用于控制T1定时多久或计数达到多少再进入中断。
	他们值用软件计算,也可以通过公式计算出来。
	波特率4800,定时器方式选择方式2,晶振频率为12MHz,SMOD=1,计算结果是:F3H
	TH1:0XF3
	TL1:0XF3
	*/
	TH1=0XF3;			// 计数器初始值设置,注意波特率是4800的
	TL1=0XF3;
	
	/*
	下面三个变量查看定时/计数器中断那一章有解释。
	*/
	ES=1;				// 打开接收中断
	EA=1;				// 打开总中断
	TR1=1;				// 打开计数器
}

// **************************** 发送数字1,跑马灯
/**************************************************************************************
    8×8LED点阵———点亮一个点实验
    实现现象:下载程序后点阵左上角第一个点点亮     
    注意事项:一定要将74HC595模块上的JP595短接片短接,并且将JOE短接片短接到GND端。                                                                          
**************************************************************************************/
 // 蜂鸣器的引脚(查看原理图可知,其引脚为P1.5)
sbit buzzer = P1^5;
 
// 延迟函数
void delay(u16 time)
{
    while(time--);      // 大概延迟10us
}
 
// 主函数
void fengmingqi(void)
{
    while(1)
    {
        buzzer = ~buzzer;       // 取反,或者buzzer = !buzzer;
        delay(10);                  // 设置信号改变周期,即频率,蜂鸣器的频率在1.5-2.5KHZ
    }
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	usartInit();  	// 串口初始化
	while(1);	
}

/*******************************************************************************
* 函数名         : usart() interrupt 4
* 函数功能		  : 串口通信中断函数,串口通信的中断号是4
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void usart() interrupt 4
{
	/*
	SBUF:接收、发送缓冲器
	*/
	receiveData=SBUF;	// 出去接收到的数据
	RI = 0;				// 清除接收中断标志位
	// ***************** 到这里,表示数据从上位机发送到下位机完成
	
	// ***************** 以下是,数据从下位机发送到上位机显示的过程
	SBUF=receiveData;	// 将接收到的数据放入到发送寄存器
	/* 
	TI:发送中断标志位。
	在方式0时,当串行发送第8位数据结束时,或在其它方式,串行发送停止位的开始时,
	由内部硬件使TI置1,向CPU发中断申请。在中断服务程序中,必须用软件将其清0,取消此中断申请
	当数据发送完成时,TI=1(由内部硬件自动完成设置),!TI=0,跳出while循环,否则一直在发送数据
	*/
	while(!TI);			// 等待发送数据完成,
	TI=0;				// 清除发送完成标志位,这里内部硬件不会自动清除,必须手动(软件)清除
	
	
	// ************************  其他功能 *********************
	if(receiveData == \'1\')	// 发送1,蜂鸣器响
	{
		fengmingqi();
	}
	if(receiveData == \'2\')
	{
		
	}
	// ************************  其他功能 *********************	
}

实验现象:在串口助手中发送数字1,蜂鸣器响,但是再也不能发送其他数字了

 ——————————————————————————————————————————————————————

第二次看视频写的程序和注释理解:

/* 
串口通信:
1、由PC机通过串行口向单片机发送数据,这个数据是存放在单片机的接收缓冲器SBUF中的;
2、单片机将串行口中的数据存放在一个临时变量中;
3、单片机将存放在临时变量中的数据发送到发送缓冲器SBUF中,在PC机上显示。
*/

#include <reg52.h>

#define u16 unsigned int
#define u8 unsigned char
	
// 串行口通信初始化函数
void StartInit()
{
	/*
	1、确定T1的工作方式(编程TMOD寄存器):因为串行口中断是由定时器T1决定的,
	所以,低四位全部为0,高四位中,GATE=0,C/T非=0,选择工作方式1(8位的自动重装载),即M1M0=10
	所以是:00100000,转成十六进制数是:0x20
	*/
	TMOD=0x20;
	
	/*
	2、计算T1的初值,装载TH1、TL1:使用工具生成,设置参数,定时器方式:方式2;晶振频率:12Mhz;
	波特率:4800;SMOD:波特率倍增位,1,即增加1倍;计算结果是:F3H
	所以TH1=0xF3,TL1=0xF3,自动重装载
	*/
	TH1=0xF3;
	TL1=0xF3;
	
	/*
	PCON:与串行口工作相关的参数,只有一位SMOD(最高位),在串行口方式1、方式2、方式3时,
	波特率与SMOD有关,当SMOD=1时,波特率提高一倍。复位时,SMOD=0,
	这里波特率提高一倍,所以SMOD=1,即10000000,转成十六进制数字是:0x80
	*/
	PCON=0x80;
	
	/*
	4、启动T1(编程TCON中的TR1位):TR1=1时,定时器T1才开始启动
	*/
	TR1=1;
	
	/*
	5、确定串行口控制(编程SCON寄存器):选择工作方式1(10位异步收发器,8位数据,1位起始位,1位停止位),
	所以SM0=0,SM1=1;不需要RB8控制RI的激活(就是为了简单),设置SM2=0(SM2是多机通信控制位);
	REN,允许串行接收位,启动串行口接收数据,REN=1;
	TB8,RB8,TI,RI均为0(看资料),所以是:01010000,转成十六进制数是:0x50
	*/
	SCON=0x50;	
	
	/*
	6、中断位的开启,总中断允许位EA=1;串行口中断允许位ES=1
	*/
	EA=1;
	ES=1;
}

// 主函数
void main()
{
	StartInit();	// 串行口通信初始化
	while(1);		// 等待数据的发送和接收
}

// 发送或接收完一帧数据引起中断,串行口中断函数
void Start() interrupt 4
{
	u8 receiveData;		// 用一个变量存放数据
	receiveData=SBUF;	// 从单片机的接收缓冲器中获取数据
	RI=0;	// 当数据接收完成后,由内部硬件将RI置1,所以这里需要把RI置0,等待下一次继续接收数据
	SBUF=receiveData;	// 把变量中的数据放到发送缓冲器中,向PC机发送数据
	while(!TI);	// 当数据发送完成后(即串行口在发送停止位时,由内部硬件将TI置1,所以数据发送完成时TI=1)
	TI=0;	// 数据发送完成时,要将TI置0,等待下一次继续发送数据
}

执行: