51单片机笔记[4]-串行口模块

实验目的

  1. 熟悉Keil,Proteus软件的使用
  2. 熟悉串行口的编程、应用

实验内容

  1. 使用其他软件编写串口通信界面
  2. 使用串口调试助手。需要安装虚拟串口驱动(Virtual Serial Port Driver),并安装串口助手设置串口参数

完成双机通信实验

  1. 完成电路图绘制
  2. 通过甲机的按键,控制甲、乙两机的发光二极管点亮熄灭的状态
状态
LED1亮,LED2亮
LED1亮,LED2灭
LED1灭,LED2亮
LED1灭,LED2灭

四种状态循环

  1. 通过乙机的按键控制甲机的八段数码管显示,内容为0-9

PC机与单片机通信

  1. 完成电路图绘制
  2. 通过JAVA或者其他软件编写控制串口程序,实现向单片机发送字符0-9,单片机通过数码管显示0-9
  3. 通过编写单片机程序,按下按键K1,向PC机发送本组学生的学号

原理

通信

单片机进行通信的常用方式:

  • 蓝牙
  • WIFI
  • 串口
  • IO口

数据传输方式

  • 单工通信:数据传输仅能沿一个方向,不能实现反向传输
  • 半双工通信:数据传输可以沿两个方向,但需要同时进行
  • 全双工通信:数据同时进行双向传输

  • 串行通信:使用一条数据线将数据一位一位地依次传输,每一位数据占据一个固定的时间长度。
  • 并行通信:将数据字节的各位用多条数据线同时进行传送,长距离传输抗干扰能力差

  • 异步通信:通信的发送与接收设备使用各自的时钟控制数据的发送和接收。
  • 同步通信:同步通信时要建立发送方时钟对接收方时钟的直接控制,使双方达到完全同步。

通信速率

  1. 比特率为每秒传输二进制代码的位数,单位:位/秒(bps),如每秒传输240字符,每个字符二进制格式为10位(1个起始,1个停止位,8个数据位),比特率为:10bit x 240 = 2400 bps
  2. 波特率为每秒传输码元的个数。码元常指时间间隔相同的符号表示二进制数字的信号,如0V表示0,5V表示1,一个码元可以表示0和1两种状态;如0V表示00,2V表示01,4V表示10,6V表示11,那么每个码元可以表示四种状态。
    波特率的计算
串口工作方式 解释 波特率公式
方式0 串行口为同步移位寄存器的输入输出方式 $$ \frac{f_{osc}}{12} $$
方式1 10位数据异步通信 $$ \frac{2^{SMOD}}{64}\dot f_{osc} $$
方式2 11位数据异步通信 $$ \frac{2^{SMOD}}{32}\dot (\frac{f_{osc}}{12 \times (256-TH1)}) $$
方式3 11位数据异步通信 $$ \frac{2^{SMOD}}{32}\dot (\frac{f_{osc}}{12 \times (256-TH1)}) $$
  1. 码率
    理论上应该是按照编码方式无损传输,但现实没有这么美好。传输时需要加入一些用于纠错的信息码,用冗余换取高可靠度。码率就是排除纠错码之后实际真实传输的数据码占理论值的比例。

串口通信

串口通信最简系统需要包括TXD,RXD,SGND三个引脚.
接线:
发送方TXD接到接收方RXD,发送方RXD接到接收方TXD.
单片机一般只能处理TTL电平,而有时候串口会有其他方式来表示逻辑状态,如RS-232用正负电压来表示逻辑状态。

Keil显示中文乱码或者与其他软件中文编码不同

现在的代码编辑器(VScode)一般都是UTF8编码,如果直接复制网上的代码有可能会中文乱码,
Keil中,Configuration设置Encoding为UTF-8

配置stc15引脚为串口

