国学芯用 发表于 2026-7-2 13:19:45

86-普通IO口中断-休眠唤醒,AI8051U实验箱演示程序

86-普通IO口中断-休眠唤醒,AI8051U实验箱演示程序

主程序main.C代码如下(汇编版本在附件中):

/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- BBS: www.STCAIMCU.com-----------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序            */
/*---------------------------------------------------------------------*/

/*************功能说明    **************



本例程基于AI8051U为主控芯片的实验箱进行编写测试。

使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。

edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。

显示效果为: 上电后跑马灯显示2秒, 然后进入睡眠模式.

按板上的P32、P33、P34、P35按键唤醒, 继续显示2秒后再进入睡眠模式.

下载时, 选择时钟 24MHz (用户可自行修改频率).

******************************************/

#include "..\comm\AI8051U.h"
#include "intrins.h"
#include "stdio.h"

typedef   unsigned char    u8;
typedef   unsigned int    u16;
typedef   unsigned long   u32;

//==========================================================================

#define MAIN_Fosc       24000000UL
#define Baudrate      115200L
#define TM            (65536 -(MAIN_Fosc/Baudrate/4))
#define PrintUart       1      //1:printf 使用 UART1; 2:printf 使用 UART2

/*************本地常量声明    **************/

u8 code ledNum[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

/*************本地变量声明    **************/

u8 ledIndex;
u16 msecond;    //1000ms计数
u8 ioIndex;

/*************本地函数声明    **************/

void delay_ms(u8 ms);
void UartInit(void);

/******************** 主函数 **************************/
void main(void)
{
    WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXSFR();//扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

    P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口

    P40 = 0;    //LED Power On

    //PnIM1,PnIM000:下降沿中断; 01:上升沿中断; 10:低电平中断; 11:高电平中断
//    P0IM0 = 0xff;//高电平中断
//    P0IM1 = 0xff;
//    P0INTE = 0xff; //使能 P0 口中断
//    P0WKUE = 0xff; //使能 P0 口中断唤醒

//    P1IM0 = 0xff;//上升沿中断
//    P1IM1 = 0x00;
//    P1INTE = 0xff; //使能 P1 口中断
//    P1WKUE = 0xff; //使能 P1 口中断唤醒

//    P2IM0 = 0x00;//低电平中断
//    P2IM1 = 0xff;
//    P2INTE = 0xff; //使能 P2 口中断
//    P2WKUE = 0xff; //使能 P2 口中断唤醒

    P3IM0 = 0x00;//下降沿中断
    P3IM1 = 0x00;
    P3INTE = 0x3c; //使能 P3.2~P3.5 口中断
    P3WKUE = 0x3c; //使能 P3.2~P3.5 口中断唤醒

//    P4IM0 = 0x00;//下降沿中断
//    P4IM1 = 0x00;
//    P4INTE = 0xff; //使能 P4 口中断
//    P4WKUE = 0xff; //使能 P4 口中断唤醒

//    P5IM0 = 0x00;//下降沿中断
//    P5IM1 = 0x00;
//    P5INTE = 0xff; //使能 P5 口中断
//    P5WKUE = 0xff; //使能 P5 口中断唤醒

    UartInit();
   
//    IRCDB = 0x10;

    P0INTF = 0;   //清中断标志
    P1INTF = 0;
    P2INTF = 0;
    P3INTF = 0;
    P4INTF = 0;
    P5INTF = 0;
    EA = 1;   //允许总中断

    while(1)
    {
      delay_ms(100);      //延时100ms
      //跑马灯指示工作状态
      P0 = ~ledNum;    //输出低驱动
      ledIndex++;
      if(ledIndex > 7)
      {
            ledIndex = 0;
      }

      //2秒后MCU进入休眠状态
      if(++msecond >= 20)
      {
            msecond = 0;    //清计数

            P0 = 0xff;      //先关闭显示,省电
            printf("MCU Sleep.\r\n");

            PCON |= 0x02;   //Sleep
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            printf("MCU wakeup from P%b02X.\r\n", ioIndex);
      }
    }
}

//========================================================================
//由于中断向量大于 31,在 KEIL 中无法直接编译
//借用第 13 号中断入口地址,需添加"isr.asm"文件到项目
//========================================================================
void common_isr() interrupt 13
{
    u8 intf;

    intf = P0INTF; //P0 口中断
    if (intf)
    {
      P0INTF = 0x00;
      if (intf & 0x01) ioIndex = 0x00;
      if (intf & 0x02) ioIndex = 0x01;
      if (intf & 0x04) ioIndex = 0x02;
      if (intf & 0x08) ioIndex = 0x03;
      if (intf & 0x10) ioIndex = 0x04;
      if (intf & 0x20) ioIndex = 0x05;
      if (intf & 0x40) ioIndex = 0x06;
      if (intf & 0x80) ioIndex = 0x07;
    }

    intf = P1INTF; //P1 口中断
    if (intf)
    {
      P1INTF = 0x00;
      if (intf & 0x01) ioIndex = 0x10;
      if (intf & 0x02) ioIndex = 0x11;
      if (intf & 0x04) ioIndex = 0x12;
      if (intf & 0x08) ioIndex = 0x13;
      if (intf & 0x10) ioIndex = 0x14;
      if (intf & 0x20) ioIndex = 0x15;
      if (intf & 0x40) ioIndex = 0x16;
      if (intf & 0x80) ioIndex = 0x17;
    }

    intf = P2INTF; //P2 口中断
    if (intf)
    {
      P2INTF = 0x00;
      if (intf & 0x01) ioIndex = 0x20;
      if (intf & 0x02) ioIndex = 0x21;
      if (intf & 0x04) ioIndex = 0x22;
      if (intf & 0x08) ioIndex = 0x23;
      if (intf & 0x10) ioIndex = 0x24;
      if (intf & 0x20) ioIndex = 0x25;
      if (intf & 0x40) ioIndex = 0x26;
      if (intf & 0x80) ioIndex = 0x27;
    }

    intf = P3INTF; //P3 口中断
    if (intf)
    {
      P3INTF = 0x00;
      if (intf & 0x01) ioIndex = 0x30;
      if (intf & 0x02) ioIndex = 0x31;
      if (intf & 0x04) ioIndex = 0x32;
      if (intf & 0x08) ioIndex = 0x33;
      if (intf & 0x10) ioIndex = 0x34;
      if (intf & 0x20) ioIndex = 0x35;
      if (intf & 0x40) ioIndex = 0x36;
      if (intf & 0x80) ioIndex = 0x37;
    }

    intf = P4INTF; //P4 口中断
    if (intf)
    {
      P4INTF = 0x00;
      if (intf & 0x01) ioIndex = 0x40;
      if (intf & 0x02) ioIndex = 0x41;
      if (intf & 0x04) ioIndex = 0x42;
      if (intf & 0x08) ioIndex = 0x43;
      if (intf & 0x10) ioIndex = 0x44;
      if (intf & 0x20) ioIndex = 0x45;
      if (intf & 0x40) ioIndex = 0x46;
      if (intf & 0x80) ioIndex = 0x47;
    }

    intf = P5INTF; //P5 口中断
    if (intf)
    {
      P5INTF = 0x00;
      if (intf & 0x01) ioIndex = 0x50;
      if (intf & 0x02) ioIndex = 0x51;
      if (intf & 0x04) ioIndex = 0x52;
      if (intf & 0x08) ioIndex = 0x53;
      if (intf & 0x10) ioIndex = 0x54;
      if (intf & 0x20) ioIndex = 0x55;
      if (intf & 0x40) ioIndex = 0x56;
      if (intf & 0x80) ioIndex = 0x57;
    }
}

//========================================================================
// 函数: void delay_ms(unsigned char ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-1-10
// 备注:
//========================================================================
void delay_ms(u8 ms)
{
    u16 i;
    do{
      i = MAIN_Fosc / 6000;
      while(--i);
    }while(--ms);
}

/******************** 串口打印函数 ********************/
void UartInit(void)
{
#if(PrintUart == 1)
    P_SW1 &= ~S1_S1;      //UART1 switch to, 0x00: P3.0 P3.1, 0x40: P3.6 P3.7, 0x80: P1.6 P1.7, 0xC0: P4.3 P4.4
    P_SW1 &= ~S1_S0;
    SCON = (SCON & 0x3f) | 0x40;
    AUXR |= (1<<6);      //定时器时钟1T模式
    AUXR &= ~S1BRT;      //串口1选择定时器1为波特率发生器
    TL1= TM;
    TH1= TM>>8;
    TR1 = 1;      //定时器1开始计时

//    SCON = (SCON & 0x3f) | 0x40;
//    T2L= TM;
//    T2H= TM>>8;
//    AUXR |= 0x15; //串口1选择定时器2为波特率发生器
#else
    P_SW2 |= S2_S;       //UART2 switch to: 0: P1.2 P1.3,1: P4.2 P4.3
    S2CFG |= 0x01;//使用串口2时,W1位必需设置为1,否则可能会产生不可预期的错误
    S2CON = (SCON & 0x3f) | 0x40;
    T2L= TM;
    T2H= TM>>8;
    AUXR |= 0x14;   //定时器2时钟1T模式,开始计时
#endif
}

void UartPutc(unsigned char dat)
{
#if(PrintUart == 1)
    SBUF = dat;
    while(TI==0);
    TI = 0;
#else
    S2BUF= dat;
    while((S2CON & S2TI)==0);
    S2CON &= ~S2TI;    //Clear Tx flag
#endif
}

char putchar(char c)
{
    UartPutc(c);
    return c;
}


页: [1]
查看完整版本: 86-普通IO口中断-休眠唤醒,AI8051U实验箱演示程序