1.实现目标
把汇编编写的Intel8259中断接收程序,转成C语言实现。
2.串口芯片PC16550初始化
直接适用嵌入式汇编实现。
cpp
/* ; 16550寄存器偏移
UART_BASE EQU 100H
RBR_THR EQU UART_BASE + 0 ; 接收缓冲/发送保持寄存器
IER EQU UART_BASE + 1 ; 中断使能寄存器
IIR_FCR EQU UART_BASE + 2 ; 中断标识/FIFO控制寄存器
LCR EQU UART_BASE + 3 ; 线路控制寄存器
MCR EQU UART_BASE + 4 ; 调制解调器控制寄存器
LSR EQU UART_BASE + 5 ; 线路状态寄存器
DLL EQU UART_BASE + 0 ; 除数锁存低字节 (DLAB=1)
DLM EQU UART_BASE + 1 ; 除数锁存高字节 (DLAB=1) */
#define UART_BASE 0x100
#define RBR_THR UART_BASE+0
#define IER UART_BASE+1
#define IIR_FCR UART_BASE+2
#define LCR UART_BASE+3
#define MCR UART_BASE+4
#define LSR UART_BASE+5
#define DLL UART_BASE+0
#define DLM UART_BASE+1
//#define RBR_THR UART_BASE+0
void uart_pc16550_init(void)
{
__asm
{
; 设置波特率除数 (9600 @ 18.432MHz)
MOV DX, LCR
MOV AL, 80H ; 设置DLAB=1
OUT DX, AL
MOV DX, DLL ; 除数锁存低字节
MOV AL, 78H ; 120 = 78H (18.432MHz / (16 * 9600))
OUT DX, AL
MOV DX, DLM ; 除数锁存高字节
MOV AL, 00H
OUT DX, AL
; 设置线路参数: 8位数据, 1停止位, 无校验
MOV DX, LCR
MOV AL, 03H ; 8N1, DLAB=0
OUT DX, AL
; 启用并复位FIFO
MOV DX, IIR_FCR
MOV AL, 0C7H ; 启用FIFO, 14字节触发点, 清除接收FIFO
OUT DX, AL
; 设置调制解调器控制
MOV DX, MCR
MOV AL, 0BH ; 启用OUT2(中断使能), RTS和DTR
OUT DX, AL
; 启用接收数据中断
MOV DX, IER
MOV AL, 01H ; 仅启用接收数据中断
OUT DX, AL
}
}
2.Intel8259设置
cpp
//////////////////////////////////////////////////////////////////////////////////
//8259 part
//////////////////////////////////////////////////////////////////////////////////
#define PIC1_CMD 0x400 // 命令端口 (A0=0)
#define PIC1_DATA 0x402 // 数据端口 (A0=1) !!!!!!!!!!
// 初始化8259(设置自动EOI)
void init_8259(void) {
// ICW1: 边沿触发 | 单片 | 需要ICW4
outp(PIC1_CMD, 0x17);
// ICW2: 中断向量基址=20h
outp(PIC1_DATA, 0x08);
// ICW4: 8086模式 | 自动EOI (0x03)d
outp(PIC1_DATA, 0x0f); // 关键修改:设置自动EOI模式
// OCW1: 只允许IR0中断 (11111110b)
// outp(PIC1_DATA, 0xfe);
outp(PIC1_DATA, 0xfd); // OCW1: 只允许IR0,IR1中断 (111111100b)
}
3.完整汇编源程序
cpp
; =============================================
; PC16550 UART接收中断处理示例
; 功能: 接收字符并回显,显示中断触发与释放状态
; 硬件配置:
; - UART基地址: 100H
; - 8259 PIC端口: 400H(命令), 402H(数据)
; - 中断请求线: IRQ1 (8259 IR1)
; - 中断向量号: 21H
; - 时钟频率: 18.432MHz
; - 波特率: 9600 bps (除数78H)
; =============================================
ORG 100H
JMP INITIALIZATION ; 跳过数据区到初始化代码
; 数据段定义
int_triggered DB 0 ; 中断触发标志
int_released DB 0 ; 中断释放标志
recv_char DB 'A' ; 接收的字符
; 状态消息
trigger_msg DB 0Dh, 0Ah, '>>> Interrupt TRIGGERED', 0
release_msg DB 0Dh, 0Ah, '<<< Interrupt RELEASED (EOI sent)', 0
recv_msg DB 0Dh, 0Ah, 'Received char: ', 0
start_msg DB 0Dh, 0Ah, 'UART Interrupt Demo Started', 0Dh, 0Ah
DB 'Send characters to test interrupt...', 0Dh, 0Ah, 0
end_msg DB 0Dh, 0Ah, 'Program terminated.', 0Dh, 0Ah, 0
; 16550寄存器偏移
UART_BASE EQU 100H
RBR_THR EQU UART_BASE + 0 ; 接收缓冲/发送保持寄存器
IER EQU UART_BASE + 1 ; 中断使能寄存器
IIR_FCR EQU UART_BASE + 2 ; 中断标识/FIFO控制寄存器
LCR EQU UART_BASE + 3 ; 线路控制寄存器
MCR EQU UART_BASE + 4 ; 调制解调器控制寄存器
LSR EQU UART_BASE + 5 ; 线路状态寄存器
DLL EQU UART_BASE + 0 ; 除数锁存低字节 (DLAB=1)
DLM EQU UART_BASE + 1 ; 除数锁存高字节 (DLAB=1)
; 8259 PIC端口
PIC_CMD EQU 400H
PIC_DATA EQU 402H
; 中断向量号
UART_IRQ EQU 21H ; IRQ1对应中断21H
; =============================================
; UART初始化子程序
; =============================================
INIT_UART:
; 设置波特率除数 (9600 @ 18.432MHz)
MOV DX, LCR
MOV AL, 80H ; 设置DLAB=1
OUT DX, AL
MOV DX, DLL ; 除数锁存低字节
MOV AL, 78H ; 120 = 78H (18.432MHz / (16 * 9600))
OUT DX, AL
MOV DX, DLM ; 除数锁存高字节
MOV AL, 00H
OUT DX, AL
; 设置线路参数: 8位数据, 1停止位, 无校验
MOV DX, LCR
MOV AL, 03H ; 8N1, DLAB=0
OUT DX, AL
; 启用并复位FIFO
MOV DX, IIR_FCR
MOV AL, 0C7H ; 启用FIFO, 14字节触发点, 清除接收FIFO
OUT DX, AL
; 设置调制解调器控制
MOV DX, MCR
MOV AL, 0BH ; 启用OUT2(中断使能), RTS和DTR
OUT DX, AL
; 启用接收数据中断
MOV DX, IER
MOV AL, 01H ; 仅启用接收数据中断
OUT DX, AL
RET
; =============================================
; 8259 PIC初始化
; =============================================
INIT_PIC:
; 初始化8259
MOV DX, PIC_CMD
MOV AL, 17H ; ICW1: 边沿触发, 级联, 需要ICW4
OUT DX, AL
MOV DX, PIC_DATA
MOV AL, UART_IRQ-1 ; ICW2: 中断向量基值
OUT DX, AL
MOV AL, 01H ; ICW4: 8086模式, 非缓冲, 正常EOI
OUT DX, AL
; 允许IRQ1中断
IN AL, DX
AND AL, 0FDH ; 清除IRQ1屏蔽位(11111101)
OUT DX, AL
RET
; =============================================
; 设置中断向量
; =============================================
SET_INTERRUPT_VECTOR:
CLI ; 关中断
XOR AX, AX
MOV ES, AX ; ES = 0 (中断向量表段地址)
; 计算中断向量位置 (中断号 * 4)
MOV AX, UART_IRQ
SHL AX, 2 ; 乘以4
; 设置中断向量
MOV DI, AX
MOV AX, OFFSET UART_ISR
CLD
STOSW ; 存储偏移地址
MOV AX, CS
STOSW ; 存储段地址
STI ; 开中断
RET
; =============================================
; UART中断服务程序 (IRQ1)
; 演示中断触发和释放过程
; =============================================
UART_ISR PROC FAR
; 保存寄存器
PUSH AX
PUSH DX
PUSH DS
; 设置DS为当前数据段
MOV AX, CS
MOV DS, AX
; 设置中断触发标志
MOV [int_triggered], 1
; 发送中断触发消息
MOV SI, OFFSET trigger_msg
CALL SEND_STRING
;ISR_LOOP:
; ; 检查中断源
; MOV DX, IIR_FCR
; IN AL, DX
; TEST AL, 01H ; 检查是否有待处理中断 (bit0=1表示无中断)
; JNZ ISR_EXIT ; 无中断则退出
;
; ; 检查是否为接收数据中断
; TEST AL, 04H ; 检查中断类型位 (bit1-2)
; JNZ CHECK_OTHER ; 不是接收中断则检查其他
;
; ; 处理接收数据中断
; MOV DX, RBR_THR
; IN AL, DX ; 读取接收到的字符
; MOV [recv_char], AL ; 保存字符
;
; ; 发送接收消息
; MOV SI, OFFSET recv_msg
; CALL SEND_STRING
; MOV AL, [recv_char]
; CALL SEND_CHAR
;
; ; 继续检查其他中断
; JMP ISR_LOOP
;
;CHECK_OTHER:
; ; 可以添加其他中断类型的处理
; ; ...
;
ISR_EXIT:
; 发送中断释放消息
MOV SI, OFFSET release_msg
CALL SEND_STRING
; ; 发送EOI到8259
; MOV AL, 20H
; MOV DX, PIC_CMD
; OUT DX, AL
;
; ; 设置中断释放标志
; MOV [int_released], 1
CALL CLEAR_ALL_INTERRUPTS
; 恢复寄存器
POP DS
POP DX
POP AX
IRET
UART_ISR ENDP
; =============================================
; 串口发送字符子程序
; 输入: AL = 要发送的字符
; =============================================
SEND_CHAR:
PUSH AX
PUSH DX
; 保存字符
MOV AH, AL
SEND_WAIT:
; 检查发送保持寄存器是否为空
MOV DX, LSR
IN AL, DX
TEST AL, 20H ; 检查THRE位(bit5)
JZ SEND_WAIT ; 不为空则等待
; 发送字符
MOV DX, RBR_THR
MOV AL, AH
OUT DX, AL
POP DX
POP AX
RET
; =============================================
; 串口发送字符串
; 输入: SI = 字符串偏移地址
; =============================================
SEND_STRING:
PUSH AX
PUSH SI
SEND_STR_LOOP:
LODSB ; 加载字符到AL
OR AL, AL ; 检查是否结束(0)
JZ SEND_STR_DONE ; 是则结束
CALL SEND_CHAR ; 发送字符
JMP SEND_STR_LOOP ; 继续发送
SEND_STR_DONE:
POP SI
POP AX
RET
; =============================================
; 强制清除所有中断状态
; =============================================
CLEAR_ALL_INTERRUPTS:
; 读取所有状态寄存器以清除中断
; MOV DX, LSR
; IN AL, DX ; 清除线路状态中断
MOV DX, MCR
IN AL, DX ; 清除调制解调器状态中断
READ_AGAIN:
MOV DX, RBR_THR
IN AL, DX ; 清除接收数据中断
MOV [recv_char], AL ; 保存字符
CALL SEND_CHAR
MOV DX, LSR
IN AL, DX ; 清除线路状态中断
TEST AL,01H ; 1---fifo 不空 0---FIFO 空
JNZ READ_AGAIN ;不空,继续读取
;
; MOV DX, IIR_FCR
; IN AL, DX ; 清除中断标识
;
; 发送EOI到8259
MOV AL, 20H
MOV DX, PIC_CMD
OUT DX, AL
RET
; =============================================
; 主初始化程序
; =============================================
INITIALIZATION:
; 初始化标志
CLI
MOV AX,01F0H ;老版BIOS重新设置CS寄存器地址为01F0H
MOV DS,AX
MOV SS,AX
MOV ES,AX
MOV AX,5FFFH
MOV SP,AX
;MOV AX,0000H ;CS 老版BIOS重新设置CS寄存器地址为01F0H
;PUSH AX
;MOV AX,OFFSET START123 ;IP
;PUSH AX
; IRET
;MOV SS,AX
;MOV DS,AX
;MOV AX, 01F0H
START123:
NOP
NOP
MOV [int_triggered], 0
MOV [int_released], 0
; 初始化UART
CALL INIT_UART
; 初始化8259 PIC
CALL INIT_PIC
; 设置中断向量
CALL SET_INTERRUPT_VECTOR
; 通过串口发送启动消息
MOV SI, OFFSET start_msg
CALL SEND_STRING
STI
; =============================================
; 主程序循环
; =============================================
MAIN_LOOP:
; 可以在这里添加其他任务
; 例如: 检查中断标志状态等
; 简单的延时循环
MOV CX, 0FFFFH
DELAY_LOOP:
LOOP DELAY_LOOP
; 检查退出条件(可选)
; ...
;CALL CLEAR_ALL_INTERRUPTS
; MOV AL, [recv_char]
; CALL SEND_CHAR
JMP MAIN_LOOP
DB 55H,55H,55H,55H,55H
; =============================================
; 退出程序(可选)
; =============================================
; 此示例程序将无限运行
; 在实际应用中可添加退出逻辑
4.完整C程序
cpp
#include "tiny_stdarg.h" // 使用自定义可变参数实现
#define ADR_273 0x0200
#define ADR_244 0x0400
#define LED_PORT 0x800
#define PC16550_THR 0x1f0
#define PC16550_LSR 0x1f5
/* ; 16550寄存器偏移
UART_BASE EQU 100H
RBR_THR EQU UART_BASE + 0 ; 接收缓冲/发送保持寄存器
IER EQU UART_BASE + 1 ; 中断使能寄存器
IIR_FCR EQU UART_BASE + 2 ; 中断标识/FIFO控制寄存器
LCR EQU UART_BASE + 3 ; 线路控制寄存器
MCR EQU UART_BASE + 4 ; 调制解调器控制寄存器
LSR EQU UART_BASE + 5 ; 线路状态寄存器
DLL EQU UART_BASE + 0 ; 除数锁存低字节 (DLAB=1)
DLM EQU UART_BASE + 1 ; 除数锁存高字节 (DLAB=1) */
#define UART_BASE 0x100
#define RBR_THR UART_BASE+0
#define IER UART_BASE+1
#define IIR_FCR UART_BASE+2
#define LCR UART_BASE+3
#define MCR UART_BASE+4
#define LSR UART_BASE+5
#define DLL UART_BASE+0
#define DLM UART_BASE+1
//#define RBR_THR UART_BASE+0
void uart_pc16550_init(void)
{
__asm
{
; 设置波特率除数 (9600 @ 18.432MHz)
MOV DX, LCR
MOV AL, 80H ; 设置DLAB=1
OUT DX, AL
MOV DX, DLL ; 除数锁存低字节
MOV AL, 78H ; 120 = 78H (18.432MHz / (16 * 9600))
OUT DX, AL
MOV DX, DLM ; 除数锁存高字节
MOV AL, 00H
OUT DX, AL
; 设置线路参数: 8位数据, 1停止位, 无校验
MOV DX, LCR
MOV AL, 03H ; 8N1, DLAB=0
OUT DX, AL
; 启用并复位FIFO
MOV DX, IIR_FCR
MOV AL, 0C7H ; 启用FIFO, 14字节触发点, 清除接收FIFO
OUT DX, AL
; 设置调制解调器控制
MOV DX, MCR
MOV AL, 0BH ; 启用OUT2(中断使能), RTS和DTR
OUT DX, AL
; 启用接收数据中断
MOV DX, IER
MOV AL, 01H ; 仅启用接收数据中断
OUT DX, AL
}
}
/////////////////////////////////////////////////////////////////////////////////
//基本的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);
}
}
}
//定时中断,8位数码管动态显示
//int ip_disp=0;
char buffer[80];
void uart_fifo_read(void);
void display_intr()
{
unsigned char digits[] = {1, 2, 3, 4, 5, 6, 7, 8}; // 要显示的数字
static int ip_disp=0;
tiny_sprintf(buffer,"%%%%%%%%%%%%%%%%%%\r\n");
uart_str_send(buffer);
// 设置位选 (选中当前位)
outp(PORT_8255_B, ~(1 << ip_disp));
// 设置段码
outp(PORT_8255_A, ~seg_codes[digits[ip_disp]]);
//outp(PORT_8255_A, 0x06);
// 延时保持显示
delay(1);
uart_fifo_read();
// 关闭当前位显示 (消除鬼影)
//outp(PORT_8255_A, 0x00);
ip_disp++;
if(ip_disp>7)
{ip_disp=0;}
}
//////////////////////////////////////////////////////////////////////////////////
//8253 part
//////////////////////////////////////////////////////////////////////////////////
// 8253定时器端口定义
#define PORT_8253_CNT0 0x300 // 计数器0地址
#define PORT_8253_CNT1 0x301 // 计数器1地址
#define PORT_8253_CNT2 0x302 // 计数器2地址
#define PORT_8253_CTRL 0x303 // 控制寄存器地址
// 时钟频率定义 (根据原理图第4页)
#define PCLK_FREQUENCY 1193182 // 标准8253时钟频率(1.193182MHz)
//#define OUTPUT_FREQUENCY 200 // 目标输出频率(1kHz)
#define OUTPUT_FREQUENCY 20 // 目标输出频率(1kHz)
// 计算计数器初值
#define COUNTER_VALUE (unsigned int)(PCLK_FREQUENCY / OUTPUT_FREQUENCY)
// 初始化8253定时器
void init_8253() {
// 控制字: 00110110 (0x36)
// 选择计数器0 | 写入高低字节 | 模式3(方波) | 二进制计数
outp(PORT_8253_CTRL, 0x36);
// 写入计数器初值 (先低字节后高字节)
outp(PORT_8253_CNT0, COUNTER_VALUE & 0xFF); // 低字节
outp(PORT_8253_CNT0, (COUNTER_VALUE >> 8) & 0xFF); // 高字节
}
//////////////////////////////////////////////////////////////////////////////////
//8259 part
//////////////////////////////////////////////////////////////////////////////////
#define PIC1_CMD 0x400 // 命令端口 (A0=0)
#define PIC1_DATA 0x402 // 数据端口 (A0=1) !!!!!!!!!!
// 初始化8259(设置自动EOI)
void init_8259(void) {
// ICW1: 边沿触发 | 单片 | 需要ICW4
outp(PIC1_CMD, 0x17);
// ICW2: 中断向量基址=20h
outp(PIC1_DATA, 0x08);
// ICW4: 8086模式 | 自动EOI (0x03)d
outp(PIC1_DATA, 0x0f); // 关键修改:设置自动EOI模式
// OCW1: 只允许IR0中断 (11111110b)
// outp(PIC1_DATA, 0xfe);
outp(PIC1_DATA, 0xfd); // OCW1: 只允许IR0,IR1中断 (111111100b)
}
//////////////////////////////////////////////////////////////////////////////////
//char end_flag[5]={0x55,0x55,0x55,0x55,0x55};
extern void nmi_handler(void);
//////////////////////////////////////////////////////////////////////
//timer clock
/////////////////////////////////////////////////////////////////////
//声明时钟结构体类型
typedef struct
{
int hour;
int min;
int sec;
/* data */
}TIMER_CLOCK;
TIMER_CLOCK *t_clock;//定义时钟结构体变量
void t_clock_init(TIMER_CLOCK *p)//时钟变量初始化
{
p->hour=12;
p->min=59;
p->sec=00;
}
void t_clock_uart_out(TIMER_CLOCK *p)
{
char buffer[80];
tiny_sprintf(buffer,"******************************************\r\n");
uart_str_send(buffer);
tiny_sprintf(buffer,"Clock Hour= %d \r\n",p->hour);
uart_str_send(buffer);
tiny_sprintf(buffer,"Clock min= %d \r\n",p->min);
uart_str_send(buffer);
tiny_sprintf(buffer,"Clock sec= %d \r\n",p->sec);
uart_str_send(buffer);
tiny_sprintf(buffer,"******************************************\r\n");
uart_str_send(buffer);
}
unsigned char r_data=0;
void uart_fifo_read(void)
{
__asm
{
READ_AGAIN:
MOV DX, RBR_THR
IN AL, DX ; 清除接收数据中断
MOV r_data, AL ; 保存字符
;CALL SEND_CHAR
MOV DX, LSR
IN AL, DX ; 清除线路状态中断
TEST AL,01H ; 1---fifo 不空 0---FIFO 空
JNZ READ_AGAIN ;不空,继续读取
}
}
/////////////////////////////////////////////////////////////////////
/// @param
void main(void)
/*检测按键状态并由LED发光二极管显示,
若按键闭合对应LED发光二极管点亮,
若按键断开对应LED发光二极管灭.*/
{
int i=0;
char buffer[80];
unsigned char key_code=0xff; // 使用安全格式化
//tiny_sprintf(buffer, "Hex: %x\n",255);
// 使用安全格式化
asm cli
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);
set_int(0x08, (void *)&nmi_handler);//8259 与NMI共用一个中断服务函数
set_int(0x09, (void *)&nmi_handler);//8259 与NMI共用一个中断服务函数
init_8255();
init_8253();
uart_pc16550_init();
asm cli
init_8259();
asm nop
asm sti
t_clock_init(t_clock);
while (1)
{
//char button_state;
//button_state=inp(ADR_244);
//int i=0;
//uart_str_send(str);
t_clock_uart_out(t_clock);
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,"8259 Interrupt count=%d \r\n",nmi_count);
uart_str_send(buffer);
tiny_sprintf(buffer,"******************************************\r\n");
uart_str_send(buffer);
key_code=inp(PORT_8255_C)&0x0f;
tiny_sprintf(buffer,"Key_code= 0X%x \r\n",key_code);
uart_str_send(buffer);
tiny_sprintf(buffer,"uart_get_data=%c \r\n",r_data);
uart_str_send(buffer);
//asm int 8
//uart_send(cx);
//display_intr();
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.测试结果
