当前位置: 首页 > news >正文

PC16550 C语言版本(适用于8088单板机小型C编译器)

1.程序

/*----------------------------------------------------------- PC16550 UART 接收程序 for 8088 SBC (Small C Compiler) 使用直接端口访问 -----------------------------------------------------------*/ #define BASE_ADDR 0x3F8 /* COM1基地址 */ /* UART寄存器偏移 */ #define UART_RBR 0 /* 接收缓冲寄存器 */ #define UART_THR 0 /* 发送保持寄存器 */ #define UART_DLL 0 /* 除数锁存器低字节 */ #define UART_DLM 1 /* 除数锁存器高字节 */ #define UART_IER 1 /* 中断使能寄存器 */ #define UART_IIR 2 /* 中断识别寄存器 */ #define UART_FCR 2 /* FIFO控制寄存器 */ #define UART_LCR 3 /* 线路控制寄存器 */ #define UART_MCR 4 /* 调制解调器控制寄存器 */ #define UART_LSR 5 /* 线路状态寄存器 */ #define UART_MSR 6 /* 调制解调器状态寄存器 */ /* 线路状态寄存器标志 */ #define LSR_DR 0x01 /* 数据就绪 */ #define LSR_OE 0x02 /* 溢出错 */ #define LSR_PE 0x04 /* 奇偶错 */ #define LSR_FE 0x08 /* 帧错误 */ #define LSR_THRE 0x20 /* 发送保持寄存器空 */ #define LSR_TEMT 0x40 /* 发送移位寄存器空 */ /* 线路控制寄存器标志 */ #define LCR_WL8 0x03 /* 8位数据 */ #define LCR_STOP 0x04 /* 2位停止位 */ #define LCR_DLAB 0x80 /* 除数锁存器访问使能 */ /* 函数声明 */ void outportb(unsigned short port, unsigned char value); unsigned char inportb(unsigned short port); void init_uart(void); unsigned char receive_byte(void); int receive_data(unsigned char *buffer, int max_bytes); void display_string(char *str); void display_char(unsigned char ch); void display_hex(unsigned char value); void delay(unsigned int count); unsigned char check_rx_ready(void); unsigned char get_line_status(void); /*----------------------------------------------------------- 端口输出函数(内联汇编) -----------------------------------------------------------*/ void outportb(unsigned short port, unsigned char value) { __asm { mov dx, port mov al, value out dx, al } } /*----------------------------------------------------------- 端口输入函数(内联汇编) -----------------------------------------------------------*/ unsigned char inportb(unsigned short port) { unsigned char value; __asm { mov dx, port in al, dx mov value, al } return value; } /*----------------------------------------------------------- 初始化UART 设置:9600波特率, 8位数据, 1位停止位, 无校验 -----------------------------------------------------------*/ void init_uart(void) { /* 设置DLAB=1,访问除数锁存器 */ outportb(BASE_ADDR + UART_LCR, LCR_DLAB); delay(100); /* 设置波特率9600 (1843200/16/9600=12) */ outportb(BASE_ADDR + UART_DLL, 12); /* 低字节 */ outportb(BASE_ADDR + UART_DLM, 0); /* 高字节 */ /* 设置数据格式:8位数据,1停止位,无校验 */ outportb(BASE_ADDR + UART_LCR, LCR_WL8); delay(100); /* 使能FIFO,设置触发点为14字节 */ outportb(BASE_ADDR + UART_FCR, 0xC7); /* 使能FIFO,清除FIFO,触发点14 */ /* 使能DTR和RTS */ outportb(BASE_ADDR + UART_MCR, 0x03); /* 禁用中断(使用查询方式) */ outportb(BASE_ADDR + UART_IER, 0); /* 清除接收FIFO */ outportb(BASE_ADDR + UART_FCR, 0x02); display_string("UART initialized at 9600,8,N,1\r\n"); } /*----------------------------------------------------------- 检查是否有数据可接收 返回:1=有数据,0=无数据 -----------------------------------------------------------*/ unsigned char check_rx_ready(void) { unsigned char lsr; lsr = inportb(BASE_ADDR + UART_LSR); return (lsr & LSR_DR) ? 1 : 0; } /*----------------------------------------------------------- 获取线路状态 -----------------------------------------------------------*/ unsigned char get_line_status(void) { return inportb(BASE_ADDR + UART_LSR); } /*----------------------------------------------------------- 接收一个字节(等待) -----------------------------------------------------------*/ unsigned char receive_byte(void) { /* 等待数据就绪 */ while (!check_rx_ready()) { delay(100); } /* 检查错误 */ if (get_line_status() & (LSR_OE | LSR_PE | LSR_FE)) { display_string("Error detected!\r\n"); } /* 读取数据 */ return inportb(BASE_ADDR + UART_RBR); } /*----------------------------------------------------------- 带超时的数据接收 参数:buffer - 接收缓冲区 max_bytes - 最大接收字节数 timeout - 超时时间(毫秒) 返回:实际接收字节数 -----------------------------------------------------------*/ int receive_data_timeout(unsigned char *buffer, int max_bytes, int timeout) { int count = 0; unsigned long start_time; unsigned long current_time; /* 获取开始时间(需要实现timer函数)*/ start_time = get_timer(); while (count < max_bytes) { /* 检查超时 */ current_time = get_timer(); if ((current_time - start_time) > timeout) { break; } if (check_rx_ready()) { buffer[count++] = receive_byte(); start_time = get_timer(); /* 重置超时 */ } delay(100); /* 延时10ms */ } return count; } /*----------------------------------------------------------- 清空接收FIFO -----------------------------------------------------------*/ void clear_rx_fifo(void) { outportb(BASE_ADDR + UART_FCR, 0x02); /* 清除接收FIFO */ outportb(BASE_ADDR + UART_FCR, 0x07); /* 重新使能FIFO */ } /*----------------------------------------------------------- 显示字符串(使用BIOS中断) -----------------------------------------------------------*/ void display_string(char *str) { while (*str) { display_char(*str++); } } /*----------------------------------------------------------- 显示字符(使用BIOS中断) -----------------------------------------------------------*/ void display_char(unsigned char ch) { __asm { mov ah, 0x0e /* BIOS teletype输出 */ mov al, ch mov bh, 0 mov bl, 7 int 0x10 } } /*----------------------------------------------------------- 显示十六进制数 -----------------------------------------------------------*/ void display_hex(unsigned char value) { unsigned char nibble; nibble = (value >> 4) & 0x0F; if (nibble < 10) display_char(nibble + '0'); else display_char(nibble - 10 + 'A'); nibble = value & 0x0F; if (nibble < 10) display_char(nibble + '0'); else display_char(nibble - 10 + 'A'); } /*----------------------------------------------------------- 显示换行 -----------------------------------------------------------*/ void display_newline(void) { display_char(0x0D); display_char(0x0A); } /*----------------------------------------------------------- 简单延时函数(基于循环) -----------------------------------------------------------*/ void delay(unsigned int count) { unsigned int i, j; for (i = 0; i < count; i++) { for (j = 0; j < 100; j++) { /* 空循环 */ } } } /*----------------------------------------------------------- 主程序 -----------------------------------------------------------*/ void main(void) { unsigned char rx_buffer[256]; int rx_count; int i; display_string("\r\nPC16550 UART Receiver for 8088 SBC\r\n"); display_string("==================================\r\n\r\n"); /* 初始化UART */ init_uart(); display_string("Waiting for data...\r\n"); display_string("Press 'Q' to quit\r\n\r\n"); while (1) { /* 检查键盘输入(用于退出)*/ __asm { mov ah, 0x01 /* 检查键盘状态 */ int 0x16 jz no_key mov ah, 0x00 /* 读取按键 */ int 0x16 cmp al, 'q' je exit_program cmp al, 'Q' je exit_program no_key: } /* 检查并接收数据 */ if (check_rx_ready()) { rx_count = receive_data_timeout(rx_buffer, 256, 1000); if (rx_count > 0) { display_string("\r\nReceived "); display_char(rx_count + '0'); display_string(" bytes: "); /* 显示接收的数据 */ for (i = 0; i < rx_count && i < 50; i++) { if (rx_buffer[i] >= 0x20 && rx_buffer[i] <= 0x7E) { display_char(rx_buffer[i]); } else { display_char('.'); } } if (rx_count > 50) { display_string("..."); } display_newline(); /* 以十六进制显示 */ display_string("Hex: "); for (i = 0; i < rx_count && i < 16; i++) { display_hex(rx_buffer[i]); display_char(' '); } display_newline(); } } delay(1000); /* 延时10ms */ } exit_program: display_string("\r\nProgram terminated\r\n"); /* 返回DOS */ __asm { mov ah, 0x4c int 0x21 } }

