news 2026/6/23 21:11:15

8255驱动数码管动态显示

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
8255驱动数码管动态显示

1.原理图

2.8255的端口地址

_8255_port3 equ 203h ;A 口 _8255_porta equ 200h ;B 口 _8255_portb equ 201h ;C 口 _8255_portc equ 202h ;控制端口

3.动态显示原理

当数码管对应的位码为0时,对应的数码管显示打开,显示内容为此时8255 A口送出的段码。4.

// 数码管段码表 (共阴极) unsigned char seg_codes[] = { 0x3F, // 0 0x06, // 1 0x5B, // 2 0x4F, // 3 0x66, // 4 0x6D, // 5 0x7D, // 6 0x07, // 7 0x7F, // 8 0x6F // 9 };

4.完整的C程序测试代码为

#include "tiny_stdarg.h" // 使用自定义可变参数实现 #define ADR_273 0x0200 #define ADR_244 0x0400 #define LED_PORT 0x800 #define PC16550_THR 0x1f0 #define PC16550_LSR 0x1f5 ///////////////////////////////////////////////////////////////////////////////// //基本的IO操作函数 ///////////////////////////////////////////////////////////////////////////////// char str[]="Hello World! 20250531 Very Ok!!!\r\n"; //char buff[60] char cx='A'; unsigned int cs_adr=0,ds_adr=0,ss_adr=0; //////////////////////////////////////////////////////////////////////////////////// /// @brief /// @param addr /// @param data void outp(unsigned int addr, char data) // 输出一字节到I/O端口 { __asm { mov dx, addr mov al, data out dx, al } } char inp(unsigned int addr) // 从I/O端口输入一字节 { char result; __asm { mov dx, addr in al, dx mov result, al } return result; } void register_read(void) { __asm { mov ax,CS mov cs_adr,ax mov ax,DS mov ds_adr,ax mov ax,SS mov ss_adr,ax } } //////////////////////////////////////////////////////////////////////////////////// //串口发送函数 //////////////////////////////////////////////////////////////////////////////////// void uart_send(char x) { int temp; while(1) { temp=inp(PC16550_LSR); if((temp&0x20)==0x20) { break; } } outp(PC16550_THR,x); } void uart_str_send(char *p) { //int i=0; //char str1[20]="Hello World!\r\n"; //char *p; //p=str1; while(*p!='\0') { uart_send(*p); p++; } /* for(i=0;i<14;i++) { uart_send(str1[i]); } */ } /////////////////////////////////////////////////////////////////////////////////// /* sprintf()函数实现 */ /* tiny_sprintf.c */ #include "tiny_stdarg.h" static void itoa(unsigned num, int base, char *out) { char buf[6]; // 16位整数最大5位数字 + 结束符 char *p = buf; int i = 0; if (num == 0) { *out++ = '0'; *out = '\0'; return; } while (num > 0) { int r = num % base; *p++ = (r < 10) ? (r + '0') : (r - 10 + 'a'); num /= base; i++; } while (i-- > 0) { *out++ = *--p; } *out = '\0'; } int tiny_sprintf(char *buf, const char *fmt, ...) { va_list args; char *p = buf; const char *s = fmt; va_start(args, fmt); while (*s) { if (*s != '%') { *p++ = *s++; continue; } s++; switch (*s) { case 'd': { int num = va_arg(args, int); if (num < 0) { *p++ = '-'; num = -num; } itoa(num, 10, p); while (*p) p++; s++; break; } case 'x': { unsigned num = va_arg(args, unsigned); itoa(num, 16, p); while (*p) p++; s++; break; } case 's': { char *str = va_arg(args, char *); while (*str) *p++ = *str++; s++; break; } case 'c': { char c = (char)va_arg(args, int); *p++ = c; s++; break; } case '%': { *p++ = '%'; s++; break; } default: { *p++ = '%'; *p++ = *s++; break; } } } *p = '\0'; va_end(args); return p - buf; } /////////////////////////////////////////////////////////////////////////////////// //NMI 中断 ////////////////////////////////////////////////////////////////////////////////// /* NMI 计数器 */ volatile unsigned char nmi_count =10; //设置中断失量表 void set_int(unsigned char int_no, void * service_proc) { _asm { push es xor ax, ax mov es, ax mov al, int_no xor ah, ah shl ax, 1 shl ax, 1 mov si, ax mov ax, service_proc mov es:[si], ax inc si inc si mov bx, cs mov es:[si], bx pop es } } //中断处理函数 /* void _interrupt near nmi_handler(void) { nmi_count++; } */ ////////////////////////////////////////////////////////////////////////////////// //8255 ////////////////////////////////////////////////////////////////////////////////// // 定义8255端口地址 (根据原理图译码确定) #define PORT_8255_A 0x200 // PA端口地址 #define PORT_8255_B 0x201 // PB端口地址 #define PORT_8255_C 0x202 // PC端口地址 #define PORT_8255_CTRL 0x203 // 控制寄存器地址 // 数码管段码表 (共阴极) unsigned char seg_codes[] = { 0x3F, // 0 0x06, // 1 0x5B, // 2 0x4F, // 3 0x66, // 4 0x6D, // 5 0x7D, // 6 0x07, // 7 0x7F, // 8 0x6F // 9 }; // 延时函数 void delay(unsigned int ms) { for (unsigned int i = 0; i < ms; i++) { for (unsigned int j = 0; j < 100; j++) { // 空循环延时 } } } // 初始化8255 void init_8255() { // 控制字: 10000001 (0x81) // A口输出, B口输出, C口输出 outp(PORT_8255_CTRL, 0x81); } // 显示8位数字 void display_numbers() { unsigned char digits[] = {1, 2, 3, 4, 5, 6, 7, 8}; // 要显示的数字 while (1) { // 按任意键退出 for (int i = 0; i < 8; i++) { // 设置位选 (选中当前位) outp(PORT_8255_B, ~(1 << i)); // 设置段码 outp(PORT_8255_A, ~seg_codes[digits[i]]); // 延时保持显示 delay(1); // 关闭当前位显示 (消除鬼影) outp(PORT_8255_A, 0x00); } } } ////////////////////////////////////////////////////////////////////////////////// //char end_flag[5]={0x55,0x55,0x55,0x55,0x55}; extern void nmi_handler(void); void main(void) /*检测按键状态并由LED发光二极管显示, 若按键闭合对应LED发光二极管点亮, 若按键断开对应LED发光二极管灭.*/ { int i=0; char buffer[80]; // 使用安全格式化 //tiny_sprintf(buffer, "Hex: %x\n",255); // 使用安全格式化 tiny_sprintf(buffer, "Decimal: %d \n" "Hex: %x \n" "String: %s \r\n", -123, 0xABCD, "Hello"); register_read(); //set_nmi_handler(); set_int(0x02, (void *)&nmi_handler); init_8255(); while (1) { //char button_state; //button_state=inp(ADR_244); //int i=0; //uart_str_send(str); uart_str_send(buffer); tiny_sprintf(buffer,"******************************************\r\n"); uart_str_send(buffer); tiny_sprintf(buffer,"CS_ADR= 0X%x \r\n",cs_adr); uart_str_send(buffer); tiny_sprintf(buffer,"DS_ADR= 0X%x \r\n",ds_adr); uart_str_send(buffer); tiny_sprintf(buffer,"SS_ADR= 0X%x \r\n",ss_adr); uart_str_send(buffer); tiny_sprintf(buffer,"NMI Interrupt count=%x \r\n",nmi_count); uart_str_send(buffer); tiny_sprintf(buffer,"******************************************\r\n"); uart_str_send(buffer); //uart_send(cx); for(i=0;i<5000;i++); for(i=0;i<5000;i++); outp(LED_PORT, 0xff); for(i=0;i<5000;i++); for(i=0;i<5000;i++); outp(LED_PORT, 0x00); display_numbers(); } } char end_flag[5]={0x55,0x55,0x55,0x55,0x55};

