2019-03-05 17:56:22 kafmws 阅读数 178
  • 单片机到底是个什么东西-1.2.第1季第2部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第2个课程,用通俗易懂的语言讲了很多和单片机有关的技术概念,如CPU、ROM、RAM、外设、电路板、软件硬件工作的差别等。目的是希望大家在轻松愉悦的氛围中对单片机加深认识。

    3038 人正在学习 去看看 朱有鹏
单片机串行口结构

在这里插入图片描述
  串行口结构如上图
  发送时,SBUF中写入数据后,串行口通过发送控制器,将SBUF中的数据逐个逐位地通过串行输出口TXD引脚逐个发出,当一个字节发送结束后,触发TI中断位,通知单片机发送结束
  接收时,先向REN引脚写1,外部引脚RXD会实时检测电平变化,当满足串行接收数据的条件时,会逐位接收数据并保存到SBUF,当一个字节接收结束后,触发RI中断位,通知单片机接收结束


串行口控制寄存器SCON

SCON D7 D6 D5 D4 D3 D2 D1 D0
98H SM0 SM1 SM2 REN TB8 RB8 TI RI

SM0、SM1用于设定串行口工作方式   fosc :晶振频率

SM0 SM1 方式 功能 波特率
0 0 方式0 移位寄存器方式 fosc/12
0 1 方式1 8位异步通信方式 可变
1 0 方式2 9位异步通信方式 fosc/32或fosc/64
1 1 方式3 9位异步通信方式 可变

SM2:多机通信控制位
REN:允许接收控制位
TB8/RB:发送/接收的第9位数据
TI:发送中断标志位
RI:接收中断标志位


电源控制寄存器

PCON D7 D6 D5 D4 D3 D2 D1 D0
87H SMOD

当SMOD位为1时,串行口方式1、方式2、方式3的波特率加倍


这里只介绍方式0与方式1的应用

方式0
  方式0通常用来外接移位寄存器,用作扩展I/O口,方式0工作时波特率固定为 fsoc/12,工作时,串行数据通过RXD输入、输出,同步时钟通过TXD输出
  发送:TI = 0 时,SBUF写入数据后,发送过程启动,发送结束后,TI被置为1,并向CPU申请中断
  接收:在 RI = 0 时,将REN置"1"就启动一次接收过程,RXD上的串行数据一次移入移位寄存器,当一个字节发送完成之后,接收中断标志RI被置为"1",同时向CPU申请中断
  方式0波特率固定,也无需编程设定定时器

方式0应用实例:扩展并行I/O口
  当外接串入并出的移位寄存器时,即是扩展并行输出口,当外接并入串出的移位寄存器时,相当于扩展并行输入口

原理图如下
在这里插入图片描述
4094模块使用方式:
在这里插入图片描述
D接RXD,CLK接TXD,STB接P1.0,OE接EA

扩展并行输出口控制流水灯程序如下:

#include<reg52.h>
sbit P1_0 = P1^0;
void main(){
	unsigned char i;
	unsigned int j;
	SCON = 0x00;//设置串行口工作方式
	i = 0x01;//00000001b   发送的用于控制LED灯的变量
	for(;;){
		P1_0 = 0;//将4094接入串口
		SBUF = i;//
		while(TI==0);
		P1_0 = 1;//将STB置1,准备4094发送
		TI = 0;//TI归位
		for(j = 0;j<0xffff;j++);//适当延时
		i = i*2;
		if(i==0){
			i = 0x01;//循环
		}
	}
}

方式1
  方式1位8位异步通信方式,在方式1下,一帧信息为10位,1位起始位(0),8位数据位(低位在前)和1位停止位(1)
  发送:在 TI = 0 时,向SBUF写入数据,启动发送过程,数据有TXD引脚送出,当一帧数据发送完毕后,TI 被置为"1"
  接收:当 REN = 1 时,接收控制器开始接收数据,数据依次被移入移位寄存器,当8位数据及停止位全部移入后,进行响应操作
  方式1下,TXD数据发送端,RXD为数据接收端,波特率可变,由定时/计数器T1的溢出率和电源控制寄存器PCON中的SMOD位决定,故可编程设定定时器以设定波特率,其中溢出率 = 计数器一秒钟内溢出的次数
 波特率 = 2SMOD × (T1的溢出率) / 32
 T1溢出率 = fsoc / ( 12 × 计数值 )
所以
 T1的初值 = MAX值 - fsoc × 2SMOD / (12 × 波特率 × 32)

在这里插入图片描述
分析如下:
在这里插入图片描述
甲机发送程序:

