【原创】用单片机做FC的串口

发布时间:2026/6/30 13:45:42
【原创】用单片机做FC的串口 一、整体架构设计路线A 带FIFO缓冲 批量收发 FC中断通知1. 核心设计要点发送侧FC → PCFC单次把数据写入51内置软件发送FIFO缓冲区写完一批后FC执行一条「启动批量发送」指令51才把FIFO内所有数据通过硬件UART一次性发给RS232避免FC频繁总线交互拖慢运行。接收侧PC → FCSTC12硬件UART持续接收PC数据存入接收FIFO当检测到串口空闲超时连续若干波特率周期无新字节判定一批数据接收完毕立刻拉低FC的IRQ中断引脚触发FC硬件中断FC进入中断服务程序后连续批量读取51接收FIFO整批数据。寄存器兼容W65C51地址映射$7F00(数据)、$7F01(状态命令)、$7F02(FIFO长度)硬件新增关键改动FC主板IRQ引脚 → STC12某IO推荐P1.1默认高电平收到整批数据后置低触发FC中断FC读完缓冲区恢复高。原有INT0(P3.2)片选CS#、P3.6WR#、P3.7RD#、P3.0/P3.1硬件UART不变。必须保留74HC245总线缓冲 74HC373锁存 74HC138地址译码解决6502与STC12时序不匹配问题。2. 寄存器定义FC侧内存映射 $7F00~$7F021$7F00DATA_PORT 数据端口FC写将1字节压入STC发送FIFOFC读从STC接收FIFO弹出1字节2$7F01CMD_STATUS 命令/状态寄存器Bit名称说明D0TX_RDY发送FIFO是否有空位(1可写入)D1RX_AVL接收FIFO有数据待读D2TX_STARTFC写1触发STC批量发送整个发送FIFO硬件自动清零D3IRQ_PENDING1STC已拉IRQ通知FC来读批量数据3$7F02FIFO_LEN 寄存器读当前接收FIFO有效字节数FC批量读取前先获取长度避免越界读取FIFO参数设定STC12内部RAM发送FIFOTX_FIFO_BUF 32字节头TX_HEAD、尾TX_TAIL接收FIFORX_FIFO_BUF 32字节头RX_HEAD、尾RX_TAIL串口空闲超时阈值固定32个波特率位时间9600下≈3.3ms无新数据判定一批接收结束3. 时序与中断逻辑说明1FC批量发送流程FC循环向$7F00写入待发数据每次读$7F01.0判断FIFO是否可写全部数据写入发送FIFO后FC向$7F01.2写1下发批量发送启动命令STC收到命令在主循环中将TX_FIFO内所有字节依次从硬件UART发出发完清空FIFO。2PC批量接收FC硬件中断流程STC串口中断持续接收字节写入RX_FIFO同时启动空闲超时定时器超时时间内无新串口数据 → 判定整批数据接收完成STC拉低IRQ引脚P1.1置0置位$7F01.3(IRQ_PENDING)FC触发IRQ中断进入中断服务读取$7F02获取接收字节总数循环N次读取$7F00取出全部数据FC读完所有数据后向状态位写命令清除中断STC拉高IRQ引脚等待下一批。3时序保障方案FC总线访问由INT0下降沿捕获中断内仅做FIFO入队/出队、状态寄存器更新不做串口发送批量UART发送、串口空闲超时检测全部放在主循环避开总线时序压力74HC373锁存总线信号STC中断响应几μs内安全读写锁存数据不会违反6502总线建立时间。二、硬件引脚完整分配STC12(11.0592MHz)引脚定义引脚功能连接对象P0.0~P0.78位并行数据74HC245 B侧P3.2(INT0)CS#片选(下降沿中断)74HC138译码输出P3.6WR# 写信号(低有效)FC R/W0P3.7RD# 读信号(高有效)FC R/W1P3.1UART_TXMAX232 T1INP3.0UART_RXMAX232 R1OUTP1.1FC_IRQ#(低触发)FC主板IRQ引脚默认高电平三、STC12 51汇编实现FIFO批量收发空闲中断FC硬件IRQ; ; STC12 11.0592MHz 模拟W65C51 批量FIFO收发 ; 支持FC批量写入FIFO触发发送PC批量接收超时后拉FC IRQ中断 ; UART:9600 8N1 FIFO深度:32字节 ; 寄存器映射: ; $7F00 DATA_PORT ; $7F01 CMD_STATUS ; $7F02 FIFO_LEN ; ORG 0000H LJMP MAIN ORG 0003H LJMP BUS_INT0_ISR ; 总线访问中断 ORG 0023H LJMP UART_ISR ; 串口收发中断 ; RAM变量定义 TX_FIFO_BUF EQU 30H TX_HEAD EQU 50H TX_TAIL EQU 51H RX_FIFO_BUF EQU 60H RX_HEAD EQU 70H RX_TAIL EQU 71H CMD_REG EQU 72H RX_TIMEOUT EQU 73H IRQ_FLAG EQU 74H FIFO_DEPTH EQU 32 ; 状态位定义 TX_RDY_BIT EQU 0 RX_AVL_BIT EQU 1 TX_START_BIT EQU 2 IRQ_PEND_BIT EQU 3 ; 初始化入口 MAIN: MOV SP,#60H MOV P0,#0FFH SETB P1.1 ; IRQ默认高电平(无中断) SETB IT0 SETB EX0 SETB EA ; UART 960011.0592 T1模式2 MOV TMOD,#21H ; T1:模式2串口, T0:模式1定时超时检测 MOV TH1,#0FDH MOV TL1,#0FDH SETB TR1 MOV SCON,#50H SETB ES ; FIFO初始化 MOV TX_HEAD,#0 MOV TX_TAIL,#0 MOV RX_HEAD,#0 MOV RX_TAIL,#0 MOV IRQ_FLAG,#0 MOV RX_TIMEOUT,#0 MAIN_LOOP: ; 1.检测是否需要批量发送TX FIFO JB CMD_REG.TX_START_BIT,START_TX_BATCH ; 2.检测串口接收超时触发FC IRQ LCALL CHECK_RX_TIMEOUT SJMP MAIN_LOOP ; 批量发送整个发送FIFO START_TX_BATCH: CLR CMD_REG.TX_START_BIT TX_LOOP: MOV A,TX_HEAD CJNE A,TX_TAIL,TX_SEND_BYTE SJMP TX_END TX_SEND_BYTE: MOV R0,#TX_FIFO_BUF ADD A,R0 MOV A,R0 MOV SBUF,A JNB TI,$ CLR TI INC TX_HEAD MOV A,TX_HEAD CJNE A,#FIFO_DEPTH,TX_LOOP MOV TX_HEAD,#0 TX_END: SJMP MAIN_LOOP ; 串口空闲超时检测(32位时间) CHECK_RX_TIMEOUT: MOV A,RX_HEAD CJNE A,RX_TAIL,START_TIMEOUT_TIMER RET START_TIMEOUT_TIMER: MOV TH0,#0FFH MOV TL0,#0E0H SETB TR0 JNB TF0,$ CLR TF0 CLR TR0 ; 超时判定拉FC IRQ JB IRQ_FLAG,CHECK_RET SETB IRQ_FLAG CLR P1.1 SETB CMD_REG.IRQ_PEND_BIT CHECK_RET: RET ; 总线INT0中断服务FC读写寄存器 BUS_INT0_ISR: PUSH ACC PUSH PSW ; WR有效FC写数据/命令 JB P3.6,BUS_WR_OP ; RD有效FC读数据/状态/长度 JB P3.7,BUS_RD_OP SJMP BUS_EXIT BUS_WR_OP: MOV A,P0 ; 判断写入寄存器地址(A0,A1来自锁存地址低两位) JB P1.0,WR_CMD_REG ; $7F00 写入发送FIFO LCALL TX_FIFO_PUSH SJMP BUS_EXIT WR_CMD_REG: MOV CMD_REG,A SJMP BUS_EXIT BUS_RD_OP: JB P1.0,RD_STATUS_LEN ; $7F00 读接收FIFO LCALL RX_FIFO_POP MOV P0,A SJMP BUS_EXIT RD_STATUS_LEN: JB P1.1,RD_FIFO_LEN ; $7F01 读状态寄存器 LCALL GET_STATUS MOV P0,A SJMP BUS_EXIT RD_FIFO_LEN: ; $7F02 返回当前接收FIFO字节数 LCALL GET_RX_COUNT MOV P0,A BUS_EXIT: POP PSW POP ACC RETI ; FIFO入队FC写入发送缓冲区 TX_FIFO_PUSH: PUSH ACC MOV A,TX_TAIL INC A CJNE A,#FIFO_DEPTH,TX_NO_WRAP MOV A,#0 TX_NO_WRAP: CJNE A,TX_HEAD,TX_PUSH_OK POP ACC RET TX_PUSH_OK: MOV R0,#TX_FIFO_BUF ADD A,R0 POP ACC MOV R0,A MOV TX_TAIL,A RET ; FIFO出队FC读取接收缓冲区 RX_FIFO_POP: MOV A,RX_HEAD CJNE A,RX_TAIL,RX_POP_OK MOV A,#0FFH RET RX_POP_OK: MOV R0,#RX_FIFO_BUF ADD A,R0 MOV A,R0 INC RX_HEAD MOV R1,RX_HEAD CJNE R1,#FIFO_DEPTH,RX_NO_WRAP MOV RX_HEAD,#0 RX_NO_WRAP: RET ; 获取状态寄存器值 GET_STATUS: MOV A,#0 ; TX是否有空位 MOV R0,TX_TAIL INC R0 CJNE R0,#FIFO_DEPTH,TX_FREE MOV R0,#0 TX_FREE: CJNE R0,TX_HEAD,SET_TX_RDY SJMP CLR_TX_RDY SET_TX_RDY: SETB ACC.TX_RDY_BIT SJMP CHECK_RX CLR_TX_RDY: CLR ACC.TX_RDY_BIT CHECK_RX: MOV R0,RX_HEAD CJNE R0,RX_TAIL,SET_RX_AVL SJMP STATUS_IRQ SET_RX_AVL: SETB ACC.RX_AVL_BIT STATUS_IRQ: MOV C,CMD_REG.IRQ_PEND_BIT MOV ACC.IRQ_PEND_BIT,C RET ; 获取接收FIFO有效字节数 GET_RX_COUNT: MOV A,RX_TAIL CLR C SUBB A,RX_HEAD JC RX_WRAP_COUNT RET RX_WRAP_COUNT: ADD A,#FIFO_DEPTH RET ; 串口中断接收数据进RX FIFO UART_ISR: PUSH ACC JB RI,UART_RX CLR TI SJMP UART_EXIT UART_RX: CLR RI MOV A,SBUF ; 写入接收FIFO MOV R0,RX_TAIL INC R0 CJNE R0,#FIFO_DEPTH,RX_SAVE MOV R0,#0 RX_SAVE: CJNE R0,RX_HEAD,RX_STORE SJMP UART_EXIT RX_STORE: MOV R1,#RX_FIFO_BUF ADD A,R1 MOV R1,A MOV RX_TAIL,R0 ; 每次收到字节重置超时计时器 MOV RX_TIMEOUT,#0 UART_EXIT: POP ACC RETI END四、FC侧配套极简操作示例6502汇编示意1.FC批量发送数据流程; 循环写入待发数据到FIFO SEND_LOOP: LDA DATA STA $7F00 LDA $7F01 AND #$01 BEQ SEND_LOOP ... ; 全部写完触发批量发送 LDA $7F01 ORA #(12) STA $7F012.FC IRQ中断服务批量读取接收数据FC_IRQ_ISR: PHA LDA $7F02 ; 获取接收总长度 TAX RX_BUF_LOOP: LDA $7F00 STA RX_BUFFER,X DEX BNE RX_BUF_LOOP ; 清除中断标志释放IRQ引脚 LDA $7F01 AND #~(13) STA $7F01 PLA RTI五、稳定性优化补充建议FIFO深度建议固定32字节平衡RAM占用与批量传输效率可根据需求改成16/64字节。串口空闲超时定时器基于T0硬件定时避免软件轮询干扰总线时序。FC读取完整批数据后必须手动清除IRQ_PEND标志STC才会拉高IRQ电平避免重复触发中断。总线锁存器必须靠近FC CPU引脚缩短走线长度减少信号反射与时序畸变。需要我补充一份FC侧6502完整收发测试汇编代码包含IRQ中断服务例程吗