ubuntu12.04下使用android emulator,启用kvm加速,模拟i8254定时器的代码比较旧,对应于qemu0.14或者之前的版本,这时还没有QOM(qemu object model)模型,虚拟设备的代码是比较简单的。
玩虚拟设备之前,首先得搞明白真实设备怎么玩,有篇文档:http://blog.youkuaiyun.com/u013007900/article/details/50408903,看不太明白就再看看计组和哈工大出版的C语言测控,以前上课用的这个。
8254使用的端口时0x40~0x43,共计4个8bit端口,输入时钟频率1193kHZ,使用IRQ0,对应中断向量表中的INT 8。怎么对应,看http://www.360doc.com/content/09/1017/08/128139_7395798.shtml和http://blog.youkuaiyun.com/duguteng/article/details/7552774。
8259主片的IRQ0~7对应INT 8~INT F,从片的IRQ8~IRQ15对应INT 70~INT 77。
有份以前上C语言测控时写的代码,使用了8254的,输入采样周期(in ms)和采样次数,每次采样时打印一个'8'。
注意定时器的最大周期比较短,大约55ms,所以需要使用软件方式扩大定时器的周期,注意周期不是10ms的倍数时的特殊处理。
定时器0工作于模式3,方波发生器。用学硬件的话来说,就是自动重装定时器;用学软件的话来说,就是周期定时器,不是oneshot的。
/* C语言测控程序设计
* 2012年3月29日
* 系统XP sp3,编译器:TC3.0,编辑器:VIM7.3
* */
#include <stdio.h>
#include <dos.h>
#include <graphics.h>
#include <math.h>
#include <string.h>
/*参数*/
float gfT; //采样周期
long glN; //采样次数
int giFlag; //标记时间到
long glUserCnt; //已采样次数
int giTimerN; //采样周期除以10ms
int giTimerSmallValue; //采样周期模10ms后,对应的定时器初值
int giTimerCnt; //定时器中断次数
void LoadConfig(void); //读取配置文件
void interrupt (*OldIsr08)(void); //原先的中断函数指针
void interrupt MyIsr08(void); //自定义的中断函数
void TimerInit(void); //定时器初始化函数
void TimerExit(void); //定时器恢复函数
void UserTimerIsr(void); //每个采样周期都会调用的函数
int main()
{
/*读取配置*/
LoadConfig();
/*初始化*/
TimerInit();
while((glUserCnt < glN) || (glN == 0))
{
if(kbhit()) //特定按键退出
{
if(getch() == ' ')
break;
}
if(giFlag)
{
giFlag = 0;
putchar('8');
}
}
/*恢复定时器和dos界面*/
TimerExit();
printf("\nthe times of interrupt is: %ld\n",glUserCnt);
getch();
return 0;
}
/*定时器中断函数,每到用户设定的时间,调用一次UserTimerIsr()*/
void interrupt MyIsr08(void)
{
giTimerCnt++;
if(giTimerN == 0) //采样周期小于10ms的情况
{
giTimerCnt = 0;
UserTimerIsr();
outportb(0x20, 0x20); //清除中断标志位,可以看8259相关的资料
return;
}
if((giTimerSmallValue == 0) && (giTimerCnt == giTimerN)) //采样周期是10ms的倍数的情况
{
giTimerCnt = 0;
UserTimerIsr();
outportb(0x20, 0x20);
return;
}
if