romeo 发表于 2025-12-24 21:35:13

定时器中断 | 集中在这个帖子打卡

学习了第七集定时器中断,效果很好,加上自己修改、综合了其他程序加入,也成功实现了,在之前没解决的问题也解决了,对于新手小白非常友好!还得是8051u!


#include <AI8051U.H>
#include "led.h"
#include "ai_usb.h"
#include "timer.h"

//LED变量
unsigned char ucLed = 0x01;                //0000 0001


//Timer变量
unsigned int xms = 0;
unsigned int Led_Dly = 0;

//function
void Led_Proc(void);

void main(void)
{
      EAXFR = 1;                                        //
      WTST = 0;                                        //
      CKCON = 0;                                        //
      
    P0M0 = 0x00; P0M1 = 0x00;      //
    P1M0 = 0x00; P1M1 = 0x00;
    P2M0 = 0x00; P2M1 = 0x00;
    P3M0 = 0x00; P3M1 = 0x00;
    P4M0 = 0x00; P4M1 = 0x00;
    P5M0 = 0x00; P5M1 = 0x00;
    P6M0 = 0x00; P6M1 = 0x00;
    P7M0 = 0x00; P7M1 = 0x00;

      Timer0_Init();
      usb_init();
      EA = 1;
      
      while(1)
      {
                if(bUsbOutReady)
                {
                        usb_OUT_done();
                }
                Led_Proc();
      }
}



void Timer0_Isr(void) interrupt 1
{
      xms++;
      Led_Dly++;
      
      Led_Display(ucLed);
}


void Led_Proc(void)
{
      if(Led_Dly < 500)return;
      Led_Dly = 0;
      
      ucLed = _crol_(ucLed,1);      //zuoyi 1 wei
}

神农鼎 发表于 2025-12-24 21:52:08





#include <AI8051U.H>                //AI8051U的通用头文件,头文件不分大小写
#include "ai_usb.h"                        //USB库的头文件,头文件不分大小写
/*
如何获得上面这2个头文件,如已按照前面介绍的方法:
从www.STCAI.com 网站,【软件工具 | 工具软件】处,下载安装最新的【AIapp-ISP 软件】,
选择其中的选项卡 【Keil仿真设置 】,
点击【添加型号和头文件到Keil中,并添加仿真器驱动到Keil中】按钮,
则 Ai8051U.h 和 AI_usb.h 都会自动复制到Keil 中, 包含进来就可以直接使用,
大家可以打开看下其中的内容,AI_usb.h 和 stc32_stc8_usb.h是相似的,只需用其中的1个头文件,
具体见 Keil_v5\C251\INC\STC 目录,或 Keil_v5\C51\INC\STC 目录。
如将对应的 USB库文件添加到 项目中,后续用户程序中,USB如收到命令字符串 "@STCISP#"
USB库函数就会自动软复位到系统ISP程序区,实现 USB不停电下载,具体见相应部分的说明。
//char *USER_DEVICEDESC = NULL;
//char *USER_PRODUCTDESC = NULL;
//char *USER_STCISPCMD = "@STCISP#";
//使用20250319之前版本的库函数时需要在用户代码中增加上面3行定义。
//使用20250319及以后的版本都不再需要上面的定义
*/

bit         t0_flag = 0;                   //定义1个位变量,T0事件位变量标志,记录定时器0已产生中断
// 供主循环查询到该定时器已产生中断,在主循环中处理定时器0的中断任务,不堵塞其他中断
bit         t1_flag = 0;                   //定义1个位变量,T1事件位变量标志,记录定时器1已产生中断
// 供主循环查询到该定时器已产生中断,在主循环中处理定时器1的中断任务,不堵塞其他中断

void Timer0_Isr(void) interrupt TMR0_VECTOR                //定时器0中断服务程序
{
        P00 = ~P00;                                //P00灯闪烁,中断服务程序中尽量少执行长的任务,防止堵塞其他中断
        t0_flag = 1;                        //置1,记录定时器0已产生中断,供主循环判断要处理定时器0的中断任务
}
//定时器0中断服务程序,TMR0_VECTOR在AI8051U.H头文件中已宏定义为1

void Timer0_Init(void)                //定时器0初始化,2秒@40.000MHz
{
        TM0PS = 0x65;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
        AUXR &= 0x7F;                        //定时器时钟12T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TL0 = 0xB1;                                //设置定时初始值
        TH0 = 0x00;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时
        ET0 = 1;                                //使能定时器0中断
}

