tlxfif 发表于 2026-5-4 13:30:52

STC8H1K08 请问如何模拟一个串口呢?

STC8H1K08 有两个串口,都在使用

现在需要额外模拟一个串口
我按照AI给的教程写了代码,麻烦各位大佬看看,是不是有问题啊,我新手小白不太懂{:zhemo:}

#include <STC8H.H>
// ==================== 环形缓冲区通用定义 ====================
#define BUFFER_SIZE 20
// 模拟串口(UART3)缓冲区
unsigned char rx_buffer3;
unsigned char rx_in3 = 0;
unsigned char rx_out3 = 0;
unsigned char rx_count3 = 0;

// 接收状态机
unsigned char soft_rx_state = 0;    // 0:空闲, 1:起始位, 2:数据位, 3:停止位
unsigned char soft_rx_byte = 0;   // 接收到的字节暂存
unsigned char soft_rx_bit_cnt = 0;// 数据位计数
unsigned char soft_rx_stop_bit = 0; // 停止位标志


// ==================== 模拟串口相关变量 ====================
sbit SOFT_TXD = P3^6;   // 发送引脚
sbit SOFT_RXD = P3^7;   // 接收引脚
#define BIT_TIME_RELOAD_H 0xF1 // 示例值,需根据实际调试微调
#define BIT_TIME_RELOAD_L 0x9A
// ==================== 模拟串口初始化(P3.6 TXD, P3.7 RXD) ====================
void SoftUart_Init(void) {
               // 引脚配置
    P3M0 &= ~0xC0;
    P3M1 &= ~0xC0;
    P3M0 |= 0x40;   // P3.6 推挽输出 (TXD)
    P3M1 |= 0x80;   // P3.7 高阻输入 (RXD)
    SOFT_TXD = 1;

    // 定时器0配置 (16-bit自动重载,3倍采样)
    TMOD &= 0xF0;   // 清除T0模式位
    TMOD |= 0x01;   // T0模式1: 16位(不可自动重载,在ISR中手动重载)
    TL0 = BIT_TIME_RELOAD_L;
    TH0 = BIT_TIME_RELOAD_H;
    ET0 = 1;      // 使能定时器0中断
    TR0 = 1;      // 启动定时器0
    EA = 1;         // 确保总中断开通
    soft_rx_state = 0;
}

// 重写SoftUart_SendByte使用BitDelay
void SoftUart_SendByte(unsigned char dat) {
    unsigned char i;
    // 关闭定时器3中断,避免发送过程被接收中断干扰
    IE2 &= ~0x20;
    // 起始位
    SOFT_TXD = 0;
    BitDelay();
    // 发送8个数据位(LSB first)
    for (i = 0; i < 8; i++) {
      if (dat & 0x01) SOFT_TXD = 1;
      else SOFT_TXD = 0;
      BitDelay();
      dat >>= 1;
    }
    // 停止位
    SOFT_TXD = 1;
    BitDelay();
    // 恢复定时器3中断
    IE2 |= 0x20;
}

void Timer0_Isr(void) interrupt 1 {
    // 手动重载定时器0(提升时序准确性)
    TL0 = BIT_TIME_RELOAD_L;
    TH0 = BIT_TIME_RELOAD_H;

    switch (soft_rx_state) {
      case 0: // 空闲,检测起始位
            if (SOFT_RXD == 0) {
                soft_rx_state = 1;
                soft_rx_bit_cnt = 0;
                soft_rx_byte = 0;
            }
            break;
      case 1: // 起始位确认(延迟半位中心)
            soft_rx_state = 2;
            break;
      case 2: // 接收数据位(每次中断采集一位)
            soft_rx_byte >>= 1;
            if (SOFT_RXD) soft_rx_byte |= 0x80;
            if (++soft_rx_bit_cnt >= 8) {
                soft_rx_state = 3;
            }
            break;
      case 3: // 停止位校验
            if (SOFT_RXD == 1) {
                                                          P12 = ~P12;
                if (rx_count3 < BUFFER_SIZE) {
                  rx_buffer3 = soft_rx_byte;
                  rx_in3 = (rx_in3 + 1) % BUFFER_SIZE;
                  rx_count3++;
                }
            }
            soft_rx_state = 0;
            break;
      default:
            soft_rx_state = 0;
    }
}



void main() {
    P_SW2 |= 0x80;
    SoftUart_Init();   // 初始化模拟串口
P1M0 = 0x00;
    P1M1 = 0x00;
while(1) {
if (rx_count3 > 0) {
            unsigned char data3 = rx_buffer3;
            SBUF = data3;
            while(!TI);
            TI = 0;
            rx_out3 = (rx_out3 + 1) % BUFFER_SIZE;
            rx_count3--;
            //P12 = 1;
            //Delay10ms();
      }
}


}







神农鼎 发表于 2026-5-4 13:43:34


神农鼎 发表于 2026-5-4 13:45:25


https://www.stcaimcu.com/data/download/Datasheet/STC32G.pdf




STC32CL8K64 有 3组 串口





神农鼎 发表于 2026-5-4 13:46:51

https://www.stcaimcu.com/data/download/Datasheet/STC32G.pdf

tlxfif 发表于 2026-5-4 14:18:21

神农鼎 发表于 2026-5-4 13:43


STC8h也能用吗

tlxfif 发表于 2026-5-4 14:18:51

神农鼎 发表于 2026-5-4 13:45
https://www.stcaimcu.com/data/download/Datasheet/STC32G.pdf




我是STC8H

C_wolf 发表于 2026-5-4 14:37:43

新手就换芯片吧,别折磨自己了。

不要过度依赖AI,看看官方例程。

zhx 发表于 2026-5-4 14:42:03

tlxfif 发表于 2026-5-4 14:18
我是STC8H
你可以让一个串口,在不同的管脚上切换,比如读传感器数据,这个读的时刻你能掌握,就可以切换引脚,发读命令,读数据,而后回监听引脚,或者做日志发送,也可以切换发送,然后再换回监听,或者在引脚上用下降沿中断,触发本引脚的切换,这些都比你模拟的串口可靠.
我用printf输出调试信息,就是这样做的
////////////////////////////////////////
// 重写printf字符发送重定向函数
// 入口参数: dat (printf函数待打印的字符)
// 函数返回: 需要返回入口参数的数据
////////////////////////////////////////

char putchar (char dat) //将串口1和printf函数绑定
{
        unsigned int xdata t;

P_SW1 &= ~0xc0; //UART1/USART1: RxD(P3.0), TxD(P3.1)
TI=0;
SBUF=dat;
        t=65535;
while (!TI && (t--)!=0);
TI=0;
P_SW1 = (P_SW1 & ~0xc0) | 0x40;                //UART1/USART1: RxD(P3.6), TxD(P3.7)
return dat;
}


tlxfif 发表于 2026-5-4 18:11:51

C_wolf 发表于 2026-5-4 14:37
新手就换芯片吧,别折磨自己了。

不要过度依赖AI,看看官方例程。

但是其他芯片贵嘛,我想着能省点钱{:ciya:}

tlxfif 发表于 2026-5-4 18:12:53

zhx 发表于 2026-5-4 14:42
你可以让一个串口,在不同的管脚上切换,比如读传感器数据,这个读的时刻你能掌握,就可以切换引脚,发读命令, ...

这个更没玩过了
页: [1] 2
查看完整版本: STC8H1K08 请问如何模拟一个串口呢?