1. STC8G1K08A-SOP8串口通信实现详解
STC8G1K08A是STC公司推出的一款增强型8051内核单片机,SOP8封装仅有8个引脚却具备完整串口通信功能。本文将基于定时器T1作为波特率发生器,实现稳定可靠的串口数据收发。
1.1 硬件资源分析
STC8G1K08A的串口1使用P3.0(RXD)和P3.1(TXD)引脚,其内部结构具有以下特点:
- 独立波特率发生器(支持定时器1/2)
- 4级接收缓冲器
- 帧错误检测功能
- 支持多机通信模式
在SOP8封装下,P3.0和P3.1与其它功能引脚复用,需在初始化时正确配置端口模式寄存器(PxM0/PxM1)。
1.2 定时器1波特率配置
定时器1工作在模式2(8位自动重装)时,波特率计算公式为:
code复制波特率 = (2^SMOD/32) × (系统时钟频率)/(12 × (256 - TH1))
其中SMOD为PCON寄存器的最高位,默认为0。假设使用11.0592MHz晶振,要配置9600波特率:
c复制#define BRT (256 - 11059200L/12/32/9600) // 计算结果为0xFD
2. 串口初始化与数据结构设计
2.1 初始化函数实现
c复制void Uart1_Init() {
SCON = 0x50; // 模式1,允许接收
TMOD &= 0x0f; // 清零T1控制位
TMOD |= 0x20; // T1模式2
TL1 = BRT; // 波特率设置
TH1 = BRT;
TR1 = 1; // 启动定时器1
ES = 1; // 允许串口中断
EA = 1; // 开总中断
// 初始化数据结构
_Usart1data.over = 0;
_Usart1data.busy = 0;
_Usart1data.cstime = 0;
_Usart1data.rindex = 0;
_Usart1data.tindex = 0;
_Usart1data.tlen = 0;
DRE_up = 0;
}
关键点说明:
- SCON配置为01010000b:串口模式1(8位UART),允许接收
- TMOD配置需保留T0设置,只修改T1相关位
- 数据结构初始化确保所有状态变量归零
2.2 通信协议设计
示例代码中实现了简单的帧结构:
code复制起始符1 | 起始符2 | 长度 | 命令 | 地址 | 数据... | 校验和 | 结束符1 | 结束符2
这种设计具有以下优点:
- 双起始符提高帧识别可靠性
- 包含长度字段支持可变长数据
- 校验和确保数据完整性
- 双结束符明确帧边界
3. 数据发送实现细节
3.1 发送函数解析
c复制void Uart1_Trans(void) {
u8 i,j;
_Usart1data.cstime = 50; // 通信超时设置
DRE_up = 1; // 数据准备标志
// 构建帧头
_Usart1data.tbuf[0] = USART_START_B1;
_Usart1data.tbuf[1] = USART_START_B2;
j=3;
_Usart1data.tbuf[j++] = USART_CMD_READ;
_Usart1data.tbuf[j++] = SYS_ADDR;
// 填充AD转换数据
for(i=0;i<2;i++) {
_Usart1data.tbuf[j++] = _Sysrun.ad_ave[i]>>8;
_Usart1data.tbuf[j++] = _Sysrun.ad_ave[i];
}
// 设置长度和校验和
_Usart1data.tbuf[2] = j-1;
_Usart1data.tbuf[j] = 0;
for(i=2;i<j;i++) {
_Usart1data.tbuf[j] += _Usart1data.tbuf[i];
}
j++;
// 添加帧尾
_Usart1data.tbuf[j++] = USART_END_B1;
_Usart1data.tbuf[j++] = USART_END_B2;
// 启动发送
_Usart1data.tlen = j;
_Usart1data.tindex = 0;
_Usart1data.busy = 1;
SBUF = _Usart1data.tbuf[_Usart1data.tindex++];
}
3.2 发送中断处理
c复制if (TI) {
TI = 0;
if(_Usart1data.tindex >= _Usart1data.tlen) {
// 发送完成
_Usart1data.tindex = 0;
_Usart1data.busy = 0;
DRE_up = 0;
} else {
// 发送下一字节
SBUF = _Usart1data.tbuf[_Usart1data.tindex++];
}
}
注意事项:
- 必须先清除TI标志再发送数据
- busy标志防止发送过程被中断
- 采用中断方式发送可释放CPU资源
4. 数据接收与处理机制
4.1 接收中断实现
c复制void Uart1Isr() interrupt 4 {
u8 BT;
if (RI) { // 接收中断
RI = 0;
BT = SBUF;
_Usart1data.cstime = 5; // 通信超时复位
if(_Usart1data.rindex < USART_RLEN) {
_Usart1data.rbuf[_Usart1data.rindex++]=BT;
_Usart1data.rlen = _Usart1data.rindex;
} else {
// 缓冲区溢出处理
_Usart1data.rindex = 0;
_Usart1data.rlen = 0;
}
}
// 发送中断处理...
}
4.2 数据帧处理流程
c复制void Uart1_proc(void) {
u8 sum,i;
if(_Usart1data.over) { // 收到完整帧
_Usart1data.over = 0;
_Usart1data.cstime = 50;
// 验证帧头
if((_Usart1data.rbuf[0] == USART_START_B1)&&
(_Usart1data.rbuf[1] == USART_START_B2)) {
// 计算校验和
sum = 0;
for(i=2;i<=_Usart1data.rlen-4;i++) {
sum += _Usart1data.rbuf[i];
}
// 校验通过处理
if(sum == _Usart1data.rbuf[_Usart1data.rlen-3]) {
if((_Usart1data.rbuf[3] == USART_CMD_READ)&&
(_Usart1data.rbuf[4] == SYS_ADDR)) {
LedCOM_On_10ms(10); // 通信指示灯
Uart1_Trans(); // 回复数据
}
}
_Usart1data.rlen = 0; // 清空接收缓冲区
}
}
}
5. 实际应用中的经验技巧
5.1 稳定性优化措施
-
波特率精度优化:
- 优先选用11.0592MHz晶振,可精确产生标准波特率
- 必要时启用SMOD位(PCON.7)提高波特率精度
-
抗干扰设计:
c复制// 在IO口初始化时配置 P3M0 &= ~0x03; // P3.0/P3.1设置为准双向模式 P3M1 &= ~0x03; -
超时处理机制:
c复制// 在主循环中添加超时检测 if(_Usart1data.cstime) { if(--_Usart1data.cstime == 0) { // 超时处理 _Usart1data.rindex = 0; _Usart1data.rlen = 0; } }
5.2 常见问题排查
-
无法接收数据:
- 检查RXD/TXD接线是否交叉连接
- 确认SCON寄存器配置正确(SM0/SM1=01)
- 验证ES和EA中断使能位已置1
-
数据错位或乱码:
- 确认双方波特率设置一致
- 检查晶振频率是否准确
- 测量线路电压是否稳定(建议3.3V电平)
-
通信距离短:
- 增加MAX485等RS485转换芯片
- 降低波特率(长距离建议≤9600bps)
- 使用双绞线并加终端电阻
在实际项目中,我发现STC8G1K08A的串口通信非常稳定可靠,关键是要做好以下几点:精确计算波特率、合理设计通信协议、完善错误处理机制。对于资源受限的SOP8封装,可以通过共用定时器1来节省资源,但要注意避免与其它定时器功能冲突。