voidTimer1_Isr(void)interruptTMR1_VECTOR
{
        P07 = ~P07;                                //P07灯闪烁,中断服务程序中尽量少执行长的任务,防止堵塞其他中断
        t1_flag = 1;                        //置1,记录定时器1已产生中断,供主循环判断要处理定时器1的中断任务
}
//定时器1中断服务程序,TMR1_VECTOR在AI8051U.H头文件中已宏定义为3

void Timer1_Init(void)                //定时器1初始化,500毫秒@40.000MHz
{
        TM1PS = 0x19;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
        AUXR &= 0xBF;                        //定时器时钟12T模式
        TMOD &= 0x0F;                        //设置定时器模式
        TL1 = 0x99;                                //设置定时初始值
        TH1 = 0x05;                                //设置定时初始值
        TF1 = 0;                                //清除TF1标志
        TR1 = 1;                                //定时器1开始计时
        ET1 = 1;                                //使能定时器1中断
}

voidsys_init(void)                        //系统初始化
{
        EAXFR = 1;                                        //允许访问扩展的特殊寄存器,XFR
        WTST = 0;                                        //设置取程序代码等待时间,赋值为 0 表示不等待,程序以最快速度运行
        CKCON = 0;                                        //设置访问片内的 xdata 速度,赋值为 0 表示用最快速度访问,不增加额外的等待时间

        P0M0 = 0x00; P0M1 = 0x00;         //设置 P0 口为准双向口模式
        P1M0 = 0x00; P1M1 = 0x00;         //设置 P1 口为准双向口模式
        P2M0 = 0x00; P2M1 = 0x00;         //设置 P2 口为准双向口模式
        P3M0 = 0x00; P3M1 = 0x00;         //设置 P3 口为准双向口模式
        P4M0 = 0x00; P4M1 = 0x00;         //设置 P4 口为准双向口模式
        P5M0 = 0x00; P5M1 = 0x00;         //设置 P5 口为准双向口模式
        P6M0 = 0x00; P6M1 = 0x00;         //设置 P6 口为准双向口模式
        P7M0 = 0x00; P7M1 = 0x00;         //设置 P7 口为准双向口模式
}

voidmain(void)
{
        sys_init();                                        //调用系统初始化函数
        usb_init();                                        //调用USB初始化函数,不需要立即判断电脑已正确识别到USB从设备
        /*         USB型单片机从设备,如需要主动向电脑发送数据,
                在执行USB_SendData( )函数和printf_usb( )函数时,
                这两个函数已增加了判断电脑是否已正确识别到USB从设备的程序。
                如果电脑要主动发送数据给USB从设备,电脑自己会主动判断与USB从设备是否已正确连接。
        */
        EA = 1;                                                //使能中断

        Timer0_Init();                                //调用定时器0初始化函数
        Timer1_Init();                                //调用定时器1初始化函数

        P40 = 0;                                        //给LED灯供电

        while(1)                                      //主循环中查询需要处理的各种事件,如T0/T1中断事件,并打印输出状态
        {
                if(t0_flag)                                //主循环中查询,定时器0是否已产生中断,是否有需要处理的定时器0事件
                {
                        t0_flag = 0;                //清0,T0事件位变量标志
                        printf_usb("Timer0!\r\n");
                }
                if(t1_flag)                                //主循环中查询,定时器1是否已产生中断,是否有需要处理的定时器1事件
                {
                        t1_flag = 0;                //清0,T1事件位变量标志
                        printf_usb("Timer1!\r\n");
                }
        }
}


神农鼎 发表于 2025-12-24 23:18:01

要 做到 USB不停电下载;
要 尝试 AiCube 图形化自动配置生成程序工具;
推荐优先看的:
printf_usb("Hello World !\r\n")及
USB不停电下载, 演示视频链接:
https://www.stcaimcu.com/thread-19077-1-1.html

下载 最新的 AiCube-ISP-V6.96L 或以上版本软件 !
深圳国芯人工智能有限公司-工具软件

下载 最新的 USB库函数,永远用最新的 USB库函数 !
深圳国芯人工智能有限公司-库函数
下载 最新的 用户手册 !
下载 最新的 上机实践指导书 !

下载 最新的 Ai8051U 用户手册
https://www.stcaimcu.com/data/download/Datasheet/AI8051U.pdf

下载 最新的 Ai8051U 实验指导书,
有 AiCube 图形化自动配置生成程序工具使用说明
https://www.stcaimcu.com/data/do ... %AF%BC%E4%B9%A6.pdf

