21IC 电子工程师笔记系统,   “我”的笔记


载入中...

最新日志

载入中...

最近的评论

载入中...

连接






LPCARM中断喂狗正确方法及异常模拟裸奔程序详解
雁塔菜农 发表于 2006-12-26 21:36:00

/*-----------------------------------------------------------------------------------------------------------
          LPCARM中断喂狗正确方法及异常模拟裸奔程序详解(别名ARM疯狗)
雁塔菜农HotPower   2006.12.26 21:32   于菜地Http://HotPower.21ic.org/
------------------------------------------------------------------------------------------------------------*/
#i nclude <LPC213xDEF.H> //ARM菜鸟HotPower创建定义文件(最新为倒塌版)
/*---------------------------------------------------------------------------------
注意:(今天是菜农时代伟人的113年诞辰日,特发此帖!!!)
  (姊妹篇--LPCARM主程序喂狗正确方法及异常模拟裸奔程序详解)---随后发布
菜农累了,不想多费口舌,先自己看明白吧。欢迎拍砖有利于菜农进一步改进
 
LPC213XDEF.H文件请在user1/46/archives/2006/16994.html下载
可将LPC213XDEF.H拷贝到Keil\ARM\INC\PHILIPS目录下
点击下栽本裸奔程序详解完整包:uploadfile-/2006-12/1226389582.rar
----------------------------------------------------------------------------------*/
/*---------------------------------------------------------
        时钟参数定义
---------------------------------------------------------*/
#define Fosc 11059200
#define Fcclk (Fosc * 4)
#define Fcco (Fcclk * 4)
#define Fpclk (Fcclk / 4) * 1


/*---------------------------------------------------------
        申请系统变量
---------------------------------------------------------*/
__noinit__ volatile unsigned int PFCount;//申请掉电计数器(复位不初始化)
__noinit__ volatile unsigned int WdtCount;//申请软狗计数器(复位不初始化)
__noinit__ volatile unsigned int MainLoopAddr;//主程序循环地址寄存器(用于模拟主程序飞后的随机地址)
__noinit__ volatile unsigned int SystemRamTest;//RAM不初始化(用于判别是否是首次上电或内存完好情况)

/*---------------------------------------------------------
        系统函数声明
---------------------------------------------------------*/
void SystemInit(void);//系统初始化
void VicInit(void);//向量中断初始化
void PortInit(void);//IO初始化
void Timer0Init(void);//定时器初始化
void KeyInit(void);//键盘初始化
void VicIntSetup(void);//向量中断设置
void Enable_WDT(unsigned int);//使能看门狗(并设置复位参数)
void Reset_WDT(void);//复位看门狗(首次实际是启动看门狗)
void MainLoop(void);

void __swi(0) Enable_IRQ(void);//开放向量中断总开关
void __SWI_0      (void) {
int tmp;
  __asm
  {
    MRS tmp, SPSR
    BIC tmp, tmp, #0x80
    MSR SPSR_c, tmp
  }
}

void __swi(1) Disable_IRQ(void);//关闭向量中断总开关
void __SWI_1       (void) {
int tmp;
  __asm
  {
    MRS tmp, SPSR
    ORR tmp, tmp, #0x80
    MSR SPSR_c, tmp
  }
}

void __swi(2) Enable_FIQ(void);//开放快速中断总开关
void __SWI_2      (void) {
int tmp;
  __asm
  {
    MRS tmp, SPSR
    BIC tmp, tmp, #0x40
    MSR SPSR_c, tmp
  }
}

void __swi(3) Disable_FIQ(void);//关闭快速中断总开关
void __SWI_3       (void) {
int tmp;
  __asm
  {
    MRS tmp, SPSR
    ORR tmp, tmp, #0x40
    MSR SPSR_c, tmp
  }
}

void __swi(4) Enable_VIC(void);//开放对VIC的写入保护
void __SWI_4      (void) {
  VIC->Protection = 0;//开放对VIC的写入保护
}

#define Disable_VIC() VIC->Protection = 1;//关闭在用户级对VIC的一些写操作,保护在用户级VIC不被以外改写


/*----------------------------------------------------------------------
   外部中断0异常处理程序(按P0.1关闭定时器0,使定时器0中断不能喂硬狗!)
----------------------------------------------------------------------*/
extern void FIQ_EINT0 (void) __irq
{
  T0->TIMER_TCR &= ~0x01;//关闭定时器0(使定时器0中断不能喂狗)
  VIC->SoftIntClr = (1 << VICIntSel_EINT0);//增强安全性
  INTCON->EXT_INT = (1 << EINT0);//清除INT0中断标志
  VIC->VectAddr = 0;
}

