UART串口通信
串口通信
串口通信简介
串口通信(Serial Communication)是一种用于计算机和其他设备之间进行数据传输的通信方式。串口通信使用串行数据流,通过一条数据线进行数据传输,可以实现数据的同步传输。
串口通信最简单使用方法
参考数据手册 的第 13 章(第457页),串口通信。
一.使用定时器1的8位自动重载模式
此模式下9600波特率是可以正常工作的,115200工作不太正常
1. 初始化串口(使用定时器1的8位自动重载模式)
c
#define FOSC 35000000L // 定义主时钟频率为35MHz
#define BAUD 9600 // 目标波特率
// 定时器1重载值计算(1T模式,8位自动重装模式)
#define TIMER1_RELOAD (256 - (FOSC / 32 / BAUD))
void Uart_Init(void) {
// 设置串口引脚模式(P3.0为RX准双向,P3.1为TX强推挽)
P3M0 = 0x02; // P3.1(TX)设置为强推挽输出
P3M1 = 0x00; // 其他引脚默认准双向
// 配置串口控制寄存器(SCON)
SCON = 0x50; // 串口模式1(8位数据,可变波特率),允许接收
AUXR |= 0x40; // 定时器1为1T模式(AUXR.6=1)
AUXR &= 0xFE; // 串口1选择定时器1为波特率发生器(AUXR.0=0)
// 配置定时器1(定时器1为1T模式)
TMOD &= 0x0F; // 清除定时器1模式位
TMOD |= 0x20; // 定时器1模式2(8位自动重装)
TH1 = TL1 = TIMER1_RELOAD; // 设置重载值
TR1 = 1; // 启动定时器1
// 配置中断
ES = 1; // 允许串口中断(可选)
EA = 1; // 开启总中断(可选)
}
需要说明:
- 串口初始化时,需要设置串口引脚模式,包括RX和TX的模式。
- 配置串口控制寄存器(SCON),设置串口模式和使能接收。
- 串口发送数据,需要一个波特率,这个波特率是由定时器来控制的. 通过 AUXR 来选择定时器1为波特率发生器。
- 配置定时器的工作模式:
TMOD
寄存器的相关位来设置定时器的工作模式。 - 配置定时器的重载值:
TH1
和TL1
寄存器来设置定时器的重载值。 - 启动定时器:
TR1
寄存器的相关位来启动定时器。 - 配置中断:
ES
寄存器的相关位来使能串口中断(可选),EA
寄存器的相关位来开启总中断(可选)。
以上的每一步都是必需的,否则串口通信将无法正常工作。
2. 发送数据
c
void UartSendByte(unsigned char dat) {
SBUF = dat; // 发送当前数据
while(!(TI)); // 等待数据发送完成
TI = 0; // 清除发送完成标志
}
需要说明:
- 发送数据时,需要将要发送的数据写入到
SBUF
寄存器中。只要SBUF
寄存器的值不为空,就会自动发送。 - 等待前一个数据发送完成: 可以通过检查
TI
寄存器的状态来等待前一个数据发送完成。 - 清除发送完成标志: 发送完成后,需要手动清除
TI
寄存器的状态。
二.使用定时器1的16位自动重载模式
这种模式下,波特率9600或是115200,都是可以正常工作的。
1. 初始化串口(使用定时器1的16位自动重载模式)
c
#define FOSC 35000000L // 定义主时钟频率为35MHz(烧录时,必须选择35MHz的晶振)
#define BAUD 115200 // 目标波特率
#define BRT (65536 - (FOSC / 4 / BAUD))// 波特率重装值(p473)
void Uart_Init(void) {
// 设置串口引脚模式(P3.0为RX准双向,P3.1为TX强推挽)
P3M0 = 0x02; // P3.1(TX)设置为强推挽输出
P3M1 = 0x00; // 其他引脚默认准双向
// 关于串口的配置
SCON = 0x50; // 8位数据,可变波特率(p469)
AUXR &= 0xBE;
AUXR |= 0x40; // 串口1选择定时器1为波特率发生器(p470)
//关于定时器2的配置(p376)
TMOD &= 0x0F; // 清除定时器1模式位
TMOD |= 0x00; // 定时器1模式0(16位自动重装)
TL1 = BRT; // 设置定时初始值
TH1 = BRT >> 8; // 设置定时初始值
TR1 = 1; // 启动定时器1
ES = 1; // 允许串口中断(可选)
EA = 1; // 开启总中断(可选)
}
需要说明:
- 串口初始化时,需要设置串口引脚模式,包括RX和TX的模式。
- 配置串口控制寄存器(SCON),设置串口模式和使能接收。
- 串口发送数据,需要一个波特率,这个波特率是由定时器来控制的. 通过 AUXR 来选择定时器1为波特率发生器。
- 配置定时器的工作模式:
TMOD
寄存器的相关位来设置定时器的工作模式。 - 配置定时器的重载值:
TH1
和TL1
寄存器来设置定时器的重载值。 - 启动定时器:
TR1
寄存器的相关位来启动定时器。 - 配置中断:
ES
寄存器的相关位来使能串口中断(可选),EA
寄存器的相关位来开启总中断(可选)。 以上的每一步都是必需的,否则串口通信将无法正常工作。
2. 发送数据
c
void UartSendByte(unsigned char dat) {
SBUF = dat; // 发送当前数据
while(!(TI)); // 等待前一个数据发送完成
TI = 0; // 清除发送完成标志
}
void UartSendStr(char *s) {
while(*s) { // 检测字符串结束符
UartSendByte(*s++);// 发送当前字符
}
}
需要说明:
- 发送数据时,需要将要发送的数据写入到
SBUF
寄存器中。只要SBUF
寄存器的值不为空,就会自动发送。 - 等待前一个数据发送完成: 可以通过检查
TI
寄存器的状态来等待前一个数据发送完成。 - 清除发送完成标志: 发送完成后,需要手动清除
TI
寄存器的状态。
三.如何进行串口接收数据
- 添加中断服务函数
- 开启串口接收中断
- 读取接收数据
1.中断服务函数
c
#define BUFFER_SIZE 32
xdata uint8_t rx_buffer[32];
volatile unsigned char rx_index;
volatile bit data_ready;
void Uart_ISR(void) interrupt 4 {
if(RI) {
RI = 0; // 必须手动清除接收标志
rx_buffer[rx_index] = SBUF; // 读取接收数据
// 检测结束符(如回车换行)
if(rx_buffer[rx_index] == '\n' && rx_buffer[rx_index - 1] == '\r') {
rx_buffer[rx_index - 1] = '\0'; // 终止字符串
data_ready = 1; // 设置数据就绪标志
rx_index = 0; // 重置索引
} else {
if(++rx_index >= BUFFER_SIZE) rx_index = 0; // 防溢出
}
}
}
需要说明:
- 中断服务函数的名称必须为
UART_ISR
,中断号为4。 - 检查接收中断标志: 可以通过检查
RI
寄存器的状态来判断是否有数据接收到。 - 读取接收到的数据: 可以通过读取
SBUF
寄存器来获取接收到的数据。 - 清除接收中断标志: 读取完数据后,需要手动清除
RI
寄存器的状态。 - 特别说明:
xdata
关键字用于定义变量在外部数据区,这样可以提高变量的访问速度。因为单片机的内部数据区太小了.只是能使用扩展数据区.
2.开启串口接收中断
c
void Uart_Init(void) {
// 设置串口引脚模式(P3.0为RX准双向,P3.1为TX强推挽)
P3M0 = 0x02; // P3.1(TX)设置为强推挽输出
P3M1 = 0x00; // 其他引脚默认准双向
// 关于串口的配置
SCON = 0x50; // 8位数据,可变波特率(p469)
AUXR &= 0xBE;
AUXR |= 0x40; // 串口1选择定时器1为波特率发生器(p470)
//关于定时器2的配置(p376)
TMOD &= 0x0F; // 清除定时器1模式位
TMOD |= 0x00; // 定时器1模式0(16位自动重装)
TL1 = BRT; // 设置定时初始值
TH1 = BRT >> 8; // 设置定时初始值
TR1 = 1; // 启动定时器1
ES = 1; // 允许串口中断(可选)
EA = 1; // 开启总中断(可选)
}
需要说明:
ES=1
允许串口中断,EA=1
开启总中断。 这样,当串口接收到数据时,就会触发中断。SCON
寄存器的REN
位为1,表示允许接收。- 其它的部分都是与上一个例子相同的。在发送数据时也需要相应的配置.
3.数据处理
c
bit Uart_DataReady(void) {
return data_ready;
}
char *Uart_GetData(void) {
data_ready = 0; // 清除数据就绪标志
return rx_buffer;
}
需要说明:
- 检查数据是否就绪: 可以通过检查
data_ready
标志来判断是否有数据接收到。 - 获取接收到的数据: 可以通过返回
rx_buffer
数组的指针来获取接收到的数据。 - 清除数据就绪标志: 获取完数据后,需要手动清除
data_ready
标志。
4.数据使用
在 main
函数中,可以通过调用 Uart_DataReady
函数来检查是否有数据接收到,然后调用 Uart_GetData
函数来获取接收到的数据。
c
void main(void) {
while(1) {
if(Uart_DataReady()) { // 检测是否有数据到达
dat = Uart_GetData(); // 获取接收到的数据
UartSendStr(dat); // 发送接收到的数据
}
}
}
需要说明:
- 在
main
函数中,可以通过调用Uart_DataReady
函数来检查是否有数据接收到,然后调用Uart_GetData
函数来获取接收到的数据。
四.具体的代码
这是最简单的代码:
c
#include <STC8G.H>
// 串口初始化
void UART_Init() {
SCON = 0x50; // 8位数据,可变波特率
AUXR |= 0x40; // 定时器1时钟为Fosc,即1T
AUXR &= 0xFE; // 串口1选择定时器1为波特率发生器
TMOD &= 0x0F; // 设定定时器1为16位自动重装方式
TL1 = 0xE0; // 设定定时初值
TH1 = 0xFE; // 设定定时初值
ET1 = 0; // 禁止定时器1中断
TR1 = 1; // 启动定时器1
ES = 1; // 使能串口中断
EA = 1; // 开启全局中断
}
// 发送字符串
void UART_SendString(char *s) {
while(*s) {
SBUF = *s++;
while(!TI);
TI = 0;
}
}