STC15W408AS串口调试不通
使用的芯片是STC15W408AS,使用ISP的CDC/HID串口助手,只有发送没有接收,串口调不通。软件代码如下:#include <STC15.h>
#include <intrins.h>
typedef unsigned int u16;
typedef unsigned char u8;
sbit Beep = P1^6;// 定义LED控制引脚
void UART_SendByte(u8 dat);
void UART_SendString(const char *s);
bit tx_busy = 0;// 发送忙标志
void Uart1_Init(void) //115200bps@24.000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器时钟1T模式
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xCC; //设置定时初始值
TH1 = 0xFF; //设置定时初始值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
ES = 1; //打开接收中断
EA = 1; //打开总中断
}
void main()
{
u16 i;
Beep=0;
Uart1_Init();
while(1)
{
Beep=0;
UART_SendString("System Started!\r\n");
for(i = 0; i < 30000; i++)
{
_nop_();
}
Beep=1;
}
}
// 发送字符串函数
void UART_SendString(const char *s)
{
while(*s) // 遍历字符串直到结束符
{
UART_SendByte(*s++); // 发送每个字符
}
}
// 发送单字节函数
void UART_SendByte(u8 dat)
{
while(tx_busy); // 等待前一个字节发送完成
tx_busy = 1; // 设置发送忙标志
SBUF = dat; // 启动发送
}
//=======================串口中断========================
void uart() interrupt 4 // 串口通信中断函数
{
u8 rec_data;
if(RI)
{
RI = 0; // 清除接收中断标志位
rec_data = SBUF; // 存储接收到的数据
SBUF = rec_data; // 将接收到的数据放入发送寄存器
}
if(TI)
{
TI = 0; // 清除发送完成标志位
tx_busy = 0;
}
}
你好,关于你使用 STC15W408AS 芯片进行串口通信调试过程中出现“只有发送没有接收”的问题,下面我将从硬件、软件、配置、调试工具等多个方面进行分析,并给出可能的排查建议和优化方向。
一、问题描述总结
你当前使用的芯片为 STC15W408AS,使用 ISP 的 CDC/HID 串口助手进行串口通信调试,发现:
发送功能正常(可以打印“System Started!”);
接收无响应(没有收到任何数据);
已开启接收中断(ES = 1),也开启了总中断(EA = 1);
使用的是 串口1(UART1),波特率为 115200 bps,晶振为 24MHz。
二、代码分析
我们先来看你的串口初始化函数:
c
void Uart1Init(void) //115200bps@24000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器时钟1T模式
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xCC; //设置定时初始值
TH1 = 0xFF; //设置定时初始值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
ES = 1; //打开接收中断
EA = 1; //打开总中断
}
这段代码看起来是标准的 STC15 系列 UART 初始化配置,但有几个细节需要进一步确认:
1. 波特率是否准确?
你使用的是 24MHz 晶振,波特率为 115200 bps,使用定时器1在1T模式下作为波特率发生器。
计算公式如下:
Baud = Fosc / (3212(256 - TH1))
代入你设置的 TH1 = 0xFF, TL1 = 0xCC:
TH1 = 0xFF, TL1 = 0xCC → 重载值为 0xFFCC → 十进制为 65484
256 - (65484 / 256) ≈ 256 - 255.816 ≈ 0.184
Baud = 24000000 / (32120.184) ≈ 33690 bps
结论:波特率设置错误!
你当前设置的定时器初值无法达到 115200 bps,实际波特率约为 33k bps,与串口助手设置的 115200 不匹配,会导致接收失败。
✅ 建议:重新计算正确的波特率初值
推荐使用 STC 官方提供的 波特率计算工具或以下公式重新设置:
TH1 = TL1 = 256 - Fosc / (3212Baud)
代入 Fosc = 24MHz,Baud = 115200:
TH1 = TL1 = 256 - 24000000 / (3212115200)
≈ 256 - 24000000 / 4423680
≈ 256 - 5.426 ≈ 250.574 → 取 250 → 0xFA
因此,应修改为:
c
TL1 = 0xFA;
TH1 = 0xFA;
三、接收中断未定义处理函数
你在代码中开启了接收中断:
c
ES = 1;
EA = 1;
但你没有提供接收中断服务函数,如:
c
void UART1ISR(void) interrupt 4
{
if(RI)
{
RI = 0;
// 处理接收数据
}
if(TI)
{
TI = 0;
txbusy = 0;
}
}
问题: 没有定义中断服务函数,会导致中断触发后无法处理,甚至程序跑飞。
✅ 建议:补充串口接收中断服务函数
例如:
c
void UART1ISR(void) interrupt 4
{
if(RI)
{
RI = 0;
u8 dat = SBUF;
// 可以回显或者处理接收到的数据
UARTSendByte(dat);
}
if(TI)
{
TI = 0;
txbusy = 0;
}
}
四、硬件连接问题排查
1. 串口引脚是否正确连接?
STC15W408AS 的串口1引脚为:
P3.0(RXD):接收;
P3.1(TXD):发送。
请确认:
你是否将 TXD 接到 USB 转 TTL 模块的 RX;
RXD 是否接到 USB 模块的 TX;
GND 是否共地;
电平是否匹配(3.3V / 5V);
2. 使用的是 ISP 下载口自带的串口?
有些 ISP 下载器(如 STC-USB)内部使用的是虚拟串口(CDC),在使用时需注意:
驱动是否安装;
串口号是否正确;
是否与其他串口冲突;
是否支持全双工通信(有些只支持下载,不支持调试);
五、调试建议
1. 使用逻辑分析仪或示波器查看 TXD 波形
确认 TXD 是否有发送数据;
查看波特率是否与设置一致;
判断是否因电平、波特率不匹配导致接收失败。
2. 使用串口助手发送数据测试
手动发送“HELLO”等字符;
观察是否能触发接收中断;
在中断中添加 LED 闪烁或打印回显判断是否收到数据。
六、完整修正后的代码示例
c
include
include
typedef unsigned int u16;
typedef unsigned char u8;
sbit Beep = P1^6;
bit txbusy = 0;
void UARTSendByte(u8 dat)
{
while(txbusy); // 等待上次发送完成
SBUF = dat;
txbusy = 1;
}
void UARTSendString(const char s)
{
while(s)
{
UARTSendByte(s++);
}
}
void Uart1Init(void)
{
SCON = 0x50; // 8位数据,可变波特率
AUXR |= 0x40; // 定时器时钟为1T模式
AUXR &= 0xFE; // 串口1选择定时器1为波特率发生器
TMOD &= 0x0F; // 设置定时器模式
TL1 = 0xFA; // 115200@24MHz
TH1 = 0xFA;
ET1 = 0; // 禁止定时器1中断
TR1 = 1; // 启动定时器1
ES = 1; // 使能串口中断
EA = 1; // 使能全局中断
}
void UART1ISR(void) interrupt 4
{
if(RI)
{
RI = 0;
u8 dat = SBUF;
UARTSendByte(dat);// 回显
}
if(TI)
{
TI = 0;
txbusy = 0;
}
}
void main()
{
u16 i;
Beep = 0;
Uart1Init();
while(1)
{
Beep = 0;
UARTSendString("System Started!\r\n");
for(i = 0; i < 30000; i++);
}
}
七、总结
| 问题点 | 原因 | 解决方案 |
|--------|------|-----------|
| 波特率设置错误 | TH1/TL1 初值不匹配 115200 | 修改为 0xFA |
| 无接收中断处理 | 没有定义中断函数 | 添加 UART1ISR 函数 |
| 硬件连接问题 | 引脚接错或电平不匹配 | 检查串口连接、电平、共地 |
| 调试工具问题 | ISP 串口不支持接收 | 使用独立 USB 转 TTL 模块 |
八、扩展建议
使用串口调试助手(如 XCOM、SSCOM)进行收发测试;
使用串口缓冲区实现更复杂的接收逻辑;
使用定时器或延时函数控制发送频率;
若需更高波特率或稳定通信,可考虑使用 定时器2 或 独立波特率发生器模块(部分 STC15 支持)。
如仍有问题,欢迎提供更详细的硬件连接图、串口助手截图或波形图,我可以进一步协助排查。
祝调试顺利!
[本文内容由国芯人工智能辅助生成,仅供参考] 注意此型号无定时器1
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0xCC; //设置定时初始值
T2H = 0xFF; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
ES = 1; //使能串口1中断
EA = 1; //打开总中断
ercircle 发表于 2025-9-29 11:15
注意此型号无定时器1
我把定时器改为T2了,重新修改了代码,但是和之前现象一样,也没有发送数据的回显,也没有接收,能帮我再看下代码吗,有劳您?代码如下:
#include <STC15.h>
#include <intrins.h>
typedef unsigned int u16;
typedef unsigned char u8;
sbit Beep = P1^6;// 定义LED控制引脚
void UART_SendByte(u8 dat);
void UART_SendString(const char *s);
bit tx_busy = 0;// 发送忙标志
void Uart1_Init(void) //9600bps @24.000MHz
{
SCON = 0x50; //8位数据,可变波特率
//PCON = 0x00; //波特率不加倍
AUXR = 0x05; //定时器时钟1T模式 串口1选择定时器2为波特率发生器
T2L = 0x8F; //设置定时初始值
T2H = 0xFD; //设置定时初始值
AUXR |= 0x10; //启动定时器2
ES = 1; //打开接收中断
EA = 1; //打开总中断
}
void main()
{
u16 i;
Beep=0;
Uart1_Init();
while(1)
{
Beep=0;
UART_SendString("System Started!\r\n");
for(i = 0; i < 30000; i++)
{
_nop_();
}
Beep=1;
}
}
// 发送字符串函数
void UART_SendString(const char *s)
{
while(*s) // 遍历字符串直到结束符
{
UART_SendByte(*s++); // 发送每个字符
}
}
// 发送单字节函数
void UART_SendByte(u8 dat)
{
while(tx_busy); // 等待前一个字节发送完成
tx_busy = 1; // 设置发送忙标志
SBUF = dat; // 启动发送
}
//=======================串口中断========================
void uart() interrupt 4 // 串口通信中断函数
{
u8 rec_data;
if(RI)
{
RI = 0; // 清除接收中断标志位
rec_data = SBUF; // 存储接收到的数据
UART_SendByte(rec_data);
SBUF = rec_data; // 将接收到的数据放入发送寄存器
}
if(TI)
{
TI = 0; // 清除发送完成标志位
tx_busy = 0;
}
}
串口情况如下:
张旗红 发表于 2025-9-29 14:47
我把定时器改为T2了,重新修改了代码,但是和之前现象一样,也没有发送数据的回显,也没有接收,能帮我再 ...
早上在15W408AS测过的代码,24M下载,波特率115200,还不行的话检查下硬件连接:
#include <STC15.h>
#include <intrins.h>
typedef unsigned int u16;
typedef unsigned char u8;
sbit Beep = P1^6;// 定义LED控制引脚
void UART_SendByte(u8 dat);
void UART_SendString(const char *s);
bit tx_busy = 0;// 发送忙标志
void Uart1_Init(void) //115200bps@24.000MHz
{
// SCON = 0x50; //8位数据,可变波特率
// AUXR |= 0x40; //定时器时钟1T模式
// AUXR |= 0x01; //串口1选择定时器2为波特率发生器
// //AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
// TMOD &= 0x0F; //设置定时器模式
// TL1 = 0xCC; //设置定时初始值
// TH1 = 0xFF; //设置定时初始值
// ET1 = 0; //禁止定时器中断
// TR1 = 1; //定时器1开始计时
// ES = 1; //打开接收中断
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0xCC; //设置定时初始值
T2H = 0xFF; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
ES = 1; //使能串口1中断
EA = 1; //打开总中断
}
void main()
{
u16 i;
Beep=0;
Uart1_Init();
while(1)
{
Beep=0;
UART_SendString("System Started!\r\n");
for(i = 0; i < 30000; i++)
{
_nop_();
}
Beep=1;
}
}
// 发送字符串函数
void UART_SendString(const char *s)
{
while(*s) // 遍历字符串直到结束符
{
UART_SendByte(*s++); // 发送每个字符
}
}
// 发送单字节函数
void UART_SendByte(u8 dat)
{
while(tx_busy); // 等待前一个字节发送完成
tx_busy = 1; // 设置发送忙标志
SBUF = dat; // 启动发送
}
//=======================串口中断========================
void uart() interrupt 4 // 串口通信中断函数
{
u8 rec_data;
if(RI)
{
RI = 0; // 清除接收中断标志位
rec_data = SBUF; // 存储接收到的数据
SBUF = rec_data; // 将接收到的数据放入发送寄存器
}
if(TI)
{
TI = 0; // 清除发送完成标志位
tx_busy = 0;
}
}
ercircle 发表于 2025-9-29 15:13
早上在15W408AS测过的代码,24M下载,波特率115200,还不行的话检查下硬件连接:
我用你测试的这个代码也测了一下,我只发了数字9,能正常进入中断和发送波形,但是串口助手选择了串口,设置波特率,打开串口后,却没有任何接收。麻烦帮我再看下哈,
串口界面如下(帮看下是否有设置不对的地方):
张旗红 发表于 2025-9-29 17:06
我用你测试的这个代码也测了一下,我只发了数字9,能正常进入中断和发送波形,但是串口助手选择了串口,设 ...
按你编写的逻辑这个代码正常运行应一直在发送:
System Started!\r\n
收到PC消息后原文回传。
可以发下硬件原理图和实物连接看看
硬件原理图:P31和P30复用为IIC的时钟线和数据线,但现在应该不影响串口,
实物连接如下:
另外打开串口前,使用外部电源给板子供电。
张旗红 发表于 2025-9-29 17:28
硬件原理图:P31和P30复用为IIC的时钟线和数据线,但现在应该不影响串口,
实物连接如下:
这工具看着是短接的I2C当前不在串口模式?
先换个不复用的板子和常规串口工具测吧,测正常了再替换图里这个工具和板子,对比差异。
ercircle 发表于 2025-9-29 17:57
这工具看着是短接的I2C当前不在串口模式?
先换个不复用的板子和常规串口工具测吧,测正常了再替换图里 ...
换了一个串口工具测试,串口助手可以正常接收mcu发来的数据,在接收数据之前需要在串口助手的发送窗预先发送一个信令,以启动串口助手的接收。
所以,ISP的CDC/HID助手是否也需要一个类似的启动接收信令啊{:wunai:}
页:
[1]
2