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