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();
}
}
}
https://www.stcaimcu.com/data/download/Datasheet/STC32G.pdf
STC32CL8K64 有 3组 串口
https://www.stcaimcu.com/data/download/Datasheet/STC32G.pdf
神农鼎 发表于 2026-5-4 13:43
STC8h也能用吗 神农鼎 发表于 2026-5-4 13:45
https://www.stcaimcu.com/data/download/Datasheet/STC32G.pdf
我是STC8H 新手就换芯片吧,别折磨自己了。
不要过度依赖AI,看看官方例程。
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;
}
C_wolf 发表于 2026-5-4 14:37
新手就换芯片吧,别折磨自己了。
不要过度依赖AI,看看官方例程。
但是其他芯片贵嘛,我想着能省点钱{:ciya:} zhx 发表于 2026-5-4 14:42
你可以让一个串口,在不同的管脚上切换,比如读传感器数据,这个读的时刻你能掌握,就可以切换引脚,发读命令, ...
这个更没玩过了
页:
[1]
2