分享一个51单片机的串口结构
说明
- 目前主要封装了串口1的实例,采用可移植数据类型,可以同步移植到STM32、STM8等单片机;
- 需自行实现串口接收回调函数内容;
- 欢迎各位指正并分享;
头文件
#ifndef __SERIAL_H__
#define __SERIAL_H__
#include <reg52.h>
#ifndef uint8_t
typedef unsigned char uint8_t;
#endif
#ifndef uint16_t
typedef unsigned int uint16_t;
#endif
#ifndef uint32_t
typedef unsigned long uint32_t;
#endif
/* 晶振频率 */
#define FOSC 11059200L
/* 单片机周期数,默认为12T */
#define FOSC_DIV 12
/* 接收缓冲区大小 */
#define RECV_BUF_SIZE 64
/* 波特率列表 */
#define BAUD_2400 2400L
#define BAUD_4800 4800L
#define BAUD_9600 9600L
#define BAUD_14400 14400L
#define BAUD_19200 19200L // 使用此波特率需要加倍
#define BAUD_38400 38400L // 使用此波特率及以上,1T单片机才支持,或者修改晶振频率
#define BAUD_43000 43000L
#define BAUD_57600 57600L
#define BAUD_115200 115200L
#define BAUD_230400 230400L
#define BAUD_460800 460800L
/* 校验类型 */
typedef enum
{
NONE_PARITY = 0, /* 无校验 */
ODD_PARITY, /* 奇校验 */
EVEN_PARITY, /* 偶校验 */
MARK_PARITY, /* Mark parity */
SPACE_PARITY, /* Space parity */
} EtypeParity;
/* 串口模式 */
typedef enum
{
Mode0 = 0, /* 同步移位寄存器 */
Mode1, /* 8位串口,波特率可变 */
Mode2, /* 9位串口,波特率固定 */
Mode3, /* 9位串口,波特率可变 */
} EtypeSerialMode;
/* 串口数据结构 */
typedef struct
{
uint32_t m_baudrate; /* 波特率 */
EtypeParity m_parity; /* 校验方式 */
uint8_t busy_flag; /* 缓冲区忙标志位, 1:表示忙, 0:空闲 */
uint8_t m_bInterrupt; /* 使能中断, 1=enable, 0=disable */
uint8_t (*InitSerial)(uint32_t baud); /* 初始化函数指针 */
uint8_t (*SendByte)(const uint8_t byte_data); /* 发送函数指针 */
uint8_t (*SendString)(uint8_t *p_buf); /* 发送函数指针 */
void (*receive_callback)(void); /* 回调函数指针 */
uint8_t *recv_buf; /* 接收缓冲区指针 */
EtypeSerialMode m_mode; /* 串口模式,暂时为保留参数,缺省Mode1 */
} SerialPort_t;
/* 串口实例 */
extern SerialPort_t Serial;
#endif /* __SERIAL_H__ */
源文件
#include "serial.h"
xdata uint8_t recv_buf[RECV_BUF_SIZE] = {0};
static uint8_t InitSerial(uint32_t baud);
static uint8_t SendByte(uint8_t byte_data); /* 发送函数指针 */
static uint8_t SendString(const uint8_t *p_buf); /* 发送函数指针 */
static void receive_callback(void); /* 回调函数指针 */
// 允许输出
static unsigned char flag_Parity_out = 1;
/* 串口对象 */
SerialPort_t Serial =
{
BAUD_9600,
NONE_PARITY,
0,
1,
InitSerial,
SendByte,
SendString,
receive_callback,
recv_buf,
Mode1,
};
static uint8_t InitSerial(uint32_t baud)
{
uint8_t double_baud = 1;
uint8_t div = 32;
Serial.m_baudrate = baud;
switch(Serial.m_parity)
{
/* 8-bit variable UART */
case NONE_PARITY:
SCON = 0x50;
Serial.m_mode = Mode1;
break;
/* 9-bit variable UART,parity bit initial to 1 */
case ODD_PARITY:
case EVEN_PARITY:
case MARK_PARITY:
SCON = 0xda;
Serial.m_mode = Mode3;
break;
/* 9-bit variable UART,parity bit initial to 0 */
case SPACE_PARITY:
SCON = 0xd2;
Serial.m_mode = Mode3;
break;
}
TMOD = 0x20; /* Set Timer1 as 8-bit auto reload mode */
PCON &= 0x7F;
if(Serial.m_baudrate > 14400 && FOSC_DIV == 12) // 12T单片机需要倍增波特率
{
PCON |= 0x80;
double_baud = 2;
}
div /= double_baud;
TH1 = TL1 = 256 - (FOSC / FOSC_DIV / div / Serial.m_baudrate); /* Set auto-reload value */
TR1 = 1;
ES = Serial.m_bInterrupt;
EA = 1;
return 0;
}
static uint8_t SendByte(uint8_t byte_data)
{
while(Serial.busy_flag);
ACC = byte_data; // 计算校验和
switch(Serial.m_parity)
{
case SPACE_PARITY:
TB8 = 0;
break;
case MARK_PARITY:
TB8 = 1;
break;
case EVEN_PARITY:
TB8 = P;
break;
case ODD_PARITY:
TB8 = ~P;
break;
default:
break;
}
Serial.busy_flag = 1;
SBUF = byte_data;
return 0;
}
static uint8_t SendString(const uint8_t *p_buf)
{
int ncount = 0;
while(*p_buf != '\0')
{
SendByte(*p_buf++);
ncount++;
}
return ncount;
}
static void receive_callback(void)
{
/* Add your code here */
uint8_t dat = SBUF;
SendByte(dat);
}
void UartInterrupt(void) interrupt 4 using 1
{
unsigned char flag_Parity = 0;
if(RI)
{
RI = 0; /* clear receive interrupt flag */
if(Serial.m_parity != NONE_PARITY)
P = RB8;
receive_callback(); /* 调用串口接收回调函数 */
}
if(TI)
{
TI = 0;
Serial.busy_flag = 0;
}
}
Posted By veis