/*-----------------------------------------------------------------------------
   外部中断1异常处理程序(按P0.3改写定时器0中断地址,使定时器0中断不能喂硬狗!)
------------------------------------------------------------------------------*/
void IRQ_EINT1 (void) __irq
{
  VIC->VectAddrs[2] = (unsigned int)PFCount;//修改中断服务程序地址,制造中断程序飞
  VIC->SoftIntClr = (1 << VICIntSel_EINT1);;//增强安全性
  INTCON->EXT_INT = (1 << EINT1);//清除INT1中断标志
  VIC->VectAddr = 0;
}


/*----------------------------------------------------------------------------
   外部中断2异常处理程序(按P0.7改写主循环地址,定时器0中断正常也不能喂硬狗!)
-----------------------------------------------------------------------------*/
void IRQ_EINT2 (void) __irq
{
  MainLoopAddr = (unsigned int)T0->TIMER_TC;//修改主循环程序地址,制造主程序飞
  VIC->SoftIntClr = (1 << VICIntSel_EINT2);;//增强安全性
  INTCON->EXT_INT = (1 << EINT2);//清除INT2中断标志
  VIC->VectAddr = 0;
}

/*----------------------------------------------------------------------
       定时器0中断
----------------------------------------------------------------------*/
void IRQ_Timer0 (void) __irq
{
  if (WdtCount > 0) {//说明主程序在运行中,即程序正常。
    WdtCount = 0;//软狗计数器复位
    Reset_WDT();//复位看门狗,首次实际是启动看门狗
  }
  T0->TIMER_IR = 0x01;//清除中断标志,相当于VIC->IRQStatus &= ~(1 << VICIntSel_Time0);//可惜IRQStatus只能写
  VIC->SoftIntClr = (1 << VICIntSel_Time0);//也应该清除安全些!!!
  VIC->VectAddr = 0x00;  //通知VIC中断处理结束
}

/*----------------------------------------------------------------------
       系统默认中断处理
----------------------------------------------------------------------*/
void IRQ_Default (void) __irq
{
unsigned int status;
  status = VIC->IRQStatus | VIC->FIQStatus;//合并2种中断一起处理
  switch(status) {
    case (1 << VICIntSel_EINT0)://拦截非法INT0中断
      INTCON->EXT_INT = (1 << EINT0);//清除非法INT0中断标志
      VIC->SoftIntClr = (1 << VICIntSel_EINT0);//清除非法INT0软件中断标志
   break;
    case (1 << VICIntSel_EINT1)://拦截非法INT1中断
      INTCON->EXT_INT = (1 << EINT1);//清除非法INT1中断标志
      VIC->SoftIntClr = (1 << VICIntSel_EINT1);//清除非法INT1软件中断标志
   break;
    case (1 << VICIntSel_EINT2)://拦截非法INT2中断
      INTCON->EXT_INT = (1 << EINT2);//清除非法INT2中断标志
      VIC->SoftIntClr = (1 << VICIntSel_EINT2);//清除非法INT2软件中断标志
   break;
    case (1 << VICIntSel_EINT3)://拦截非法INT3中断
      INTCON->EXT_INT = (1 << EINT3);//清除非法INT2中断标志
      VIC->SoftIntClr = (1 << VICIntSel_EINT3);//清除非法INT3软件中断标志
   break;
    case (1 << VICIntSel_SoftInt23)://拦截非法用户软件中断VICIntSel_SoftInt23
      VIC->SoftIntClr = (1 << VICIntSel_SoftInt23);//清除非法用户软件中断标志
   break;
    case (1 << VICIntSel_SoftInt24)://拦截非法用户软件中断VICIntSel_SoftInt24
      VIC->SoftIntClr = (1 << VICIntSel_SoftInt24);//清除非法用户软件中断标志
   break;
    case (1 << VICIntSel_SoftInt25)://拦截非法用户软件中断VICIntSel_SoftInt25
      VIC->SoftIntClr = (1 << VICIntSel_SoftInt25);//清除非法用户软件中断标志
   break;
    case (1 << VICIntSel_SoftInt26)://拦截非法用户软件中断VICIntSel_SoftInt26
      VIC->SoftIntClr = (1 << VICIntSel_SoftInt26);//清除非法用户软件中断标志
   break;
    default:
      VIC->SoftIntClr = 0xffffff;//清除所有非法用户软件中断标志
  }
  VIC->VectAddr = 0;//结束中断处理
}


