babyos2(7)——键盘中断、时钟中断、实时钟
来源:互联网 发布:拍照最好的手机 知乎 编辑:程序博客网 时间:2024/06/05 22:58
babyos2暂时还是使用8259a作为中断控制器,后续可能会尝试使用APIC。
/* * guzhoudiaoke@126.com * 2017-11-7 */#ifndef _I8259A_H_#define _I8259A_H_#include "types.h"#define IRQ_0 (0x20)#define IRQ_NUM (0x10)#define IRQ_TIMER (0x0)#define IRQ_KEYBOARD (0x1)#define IRQ_HARDDISK (0xe)#define IRQ_SYSCALL (0x80)class i8259a_t {public: i8259a_t(); ~i8259a_t(); void init(); void enable_irq(uint32 irq);};#endif/* * guzhoudiaoke@126.com * 2017-11-7 */#include "i8259a.h"#include "x86.h"i8259a_t::i8259a_t(){}i8259a_t::~i8259a_t(){}void i8259a_t::init(){ //console()->kprintf(WHITE, "i8259a_t::init()\n"); /* ICW1:0x11, 表示边沿触发、多片级联、需要发送ICW4 */ outb(0x20, 0x11); outb(0xa0, 0x11); /* ICW2: * 重新映射 IRQ0~IRQ7 到 0x20~0x27,重新映射 IRQ8~IRQ15 到 0x28~0x2F */ outb(0x21, 0x20); outb(0xa1, 0x28); /* ICW3: * A0 D7 D6 D5 D4 D3 D2 D1 D0 * master 1 S7 S6 S5 S4 S3 S2 S1 S0 * slave 1 0 0 0 0 0 ID2 ID1 ID0 * master: 0x04,表示主芯片的IR2引脚连接一个从芯片 * slave: 0x02,表示从片连接到主片的IR2 引脚 */ outb(0x21, 0x04); outb(0xa1, 0x02); /* 从片连接到主片的 IRQ2 */ /* ICW4:0x01,表示8259A芯片被设置成普通嵌套、非中断方式、 * 用于8086 及其兼容模式 */ outb(0x21, 0x01); outb(0xa1, 0x01); /* disable all interrupts */ outb(0x21, 0xff); outb(0xa1, 0xff);}void i8259a_t::enable_irq(uint32 irq){ uint8 mask; if (irq < 8) { mask = inb(0x21) & (0xff ^ (1 << irq)); outb(0x21, mask); } else if (irq < 16) { mask = inb(0x21) & 0xfb; outb(0x21, mask); mask = inb(0xa1) & (0xff ^ (1 << (irq-8))); outb(0xa1, mask); }}
8259a的初始化及开启特定中断代码如上所示。关于8259a编程可以找特定的文档,在此不多做描述。
/* * guzhoudiaoke@126.com * 2017-10-27 */#ifndef _KEYBOARD_H_#define _KEYBOARD_H_#include "types.h"#include "queue.h"#define NR_SCAN_CODES 0x80 /* 扫描码个数 */#define NR_CODE_COL 0x03 /* 扫描码列数 *//* 简单起见暂时先把键盘上所有键分为7类,分类来给每个键一个唯一标号(一个类号,一个标识号): * 可打印的字符、特殊字符、功能键、转换键、锁定键、小键盘上的键、APIC键 */#define KT_ASCII 0 /* 可打印字符键 */#define KT_SPECIAL 1 /* 特殊字符键 */#define KT_FUNCTION 2 /* 功能键 */#define KT_SHIFT 3 /* 转换键 */#define KT_LOCK 4 /* 锁定键 */#define KT_CONTROL 5 /* 中间方向键等控制键盘 */#define KT_PAD 6 /* 小键盘 */#define KT_APIC 7 /* APIC键 *//* KEY用来构造一个唯一标号 * KEY_TYPE用来获得键的类型 * KEY_VALUE用来得到键的值 */#define KEY(type, value) (((type) << 8) | (value))#define KEY_TYPE(x) ((x) >> 8)#define KEY_VALUE(x) ((x) & 0xff)/* 功能键 */#define K_F0 KEY(KT_FUNCTION, 0)#define K_F1 KEY(KT_FUNCTION, 1)#define K_F2 KEY(KT_FUNCTION, 2)#define K_F3 KEY(KT_FUNCTION, 3)#define K_F4 KEY(KT_FUNCTION, 4)#define K_F5 KEY(KT_FUNCTION, 5)#define K_F6 KEY(KT_FUNCTION, 6)#define K_F7 KEY(KT_FUNCTION, 7)#define K_F8 KEY(KT_FUNCTION, 8)#define K_F9 KEY(KT_FUNCTION, 9)#define K_F10 KEY(KT_FUNCTION, 10)#define K_F11 KEY(KT_FUNCTION, 11)#define K_F12 KEY(KT_FUNCTION, 12)/* 特殊字符键 */#define K_ESC KEY(KT_SPECIAL, 0)#define K_BACKSPACE KEY(KT_SPECIAL, 1)#define K_TAB KEY(KT_SPECIAL, 2)#define K_ENTER KEY(KT_SPECIAL, 3)#define K_GUI_L KEY(KT_SPECIAL, 4)#define K_GUI_R KEY(KT_SPECIAL, 5)#define K_APPS KEY(KT_SPECIAL, 6)/* 转换键 */#define K_SHIFT_L KEY(KT_SHIFT, 0)#define K_SHIFT_R KEY(KT_SHIFT, 1)#define K_CTRL_L KEY(KT_SHIFT, 2)#define K_CTRL_R KEY(KT_SHIFT, 3)#define K_ALT_L KEY(KT_SHIFT, 4)#define K_ALT_R KEY(KT_SHIFT, 5)/* 锁定键 */#define K_CAPS_LOCK KEY(KT_LOCK, 0)#define K_NUM_LOCK KEY(KT_LOCK, 1)#define K_SCROLL_LOCK KEY(KT_LOCK, 2)/* 控制键 */#define K_PRINTSCREEN KEY(KT_CONTROL, 0) /* Print Screen */#define K_PAUSEBREAK KEY(KT_CONTROL, 1) /* Pause/Break */#define K_INSERT KEY(KT_CONTROL, 2) /* Insert */#define K_DELETE KEY(KT_CONTROL, 3) /* Delete */#define K_HOME KEY(KT_CONTROL, 4) /* Home */#define K_END KEY(KT_CONTROL, 5) /* End */#define K_PAGEUP KEY(KT_CONTROL, 6) /* Page Up */#define K_PAGEDOWN KEY(KT_CONTROL, 7) /* Page Down*/#define K_UP KEY(KT_CONTROL, 8) /* Up */#define K_DOWN KEY(KT_CONTROL, 9) /* Down */#define K_LEFT KEY(KT_CONTROL, 10) /* Left */#define K_RIGHT KEY(KT_CONTROL, 11) /* Right *//* ACPI 键 */#define K_POWER KEY(KT_APIC, 0) /* Power */#define K_SLEEP KEY(KT_APIC, 1) /* Sleep */#define K_WAKE KEY(KT_APIC, 2) /* Wake Up *//* Num Pad */#define K_PAD_0 KEY(KT_PAD, 0) #define K_PAD_1 KEY(KT_PAD, 1) #define K_PAD_2 KEY(KT_PAD, 2) #define K_PAD_3 KEY(KT_PAD, 3) #define K_PAD_4 KEY(KT_PAD, 4) #define K_PAD_5 KEY(KT_PAD, 5) #define K_PAD_6 KEY(KT_PAD, 6) #define K_PAD_7 KEY(KT_PAD, 7) #define K_PAD_8 KEY(KT_PAD, 8) #define K_PAD_9 KEY(KT_PAD, 9) #define K_PAD_SLASH KEY(KT_PAD, 10) /* / */#define K_PAD_STAR KEY(KT_PAD, 11) /* * */#define K_PAD_MINUS KEY(KT_PAD, 12) /* - */#define K_PAD_PLUS KEY(KT_PAD, 13) /* + */#define K_PAD_ENTER KEY(KT_PAD, 14) /* Enter */#define K_PAD_DOT KEY(KT_PAD, 15) /* . */#define K_PAD_UP K_PAD_8 /* Up */#define K_PAD_DOWN K_PAD_2 /* Down */#define K_PAD_LEFT K_PAD_4 /* Left */#define K_PAD_RIGHT K_PAD_6 /* Right */#define K_PAD_HOME K_PAD_7 /* Home */#define K_PAD_END K_PAD_1 /* End */#define K_PAD_PAGEUP K_PAD_9 /* Page Up */#define K_PAD_PAGEDOWN K_PAD_3 /* Page Down*/#define K_PAD_INS K_PAD_0 /* Ins */#define K_PAD_MID K_PAD_5 /* Middle key*/#define K_PAD_DEL K_PAD_DOT /* Del *//* 将0x80个扫描码一一映射成上面的标识号 */static const uint32 keymap[NR_SCAN_CODES][NR_CODE_COL] = { /* scancode !shift shift 0xE0 0x?? */ /* -------------------------------------------------------- */ /* 0x00 */ { 0, 0, 0 }, /* 0x01 */ { K_ESC, K_ESC, 0 }, /* 0x02 */ { '1', '!', 0 }, /* 0x03 */ { '2', '@', 0 }, /* 0x04 */ { '3', '#', 0 }, /* 0x05 */ { '4', '$', 0 }, /* 0x06 */ { '5', '%', 0 }, /* 0x07 */ { '6', '^', 0 }, /* 0x08 */ { '7', '&', 0 }, /* 0x09 */ { '8', '*', 0 }, /* 0x0A */ { '9', '(', 0 }, /* 0x0B */ { '0', ')', 0 }, /* 0x0C */ { '-', '_', 0 }, /* 0x0D */ { '=', '+', 0 }, /* 0x0E */ { K_BACKSPACE, K_BACKSPACE, 0 }, /* 0x0F */ { K_TAB, K_TAB, 0 }, /* 0x10 */ { 'q', 'Q', 0 }, /* 0x11 */ { 'w', 'W', 0 }, /* 0x12 */ { 'e', 'E', 0 }, /* 0x13 */ { 'r', 'R', 0 }, /* 0x14 */ { 't', 'T', 0 }, /* 0x15 */ { 'y', 'Y', 0 }, /* 0x16 */ { 'u', 'U', 0 }, /* 0x17 */ { 'i', 'I', 0 }, /* 0x18 */ { 'o', 'O', 0 }, /* 0x19 */ { 'p', 'P', 0 }, /* 0x1A */ { '[', '{', 0 }, /* 0x1B */ { ']', '}', 0 }, /* 0x1C */ { K_ENTER, K_ENTER, K_PAD_ENTER }, /* 0x1D */ { K_CTRL_L, K_CTRL_L, K_CTRL_R }, /* 0x1E */ { 'a', 'A', 0 }, /* 0x1F */ { 's', 'S', 0 }, /* 0x20 */ { 'd', 'D', 0 }, /* 0x21 */ { 'f', 'F', 0 }, /* 0x22 */ { 'g', 'G', 0 }, /* 0x23 */ { 'h', 'H', 0 }, /* 0x24 */ { 'j', 'J', 0 }, /* 0x25 */ { 'k', 'K', 0 }, /* 0x26 */ { 'l', 'L', 0 }, /* 0x27 */ { ';', ':', 0 }, /* 0x28 */ { '\'', '"', 0 }, /* 0x29 */ { '`', '~', 0 }, /* 0x2A */ { K_SHIFT_L, K_SHIFT_L, 0 }, /* 0x2B */ { '\\', '|', 0 }, /* 0x2C */ { 'z', 'Z', 0 }, /* 0x2D */ { 'x', 'X', 0 }, /* 0x2E */ { 'c', 'C', 0 }, /* 0x2F */ { 'v', 'V', 0 }, /* 0x30 */ { 'b', 'B', 0 }, /* 0x31 */ { 'n', 'N', 0 }, /* 0x32 */ { 'm', 'M', 0 }, /* 0x33 */ { ',', '<', 0 }, /* 0x34 */ { '.', '>', 0 }, /* 0x35 */ { '/', '?', K_PAD_SLASH }, /* 0x36 */ { K_SHIFT_R, K_SHIFT_R, 0 }, /* 0x37 */ { '*', '*', 0 }, /* 0x38 */ { K_ALT_L, K_ALT_L, K_ALT_R }, /* 0x39 */ { ' ', ' ', 0 }, /* 0x3A */ { K_CAPS_LOCK, K_CAPS_LOCK, 0 }, /* 0x3B */ { K_F1, K_F1, 0 }, /* 0x3C */ { K_F2, K_F2, 0 }, /* 0x3D */ { K_F3, K_F3, 0 }, /* 0x3E */ { K_F4, K_F4, 0 }, /* 0x3F */ { K_F5, K_F5, 0 }, /* 0x40 */ { K_F6, K_F6, 0 }, /* 0x41 */ { K_F7, K_F7, 0 }, /* 0x42 */ { K_F8, K_F8, 0 }, /* 0x43 */ { K_F9, K_F9, 0 }, /* 0x44 */ { K_F10, K_F10, 0 }, /* 0x45 */ { K_NUM_LOCK, K_NUM_LOCK, 0 }, /* 0x46 */ { K_SCROLL_LOCK, K_SCROLL_LOCK, 0 }, /* 0x47 */ { K_PAD_HOME, '7', K_HOME }, /* 0x48 */ { K_PAD_UP, '8', K_UP }, /* 0x49 */ { K_PAD_PAGEUP, '9', K_PAGEUP }, /* 0x4A */ { K_PAD_MINUS, '-', 0 }, /* 0x4B */ { K_PAD_LEFT, '4', K_LEFT }, /* 0x4C */ { K_PAD_MID, '5', 0 }, /* 0x4D */ { K_PAD_RIGHT, '6', K_RIGHT }, /* 0x4E */ { K_PAD_PLUS, '+', 0 }, /* 0x4F */ { K_PAD_END, '1', K_END }, /* 0x50 */ { K_PAD_DOWN, '2', K_DOWN }, /* 0x51 */ { K_PAD_PAGEDOWN, '3', K_PAGEDOWN }, /* 0x52 */ { K_PAD_INS, '0', K_INSERT }, /* 0x53 */ { K_PAD_DOT, '.', K_DELETE }, /* 0x54 */ { 0, 0, 0 }, /* 0x55 */ { 0, 0, 0 }, /* 0x56 */ { 0, 0, 0 }, /* 0x57 */ { K_F11, K_F11, 0 }, /* 0x58 */ { K_F12, K_F12, 0 }, /* 0x59 */ { 0, 0, 0 }, /* 0x5A */ { 0, 0, 0 }, /* 0x5B */ { 0, 0, K_GUI_L }, /* 0x5C */ { 0, 0, K_GUI_R }, /* 0x5D */ { 0, 0, K_APPS }, /* 0x5E */ { 0, 0, 0 }, /* 0x5F */ { 0, 0, 0 }, /* 0x60 */ { 0, 0, 0 }, /* 0x61 */ { 0, 0, 0 }, /* 0x62 */ { 0, 0, 0 }, /* 0x63 */ { 0, 0, 0 }, /* 0x64 */ { 0, 0, 0 }, /* 0x65 */ { 0, 0, 0 }, /* 0x66 */ { 0, 0, 0 }, /* 0x67 */ { 0, 0, 0 }, /* 0x68 */ { 0, 0, 0 }, /* 0x69 */ { 0, 0, 0 }, /* 0x6A */ { 0, 0, 0 }, /* 0x6B */ { 0, 0, 0 }, /* 0x6C */ { 0, 0, 0 }, /* 0x6D */ { 0, 0, 0 }, /* 0x6E */ { 0, 0, 0 }, /* 0x6F */ { 0, 0, 0 }, /* 0x70 */ { 0, 0, 0 }, /* 0x71 */ { 0, 0, 0 }, /* 0x72 */ { 0, 0, 0 }, /* 0x73 */ { 0, 0, 0 }, /* 0x74 */ { 0, 0, 0 }, /* 0x75 */ { 0, 0, 0 }, /* 0x76 */ { 0, 0, 0 }, /* 0x77 */ { 0, 0, 0 }, /* 0x78 */ { 0, 0, 0 }, /* 0x78 */ { 0, 0, 0 }, /* 0x7A */ { 0, 0, 0 }, /* 0x7B */ { 0, 0, 0 }, /* 0x7C */ { 0, 0, 0 }, /* 0x7D */ { 0, 0, 0 }, /* 0x7E */ { 0, 0, 0 }, /* 0x7F */ { 0, 0, 0 },};class keyboard_t {public: keyboard_t(); ~keyboard_t(); void init(); void do_irq(); int32 read();private: queue_t m_queue; uint8 m_shift_l; uint8 m_shift_r; uint8 m_leading_e0;};#endif
上面代码主要参考了linux,是简化版,主要功能是实现对扫描码的分类及到相应字符的对应。
/* * guzhoudiaoke@126.com * 2017-10-27 */#include "babyos.h"#include "keyboard.h"#include "x86.h"#include "arch.h"keyboard_t::keyboard_t(){}keyboard_t::~keyboard_t(){}void keyboard_t::do_irq(){ uint8 scan_code = inb(0x60); /* read scan code */ if (!m_queue.full()) { m_queue.en_queue(scan_code); } outb(0x20, 0x20);}void keyboard_t::init(){ //console()->kprintf(WHITE, "keyboard_t::init()\n"); os()->get_arch()->get_8259a()->enable_irq(IRQ_KEYBOARD); /* enable keyboard interrupt */ m_queue.init(); m_shift_l = 0; m_shift_r = 0; m_leading_e0 = 0;}int32 keyboard_t::read(){ uint8 scan_code = 0, shift = 0; uint32 col = 0, key = 0; if (!m_queue.empty()) { m_queue.de_queue(&scan_code); /* set m_leading_e0 */ if (scan_code == 0xe0) { m_leading_e0 = 1; return 0; } /* key up */ if (scan_code & 0x80) { key = keymap[scan_code & 0x7f][col]; if (key == K_SHIFT_L) { m_shift_l = 0; } if (key == K_SHIFT_R) { m_shift_r = 0; } return 0; } shift = m_shift_l || m_shift_r; col = shift ? 1 : 0; if (m_leading_e0) { col = 2; m_leading_e0 = 0; } key = keymap[scan_code & 0x7f][col]; if (key == K_SHIFT_L) { m_shift_l = 1; } if (key == K_SHIFT_R) { m_shift_r = 1; } shift = m_shift_l || m_shift_r; if (key == K_ENTER) { key = '\n'; } else if (key == K_TAB) { key = '\t'; } else if (key == K_BACKSPACE) { key = '\b'; } else if (KEY_TYPE(key) != KT_ASCII) { return 0; } return key; } return 0;}
do_irq通过端口0x60读取一个扫描码,然后加入到队列中去。之后当有需要读取按键内容时,调用read从队列读取,并分析按键。
目前的处理比较简单,只是返回了对应的字符。
case IRQ_0 + IRQ_KEYBOARD: os()->get_arch()->get_keyboard()->do_irq(); ch = os()->get_arch()->get_keyboard()->read(); if (ch != 0) { console()->kprintf(WHITE, "%c", ch); } break;
然后简单的打印下相应的字符。
如上图所示,hello babyos这段代码是通过键盘中断敲上去的。
/* * guzhoudiaoke@126.com * 2017-10-28 */#ifndef _TIMER_H_#define _TIMER_H_#include "types.h"#define HZ (100)#define CLOCK_TICK_RATE (1193180)class timer_t {public: timer_t(); ~timer_t(); void init(); void do_irq(); uint64 get_tick();private: uint64 m_tick;};/* * guzhoudiaoke@126.com * 2017-10-28 */#include "timer.h"#include "babyos.h"#include "arch.h"#include "x86.h"timer_t::timer_t(){}timer_t::~timer_t(){}void timer_t::init(){ m_tick = 0; uint32 val = CLOCK_TICK_RATE / HZ; /* control */ outb(0x43, 0x36); /* clock 0 */ outb(0x40, uint8(val & 0xff)); outb(0x40, uint8(val >> 8)); os()->get_arch()->get_8259a()->enable_irq(IRQ_TIMER); /* enable keyboard interrupt */}void timer_t::do_irq(){ m_tick++; /* EOI */ outb(0x20, 0x20);}uint64 timer_t::get_tick(){ return m_tick;}
时钟中断比较简单,初始化时计算怎样让时钟中断频率为100HZ,即1s中断100次。do_irq时只是增加tick计数,并发送EOI。
class rtc_t {public: rtc_t(); ~rtc_t(); void init(); void update(); uint32 year() { return m_year; } uint32 month() { return m_month; } uint32 day() { return m_day; } uint32 hour() { return m_hour; } uint32 minute() { return m_minute; } uint32 second() { return m_second; }private: void get_time(); uint8 bcd_to_binary(uint8 bcd);private: uint8 m_year; uint8 m_month; uint8 m_day; uint8 m_hour; uint8 m_minute; uint8 m_second; uint32 m_tick_to_update;};void rtc_t::init(){ m_tick_to_update = HZ; get_time();}void rtc_t::update(){ if (--m_tick_to_update != 0) { return; } m_tick_to_update = HZ; m_second++; /* every 1 minute, re-read rtc from cmos */ if (m_second == 60) { get_time(); }}void rtc_t::get_time(){ m_year = bcd_to_binary(cmos_read(9)); m_month = bcd_to_binary(cmos_read(8)); m_day = bcd_to_binary(cmos_read(7)); m_hour = bcd_to_binary(cmos_read(4)); m_minute= bcd_to_binary(cmos_read(2)); m_second= bcd_to_binary(cmos_read(0));}uint8 rtc_t::bcd_to_binary(uint8 bcd){ return (bcd >> 4) * 10 + (bcd & 0xf);}
实时钟通过读取CMOS获取当前时间。
阅读全文
0 0
- babyos2(7)——键盘中断、时钟中断、实时钟
- babyos2(6)——IDT,中断,异常
- s3c2440实时时钟中断
- babyos (十二) —— 键盘中断
- 时钟中断(1)
- 时钟中断(2)
- 【单片机】时钟(不利用中断中断)
- 【中断异常】时钟中断
- Linux驱动开发(五)——中断和时钟
- 时钟中断
- 中断—什么是中断
- ucOS 时钟中断(ISR)
- ucOS 时钟中断(ISR)
- 键盘中断
- 键盘中断
- 实例二——从RTC设备学习中断(系统实时钟)
- cortex_m3_stm32嵌入式学习笔记(十四):RTC实时时钟(秒中断)
- mini2440 RTC实时时钟中断和报警功能实验
- html中的颜色表示方法
- pandas时间序列操作
- String、StringBuffer和StringBuilder的区别
- BZOJ1295 [SCOI2009]最长距离 智商
- 洛谷P1130 红牌
- babyos2(7)——键盘中断、时钟中断、实时钟
- SDUT-3344 数据结构实验之二叉树五:层序遍历
- 5.3
- springmvc的中文乱码问题主要有以下几种情形
- 算法进阶3-1
- 软件缺陷的生命周期(基本)
- 资料查询
- 查找端口占用,杀死进程
- 171111-数组的学习【连续第十九天】