S1or 发表于 2025-4-15 21:05:10

有关串口putchar函数重定向的疑惑

我在使用STC32G8K64的时候,发现像第二张图这样重定向串口会导致卡死,但是第一图就能正常使用,有没有哪位大佬解答一下,串口配置是在STC-ISP上生成的,while循环里一直发送字符串数据。

国芯人工智能 发表于 2025-4-15 21:08:00

在嵌入式开发中,串口通信是一个非常重要的功能,而putchar函数的重定向则是实现串口输出的常见方法。针对您在使用STC32G8K64时遇到的串口putchar函数重定向问题,以下是一些可能的原因和解决方案。

1. 串口配置问题
首先,确保您的串口配置是正确的。STC-ISP工具生成的串口配置通常是可靠的,但仍需检查以下几个方面:
波特率:确保波特率设置正确,且与接收端匹配。
数据位、停止位和校验位:这些参数也需要与接收端一致。
时钟频率:确保MCU的时钟频率设置正确,因为波特率的计算依赖于时钟频率。

2. putchar函数重定向的实现
putchar函数的重定向通常是通过重写标准库中的putchar函数来实现的。以下是两种常见的实现方式:

方式一:直接发送字符
c
int putchar(int ch) {
    while (!(UARTSTATUSREG & UARTTXREADYFLAG)); // 等待发送缓冲区为空
    UARTDATAREG = ch; // 发送字符
    return ch;
}
这种方式通过轮询发送缓冲区状态,确保字符被成功发送。这种方式简单直接,但可能会占用较多的CPU资源。

方式二:使用中断发送字符
c
int putchar(int ch) {
    while (!(UARTSTATUSREG & UARTTXREADYFLAG)); // 等待发送缓冲区为空
    UARTDATAREG = ch; // 发送字符
    return ch;
}
这种方式与方式一类似,但可以通过中断机制来减少CPU的占用率。具体实现需要配置串口发送中断,并在中断服务程序中处理字符发送。

3. 卡死问题的可能原因
根据您的描述,第二种方式会导致卡死,而第一种方式正常。以下是一些可能的原因:

3.1 发送缓冲区未准备好
在第二种方式中,如果发送缓冲区未准备好,程序会一直等待,导致卡死。这可能是因为:
波特率设置错误:导致发送缓冲区无法及时清空。
硬件问题:如串口硬件故障或连接问题。

3.2 中断配置错误
如果使用了中断机制,确保中断配置正确,包括:
中断优先级:确保串口中断优先级设置合理,避免被其他高优先级中断阻塞。
中断服务程序:确保中断服务程序正确实现,能够及时处理发送缓冲区。

3.3 资源竞争
在多任务或中断环境中,可能会出现资源竞争问题。例如,如果putchar函数被多个任务或中断调用,可能会导致发送缓冲区被错误地占用或清空。

4. 解决方案
针对上述可能的原因,可以尝试以下解决方案:

4.1 检查串口配置
确保串口配置正确,特别是波特率、数据位、停止位和校验位等参数。

4.2 优化putchar函数
如果使用轮询方式,可以尝试优化putchar函数,减少CPU占用率。例如,可以增加超时机制,避免无限等待。

c
int putchar(int ch) {
    uint32t timeout = 100000; // 超时计数器
    while (!(UARTSTATUSREG & UARTTXREADYFLAG) && timeout--); // 等待发送缓冲区为空或超时
    if (timeout > 0) {
      UARTDATAREG = ch; // 发送字符
    }
    return ch;
}

4.3 使用中断机制
如果使用中断机制,确保中断配置正确,并在中断服务程序中正确处理发送缓冲区。

c
volatile uint8t txbuffer;
volatile uint8t txhead = 0;
volatile uint8t txtail = 0;

void UARTISR(void) interrupt UARTINTERRUPTNUM {
    if (UARTSTATUSREG & UARTTXREADYFLAG) {
      if (txhead != txtail) {
            UARTDATAREG = txbuffer;
            txtail = (txtail + 1) % TXBUFFERSIZE;
      }
    }
}

int putchar(int ch) {
    uint8t nexthead = (txhead + 1) % TXBUFFERSIZE;
    while (nexthead == txtail); // 等待缓冲区有空闲位置
    txbuffer = ch;
    txhead = nexthead;
    UARTENABLETXINTERRUPT(); // 使能发送中断
    return ch;
}

4.4 调试和测试
通过调试工具(如逻辑分析仪或串口调试助手)监控串口通信,检查发送和接收的数据是否正确。如果发现问题,可以逐步排查硬件和软件问题。

5. 总结
在使用STC32G8K64进行串口通信时,putchar函数的重定向是一个关键步骤。通过检查串口配置、优化putchar函数、正确使用中断机制以及进行调试和测试,可以有效解决卡死问题。希望以上分析和解决方案能够帮助您顺利实现串口通信功能。

如果您在实施过程中遇到其他问题,欢迎继续交流讨论。

[本文内容由国芯人工智能辅助生成,仅供参考]

乘风飞扬 发表于 2025-4-16 12:06:58

请提供测试项目,方便大伙帮忙分析。
像这样:


不管哪种方式都能正常输出:
void UartPutc(unsigned char dat)
{
#if(PrintUart == 1)
        SBUF = dat;
//        while(TI==0);
        while(!TI);
        TI = 0;
#else
        S2BUF= dat;
        while(S2TI == 0);
        S2TI = 0;    //Clear Tx flag
#endif
}


S1or 发表于 2025-4-16 21:23:15

程序中仅使用printf打印,麻烦大佬帮看下哪一步存在问题

ercircle 发表于 2025-4-16 22:36:52

S1or 发表于 2025-4-16 21:23
程序中仅使用printf打印,麻烦大佬帮看下哪一步存在问题


这要是主流程
SBUF = c;

进中断TI = 0;

再恢复主流程
while(TI == 0);
不就卡死了吗。


参考官方例程学习

ercircle 发表于 2025-4-16 22:39:51

S1or 发表于 2025-4-16 21:23
程序中仅使用printf打印,麻烦大佬帮看下哪一步存在问题

你和楼上乘风版主的差异在于,一种是轮询模式,一种中断模式。不要混用

S1or 发表于 2025-4-17 17:57:49

ercircle 发表于 2025-4-16 22:39
你和楼上乘风版主的差异在于,一种是轮询模式,一种中断模式。不要混用 ...

感谢大佬指点
页: [1]
查看完整版本: 有关串口putchar函数重定向的疑惑