#include<reg52.h>
void main(){
	unsigned char i;
	SCON = 0x40;
	TMOD = 0x20;
	TL1 = 0xE6;
	TH1 = 0xE6;
	TR1 = 1;//设定完毕
	P1 = 0xff;//为读取准备
	while(1){
		i = P1;
		SBUF = i;
		while(TI==0);//等待发送完成
		TI = 0;
	}
}

乙机接收程序:

#include<reg52.h>
void main(){
	SCON = 0x50;
	TMOD = 0x20;
	TL1 = 0xE6;
	TH1 = 0xE6;
	TR1 = 1;
	EA = 1;
	ES = 1;
	while(1);
}

void setLED() intrrupt 4{
	if(RI){
		RI = 0;
		P2 = SBUF;
	}
}

2019/3/5

2019-11-30 16:10:40 qq_37631068 阅读数 92
  • 单片机到底是个什么东西-1.2.第1季第2部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第2个课程,用通俗易懂的语言讲了很多和单片机有关的技术概念,如CPU、ROM、RAM、外设、电路板、软件硬件工作的差别等。目的是希望大家在轻松愉悦的氛围中对单片机加深认识。

    3038 人正在学习 去看看 朱有鹏

实验目的和任务

目的:利用“模块化单片机教学实验平台”,加深对单片机的串行口的理解。

任务:利用单片机的串行口完成程序设计。

实验内容

使用AT89S52单片机的串行口通过RS232通信接口与PC机进行通信,让单片机把接收到的每一帧数据(即PC机发送给单片机的每一帧数据)直接再发送给PC机。(串行口波特率设定为9600Bit/s,使用方式1)注意:使用串口调试助手(Baud 9600、数据位8、停止位1、效验位无)作为上位机来向单片机发送数据和接收单片机串口所发的数据,观察串口调试助手接收窗口。

实验过程和结果

电路图

硬件连线:

母版

CPU

J57/J59RXD

P2P3.0

J57/J59TXD

P2P3.1

用232串口线连接计算机的USB口和MAIN_BOARD的RS2/RS1串口。

注意:实验箱的AT89S52单片机的晶振频率为11.0592MHz!

参考流程图:

 

实验结果图

  1. 实验心得

实验过程让我熟悉了中断程序和串口的编写步骤和单片机执行串口传输的工作流程。实验中由于不熟悉中端口的相关寄存器分布和功能,导致错误设置了特殊功能寄存器,程序不能正常执行,后来在老师的指导下修改了程序和中断入口地址,程序能正常执行并返回输入内容。

  1. 附录(代码)

(1)基本实验

ORG 0000H

LJMP MAIN               

ORG 0023H

LJMP U

MAIN: 

MOV SCON,#01010000B

SETB ES

SETB EA

MOV TMOD,#00100000B

MOV TH1,#0FDH

SETB TR1

LJMP $

U:

CLR RI

MOV A,SBUF

MOV SBUF,A

JNB RI,$

CLR RI

RETI

END

(2)扩展实验

ORG 0000H

LJMP MAIN               

ORG 0023H

LJMP U

MAIN: 

MOV SCON,#01010000B

SETB ES

SETB EA

MOV TMOD,#00100000B

MOV TH1,#0FDH

SETB TR1

SETB T1      ;手动执行中断

LJMP $

U:

CLR RI

MOV SBUF,#68H

MOV SBUF,#65H

MOV SBUF,#6CH

MOV SBUF,#6CH

MOV SBUF,#6FH

MOV SBUF,#26H

MOV SBUF,#20H

MOV SBUF,#77H

MOV SBUF,#6FH

MOV SBUF,#72H

MOV SBUF,#6CH

MOV SBUF,#64H

MOV SBUF,#0DH

MOV SBUF,#0AH

MOV SBUF,#0AH

JNB RI,$

CLR RI

LJMP U      ;发送完毕后回到中断程序头部,循环发送hello world

RETI

END

2011-06-01 13:00:00 s_a_n_ 阅读数 1834
  • 单片机到底是个什么东西-1.2.第1季第2部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第2个课程,用通俗易懂的语言讲了很多和单片机有关的技术概念,如CPU、ROM、RAM、外设、电路板、软件硬件工作的差别等。目的是希望大家在轻松愉悦的氛围中对单片机加深认识。

    3038 人正在学习 去看看 朱有鹏
#include <REGX52.H>

//===================================================================
//文件名:serial_traveler.h 
//  51单片机 串行口数据传输接口说明:
//	串行收发数据需要占用定时器1 和串行口 TXD、RXD
//	接口中定义了忙标志 busy_serial 1表示接口被此接口占用,0表示未被此接口占用
//	此接口中 串口工作方式1、8位异步收发、允许接收数据、需要接收有效的停止位
//	如需其它工作方式,请自行修改
//	挂起串口时,释放定时器 和 串口,串口失去时钟源,任何读 或 写串口的操作都会失败
//	如有指教,请联系我:759981398@qq.com 
//==================================================================