5.完整的汇编测试代码为

;------------------------------------------------------------------------------------------- ;2017.9.15 ;用nasm重新写原来的代码 ;推出配套的《在做中学微机原理》课程,与所销售的硬件相配套 ;从第一行程序开教,一步一步带你走入神秘的8086世界。 ; ;例程001 ;ex1.asm =example_1 ;8088启动,点亮系统板上的LED ;重点在于正确使用程序编辑环境,nasm汇编方法,EEprom的烧写方法 ; ;ex001----用下载到RAM中的程序,点亮系统板上的LED ;8088.asm是汇编源程序 ;8088.bin是编译生成的可下载执行的最终代码 ; ;编译很简单,双击make即可自动完成 ; ;Notepad++是我计算机上Notepad++的快捷方式 ;--------------------------------------------------------------------------------------------- led_port equ 800h _8255_port3 equ 203h _8255_porta equ 200h _8255_portb equ 201h _8255_portc equ 202h ;--------------------------------------------------------------------------------------------- org 2000h ;程序将由监控bios下载到内存RAM的地址(0000:2000) start: ;------------------------------------------------------ ;init part ;------------------------------------------------------ mov ax,0 mov ds,ax mov ss,ax mov sp,1fffh ;--------------------------------------------------------- ;8255 init ;--------------------------------------------------------- call _8255_init ;mov al,[LED_CODE] ;mov dx,_8255_porta ;out dx,al ;mov al,0feh ;mov dx,_8255_portb ;out dx,al st001: nop call _8255_disp ;----------------------------------------------------- ;点亮系统板上的LED ;----------------------------------------------------- ;MOV DX,800H ;800H是板子上8个LED的端口地址号 mov dx,led_port MOV AL,0aaH ;一亮一灭间隔点亮 OUT DX,AL call DELAY ;MOV DX,800H ;800H是板子上8个LED的端口地址号 mov dx,led_port MOV AL,00H ;一亮一灭间隔点亮 OUT DX,AL call DELAY mov ah,'$' call SEND ; lea di,STR1 ;nasm编译器不认 mov di, STR1 CALL STR_OUT mov di, STR3 CALL STR_OUT ;mov al,01010101b ;mov al,0f0h; ;out 25H,al ;hlt jmp st001 jmp start ;------------------------------------------------------------ ; DELAY PROC NEAR ;------------------------------------------------------------ ;push DELAY: PUSH CX PUSH BX NOP NOP mov bx,10 del1: mov cx,5882 del2: loop del2 dec bx jnz del1 ;pop cx ;pop bx POP BX POP CX RET ;------------------------------------------- ;pc16550 uart send by AH ;------------------------------------------- LSTAT EQU 1F5H DAT_165 EQU 1F0H SEND: ; PROC NEAR MOV DX,LSTAT WAITx: IN AL,DX TEST AL,20H JZ WAITx MOV AL,AH MOV DX,DAT_165 OUT DX,AL RET ;SEND ENDP ;------------------------------------------- ;串口打印字符串 ;------------------------------------------- STR_OUT :; PROC NEAR nop; LEA DI,STR1 STR_LOOP: ;MOV AH,BYTE PTR [DI] mov ah,byte [di] CMP AH,'$' JZ STR_EXIT CALL SEND INC DI JMP STR_LOOP STR_EXIT: NOP RET ;----------------------------- ;8255 init ;----------------------------- _8255_init: ;mov dx,203h mov dx, _8255_port3 ;mov al,80h mov al,89h;port a,b as output port c as input out dx,al ret _8255_disp: ;bit 0 mov al,[LED_CODE] mov dx,_8255_porta out dx,al ;mov al,0feh mov al, 011111110b mov dx,_8255_portb out dx,al call DELAY ;bit 1 mov al,[LED_CODE+1] mov dx,_8255_porta out dx,al ;mov al,0feh mov al, 011111101b mov dx,_8255_portb out dx,al call DELAY ;bit 2 mov al,[LED_CODE+2] mov dx,_8255_porta out dx,al ;mov al,0feh mov al, 011111011b mov dx,_8255_portb out dx,al call DELAY ;bit 3 mov al,[LED_CODE+3] mov dx,_8255_porta out dx,al ;mov al,0feh mov al, 011110111b mov dx,_8255_portb out dx,al call DELAY ;bit 4 mov al,[LED_CODE+4] mov dx,_8255_porta out dx,al ;mov al,0feh mov al, 011101111b mov dx,_8255_portb out dx,al call DELAY ;bit 5 mov al,[LED_CODE+5] mov dx,_8255_porta out dx,al ;mov al,0feh mov al, 011011111b mov dx,_8255_portb out dx,al call DELAY ;bit 6 mov al,[LED_CODE+6] mov dx,_8255_porta out dx,al ;mov al,0feh mov al, 010111111b mov dx,_8255_portb out dx,al call DELAY ;bit 7 mov al,[LED_CODE+7] mov dx,_8255_porta out dx,al ;mov al,0feh mov al, 001111111b mov dx,_8255_portb out dx,al call DELAY ret ;STR_OUT ENDP STR1 DB 'i8088-HELLO boy or girl!' ,13,10,'$' STR2 DB 0AH,0DH,' ',0dh,0ah,'$' STR3 db 'ex004---8255 disp demo',13,10,'$' LED_CODE db 0C0h,0F9h,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H db 55h,55h,55h,55h,55h,55h ;程序结束标志,监控bios程序,收到后自动跳转到内存0000:2000处执行 ;----------------------------------------------------------------------------------------------
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/23 20:47:35