/*----------------------------------------------------------------------
     系统初始化函数
----------------------------------------------------------------------*/
void SystemInit(void)
{
  VicInit();
  PortInit();
  KeyInit();
  Timer0Init();
  Enable_WDT(0xffff);//使能看门狗并设置复位参数
  VicIntSetup();
}

/*----------------------------------------------------------------------
     向量中断初始化函数
----------------------------------------------------------------------*/
void VicInit(void)
{
volatile unsigned int start;
  VIC->IntEnable  = 0;//关闭全部中断
  VIC->SoftIntClr = 0xffffffff;//清除所有软中断标志
  VIC->IntSelect  = 0;//全部中断为IRQ中断或默认中断
  for (start = 0; start < 10000; start ++);//系统延时等待接口稳定
}

/*----------------------------------------------------------------------
     IO初始化函数
----------------------------------------------------------------------*/
void PortInit(void)
{
  PINSEL->PIN_SEL0 = 0x00000000;//设置管脚连接GPIO
  PINSEL->PIN_SEL1 = 0x00000000;//设置管脚连接GPIO
  P0->IODIR        = 0x00000000;//设置P0口为输入
  P1->IODIR        = 0x00000000;//设置P1口为输入
}

/*----------------------------------------------------------------------
     定时器初始化函数
----------------------------------------------------------------------*/
void Timer0Init(void)
{
  T0->TIMER_TC   = 0;   //时器设置为0
  T0->TIMER_PR   = 0;   //时钟不分频
  T0->TIMER_MCR  = 0x03;  //设置T0MR0匹配后复位T0TC,并产生中断标志
  T0->TIMER_MR0  = Fpclk / 200; //5mS定时
  T0->TIMER_TCR  = 0x01;  //启动定时器
  T0->TIMER_IR   = 0x01;  //清除中断标志
}


/*----------------------------------------------------------------------
     向量中断设置函数
----------------------------------------------------------------------*/
void VicIntSetup(void)
{
unsigned int i;
  VIC->VectCntls[0] = VICIntSel_Enable | VICIntSel_EINT1;//设置外部中断1分配VIC最高优先级
  VIC->VectAddrs[0] = (unsigned int)IRQ_EINT1;//设置中断服务程序地址
  VIC->IntEnable |= (1 << VICIntSel_EINT1);//使能外部中断1

  VIC->VectCntls[1] = VICIntSel_Enable | VICIntSel_EINT2;//设置外部中断2分配VIC次优先级
  VIC->VectAddrs[1] = (unsigned int)IRQ_EINT2;//设置中断服务程序地址
  VIC->IntEnable |= (1 << VICIntSel_EINT2);//使能外部中断1

/* 设置定时器0中断IRQ */
  VIC->VectCntls[2] = VICIntSel_Enable | VICIntSel_Time0;//设置定时器0中断通道分配最高优先级
  VIC->VectAddrs[2] = (unsigned int)IRQ_Timer0;//设置中断服务程序地址
  VIC->IntEnable |= (1 << VICIntSel_Time0);//使能定时器0中断

  VIC->IntSelect   = (1 << VICIntSel_EINT0); //设置EINT0为FIQ中断


  VIC->DefVectAddr = (unsigned int)IRQ_Default;//定义除VIC->VectAddrs[0]~VIC->VectAddrs[15]外的中断函数
 
  for (i = 0; i < 16; i ++) {
    if ((VIC->VectCntls[i] & VICIntSel_Enable) == 0) {//该中断向量未使能
   VIC->VectAddrs[i] = (unsigned int)IRQ_Default;//全部以默认中断来处理
//   VIC->VectAddrs[i] = (unsigned int)0;//全部以复位来处理
 }
  }

  INTCON->EXT_INT = (1 << EINT0) //清除INT0中断标志
                  | (1 << EINT1) //清除INT1中断标志
      | (1 << EINT2) //清除INT2中断标志
      | (1 << EINT3);//清除INT3中断标志

  VIC->SoftIntClr = (1 << VICIntSel_EINT0) //清除EINT0软中断标志
                  | (1 << VICIntSel_EINT1) //清除EINT1软中断标志
                  | (1 << VICIntSel_EINT1) //清除EINT2软中断标志
                  | (1 << VICIntSel_EINT1);//清除EINT3软中断标志

  VIC->IntEnable  = (1 << VICIntSel_EINT0) //使能EINT0中断
                  | (1 << VICIntSel_EINT1) //使能EINT1中断
                  | (1 << VICIntSel_EINT2);//使能EINT2中断
 
}

