这一节我们讲一下蓝桥杯单片机比赛中断中的最后一个模块——串口。中断的其他模块在我的个人主页(4条消息) Do My Best的博客_优快云博客-蓝桥杯单片机比赛学习领域博主有兴趣的可以去学习。
通信的方式
串行通信:一条总线,一次只能传输1bit。只需要一根线节省成本,但是传输速率慢。
并行通信:多条总线,支持多位同时传输。需要多根线浪费资源,但是传输速率快。
串行通信还包括:单工、半双工、全双工方式
单工:只能发送或者只能接受。
半双工:既能发送又能接受,但不能同时进行。
全双工:能同时发送并且接受。
我们使用的串口是串行全双工通信方式。下面我们来讲一下串口相关的寄存器,如果不想了解串口的这些繁琐的寄存器,想快速入手使用串口那么请看最下面的串口的使用步骤。
串口相关的寄存器
如下图,我们是用的单片机是STC15F2K60S2系列的,所以说此单片机只有两个串口——串口1和串口2,通常情况下我们只会使用串口1.
使用串口时,我们主要使用的寄存器如下图,我们只要大致了解它的功能,不需要死记硬背,况且考试的时候也是可以查手册的。主要的有T2H/T2L、AUXR、SCON、SBUF、IE、IP等寄存器
T2H/T2L寄存器:这里我使用的定时器2来产生波特率,所以我们需要使用T2H/T2L寄存器,这里我们为什么使用定时器2而不使用定时器1、定时器0呢?主要的还是定时器2只有一种工作方式并且功能少,而定时器0/1有4种工作方式,这里用定时器2生成波特率避免浪费资源。因为定时器只能实现一种功能,当我们使用它产生波特率时就不能使用作为其他功能了,所以这里我们采用定时器2产生波特率,避免资源浪费。这里不强求使用定时器2,看自己心情!
AUXR寄存器
SCON寄存器
SM0、SM1:控制串口的工作方式,共有4种工作方式,如下图,在这里我们主要使用的是方式1——8位UART波特率可变。这里的波特率计算规则我们这里不需要明白。
SM2:允许/禁止多机位控制
REN:接收端使能位,REN=1,允许接收;REN=0,禁止接收。
TI:发送中断请求标志位,当TI=1时表示发送完成,此时必须软件清0(手动清0)才能继续下一次的发送。
RI:接收中断请求标志位,与TI位类似,当RI=1时表示接收完成,此时必须软件清0(手动清0)才能继续下一次的发送。
这几位是我们使用最多的几位,一般的SCON=0x50;
IE寄存器
一般的,在我们使用串口中断时,需要使能EA和ES分别置1,表示打开串口中断,这样就可以在串口中断中处理程序。
PCON寄存器
SMOD:波特率选择位。当用软件置位SMOD,即SMOD=1,则使串行通信方式1、2、3的波特率加倍;SMOD=0,则各工作方式的波特率加倍。复位时SMOD=0。
串口的使用步骤
1.使用烧写软件STC-ISP软件生成初始化好的串口代码,如下图
生成如下的代码:波特率为9600、8位数据、定时器2的频率为1MHz。我们发现这只是初始化串口1和定时器2,并没有中断的相关代码,所以如果你想使用中断也需要加上 EA=1; ES=1;
void UartInit(void) //9600bps@12.000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR &= 0xFB; //定时器2时钟为Fosc/12,即12T
T2L = 0xE6; //设定定时初值
T2H = 0xFF; //设定定时初值
AUXR |= 0x10; //启动定时器2
}
2.写串口发送数据函数,发送字节、发送字符串函数。
void Send_Byte(unsigned char dat) /* 发送一个字节(8bit) */
{
SBUF=dat; /* 将要发送的数据放在数据缓冲寄存器里 */
while(TI==0); /* 等待发送完成(等待TI=1) */
TI=0; /* 手动清0,便于下次发送 */
}
void Send_String(unsigned char *dat) /* 发送字符串函数 */
{
while(*dat != '0') /* 判断每个字符是否为‘0’,为‘0’说明字符串发送完毕 */
{
Send_Byte(*dat++); /* 调用发送字节函数,发送每一个字符 */
}
}
3.如果使用中断的话还要编写串口中断服务函数,如下为我编写的串口中断服务函数
void Uart1Service(void) interrupt 4
{
if(RI==1) /* 判断是否接受数据(判断上位机(电脑)是否向单片机发送数据) */
{
RI=0; /* 手动清0 */
rdat=SBUF;
if(rdat==0x01)
Send_String("I LOVE YOU");
else
Send_Byte(rdat+1);
}
}
代码实现:
题目:单片机向上位机(电脑)发送16进制0x11、0x22,通过上位机向单片机发送数据,如是0x01那么上位机接收到 “I LOVE YOU ” ,否则上位机收到+1后的数据。这里我们的接收和发送模式选择时注意,是HEX模式还是文本模式。
#include "stc15f2k60s2.h"
#include "intrins.h"
/* 选择通道并且输入数据 */
void slect_138_573(unsigned char channel, unsigned char dat)
{
P0 = 0x00;
P0 = dat; /* 这里用P0而不用其他端口是因为我们操作LED、数码管、继电器、蜂鸣器都是对P0进行操作 */
switch(channel) /* 选择通道 */
{
case 4: /* 使Y4输出低电平0,也就是操作LED */
P2 = (P2 & 0x1f) | 0x80;/* (P2 & 0x1f)就是将前3位清0,再操作前3位。将0x80转为2进制1000 0000,这里只看前3位100就是Y4 */
break;
case 5: /* 使Y5输出低电平0,也就是操作继电器和蜂鸣器 */
P2 = (P2 & 0x1f) | 0xa0;
break;
case 6: /* 使Y6输出低电平0,也就是操作8个数码管 */
P2 = (P2 & 0x1f) | 0xc0;
break;
case 7: /* 使Y7输出低电平0,也就是操作8个数码管中的1个数码管显示值 */
P2 = (P2 & 0x1f) | 0xe0;
break;
case 0: /* 关闭所有通道 */
P2 = (P2 & 0x1f) | 0x00;
break;
}
P2 = (P2 & 0x1f) | 0x00; /* 使用后,关闭所有通道 */
}
void UartInit(void) //9600bps@12.000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR &= 0xFB; //定时器2时钟为Fosc/12,即12T
T2L = 0xE6; //设定定时初值
T2H = 0xFF; //设定定时初值
AUXR |= 0x10; //启动定时器2
EA=1;
ES=1;
}
void Send_Byte(unsigned char dat)
{
SBUF=dat;
while(TI==0);
TI=0;
}
void Send_String(unsigned char *dat)
{
while(*dat != '0')
{
Send_Byte(*dat++);
}
}
unsigned char rdat;
void Uart1Service(void) interrupt 4
{
if(RI==1)
{
RI=0;
rdat=SBUF;
if(rdat==0x01)
Send_String("I LOVE YOU");
else
Send_Byte(rdat+1);
}
}
void System_init(void)
{
slect_138_573(4,0xff);
slect_138_573(5,0x00);
UartInit();
}
void main(void)
{
System_init();
Send_Byte(0x11);
Send_Byte(0x22);
while(1)
{
}
}
以上为本节的全部内容,如有错误请各位大佬指正,或有遗漏请指出。