#ifndef _SERIAL_TRAVELER_H_
#define _SERIAL_TRAVELER_H_
#define _TRUE_TRAVELER_ 1
#define _FALSE_TRAVELER_ 0

//==================================================================
//函数名:  serialStartup()
//功能:    初始化串口
//输入参数:无
//返回值:  无
//其他: 	同时占用定时器1
//==================================================================
void serialStartup();

//==================================================================
//函数名:  serialClose()
//功能:    关闭串口
//输入参数:无
//返回值:  无
//其他: 	同时关闭定时器1
//==================================================================
void serialClose();

//==================================================================
//函数名:  serialSelectBode
//功能:    设定串口波特率
//输入参数:波特率值/100
//返回值:  操作成功返回 _TRUE_TRAVELER_ ;操作失败返回 _FALSE_TRAVELER_
//其他: 	无
//==================================================================
char serialSelectBode(unsigned char bodeValue);

//==================================================================
//函数名:  serialRun()
//功能:    串口开始工作
//输入参数:无
//返回值:  无
//其他: 	占用定时器T1
//==================================================================
#ifndef serialRun
#define serialRun() TR1 = 1 
#endif

//==================================================================
//函数名:  serialClear()
//功能:   清除溢出标志位,为下一次传输做准备
//输入参数:无
//返回值:  无
//其他: 	无
//==================================================================
#ifndef serialClear
#define serialClear() TI = 0; RI = 0
#endif

//==================================================================
//函数名:  serialPauseResume
//功能:    挂起/恢复 串口
//输入参数:操作码 _TRUE_TRAVELER_~挂起串口;_FALSE_TRAVELER_~恢复串口
//返回值:  无
//其他: 	挂起后 可以解除定时器绑定 串口的sfr也可以修改作其他用处
//			恢复后串口可像挂起前一样正常工作
//==================================================================
void serialPauseResume(char opcode);

//==================================================================
//函数名:  serialWriteChar
//功能:    写字符到串口
//输入参数:待发送的字符
//返回值:  _FALSE_TRAVELER_~发送失败  /// _TRUE_TRAVELER_ ~ 发送成功
//其他: 	无
//==================================================================
char serialWriteChar(unsigned char chr);

//==================================================================
//函数名:  serialReadChar
//功能:    从串口读取1个字符
//输入参数:接收字符的单元地址
//返回值:  _FALSE_TRAVELER_~接收失败  /// _TRUE_TRAVELER_ ~ 接收成功
//其他: 	无
//==================================================================
char serialReadChar(unsigned char *chr);

//==================================================================
//函数名:  serialWriteString
//功能:    写字符串到串口
//输入参数:str 字符串首地址,应注意使字符串结束的字节为'\0'
//返回值:  返回发送成功的字符数
//其他: 	无
//==================================================================
char serialWriteString(const unsigned char *str);

//==================================================================
//函数名:  serialReadString
//功能:    从串口读取字符串
//输入参数:str 字符串首地址 ,len 允许接收的最大字节数
//返回值:  返回接收到的字符数
//其他: 	无
//==================================================================
char serialReadString(unsigned char *str,unsigned char len);

//==================================================================
//函数名:  serialWriteInt
//功能:    以字符串格式向uart发送一个整数
//输入参数:int dat 待发送的整数值
//返回值:  int 成功发送的字符个数
//其他: 	返回值若为-1 表示数据处理阶段发生错误、未发送
//==================================================================
char serialWriteInt(int dat);

#endif

 

/*
文件名:serial_traveler.c 
*/
#include <REGX52.H>
#include "serial_traveler.h"

//下表为11.0592MHz 晶振下 部分波特率对应定时器1自动重载计数初值、smod位设置 适用于串行口的方式1 和 方式3
const unsigned char bode_serial[][3]= 
{
	{192,0xfd,1},// 19.2 kb/s - 初值 0xfd  - SMOD = 1
	{96 ,0xfd,0},// 9.6  kb/s - 初值 0xfd  - SMOD = 0
	{48 ,0xfa,0},// 4.8  kb/s - 初值 0xfa  - SMOD = 0
	{24 ,0xf4,0},// 2.4  kb/s - 初值 0xf4  - SMOD = 0
	{12 ,0xe8,0} // 1.2  kb/s - 初值 0xe8  - SMOD = 0
};

//busy_serial指示是否已占用了串口和定时器1
static char busy_serial = _FALSE_TRAVELER_ ; 

