【蓝桥杯练习】串口1

通信,按照传统的理解就是信息的传输与交换。对于单片机来说,通信则与传感器、存储芯片、外围控制芯片等技术紧密结合,成为整个单片机系统的“神经中枢”。没有通信,单片机所实现的功能仅仅局限于单片机本身,就无法通过其它设备获得有用信息,也无法将自己产生的信息告诉其它设备。如果单片机通信没处理好的话,它和外围器件的合作程度就受到限制,最终整个系统也无法完成强大的功能,由此可见单片机通信技术的重要性。 UART(Universal Asynchronous Receiver/Transmitter,即通用异步收发器)串行通信是单片机最常用的一种通信技术,通常用于单片机和电脑之间以及单片机和单片机之间的通信。
通信可以简单的分为并行通信和串行通信。并行通信传输数据是各个位同时传送,可以实现字节为单位通信,但是通信线占用的资源多成本高。
比如我们前边用到的 P0 = 0xFE;一次给 P0 的 8 个 IO 口分别赋值,同时进行信号输出,类似于有 8 个车道同时可以过去 8 辆车一样,这种形式就是并行的,我们习惯上还称 P0、 P1、 P2 和 P3 为 51 单片机的 4 组并行总线。而串行通信,就如同一条车道,一次只能一辆车过去,如果一个 0xFE 这样一个字节的数据要传输过去的话,假如低位在前高位在后的话,那发送方式就是 0-1-1-1-1-1-1-1-1,一位一位的发送出去的,要发送 8 次才能发送完一个字节。(出自《手把手教你学51单片机-C语言版》)
接下来就说一下51单片机的串口通信,标准的51只有一个专门做串口的引脚,一个是P3.0,一个是P3.1,他们有一个别名叫做RXD、TXD。RXD是接收引脚,TXD是发送引脚,有他们组成的通信接口就是串行接口,简称串口。注意一下,串口通信是一对儿一对儿的,也就是说,A端的TXD对应的是B端的RXD,A端的RXD对应的是B端的RXD,其中双方还需要连接到一个地上,是电源基准一样。
串口发送的的原则是先低位后高位。比如我要发送10101110B那么TXD就首先将管脚拉低持续一段时间,就是0,然后再把管脚拉高持续一段时间,就是1……直到发送完成,那么问题来了,持续一段时间是要持续多久呢?于是就有了一个新的概念——波特率。简单来说就是双方约定的规则。然后就是考虑开始的标志和结束的标志,通信的时候双方约定起始位和停止位,也就是说我们发生一个八位的数据实际上有10位多了一位起始位和停止位,有时候可能会在加一位奇偶检验位。具体可以百度一下。或者看一下《手把手教你学51单片机-C语言版》我觉的这个说的挺详细的。
再说一下通信的基本类型
常用的通信从传输方向上可以分为单工通信、半双工通信、全双工通信三类。
单工通信就是指只允许一方向另外一方传送信息,而另一方不能回传信息。比如电视遥控器、收音机广播等,都是单工通信技术。如果串口只用一个收发,可以说是单工通信。
半双工通信是指数据可以在双方之间相互传播,但是同一时刻只能其中一方发给另外一方,比如我们的对讲机就是典型的半双工。
全双工通信就发送数据的同时也能够接收数据,两者同步进行,就如同我们的电话一样,我们说话的同时也可以听到对方的声音。
之后简单看一下51的寄存器如图

现在简单介绍一下收到设置装载值,现在默认是定时器1,计算方式就是TH1 = TL1 = 256 - 晶振值/12/2/16/波特率,和波特率有关的还有一个寄存器,是一个电源管理寄存器PCON,他的最高位可以把波特率提高一倍,也就是如果写成PCON |= 0X80以后,计算公式就成了:TH1= TL1 = 256 - 晶振值/12/16/波特率。公式中数字的含义这里解释一下, 256 是 8 位定时器的溢出值,也就是 TL1 的溢出值,
晶振值在我们的开发板上就是 11059200, 12 是说 1 个机器周期等于 12 个时钟周期,值得关注的是这个 16,我们来重点说明。在 IO 口模拟串口通信接收数据的时候,采集的是这一位数据的中间位置,而实际上串口模块比我们模拟的要复杂和精确一些。他采取的方式是把一位信号采集 16 次,其中第 7、 8、 9 次取出来,这三次中其中两次如果是高电平,那么就认定这一位数据是 1,如果两次是低电平,那么就认定这一位是 0,这样一旦受到意外干扰读错一次数据,也依然可以保证最终数据的正确性。 
还有一点是在硬件串口中51收发寄存器都叫SBUF,但是他们的物理地址是不同的。
接下来就是真正的实验了,波特率的填充值可以用软件计算(比如stc是下载器),下面是步骤


接下来就是代码

#include <STC15F2K60S2.H>
typedef unsigned int u16;
typedef unsigned char u8;

/*串口实验*/
void UartInit(void)		//[email protected]
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
	TL1 = 0xE0;		//设定定时初值
	TH1 = 0xFE;		//设定定时初值
	ET1 = 0;		//禁止定时器1中断
	ES = 1;			//开启串口中断
	TR1 = 1;		//启动定时器1
}

void close() //关闭外设
{
	P2 = (P2 & 0X1F) | 0XA0;
	P0 = 0XAF;
	P2 = (P2 & 0X1F);
	
	P2 = (P2 & 0X1F) | 0X80;
	P0 = 0XFF;
	P2 = P2 & 0X1F;
}
void main()
{
	close();
	UartInit(); //串口初始化
	EA = 1; //打开串口
	while(1)
	{
	}
}

void InterruptUART() interrupt 4 //串口中断的中断号是四
{
	if(RI) //如果接收标志位置一,
	{
		RI = 0; 
		SBUF = SBUF + 1; //就将接收寄存器的值加一再放到发送缓存区里别忘了
		//标志位清零,否则就死在这儿了
		
	}
	if(TI)  //字节发送完毕
	{
		TI = 0;  //清零
	}
}
发布了25 篇原创文章 · 获赞 19 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/little_engineer/article/details/89791358
今日推荐