2.关键特性说明

  1. 直接端口访问:使用IN/OUT指令直接操作PC16550寄存器

  2. 查询方式:不使用中断,通过轮询LSR寄存器检测数据

  3. 错误检测:检测溢出、奇偶和帧错误

  4. FIFO支持:利用PC16550的16字节FIFO

  5. 超时控制:避免无限等待

  6. 键盘控制:按Q键退出程序

3.主要功能函数

  • init_uart()- 初始化UART为9600/8/N/1

  • receive_byte()- 接收单个字节

  • receive_data_timeout()- 带超时的批量接收

  • check_rx_ready()- 检查是否有数据

  • get_line_status()- 获取线路状态

这个程序可以直接在8088单板机(如TPC-1、PC/XT兼容机)上运行,使用DOS或ROM BASIC环境。

http://www.jsqmd.com/news/840628/

相关文章:

  • ETF投资组合优化——Excel实现风险平价与均值方差模型实战
  • 如何三分钟上手iOS游戏修改:H5GG脚本引擎终极指南
  • 从API密钥管理与访问控制角度评估Taotoken的企业级安全特性
  • 地理围栏 PDF 钓鱼与 Cobalt Strike 攻击链分析 —— 以 Ghostwriter 针对乌克兰政府攻击为例
  • 3分钟搞定HS2汉化:Honey Select 2中文补丁一键安装终极指南
  • 中小团队如何利用 Taotoken 统一管理多个 AI 项目的 API 密钥与用量
  • 无电池无线智能纺织传感系统设计与实现
  • 优峰技术:可调谐激光光源选型与采购指南,深圳优峰技术 EXFO 代理优势解析
  • 弃用ChatGPT和Midjourney半年后,我在办公室摆了台AI超算,这笔账算下来惊了
  • VSCode导出PDF样式太丑?手把手教你自定义CSS,让技术简历和报告瞬间专业
  • 2003-2025年政府数字化建设指数
  • 对比直接使用官方API体验Taotoken在路由容灾上的稳定性
  • 华为云IoT设备激活后,如何玩转数据上下行?一个完整的数据流闭环实践
  • 从裸机到微内核:8088单板机微型操作系统规划设计
  • 国内AI搜索优化广告服务公司实力排行盘点 - 奔跑123
  • Ultra96-V2裸机开发实战:从零构建最小系统
  • 基于Python的Telegram Bot开发:模块化设计与自动化任务集成
  • 基于树形结构的代码知识库系统设计与实现
  • 陕西AI搜索优化广告公司排行:全域营销能力实测对比 - 奔跑123
  • MoocDownloader:三步构建个人专属离线学习库的完整指南
  • STC15W4K系列单片机入门指南:从核心特性到上手实践
  • 3步搞定Windows安装Android应用:告别模拟器的终极解决方案
  • MySQL 8.0.34安装选‘传统认证’还是‘强加密’?一次讲清区别和实际影响
  • APK Installer完整指南:3个简单步骤在Windows上安装Android应用
  • 从开关、总线到存储器:图解计算机数据通路,理解累加器R0如何工作
  • ac791 各功能位置
  • Claude Code 插件系统全解析:AI Agent 扩展生态、Marketplace、权限治理、企业级平台化关键技术
  • 【ACM出版、EI检索稳定】第二届大数据、人工智能与数字经济国际学术会议(BDAIE 2026)
  • Windows 11/10系统下,Netcat安装与环境变量配置的保姆级避坑指南(附病毒误报处理)
  • 哔咔漫画下载器:3步打造个人离线漫画库,告别网络限制烦恼