//==================================================================
//函数名:  serialStartup()
//功能:    初始化串口
//输入参数:无
//返回值:  无
//其他: 	同时占用定时器1
//==================================================================
void serialStartup()
{
	busy_serial = 1;
	TMOD &= 0x0f;//清空对定时器1的设置
	TMOD |= 0x20;//定时器1方式2 作波特率发生器
	TCON &= 0x3f;//关定时器1
	SCON  = 0x70;//设置串口 方式1 8位异步收发 允许接收数据 需要接收有效的停止位
}

//==================================================================
//函数名:  serialClose()
//功能:    关闭串口
//输入参数:无
//返回值:  无
//其他: 	同时关闭定时器1
//==================================================================
void serialClose()
{
	TMOD &= 0x0f;//清空对定时器1的设置
	TR1   = 0;//关定时器1
	busy_serial  = 0;
}

//==================================================================
//函数名:  serialSelectBode
//功能:    设定串口波特率
//输入参数:波特率值/100
//返回值:  操作成功返回 _TRUE_TRAVELER_ ;操作失败返回 _FALSE_TRAVELER_
//其他: 	无
//==================================================================
char serialSelectBode(unsigned char bodeValue)
{
	char c;
	for(c = 0;c!=5;++c)
	{
		if(bode_serial[c][0] == bodeValue)
		{
			TH1 = bode_serial[c][1];
			TL1 = bode_serial[c][1];
			PCON &= 0x7f;//SMOD位清零
			PCON |= (bode_serial[c][2]<<7);//设置SMOD位
			return _TRUE_TRAVELER_;
		}
	}
	return _FALSE_TRAVELER_;
}


//==================================================================
//函数名:  serialRun()
//功能:    串口开始工作
//输入参数:无
//返回值:  无
//其他: 	占用定时器T1
//==================================================================
#ifndef serialRun
#define serialRun() TR1 = 1 
#endif

//==================================================================
//函数名:  serialClear()
//功能:   清除溢出标志位,为下一次传输做准备
//输入参数:无
//返回值:  无
//其他: 	无
//==================================================================
#ifndef serialClear
#define serialClear() TI = 0; RI = 0
#endif

//==================================================================
//函数名:  serialPauseResume
//功能:    挂起/恢复 串口
//输入参数:操作码 _TRUE_TRAVELER_~挂起串口;_FALSE_TRAVELER_~恢复串口
//返回值:  无
//其他: 	挂起后 可以解除定时器绑定 串口的sfr也可以修改作其他用处
//			恢复后串口可像挂起前一样正常工作
//==================================================================
void serialPauseResume(char opcode)
{	
	static char th1,tl1,tmod_4567,scon,pcon_7,tcon_67;
	if(opcode == _TRUE_TRAVELER_ )//挂起操作 保护现场
	{
		th1 = TH1;
		tl1 = TL1;
		tmod_4567 = TMOD & 0XF0;
		scon = SCON;
		pcon_7 = PCON & 0X80;
		tcon_67 = TCON & 0XC0;
		TR1 = 0;
		busy_serial = 0 ;
	}
	else//恢复 恢复现场
	{
		TH1 = th1;
		TL1 = tl1;
		TMOD &= 0X0F;
		TMOD |= tmod_4567;
		SCON = scon;
		PCON &= 0X7F;
		PCON |= pcon_7;
		TCON &= 0X3F;
		TCON |= tcon_67;
		busy_serial = 1;
	}
}

//==================================================================
//函数名:  serialWriteChar
//功能:    写字符到串口
//输入参数:待发送的字符
//返回值:  _FALSE_TRAVELER_~发送失败  /// _TRUE_TRAVELER_ ~ 发送成功
//其他: 	无
//==================================================================
char serialWriteChar(unsigned char chr)
{	
	if(_FALSE_TRAVELER_ == busy_serial)//串口未启用 退出
		return _FALSE_TRAVELER_;
	if(RI)//正在接收数据 退出
		return _FALSE_TRAVELER_;
		
	SBUF = chr;
	while(!TI);
	TI = 0;
	return _TRUE_TRAVELER_;
}

//==================================================================
//函数名:  serialReadChar
//功能:    从串口读取1个字符
//输入参数:接收字符的单元地址
//返回值:  _FALSE_TRAVELER_~接收失败  /// _TRUE_TRAVELER_ ~ 接收成功
//其他: 	无
//==================================================================
char serialReadChar(unsigned char *chr)
{
	if(_FALSE_TRAVELER_ == busy_serial)//串口未启用 退出
		return _FALSE_TRAVELER_;
	if(TI) //正在发送数据 退出
		return _FALSE_TRAVELER_;
	while(!RI);
	RI = 0;
	*chr = SBUF;
	return _TRUE_TRAVELER_;
}