https://v.stcai.com/sv/1c5eec2-197fcd9b766/1c5eec2-197fcd9b766.mp4
上面是 小李 演示:Ai8051U, printf_usb("Hello World !\r\n")及usb不停电下载@AiCube之图形化程序自动生成

神农鼎 发表于 2025-12-24 23:18:51

楼主 USB程序,不是我们最优化后的程序

romeo 发表于 2026-1-14 15:10:29

感谢 www.STCAI.com 的支持 !利用注册获得Ai8051U芯片 !以下是简单的的实验程序,效果非常好!


#include "ai8051u.h"
#include "ai_usb.h"

#define MAIN_Fosc 40000000ul

unsigned char n;

unsigned char ucLed = 0x01;

void delay(unsigned int xms)
{

romeo 发表于 2026-1-14 15:12:46

用ai8051u核心功能板实现了简单流水灯的程序实现,非常棒!#include "ai8051u.h"
#include "ai_usb.h"
#define MAIN_Fosc 40000000ul
unsigned char n;
unsigned char ucLed = 0x01;
void delay(unsigned int xms)
{      unsigned int i;
      do{
                i = MAIN_Fosc / 6000;
                while(i--);
      }while(xms--);
}


void main(void)
{
      EAXFR = 1;
      WTST = 0;
      CKCON = 0;
      
      P2M0 = 0x00;
      P2M1 = 0x00;
      
      usb_init();
      EA = 1;
      
      P2 = 0x01;      //1111 1110
      while(1)
      {
                if(bUsbOutReady)
                {
                        usb_OUT_done();
                }
                for(n = 0; n < 8; n++)
                {
                        ucLed = 1 << n;
                        P2 = ~ucLed;
                        delay(500);
                }
      
      }

romeo 发表于 2026-1-14 15:14:32

学习了时钟和按键的结合,利用按键可以调整时钟的时、分、秒,结果太棒了!


#include <AI8051U.H>
#include "ai_usb.h"
#include "seg.h"
#include "timer.h"
#include "key.h"

unsigned int xms = 0;                  // 毫秒计时变量
unsigned char Seg_String;          // 显示字符串缓存(预留小数点/结束符)
unsigned char Seg_Code = {0,0,0,0,0,0,0,0}; // 数码管段码数组
unsigned char pos = 0;               // 数码管扫描位置
unsigned int Seg_Dly = 0;            // 显示刷新延时

unsigned char Key_Value;               // 按键扫描值
unsigned char Key_Old,Key_Down;      // 按键状态(旧值/下降沿)
unsigned char Key_Dly = 0;             // 按键消抖延时
unsigned char Seg_Mode = 0;            // 显示模式:0-正常时钟 1-调时 2-调分 3-调秒

// RTC时间变量
unsigned char hour = 22;
unsigned char min = 42;
unsigned char sec = 00;

void Seg_Proc(void);
void Key_Proc(void);
void RTC_Proc(void);

void main(void)
{
    EAXFR = 1;
    WTST = 0;
    CKCON = 0;

    // 所有端口设为推挽输出(根据硬件调整)
    P0M0 = 0x00; P0M1 = 0x00;
    P1M0 = 0x00; P1M1 = 0x00;
    P2M0 = 0x00; P2M1 = 0x00;
    P3M0 = 0x00; P3M1 = 0x00;
    P4M0 = 0x00; P4M1 = 0x00;
    P5M0 = 0x00; P5M1 = 0x00;
    P6M0 = 0x00; P6M1 = 0x00;
    P7M0 = 0x00; P7M1 = 0x00;

    Timer0_Init();   
    usb_init();
    EA = 1;

    while(1)
    {
      RTC_Proc();
      Seg_Proc();
      Key_Proc();
    }
}

void Seg_Proc(void)
{
    if(Seg_Dly < 500) return;
    Seg_Dly = 0;

    // 根据显示模式切换显示内容
    switch(Seg_Mode)
    {
      case 0: // 正常运行:显示时分秒(格式:HH:MM:SS)
            sprintf(Seg_String,"%02d-%02d-%02d", (int)hour, (int)min, (int)sec);
            break;
      case 1: // 调时模式:仅显示小时(闪烁/高亮,此处简化)
            sprintf(Seg_String,"%02d    ", (int)hour);
            break;
      case 2: // 调分模式:仅显示分钟
            sprintf(Seg_String,"    %02d", (int)min);
            break;
      case 3: // 调秒模式:仅显示秒
            sprintf(Seg_String,"      %02d", (int)sec);
            break;
    }

    Seg_Trans(Seg_String, Seg_Code);
}

void Key_Proc(void)
{
    if(Key_Dly < 20) return; // 按键消抖(20ms)
    Key_Dly = 0;

    // 按键扫描:下降沿检测
    Key_Value = Key_Du_Read();
    Key_Down = Key_Value & (Key_Old ^ Key_Value); // 仅捕获按键按下的下降沿
    Key_Old = Key_Value;

    switch(Key_Down)
    {
      case 2: // 模式切换键:0→1→2→3→0
            Seg_Mode++;
            if(Seg_Mode == 4) Seg_Mode = 0;
            break;

      case 3: // P33按键:调小时(仅在调时模式/正常模式下生效)
            if(Seg_Mode == 0 || Seg_Mode == 1)
            {
                hour++;
                if(hour >= 24) hour = 0; // 24小时制循环
            }
            break;

      case 4: // P34按键:调分钟(仅在调分模式/正常模式下生效)
            if(Seg_Mode == 0 || Seg_Mode == 2)
            {
                min++;
                if(min >= 60) min = 0; // 分钟0-59循环
            }
            break;

      case 5: // P35按键:调秒(仅在调秒模式/正常模式下生效)
            if(Seg_Mode == 0 || Seg_Mode == 3)
            {
                sec++;
                if(sec >= 60) sec = 0; // 秒0-59循环
            }
            break;

      default:
            break;
    }
}

void Timer0_Isr(void) interrupt 1
{
    xms++;
    Seg_Dly++;
    Key_Dly++;

    // 数码管动态扫描
    Seg_Disp(Seg_Code, pos);
    if(++pos == 8) pos = 0;
}

void RTC_Proc(void)
{
    if(xms == 1000) // 1秒计时
    {
      xms = 0;
      if(++sec == 60) // 秒满60进1分
      {
            sec = 0;
            if(++min == 60) // 分满60进1小时
            {
                min = 0;
                if(++hour == 24) // 小时满24重置
                {
                  hour = 0; // 修复原代码未重置hour的BUG
                }
            }
      }
    }
}

romeo 发表于 2026-1-14 15:15:57

刚刚学习了流水灯+led的知识,完成代码的编写、修改和输出,最后利用ai8051u核心功能板显示输出,感觉非常不错!

#include <AI8051U.H>// ==================== 硬件配置宏定义 ====================#define LED_PORT P1       // LED控制端口(P10-P17)#define LED_ON0         // 共阴极LED:0=亮,1=灭;共阳极则改为1#define LED_OFF 1// 按键引脚位掩码(P3口)- 替代P3_2/P3_3等位定义#define KEY1_MASK 0x04    // P32 = 第2位(0000 0100)#define KEY2_MASK 0x08    // P33 = 第3位(0000 1000)#define KEY3_MASK 0x10    // P34 = 第4位(0001 0000)#define KEY4_MASK 0x20    // P35 = 第5位(0010 0000)// ==================== 全局变量定义 ====================unsigned char led_mode = 1;       // 模式:1=流水灯 2=单独LED 3=全亮/全灭unsigned char flow_dir = 0;       // 流水灯方向:0=左→右 1=右→左unsigned char flow_pos = 0;       // 流水灯当前位置(0-7)unsigned char single_led = 0;   // 模式2下当前点亮的LED位bit all_led_state = 0;            // 模式3下LED状态:0=全灭 1=全亮// 按键相关变量unsigned char key_value;          // 按键扫描值unsigned char key_old, key_down;// 按键旧值/下降沿unsigned int key_dly = 0;         // 按键消抖延时unsigned int led_dly = 0;         // LED刷新延时// ==================== 函数声明 ====================void Timer0_Init(void);void Key_Scan(void);void LED_Proc(void);// ==================== 主函数 ====================void main(void){    // AI8051U核心配置    EAXFR = 1;// 使能扩展RAM访问    WTST = 0;   // 关闭等待状态    CKCON = 0;// 时钟控制寄存器默认配置    // 端口模式配置:P1口推挽输出(LED),P3口准双向输入(按键)    P1M0 = 0xFF; P1M1 = 0x00;// P1口推挽输出    P3M0 = 0x00; P3M1 = 0x00;// P3口准双向输入(默认上拉)    // 定时器0初始化(1ms中断)    Timer0_Init();    EA = 1;// 开启总中断    // 初始化LED为全灭    LED_PORT = 0xFF;    while(1)    {      Key_Scan();   // 按键扫描      LED_Proc();   // LED逻辑处理    }}// ==================== 定时器0初始化(1ms中断) ====================void Timer0_Init(void){    TMOD |= 0x01;// 定时器0工作模式1(16位)    // 11.0592MHz晶振,定时1ms初值    TH0 = 0xFC;       TL0 = 0x66;    ET0 = 1;       // 开启定时器0中断    TR0 = 1;       // 启动定时器0}// ==================== 定时器0中断服务函数(1ms) ====================void Timer0_Isr(void) interrupt 1{    // 重装初值    TH0 = 0xFC;    TL0 = 0x66;    // 计时变量累加    if(key_dly < 20) key_dly++;    // 按键消抖20ms    if(led_dly < 200) led_dly++;   // LED刷新200ms}// ==================== 按键扫描函数(修正位操作问题) ====================void Key_Scan(void){    if(key_dly < 20) return;// 未到消抖时间    key_dly = 0;            // 重置消抖延时    // 扫描P32-P35按键(低电平有效,通过位掩码判断)    key_value = 0;    if((P3 & KEY1_MASK) == 0) key_value = 1;// P32按键(模式切换)    if((P3 & KEY2_MASK) == 0) key_value = 2;// P33按键(方向切换)    if((P3 & KEY3_MASK) == 0) key_value = 3;// P34按键(LED加1)    if((P3 & KEY4_MASK) == 0) key_value = 4;// P35按键(LED减1)    // 下降沿检测:仅捕获按键按下的瞬间    key_down = key_value & (key_old ^ key_value);    key_old = key_value;    // 按键功能处理    switch(key_down)    {      case 1:// P32:模式切换(1→2→3→1)            led_mode++;            if(led_mode > 3) led_mode = 1;            flow_pos = 0;            single_led = 0;            break;      case 2:// P33:流水灯方向切换            flow_dir = !flow_dir;            break;      case 3:// P34:模式2下LED加1            if(led_mode == 2)            {                single_led++;                if(single_led > 7) single_led = 0;            }            break;      case 4:// P35:模式2下LED减1            if(led_mode == 2)            {                if(single_led == 0) single_led = 7;                else single_led--;            }            break;      default:            break;    }}// ==================== LED逻辑处理函数 ====================void LED_Proc(void){    if(led_dly < 200) return;// 未到刷新时间    led_dly = 0;               // 重置LED延时    switch(led_mode)    {      // 模式1:流水灯      case 1:            LED_PORT = 0xFF;// 先熄灭所有LED            if(flow_dir == 0)// 左→右(P10→P17)            {                LED_PORT &= ~(1 << flow_pos);                flow_pos++;                if(flow_pos > 7) flow_pos = 0;            }            else// 右→左(P17→P10)            {                LED_PORT &= ~(1 << (7 - flow_pos));                flow_pos++;                if(flow_pos > 7) flow_pos = 0;            }            break;      // 模式2:单独LED控制      case 2:            LED_PORT = 0xFF;// 熄灭所有LED            LED_PORT &= ~(1 << single_led);// 点亮指定LED            break;      // 模式3:全亮/全灭切换      case 3:            all_led_state = !all_led_state;            LED_PORT = all_led_state ? 0x00 : 0xFF;            break;      default:            led_mode = 1;// 异常模式切回流水灯            break;    }}

romeo 发表于 2026-1-14 16:07:57

顺利完成AI8051U AIcube实验一,效果非常好,AI很好用!
//<<AICUBE_USER_HEADER_REMARK_BEGIN>>
////////////////////////////////////////
// 在此添加用户文件头说明信息
// 文件名称: main.c
// 文件描述:
// 文件版本: V1.0
// 修改记录:
//   1. (2026-01-14) 创建文件
////////////////////////////////////////
//<<AICUBE_USER_HEADER_REMARK_END>>


#include "config.h"                     //默认已包含stdio.h、intrins.h等头文件


//<<AICUBE_USER_INCLUDE_BEGIN>>
// 在此添加用户头文件包含
//<<AICUBE_USER_INCLUDE_END>>


//<<AICUBE_USER_GLOBAL_DEFINE_BEGIN>>
// 在此添加用户全局变量定义、用户宏定义以及函数声明
//<<AICUBE_USER_GLOBAL_DEFINE_END>>




////////////////////////////////////////
// 项目主函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void main(void)
{
    //<<AICUBE_USER_MAIN_INITIAL_BEGIN>>
    // 在此添加用户主函数初始化代码
    //<<AICUBE_USER_MAIN_INITIAL_END>>

    SYS_Init();

    //<<AICUBE_USER_MAIN_CODE_BEGIN>>
    // 在此添加主函数中运行一次的用户代码
    //<<AICUBE_USER_MAIN_CODE_END>>

    while (1)
    {
      //USBLIB_OUT_Done();            //查询方式处理USB接收的数据

      //<<AICUBE_USER_MAIN_LOOP_BEGIN>>
      // 在此添加主函数中用户主循环代码
                printf_usb("Hello World !\r\n");

      //<<AICUBE_USER_MAIN_LOOP_END>>
    }
}

////////////////////////////////////////
// 系统初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void SYS_Init(void)
{
    EnableAccessXFR();                  //使能访问扩展XFR
    AccessCodeFastest();                //设置最快速度访问程序代码
    AccessIXramFastest();               //设置最快速度访问内部XDATA
    IAP_SetTimeBase();                  //设置IAP等待参数,产生1us时基

    //<<AICUBE_USER_PREINITIAL_CODE_BEGIN>>
    // 在此添加用户预初始化代码
    //<<AICUBE_USER_PREINITIAL_CODE_END>>

    P0M0 = 0x00; P0M1 = 0x00;         //初始化P0口为准双向口模式
    P1M0 = 0x00; P1M1 = 0x00;         //初始化P1口为准双向口模式
    P2M0 = 0x00; P2M1 = 0x00;         //初始化P2口为准双向口模式
    P3M0 = 0x00; P3M1 = 0x00;         //初始化P3口为准双向口模式
    P4M0 = 0x00; P4M1 = 0x00;         //初始化P4口为准双向口模式
    P5M0 = 0x00; P5M1 = 0x00;         //初始化P5口为准双向口模式

    PORT4_Init();                     //P4口初始化
    delay_ms(1);
    USBLIB_Init();                      //USB库初始化
    delay_ms(1);

    //<<AICUBE_USER_INITIAL_CODE_BEGIN>>
    // 在此添加用户初始化代码
    //<<AICUBE_USER_INITIAL_CODE_END>>

    EnableGlobalInt();                  //使能全局中断
}

////////////////////////////////////////
// 微秒延时函数
// 入口参数: us (设置延时的微秒值)
// 函数返回: 无
////////////////////////////////////////
void delay_us(uint16_t us)
{
    do
    {
      NOP(34);                        //(MAIN_Fosc + 500000) / 1000000 - 6
    } while (--us);
}


////////////////////////////////////////
// 毫秒延时函数
// 入口参数: ms (设置延时的毫秒值)
// 函数返回: 无
////////////////////////////////////////
void delay_ms(uint16_t ms)
{
    uint16_t i;

    do
    {
      i = MAIN_Fosc / 6000;
      while (--i);
    } while (--ms);
}

////////////////////////////////////////
// P4口初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void PORT4_Init(void)
{
    SetP4nInitLevelHigh(PIN_ALL);       //设置P4初始化电平
    SetP4nQuasiMode(PIN_7 | PIN_5 | PIN_4 | PIN_3 | PIN_2 | PIN_1 | PIN_0); //设置P4.7,P4.5,P4.4,P4.3,P4.2,P4.1,P4.0为准双向口模式
    SetP4nPushPullMode(PIN_6);          //设置P4.6为推挽输出模式

    DisableP4nPullUp(PIN_ALL);          //关闭P4内部上拉电阻
    DisableP4nPullDown(PIN_ALL);      //关闭P4内部下拉电阻
    DisableP4nSchmitt(PIN_ALL);         //使能P4施密特触发
    SetP4nSlewRateNormal(PIN_ALL);      //设置P4一般翻转速度
    SetP4nDrivingNormal(PIN_ALL);       //设置P4一般驱动能力
    SetP4nDigitalInput(PIN_ALL);      //使能P4数字信号输入功能

    //<<AICUBE_USER_PORT4_INITIAL_BEGIN>>
    // 在此添加用户初始化代码
    //<<AICUBE_USER_PORT4_INITIAL_END>>
}

////////////////////////////////////////
// USB库初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void USBLIB_Init(void)
{
    usb_init();                         //初始化USB模块
    USB_SetIntPriority(0);            //设置中断为最低优先级
    set_usb_ispcmd("@STCISP#");         //设置USB不停电下载命令

    //<<AICUBE_USER_USBLIB_INITIAL_BEGIN>>
    // 在此添加用户初始化代码
    //<<AICUBE_USER_USBLIB_INITIAL_END>>
}

////////////////////////////////////////
// 等待USB配置完成函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void USBLIB_WaitConfiged(void)
{
    while (DeviceState != DEVSTATE_CONFIGURED) //等待USB完成配置
      WDT_Clear();                  //清看门狗定时器 (防止硬件自动使能看门狗)
}

////////////////////////////////////////
// USB设备接收数据处理程序
// 入口参数: 无
// 函数返回: 无
// bUsbOutReady:USB设备接收数据标志位
// OutNumber:USB设备接收到的数据长度
// UsbOutBuffer:保存USB设备接收到的数据
////////////////////////////////////////
void USBLIB_OUT_Done(void)
{
    if (bUsbOutReady)                   //查询是否有接收到USB主机发送数据
    {
      //<<AICUBE_USER_USBLIB_ISR_CODE1_BEGIN>>
      // 在此添加中断函数用户代码
      USB_SendData(UsbOutBuffer, OutNumber); //原路返回, 用于测试
      // 在此处添加用户处理接收数据的代码
      //<<AICUBE_USER_USBLIB_ISR_CODE1_END>>
      usb_OUT_done();               //当前包的数据处理完成,通知USB主机可以发送下一包数据
    }
}



//<<AICUBE_USER_FUNCTION_IMPLEMENT_BEGIN>>
// 在此添加用户函数实现代码
//<<AICUBE_USER_FUNCTION_IMPLEMENT_END>>


romeo 发表于 2026-1-14 16:21:54

顺利完成AI8051U AIcube实验二,官方讲解视频非常详细,适合零基础小白学习!
//<<AICUBE_USER_HEADER_REMARK_BEGIN>>
////////////////////////////////////////
// 在此添加用户文件头说明信息
// 文件名称: main.c
// 文件描述:
// 文件版本: V1.0
// 修改记录:
//   1. (2026-01-14) 创建文件
////////////////////////////////////////
//<<AICUBE_USER_HEADER_REMARK_END>>


#include "config.h"                     //默认已包含stdio.h、intrins.h等头文件


//<<AICUBE_USER_INCLUDE_BEGIN>>
// 在此添加用户头文件包含
//<<AICUBE_USER_INCLUDE_END>>


//<<AICUBE_USER_GLOBAL_DEFINE_BEGIN>>
// 在此添加用户全局变量定义、用户宏定义以及函数声明
//<<AICUBE_USER_GLOBAL_DEFINE_END>>




////////////////////////////////////////
// 项目主函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void main(void)
{
    //<<AICUBE_USER_MAIN_INITIAL_BEGIN>>
    // 在此添加用户主函数初始化代码
    //<<AICUBE_USER_MAIN_INITIAL_END>>

    SYS_Init();

    //<<AICUBE_USER_MAIN_CODE_BEGIN>>
    // 在此添加主函数中运行一次的用户代码
    //<<AICUBE_USER_MAIN_CODE_END>>

    while (1)
    {
      USBLIB_OUT_Done();            //查询方式处理USB接收的数据

      //<<AICUBE_USER_MAIN_LOOP_BEGIN>>
      // 在此添加主函数中用户主循环代码
      //<<AICUBE_USER_MAIN_LOOP_END>>
    }
}

////////////////////////////////////////
// 系统初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void SYS_Init(void)
{
    EnableAccessXFR();                  //使能访问扩展XFR
    AccessCodeFastest();                //设置最快速度访问程序代码
    AccessIXramFastest();               //设置最快速度访问内部XDATA
    IAP_SetTimeBase();                  //设置IAP等待参数,产生1us时基

    //<<AICUBE_USER_PREINITIAL_CODE_BEGIN>>
    // 在此添加用户预初始化代码
    //<<AICUBE_USER_PREINITIAL_CODE_END>>

    P0M0 = 0x00; P0M1 = 0x00;         //初始化P0口为准双向口模式
    P1M0 = 0x00; P1M1 = 0x00;         //初始化P1口为准双向口模式
    P2M0 = 0x00; P2M1 = 0x00;         //初始化P2口为准双向口模式
    P3M0 = 0x00; P3M1 = 0x00;         //初始化P3口为准双向口模式
    P4M0 = 0x00; P4M1 = 0x00;         //初始化P4口为准双向口模式
    P5M0 = 0x00; P5M1 = 0x00;         //初始化P5口为准双向口模式

    PORT4_Init();                     //P4口初始化
    delay_ms(1);
    USBLIB_Init();                      //USB库初始化
    delay_ms(1);

    //<<AICUBE_USER_INITIAL_CODE_BEGIN>>
    // 在此添加用户初始化代码
    //<<AICUBE_USER_INITIAL_CODE_END>>

    EnableGlobalInt();                  //使能全局中断
}

////////////////////////////////////////
// 微秒延时函数
// 入口参数: us (设置延时的微秒值)
// 函数返回: 无
////////////////////////////////////////
void delay_us(uint16_t us)
{
    do
    {
      NOP(34);                        //(MAIN_Fosc + 500000) / 1000000 - 6
    } while (--us);
}


////////////////////////////////////////
// 毫秒延时函数
// 入口参数: ms (设置延时的毫秒值)
// 函数返回: 无
////////////////////////////////////////
void delay_ms(uint16_t ms)
{
    uint16_t i;

    do
    {
      i = MAIN_Fosc / 6000;
      while (--i);
    } while (--ms);
}

////////////////////////////////////////
// P4口初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void PORT4_Init(void)
{
    SetP4nInitLevelHigh(PIN_ALL);       //设置P4初始化电平
    SetP4nQuasiMode(PIN_7 | PIN_6 | PIN_4 | PIN_3 | PIN_2 | PIN_1 | PIN_0); //设置P4.7,P4.6,P4.4,P4.3,P4.2,P4.1,P4.0为准双向口模式
    SetP4nPushPullMode(PIN_5);          //设置P4.5为推挽输出模式

    DisableP4nPullUp(PIN_ALL);          //关闭P4内部上拉电阻
    DisableP4nPullDown(PIN_ALL);      //关闭P4内部下拉电阻
    DisableP4nSchmitt(PIN_ALL);         //使能P4施密特触发
    SetP4nSlewRateNormal(PIN_ALL);      //设置P4一般翻转速度
    SetP4nDrivingNormal(PIN_ALL);       //设置P4一般驱动能力
    SetP4nDigitalInput(PIN_ALL);      //使能P4数字信号输入功能

    //<<AICUBE_USER_PORT4_INITIAL_BEGIN>>
    // 在此添加用户初始化代码
    //<<AICUBE_USER_PORT4_INITIAL_END>>
}

////////////////////////////////////////
// USB库初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void USBLIB_Init(void)
{
    usb_init();                         //初始化USB模块
    USB_SetIntPriority(0);            //设置中断为最低优先级
    set_usb_ispcmd("@STCISP#");         //设置USB不停电下载命令

    //<<AICUBE_USER_USBLIB_INITIAL_BEGIN>>
    // 在此添加用户初始化代码
    //<<AICUBE_USER_USBLIB_INITIAL_END>>
}

////////////////////////////////////////
// 等待USB配置完成函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void USBLIB_WaitConfiged(void)
{
    while (DeviceState != DEVSTATE_CONFIGURED) //等待USB完成配置
      WDT_Clear();                  //清看门狗定时器 (防止硬件自动使能看门狗)
}

////////////////////////////////////////
// USB设备接收数据处理程序
// 入口参数: 无
// 函数返回: 无
// bUsbOutReady:USB设备接收数据标志位
// OutNumber:USB设备接收到的数据长度
// UsbOutBuffer:保存USB设备接收到的数据
////////////////////////////////////////
void USBLIB_OUT_Done(void)
{
    if (bUsbOutReady)                   //查询是否有接收到USB主机发送数据
    {
      //<<AICUBE_USER_USBLIB_ISR_CODE1_BEGIN>>
      // 在此添加中断函数用户代码
       // USB_SendData(UsbOutBuffer, OutNumber); //原路返回, 用于测试
      // 在此处添加用户处理接收数据的代码
                if (UsbOutBuffer == 6)
                                printf_usb("Hello World !\r\n");
                        else if (UsbOutBuffer == 7)
                                printf_usb("China !\r\n");

      //<<AICUBE_USER_USBLIB_ISR_CODE1_END>>
      usb_OUT_done();               //当前包的数据处理完成,通知USB主机可以发送下一包数据
    }
}



//<<AICUBE_USER_FUNCTION_IMPLEMENT_BEGIN>>
// 在此添加用户函数实现代码
//<<AICUBE_USER_FUNCTION_IMPLEMENT_END>>
页: [1] 2
查看完整版本: 定时器中断 | 集中在这个帖子打卡