一般51单片机都有P3.0和P3.1为串口,但是下载占用了这两个口,而stc15系列有4路串口,可以通过配置其他引脚来实现串口。
[https://www.cnblogs.com/hyydf/p/12593287.html]
本实验中使用P5.2/RXD4_2和P5.3/TXD4_2为串行口4
串行口4的相关寄存器

stc15引脚复用

51单片机的分时复用51单片机的分时复用功能,最直接的就是MOVX指令,用这个指令就是在分时复用P0口,执行:MOVX A,@DPTR,那么首先要送地址A0~A7给P0口,ALE有效,锁存在373上,再将这个地址的数据从P0口读入传给A。
下面是P0口既送数码管段信号,又送位信号的例子:
P0=table[a];//送段信号
duanLAH=1;
duanLAH=0;
P0=0xfe;//送位信号
weiLAH=1;
weiLAH=0;
实际上访问外部RAM时,P0口先送地址信号,ALE同时产生锁存信号,然后送数据信号,是不用程序人工干予的,这才是真正的分时复用

实验过程

原理图

串口实现双机通信

流程图

串口通信-甲机 串口通信-乙机 串口与PC机通信

代码

文件:23.c

//乙机串口接收
#include <stc15f2k60s2.h> 

#define uchar unsigned char

#define uint unsigned int
sbit KEY2 = P3^3;
unsigned char distab[16] = {
	0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d, 
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
};//0-F
uint led_status_=0;
//延时
void delay(int ms){
	int i,j;
	for(i=0;i<ms;i++){
		for(j=0;j<200;j++);
	}
}
void ck_init_master(){
	 TMOD=0x20;
  TH1=0xfd;
  TL1=0xfd;
  SCON=0x40;
  PCON=0x00;
  TR1=1;
}
uchar temp=0;
void key2_scan() interrupt 2{
	if(KEY2==0){
		delay(10);
		if(KEY2==0){
			P0=~distab[led_status_];
			led_status_++;
			if(led_status_==4) led_status_=0;
//同步数码管状态
	ck_init_master();
	}
}
}
void key_scan_init(){
	//EX0=1;
	EX1=1;
	//IT0=1;
	IT1=1;
	EA=1;
}
void ck_init_slave(){
	TMOD=0x20;
   TH1=0xfd;
   TL1=0xfd;
   SCON=0x50;
   PCON=0x00;
   TR1=1;
}


void main()
{ 
	key_scan_init();
   while(1)
   {
	ck_init_slave();
   while(RI==0);
   RI=0;
   temp=SBUF;
   P4=temp;
	temp=P0;
	SBUF=temp;
	while(TI==0);
   TI=0;
		}
	 
}

文件22.c

//甲机串行发送
//#include <reg51.h>
#include <stc15f2k60s2.h>
#define uchar unsigned char
#define uint unsigned int
sbit LED1=P4^0;
sbit LED2=P4^1;
sbit KEY1=P3^2;
sbit KEY2=P3^3;
unsigned char distab[16] = {
	0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d, 
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
};//0-F
//延时
void delay(int ms){
	int i,j;
	for(i=0;i<ms;i++){
		for(j=0;j<200;j++);
	}
}
uchar led_status[]={0x3,0x01,0x02,0x0};//全亮,单亮
void key_scan_init(){
	EX0=1;
	EX1=1;
	IT0=1;
	IT1=1;
	EA=1;
}
uint led_status_=0;
void key1_scan() interrupt 0{
	if(KEY1==0){
		delay(10);
		if(KEY1==0){
			P4=led_status[led_status_];
			led_status_++;
			if(led_status_==4) led_status_=0;
		}
	}
}
void ck_init_slave(){
	TMOD=0x20;
   TH1=0xfd;
   TL1=0xfd;
   SCON=0x50;
   PCON=0x00;
   TR1=1;
}
unsigned char temp=0;
void key2_scan() interrupt 2{
	if(KEY2==0){
		delay(10);
		if(KEY2==0){
			P0=~distab[2];
			delay(1000);
		//同步数码管状态
		ck_init_slave();
		while(RI==0);
   RI=0;
   temp=SBUF;
		
   P0=temp;
		}
	}
}


void ck_init_master(){
	 TMOD=0x20;
  TH1=0xfd;
  TL1=0xfd;
  SCON=0x40;
  PCON=0x00;
  TR1=1;
}

void main()
{
	key_scan_init();
	ck_init_slave();
  while(1)
  {
		ck_init_master();
   temp=P4;
   SBUF=temp;
   while(TI==0);
   TI=0;
   }
}

文件:20.c
//串口实现PC机与单片机通信

#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;
u8 xuehao[]={2,0,2,1,1,0,0,9,1,2,8};
sbit KEY=P3^1;
/*******************************************************************************
* 函 数 名       : uart_init
* 函数功能		 : 串口通信中断配置函数,通过设置TH和TL即可确定定时时间
* 输    入       : baud:波特率对应的TH、TL装载值
* 输    出    	 : 无
*******************************************************************************/
void uart_init(u8 baud)
{
	TMOD|=0X20;	//设置计数器工作方式2
	SCON=0X50;	//设置为工作方式1
	PCON=0X80;	//波特率加倍
	TH1=baud;	//计数器初始值设置
	TL1=baud;
	ES=1;		//打开接收中断
	EA=1;		//打开总中断
	TR1=1;		//打开计数器		
}


#define SMG_A_DP_PORT	P0	//使用宏定义数码管段码口

//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
				0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void show_num(int input){
	SMG_A_DP_PORT=gsmg_code[input];//将数组第input个数据赋值给数码管段选口
}
//串口4发送
void send(u8 _data){
	int kk;
	u8 sum;
	do{
		SBUF=_data;//SBUF»º´æ
		while(!TI);//·¢ËÍÖжϱê־λ
		TI=0;
		while(!RI);//½ÓÊÜÖжϱê־λ
		RI=0;
	}
	while( 
		(SBUF^0xbb)!=0  //SBUF²»ÎªÁãΪ0xbbʱ¾Í»áÖ´ÐÐÏÂÒ»ÌõÓï¾ä
	);
	//°´Î»·¢ËÍ 
  
	do{
		sum=0;//sumΪУÑéºÍ£¬ÇåÁã
		for(kk=0;kk<=7;kk++){
			SBUF=_data;
			sum+=_data;
			while(!TI);
			TI=0;//Èí¼þÇåÁã
		}
		SBUF=sum;//·¢ËÍУÑéºÍ
		while(!RI);
		RI=0;
	}
	while(
		SBUF!=0
	);//SBUFΪÁãÌø³öÑ­»·
}
//按键扫描
void delay(int ms){
	int i,j;
	for(i=0;i<ms;i++){
		for(j=0;j<200;j++);
	}
}
void key_scan(){
	if(KEY==0){
		delay(10);
			if(KEY==0){
				int k;
				for(k=0;k<11;k++){
					send(xuehao[k]);
				}
			}
		}
}
/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	uart_init(0XFA);//波特率为9600

	while(1)
	{			
					show_num(5);		
	}		
}

void uart() interrupt 4 //串口通信中断函数
{
	u8 rec_data;

	RI = 0;			//清除接收中断标志位
	rec_data=SBUF;	//存储接收到的数据
	show_num((int)rec_data);
	SBUF=rec_data;	//将接收到的数据放入到发送寄存器
	while(!TI);		//等待发送数据完成
	TI=0;			//清除发送完成标志位	
	delay(5000);
}
posted @ 2022-09-09 19:39  qsBye  阅读(250)  评论(0编辑  收藏  举报