//==================================================================
//函数名:  serialWriteString
//功能:    写字符串到串口
//输入参数:str 字符串首地址,应注意使字符串结束的字节为'\0'
//返回值:  返回发送成功的字符数
//其他: 	无
//==================================================================
char serialWriteString(const unsigned char *str)
{
	char c = 0;
	for(c = 0;str[c]!=0;c++)
	{//不到字符尾则继续发送
		if(_FALSE_TRAVELER_ == serialWriteChar(str[c]))	
			break; //发送失败则终止发送
	}
	return c;
}

//==================================================================
//函数名:  serialReadString
//功能:    从串口读取字符串
//输入参数:str 字符串首地址 ,len 允许接收的最大字节数
//返回值:  返回接收到的字符数
//其他: 	注意您的字符数组应预留'\0'字符的位置 即至少数组应含有len+1个元素
//==================================================================
char serialReadString(unsigned char *str,unsigned char len)
{ 
	unsigned char c = 0;
	while(c<len)
	{
		if((_FALSE_TRAVELER_ == serialReadChar(&str[c]))||str[c] =='\r' || str[c] == '\n')
		{ //如果接收字符失败或接收到的字符是回车键则终止接收字符	
			
			str[c] = 0;
			c++;
			break;
		}
		c++; //接收下一个字符
	}
	return c;
}

//==================================================================
//函数名:  serialWriteInt
//功能:    以字符串格式向uart发送一个整数
//输入参数:int dat 待发送的整数值
//返回值:  int 成功发送的字符个数
//其他: 	返回值若为-1 表示数据处理阶段发生错误、未发送
//==================================================================
char serialWriteInt(int dat)
{
	//从int型到字符数组之间的转换
	unsigned char str[11]= {0,0,0,0,0,0,0,0,0,0,0};
	char dat_tmp;
	char pos ;
	char neg = 0;
	str[10] = 0;
	pos = 10 ;
	
	if(dat<0)//处理负数 上
	{
		dat = - dat;
		neg = 1;
	}
	
	do//循环 转换数据格式
	{
		dat_tmp = dat % 10 ;
		str[--pos] = '0' + dat_tmp ;
		dat /= 10 ;
	}
	while(dat != 0) ;
	
	if(neg)//处理负数 下
	{
		str[--pos] = '-';
	}
	
	if(pos <0)//出错处理
		return -1 ;
		
	return	serialWriteString((unsigned char *)&str[pos]);
}



 

2019-01-17 09:16:29 weixin_44367275 阅读数 59
  • 单片机到底是个什么东西-1.2.第1季第2部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第2个课程,用通俗易懂的语言讲了很多和单片机有关的技术概念,如CPU、ROM、RAM、外设、电路板、软件硬件工作的差别等。目的是希望大家在轻松愉悦的氛围中对单片机加深认识。

    3038 人正在学习 去看看 朱有鹏

在这里插入图片描述
串行口是单片机与外界进行信息交换的工具。
■ 8051单片机的通信方式有两种:
并行通信:数据的各位同时发送或接收。
串行通信:数据一位一位次序发送或接收。
参看下图:
在这里插入图片描述

串行通信的方式包括异步通信和同步通信。
异步通信
它用一个起始位表示字符的开始,用停止位表示字符的结束。其每帧的格式如下:
在一帧格式中,先是一个起始位0,然后是8个数据位,规定低位在前,高位在后,接下来是奇偶校验位(能省略),最后是停止位1。用这种格式表示字符,则字符能一个接一个地传送。
在异步通信中,CPU与外设之间必须有两项规定,即字符格式和波特率。字符格式的规定是双方能够在对同一种0和1的串理解成同一种意义。原则上字符格式能由通信的双方自由制定,但从通用、方便的角度出发,一般还是使用一些标准为好,如采用ASCII标准。
波特率即数据传送的速率,其定义是每秒钟传送的二进制数的位数。例如,数据传送的速率是120字符/s,而每个字符如上述规定包含10数位,则传送波特率为1200波特。
同步通信
在同步通信中,每个字符要用起始位和停止位作为字符开始和结束的标志,占用了时间;所以在数据块传递时,为了提高速度,常去掉这些标志,采用同步传送。由于数据块传递开始要用同步字符来指示,同时要求由时钟来实现发送端与接收端之间的同步,故硬件较复杂。
通信方向
在串行通信中,把通信接口只能发送或接收的单向传送办法叫单工传送;而把数据在甲乙两机之间的双向传递,称之为双工传送。在双工传送方式中又分为半双工传送和全双工传送。半双工传送是两机之间不能同时进行发送和接收,任一时该,只能发或者只能收信息。