/*----------------------------------------------------------------------
     键盘初始化函数
----------------------------------------------------------------------*/
void KeyInit(void)
{
  PINSEL->PIN_SEL0  |= (P0_1_EINT0 << P0_1_PINSEL) //选择P0.1为INT0外部中断引脚
                     | (P0_3_EINT1 << P0_3_PINSEL) //选择P0.3为INT1外部中断引脚
                     | (P0_7_EINT2 << P0_7_PINSEL);//选择P0.7为INT2外部中断引脚

  INTCON->EXT_POLAR   = ~(1 << EXTPOLAR0);//INT0为低电平有效
  INTCON->EXT_POLAR   = ~(1 << EXTPOLAR1);//INT1为低电平有效
  INTCON->EXT_POLAR   = ~(1 << EXTPOLAR2);//INT2为低电平有效


  INTCON->EXT_MODE    = (1 << EXTMODE0)   //设置INT0为边沿触发
                      | (1 << EXTMODE1)   //设置INT1为边沿触发
                      | (1 << EXTMODE2);  //设置INT2为边沿触发
}

/*----------------------------------------------------------------------
    使能看门狗(并设置复位参数)
----------------------------------------------------------------------*/
void Enable_WDT(unsigned int wdtc)
{
  WDT->WDT_WDTC = wdtc;
  WDT->WDT_WDMOD = (1 << WDEN) | (1 << WDRESET);
  Reset_WDT();//必须在此复位看门狗一次(首次实际是启动看门狗)
}

/*----------------------------------------------------------------------
    复位看门狗(首次实际是启动看门狗)
----------------------------------------------------------------------*/
void Reset_WDT(void)
{
unsigned int tmp;//设置暂存器以取代Enable()/Disable()函数。
  tmp = VIC->IntEnable;//保护,相当与Disable()函数以代替关中断
  VIC->IntEnable = 0;//禁止所有FIQ和IRQ中断
  WDT->WDT_WDFEED = 0xaa;                                 
  WDT->WDT_WDFEED = 0x55;
  VIC->IntEnable = tmp;//恢复,相当与Enable()函数以代替开中断    
}

int main(void)
{
typedef void (* PV)(void);//函数指针
PV func;//声明函数指针
  Disable_IRQ();//关闭向量中断总开关
  Disable_FIQ();//关闭快速中断总开关

  if (SystemRamTest != 0x5555aaaa) {//内存被破坏(或真正上电)
    MainLoopAddr = (unsigned int)MainLoop;//只在真正上电时初始化
 SystemRamTest = 0x5555aaaa;//内存被破坏处理结束
  }
  else {
//下句一定要抢在Enable_WDT()前,以防止WDTOF位被改写
    if ((WDT->WDT_WDMOD & (1 << WDTOF)) == 0) {//可能是外狗或手动复位
/*----------------------------------------------------------------------
    再此添加外狗或手动复位异常处理程序
----------------------------------------------------------------------*/
//    PFCount = 0;//掉电计数器复位
    }
    else {//内狗复位
      PFCount += 0x100;//掉电计数器复位
    }
  }
  SystemInit();//系统初始化

  Enable_FIQ();//开放快速中断总开关
  Enable_IRQ();//注意现在立即进入EINT1硬件中断(因为假定P0.3/P0.14都为高电平)

  Disable_VIC();//关闭在用户级对VIC的一些写操作,保护在用户级VIC不被以外改写
  while(1) {
// POWER->P_CON = 1;//待机
    func = (PV)MainLoopAddr;
    func();//运行MainLoop()
    WdtCount ++;//软狗计数器计数
 if (WdtCount > 0x3000) {//定时器程序跑飞
/*----------------------------------------------------------------------
    可以在此添加修复定时器代码,当然也可在此死循环以等待看门狗复位。
----------------------------------------------------------------------*/
      Timer0Init();//修复定时器
   WdtCount = 0;
 }
  }
}

/*----------------------------------------------------------------------
    主程序正常的主循环等待,主程序飞可能不会运行此程序。
----------------------------------------------------------------------*/
void MainLoop(void)
{
  __nop();
  __nop();
  __nop();
}



Re:LPCARM中断喂狗正确方法及异常模拟裸奔程序详解
laoshu0902(游客)发表评论于2006-12-26 22:47:00

laoshu0902(游客)学习
个人主页 | 引用 | 返回 | 删除 | 回复

发表评论:
载入中...



公告

载入中...

专题

载入中...

留言

载入中...

统计

载入中...

 

 

 

站长个人入口