JAVA打造同城羽馆预约,一键畅享运动

利用 JAVA 开发同城羽毛球馆预约系统&#xff0c;可以结合 高并发处理、实时交互、多端适配 等特性&#xff0c;打造一个 “一键预约、智能匹配、全流程数字化” 的运动服务平台&#xff0c;让用户轻松畅享羽毛球运动的乐趣。以下是具体实现方案与核心功能设计&#xff1a;一、…

作者头像 李华
网站建设 2026/6/23 9:57:40

经验贴 | 科学制定招聘需求与预算:HR 必看的逻辑与实操要点

招聘是企业补充人才、保障发展的核心环节&#xff0c;而科学制定招聘需求与预算则是招聘工作高效落地的前提。不少 HR 在实际工作中会陷入 “需求模糊导致招聘偏差”“预算失控造成资源浪费” 的困境&#xff0c;既影响招聘效率&#xff0c;也难以匹配业务发展诉求。本文结合实…

作者头像 李华
网站建设 2026/6/23 13:36:19

经验贴 | AI 面试评估系统怎么用?HR 高效识人实操指南

在企业招聘中&#xff0c;HR 常面临简历筛选效率低、面试评估主观化、优质人才流失快等难题。尤其是大规模校招或社招时&#xff0c;海量候选人让招聘团队不堪重负&#xff0c;传统面试评估方式难以保证公平性和准确性。AI 面试评估系统作为智能化招聘的核心工具&#xff0c;通…