8051单片机的串行接口结构
8051单片机串行接口是一个可编程的全双工串行通信接口。它可用作异步通信方式(UART),与串行传送信息的外部设备相连接,或用于通过标准异步通信协议进行全双工的8051多机系统也能通过同步方式,使用TTL或CMOS移位寄存器来扩充I/O口。
8051单片机通过管脚RXD(P3.0,串行数据接收端)和管脚TXD(P3.1,串行数据发送端)与外界通信。SBUF是串行口缓冲寄存器,包括发送寄存器和接收寄存器。它们有相同名字和地址空间,但不会出现冲突,因为它们两个一个只能被CPU读出数据,一个只能被CPU写入数据。
▲串行口的控制与状态寄存器
串行口控制寄存器SCON
它用于定义串行口的工作方式及实施接收和发送控制。字节地址为98H,其各位定义如下表:
在这里插入图片描述

SM0、SM1:串行口工作方式选择位,其定义如下:

在这里插入图片描述
(注:其中fosc为晶体震荡器频率)
SM2:多机通信控制位。在方式0时,SM2一定要等于0。在方式1中,当(SM2)=1则只有接收到有效停止位时,RI才置1。在方式2或方式3当(SM2)=1且接收到的第九位数据RB8=0时,RI才置1。
REN:接收允许控制位。由软件置位以允许接收,又由软件清0来禁止接收。
TB8: 是要发送数据的第9位。在方式2或方式3中,要发送的第9位数据,根据需要由软件置1或清0。例如,可约定作为奇偶校验位,或在多机通信中作为区别地址帧或数据帧的标志位。
RB8:接收到的数据的第9位。在方式0中不使用RB8。在方式1中,若(SM2)=0,RB8为接收到的停止位。在方式2或方式3中,RB8为接收到的第9位数据。
TI:发送中断标志。在方式0中,第8位发送结束时,由硬件置位。在其它方式的发送停止位前,由硬件置位。TI置位既表示一帧信息发送结束,同时也是申请中断,可根据需要,用软件查询的办法获得数据已发送完毕的信息,或用中断的方式来发送下一个数据。TI必须用软件清0。
RI:接收中断标志位。在方式0,当接收完第8位数据后,由硬件置位。在其它方式中,在接收到停止位的中间时刻由硬件置位(例外情况见于SM2的说明)。RI置位表示一帧数据接收完毕,可用查询的办法获知或者用中断的办法获知。RI也必须用软件清0。
▲特殊功能寄存器PCON
PCON是为了在CHMOS的80C51单片机上实现电源控制而附加的。其中最高位是SMOD。

串行口的工作方式
8051单片机的全双工串行口可编程为4种工作方式,现分述如下:
方式0 移位寄存器输入/输出方式。
可外接移位寄存器以扩展I/O口,也能外接同步输入/输出设备。8位串行数据者是从RXD输入或输出,TXD用来输出同步脉冲。
输出 串行数据从RXD管脚输出,TXD管脚输出移位脉冲。CPU将数据写入发送寄存器时,立即启动发送,将8位数据以fos/12的固定波特率从RXD输出,低位在前,高位在后。发送完一帧数据后,发送中断标志TI由硬件置位。
输入 当串行口以方式0接收时,先置位允许接收控制位REN。此时,RXD为串行数据输入端,TXD仍为同步脉冲移位输出端。当(RI)=0和(REN)=1同时满足时,开始接收。当接收到第8位数据时,将数据移入接收寄存器,并由硬件置位RI。
下面两图分别是方式0扩展输出和输入的接线图。

在这里插入图片描述
<单片机串行口接线图>
方式1 波特率可变的10位异步通信接口方式。
发送或接收一帧信息,包括1个起始位0,8个数据位和1个停止位1。
输出 当CPU执行一条指令将数据写入发送缓冲SBUF时,就启动发送。串行数据从TXD管脚输出,发送完一帧数据后,就由硬件置位TI。
输入 在(REN)=1时,串行口采样RXD管脚,当采样到1至0的跳变时,确认是开始位0,就开始接收一帧数据。只有当(RI)=0且停止位为1或者(SM2)=0时,停止位才进入RB8,8位数据才能进入接收寄存器,并由硬件置位中断标志RI;不然信息丢失。所以在方式1接收时,应先用软件清零RI和SM2标志。
方式2 固定波特率的11位UART方式。
它比方式1增加了一位可程控为1或0的第9位数据。
输出: 发送的串行数据由TXD端输出一帧信息为11位,附加的第9位来自SCON寄存器的TB8位,用软件置位或复位。它可作为多机通信中地址/数据信息的标志位,也能作为数据的奇偶校验位。当CPU执行一条数据写入SUBF的指令时,就启动发送器发送。发送一帧信息后,置位中断标志TI。
输入: 在(REN)=1时,串行口采样RXD管脚,当采样到1至0的跳变时,确认是开始位0,就开始接收一帧数据。在接收到附加的第9位数据后,当(RI)=0或者(SM2)=0时,第9位数据才进入RB8,8位数据才能进入接收寄存器,并由硬件置位中断标志RI;不然信息丢失。且不置位RI。再过一位时间后,不管上述条件时否满足,接收电路即行复位,并重新检测RXD上从1到0的跳变。
方式3 波特率可变的11位UART方式。
除波特率外,其余与方式2相同。
关于波特率选择
如前所述,在串行通信中,收发双方的数据传送率(波特率)要有一定的约定。在8051串行口的四种工作方式中,方式0和2的波特率是固定的,而方式1和3的波特率是可变的,由定时器T1的溢出率控制。
▲ 方式0
方式0的波特率固定为主振频率的1/12。
▲ 方式2
方式2的波特率由PCON中的选择位SMOD来决定,可由下式表示:
波特率=2的SMOD次方除以64再乘一个fosc,也就是当SMOD=1时,波特率为1/32fosc,当SMOD=0时,波特率为1/64fosc
▲ 方式1和方式3
定时器T1作为波特率发生器,其公式如下:
在这里插入图片描述

式中T1计数率取决于它工作在定时器状态还是计数器状态。当工作于定时器状态时,T1计数率为fosc/12;当工作于计数器状态时,T1计数率为外部输入频率,此频率应小于fosc/24。产生溢出所需周期与定时器T1的工作方式、T1的预置值有关。
定时器T1工作于方式0:溢出所需周期数=8192-x;
定时器T1工作于方式1:溢出所需周期数=65536-x;
定时器T1工作于方式2:溢出所需周期数=256-x。
因为方式2为自动重装入初值的8位定时器/计数器模式,所以用它来做波特率发生器最恰当。
当时钟频率选用11.0592MHZ时,取易获得标准的波特率,所以很多单片机系统选用这个看起来“怪”的晶体震荡器就是这个道理。
下表列出了定时器T1工作于方式2常用波特率及初值。
以上所有信息仅作为学习交流使用,不作为任何学习和商业标准。若您对文中任何信息有异议,欢迎随时提出,谢谢!
关于云创硬见
云创硬见是国内最具特色的电子工程师社区,融合了行业资讯、社群互动、培训学习、活动交流、设计与制造分包等服务,以开放式硬件创新技术交流和培训服务为核心,连接了超过30万工程师和产业链上下游企业,聚焦电子行业的科技创新,聚合最值得关注的产业链资源, 致力于为百万工程师和创新创业型企业打造一站式公共设计与制造服务平台。

2010-10-07 10:19:00 gdut_lisa 阅读数 4534
  • 单片机到底是个什么东西-1.2.第1季第2部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第2个课程,用通俗易懂的语言讲了很多和单片机有关的技术概念,如CPU、ROM、RAM、外设、电路板、软件硬件工作的差别等。目的是希望大家在轻松愉悦的氛围中对单片机加深认识。

    3038 人正在学习 去看看 朱有鹏

8051单片机串行口及串行通信

 

一、串行通信的基础知识

CPU与其他外部设备要进行信息交换,一台计算机与其他计算机之间有时也要交换信息,这些信息交换就称为通信。通信有并行通信和串行通信两种。

1、并行通信

并行通信是将数据字节的各位用多条数据线同时进行传送。

 

并行通信控制简单、传输速度快;由于传输线较多,长距离传送时成本高且接收方的各位同时接受存在困难。

2、串行通信

串行通信是将数据字节分成一位一位的形式在一条传输线上逐个地传送。


串行通信传输线少,长距离传送时成本低,且可以利用电话网等现成的设备,但数据的传送控制要比并行通信复杂。

串行通信又可以分为异步通信与同步通信。

1)异步通信

异步通信是指通信的发送设备与接受设备使用各自的时钟控制数据的发送和接受过程。为使双方的收发协调,要求发送和接受设备的时钟尽可能一致。

 

异步通信是以字符(构成的帧)为单位进行传输,字符与字符之间的间隙(时间间隔)是任意的,但每个字符中的各位是以固定的时间传送的,字符之间是异步的,而同一字符内的各位是同步的。

异步通信的数据格式 :

 

异步通信的特点:不要求收发双方时钟的严格一致,实现容易,设备开销较小,但每个字符要附加2~3位用于起止位,各帧之间还有间隔,因此传输效率不高。

2)同步通信

同步通信是要建立发送方时钟对接收方时钟的直接控制,使双方达到完全同步。此时,传输数据的位之间的距离均为“位间隔”的整数倍,同时传送的字符间间不留间隙,及位同步且字符同步。发送方对接收方的同步可以通过两种方法实现。

                     

外同步:是指对同步字符的检测在串行I/O接口芯片外部进行,当外部硬件电路检测到同步信号时,就给串行接口发送一个同步信号SYNC。当串行I/O接口芯片收到同步信号后,立即进行数据传送。

