一、什么是串口通信?
51单片机——串口通信详解(STC89C51为例)_佛科院深夜学习的博客-CSDN博客
二、IAP15F2K60S2与STC89系列的区别:
1、16位自动重装载模式下波特率的计算方式不同:
![](https://i-blog.csdnimg.cn/blog_migrate/7225afe3883b78b0cd76e8eb020711b4.png)
(1)波特率与SMOD无关
(2)波特率等于溢出率除4
2、AUXR辅助寄存器:(上电后默认为0x01)
![](https://i-blog.csdnimg.cn/blog_migrate/bc7d8305e20e007d9fcc7cacc851194b.png)
(1)T2R:控制定时器2是否允许使用,置“1”为允许
(2)T2_C/T:控制定时器2用作定时器还是计数器,置“0”为定时器(默认)
(3)T2X12:控制定时器2速度,置“0”为12T模式(传统模式);置“1”为1T模式
(4)S1ST2:串口1定时器选择位,置“0”选择定时器1;置“1”选择定时器2(默认)
3、AUXR辅助寄存器1(这里我们未使用)
![](https://i-blog.csdnimg.cn/blog_migrate/4f0922474b827cdd353cfdc780b67484.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2af04080069fa4492a1177ac03780b7b.png)
5、使用的定时器不同
(1)串口1可以使用定时器1、定时器2为波特率发生器
(2)定时器2默认为16位自动重装载模式
(3)定时器2的时间常数保存在T2H、T2L
6、波特率对应定时器初值计算:
(1)溢出率(单位时间溢出的次数):
假设我们使用的是1T模式,溢出一次需要的时间 = (65536 - 初值)*(1/晶振频率),即
溢出率 = 1/溢出一次需要的时间 = 晶振频率/(65536 - 初值)
(2)波特率:
波特率 = 溢出率/4 =晶振频率/(65536 - 初值)/4
(3)定时器初值:
初值 = 65536 - 晶振频率/(波特率*4)(误差的绝对值要小于3%)
7、不需要外部晶振,通过STC-ISP可调节晶振频率
三、串口通信实验:
![](https://i-blog.csdnimg.cn/blog_migrate/2d22cbe71f489218f9d6221c0a60e3f8.png)
1、代码思路:
先配置并开启定时器2,然后配置并开启串口1,最后实现数据的收发。
2、注意:
STC-ISP中的IRC频率需要设置为12MHZ
![](https://i-blog.csdnimg.cn/blog_migrate/15c840e782dc763c13237b43fffb0f7a.png)
3、主函数:
// 使用程序前,将J13调整为IO模式(2-3脚短接)
#include "Public.h"
u8 R_sign;
u8 R_dat;
void Uart_1_TX(u8 dat);
void Uart_1_Init();
// 主函数
void main(void)
{
Close_All();
Uart_1_Init();
Uart_1_TX(0x5a);
Uart_1_TX(0xa5);
while(1)
{
if(R_sign)
{
Uart_1_TX(R_dat+1);
R_sign = 0;
}
}
}
/*****************串口**********************/
/*
输入变量:无
输出变量:无
功能:配置并开启定时器2和串口2
*/
void Uart_1_Init() //9600bps@12MHz
{
//使用了SCON、AUXR、IE、T2H、T2L寄存器
//方式1 8位数据 波特率可变
SM0 = 0;
SM1 = 1;
//定时器2速度为1T模式
AUXR |= 0x01<<2;
//串口1选择使用定时器2
AUXR |= 0x01<<0;
//定时器初值
T2L = 0xC7;
T2H = 0xFE;
//允许串口接受
REN = 1;
//开启串口中断
ES = 1;
//开启总中断
EA = 1;
//开启定时器2
AUXR |= 0x01<<4;
}
/*
输入变量:发送的八位数据
输出变量:无
功能:使用串口1发送8位数据
*/
void Uart_1_TX(u8 S_dat)
{
SBUF = S_dat;
while(!TI);
TI = 0;
}
void Uart_1_IT() interrupt 4
{
if(RI)
{
R_dat = SBUF;
RI = 0;
R_sign = 1;
}
}
四、串口通信进阶实验:
![](https://i-blog.csdnimg.cn/blog_migrate/670a1f86870cb98050caedb95566bdc7.png)
- 代码思路:
首先将无关设备关闭,然后配置并打开串口,编写发送字符串代码(记得回车换行),接着编写控制函数和读取函数
2.参考代码:
// 使用程序前,将J13调整为IO模式(2-3脚短接)
#include "Public.h"
u8 R_sign;
u8 R_dat;
u8 last_led = 0xff;
void Uart_1_TX_String(u8 *S_dat);
void Uart_1_Init();
void LED_ON_Low(u8 dat);
void LED_ON_High(u8 dat);
// 主函数
void main(void)
{
Close_All();
Uart_1_Init();
Uart_1_TX_String("Welcome come to XMF system!\r\n");
while(1)
{
if(R_sign)
{
R_sign = 0;
switch(R_dat>>4)
{
case 0x0A:
LED_ON_Low(R_dat);
break;
case 0x0B:
LED_ON_High(R_dat);
break;
case 0x0C:
Uart_1_TX_String("The system is running!\r\n");
break;
}
}
}
}
/*****************串口**********************/
/*
输入变量:无
输出变量:无
功能:配置并开启定时器2和串口2
*/
void Uart_1_Init() //9600bps@12MHz
{
//使用了SCON、AUXR、IE、T2H、T2L寄存器
//方式1 8位数据 波特率可变
SM0 = 0;
SM1 = 1;
//定时器2速度为1T模式
AUXR |= 0x01<<2;
//定时器初值
T2L = 0xC7;
T2H = 0xFE;
//允许串口接受
REN = 1;
//开启串口中断
ES = 1;
//开启总中断
EA = 1;
//开启定时器2
AUXR |= 0x01<<4;
}
void Uart_1_IT() interrupt 4
{
if(RI)
{
R_dat = SBUF;
RI = 0;
R_sign = 1;
}
}
/*
输入变量:发送的字符串
输出变量:无
功能:使用串口1发送字符串
*/
void Uart_1_TX_String(u8 *S_dat)
{
while(*S_dat != '\0')
{
SBUF = *S_dat;
while(TI == 0);
TI = 0;
S_dat++;
}
}
/*********************LED******************/
/*
输入变量:低四位灯亮灭数据。‘1’表示开灯,‘0’关灯
输出变量:无
功能:控制前四个灯亮灭,保持后四个灯灭
注意:使用前要对u8 last_led = 0XFF;进行宏定义
*/
void LED_ON_Low(u8 dat)
{
//由于P0口是公用的口,我们要对每次点灯的数据进行记录,不然会受其他操作的影响
P0 = (last_led & 0xf0) | (~dat & 0x0f);
last_led = P0;
P2 = (P2 & 0x1f) | 0x80;
P2 &= 0x1f;
}
/*
输入变量:高四位灯亮灭数据。‘1’表示开灯,‘0’关灯
输出变量:无
功能:控制后面四个灯亮灭,保持前面四个灯灭
注意:使用前要对u8 last_led = 0XFF;进行宏定义
*/
void LED_ON_High(u8 dat)
{
//由于P0口是公用的口,我们要对每次点灯的数据进行记录,不然会受其他操作的影响
P0 = (last_led & 0x0f) | (~dat & 0x0f)<<4;
last_led = P0;
P2 = (P2 & 0x1f) | 0x80;
P2 &= 0x1f;
}