作者头像 李华
网站建设 2026/6/23 17:48:20

构建个性化AI助手:LobeChat会话管理功能深度使用技巧

构建个性化AI助手&#xff1a;LobeChat会话管理功能深度使用技巧 在今天&#xff0c;每个人都在尝试打造属于自己的AI助手——无论是用来写代码、处理客服问题&#xff0c;还是辅助学习和创作。但现实是&#xff0c;即便你接入了最先进的大模型&#xff0c;如果交互界面混乱、上…

作者头像 李华
网站建设 2026/6/23 16:12:10

基于昇腾NPU的YOLOV8-seg c++部署

文章目录 实例分割 YOLOv8-seg的输入 YOLOv8-Seg的输出 核心代码 参考 实例分割 实例分割与对象检测类似,但它确定图像中的哪些像素属于对象,而不是寻找包围对象的框。这通常会产生某种掩码,例如二进制掩码。例如,在下面您可以看到两个二元蒙版,一个用于长颈鹿,一个用于…

作者头像 李华
网站建设 2026/6/23 17:47:11

26、深入探索脚本编程与系统安全基础

深入探索脚本编程与系统安全基础 1. 条件表达式的运用 脚本语言支持多种条件表达式,这些表达式能让脚本根据特定条件(通常是变量的值)执行不同操作。其中, if 是常用的使用条件表达式的命令,它能让系统依据条件的真假执行两种不同操作。 if 关键字后的条件表达式放在…

作者头像 李华