自(内)同步:是指同步字符的检测和同步控制是在串行I/O接口芯片内部进行的。自(内)同步又可分为单同步(只有一个字节的同步字符)和双同步(有两个字节的同步字符)。

 

 

二、8051的串行口

18051串行口的结构

 

有两个物理上独立的接受、发送缓冲器SBUF,它们占用同一个地址99H;接收器是双缓冲结构;因为发送时CPU是主动的,因而不会产生重叠错误。

 

28051串行口的控制寄存器

   SCON是个特殊功能寄存器,用以设定串行口的工作方式、接收/发送控制以及设置状态标志:

   SM0SM1为工作方式选择位,可选择四种工作方式:

 

SM2     多机通信控制位

REN     允许串行接受位    由软件设置REN=1,允许接受;REN=0,禁止接受。

TB8      在方式2或方式3中,是发送数据的第九位,可以用软件规定其作用。可以用作数据的奇偶校验位,或在多机通信中,作为地址帧/数据帧的标志位。

RB8      在方式2或方式3中,是接收到数据的第九位,作为奇偶校验位或地址帧/数据帧的标志位。在方式1时,若SM2=0,则为接受到的停止位。

TI        发送中断标志位

RI        接受中断标志位

     寄存器PCON中只有一位SMOD与串行口工作有关:

 

SMOD     波特率倍增位

 

三、串行口的工作方式

1、方式0

工作在方式0时,串行口为同步移位寄存器的输入输出方式。主要用于扩展并行输入或输出口。数据由RXDP3.0)引脚输入或输出,同步移位脉冲由TXD(P3.1)引脚输出。发送和接收均为8位数据,低位在先,高位在后。波特率固定为fosc/12

1)方式0输出

2)方式0的输入

  

方式0发送和接收电路

  

 2、方式1

      方式110位数据的异步通信接口。TXD为数据发送引脚,RXD为数据接收引脚,传送一帧数据的格式如图所示。其中1位起始位,8位数据位,1位停止位。

 

     3、方式2和方式3

     方式2或方式311位数据的异步通信口。TXD为数据发送引脚,RXD为数据接收引脚。


方式2和方式3一帧包括1位起始位,9位数据位,1位停止位。方式2的波特率固定为晶振频率的1/641/32,方式3波特率由定时器T1的溢出率决定。

 

四、波特率的计算

在串行通信中,收发双方对发送或接收数据的速率要有约定。通过软件可对单片机串行口编程为四种工作方式,其中方式0和方式2的波特率是固定的,方式1和方式3的波特率是可变的,由定时器T1的溢出率决定。

方式0的波特率=fosc/12

方式2的波特率=(2SMOD/64)·fosc

方式1的波特率=(2SMOD/32)·(T1溢出率)

方式3的波特率=(2SMOD/32)·(T1溢出率)

T1作为波特率发生器时,常用是使T1工作在自动再装入的8位定时方式(方式2

T1溢出率=fosc/(12*(256-TH1))

常用波特率表

 

五、原理图

其中U2为发送设备,U1为接受设备

 

六、程序设计

本程序的功能是实现U2每隔50MSU1发送数据,U1一直处于接受状态,当U2有数据接受时,则接数据传到P2口,形成流水灯。

发送设备程序:

#include<reg52.h>

 

void Delay(int n)                  //延时1ms子程序

{

   int x,y;

   for(x=0;x<110;x++)

      for(y=0;y<n;y++);

}

void main ()

{   

    int i;

    TMOD=0x20;                         //设置定时器1工作在方式2

       TH1=250;                      //设置波特率为9600kps=(2*/32)*12M/(12(256-250))

       TL1=250;

       TR1=1;                        //启动定时器1

       SCON=0x50;                         //串行口工作在方式1

       PCON=0x80;                //SMOD=1

    while(1)

       for(i=0;i<8;i++)

       {

          SBUF=~(1<<i);          //发送数

          Delay(50);

       }

}

 

接收设备程序:

#include<reg52.h>

 

void main ()

{   

    TMOD=0x20;                         //设置定时器1工作在方式2

       TH1=250;                      //设置波特率为9600kps=(2*/32)*12M/(12(256-250))

       TL1=250;

       TR1=1;                        //启动定时器1  

       SCON=0x50;                         //串行口工作在方式1  

       PCON=0x80;                         //SMOD=1

       REN=1;                                 //允许接受

    EA=1;                       //开总中断

       ES=1;                          //开串行接收中断

                    

       while(1);

}

 

void Serial() interrupt 4         //溢出中断服务子程序

{                                                  //软件清零

   RI=0;

   P2=SBUF;

}

 

 

 

 

单片机串行口

阅读数 1416

没有更多推荐了,返回首页