实验:
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,等待下一次继续发送数据
}
执行: