zhp 发表于 2025-3-31 11:44:55

神农鼎的原始代码中:
使用按位取反符号“~”,对单个的端口进行取反操作是没问题的;
按位取反符号“~”和逻辑取反“!”,对单个可以位寻址的端口进行操作,效果相同

INT0 和 INT1 中断代码,看不到预期的现象,是由于按键没有去抖动引起的

神农鼎 发表于 2025-3-31 11:54:40

国学芯用 发表于 2025-3-31 11:15
//学习 AiCube



神农鼎的原始代码中:
使用按位取反符号“~”,对单个可以位寻址的端口进行取反操作是没问题的;
按位取反符号“~”和逻辑取反“!”,对单个可以位寻址的端口进行操作,效果相同

INT0 和 INT1 中断代码,看不到预期的现象,是由于按键没有去抖动引起的

神农鼎 发表于 2025-3-31 15:09:23


https://www.stcaimcu.com/data/download/Datasheet/AI8051U.pdf
见最新 数据手册















kaily 发表于 2025-3-31 15:09:32

////////////////////////////////////////
// 文件名称: main.c
// 文件描述:
// 文件版本: V1.0
// 修改记录:
//   1. (2025-03-31) 创建文件
////////////////////////////////////////

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

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


////////////////////////////////////////
// 项目主函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void main(void)
{
    SYS_Init();

    P40 = 0;                                        //给LED灯供电
      
    while (1)
    {
      if(t0_flag)                              //主循环中查询,定时器0是否已产生中断,是否有需要处理的定时器0事件
      {
                        t0_flag = 0;                //清0,T0事件位变量标志
                        printf_usb("Timer0!\r\n");
                                                                //向电脑USB-CDC串口助手输出“Timer0!”字符串,代表主循环在处理T0不急的任务
      }
      if(t1_flag)                              //主循环中查询,定时器1是否已产生中断,是否有需要处理的定时器1事件
      {
                        t1_flag = 0;                //清0,T1事件位变量标志
                        printf_usb("Timer1!\r\n");
                                                                //向电脑USB-CDC串口助手输出“Timer1!”字符串,代表主循环在处理T1不急的任务
      }
               
      USBLIB_OUT_Done();      //查询方式处理USB接收的数据
    }
}

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

    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口为准双向口模式

    TIMER0_Init();                      //定时器0初始化
    TIMER1_Init();                      //定时器1初始化
    USBLIB_Init();                      //USB库初始化

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

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

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

////////////////////////////////////////
// 定时器0中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER0_ISR(void) interrupt TMR0_VECTOR
{
      P00 = ~P00;                //P00灯闪烁,中断服务程序中尽量少执行长的任务,防止堵塞其他中断
                                        //以上程序代表部分需特急处理的中断事件,可在中断服务程序中直接处理
                                        //但时间不要太长,否则会影响其他中断事件的实时响应速度
      t0_flag = 1;      // t0_flag置1是通知主循环处理部分T0中断事件不需要特急处理的任务
                                        //置1,记录定时器0已产生中断,供主循环查询判断有无需处理的定时器0任务

}

////////////////////////////////////////
// 定时器1中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER1_ISR(void) interrupt TMR1_VECTOR
{
      P07 = ~P07;                //P07灯闪烁,中断服务程序中尽量少执行长的任务,防止堵塞其他中断
                                        //以上程序代表部分需特急处理的中断事件,可在中断服务程序中直接处理
                                        //但时间不要太长,否则会影响其他中断事件的实时响应速度
      t1_flag = 1;      // t1_flag置1是通知主循环处理部分T1中断事件不需要特急处理的任务
                                        //置1,记录定时器1已产生中断,供主循环查询判断有无需处理的定时器1任务
      
}


////////////////////////////////////////
// 定时器0初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER0_Init(void)
{
#define T0_PSCR         102
#define T0_RELOAD       (65536 - SYSCLK / 12 / (T0_PSCR + 1) * 2 / 1)

    TIMER0_TimerMode();               //设置定时器0为定时模式
    TIMER0_12TMode();                   //设置定时器0为12T模式
    TIMER0_Mode0();                     //设置定时器0为模式0 (16位自动重载模式)
    TIMER0_DisableGateINT0();         //禁止定时器0门控
    TIMER0_SetIntPriority(0);         //设置中断为最低优先级
    TIMER0_EnableInt();               //使能定时器0中断
    TIMER0_SetPrescale(T0_PSCR);      //设置定时器0的8位预分频
    TIMER0_SetReload16(T0_RELOAD);      //设置定时器0的16位重载值
    TIMER0_Run();                     //定时器0开始运行
}

////////////////////////////////////////
// 定时器1初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void TIMER1_Init(void)
{
#define T1_PSCR         25
#define T1_RELOAD       (65536 - SYSCLK / 12 / (T1_PSCR + 1) * 500 / 1000)

    TIMER1_TimerMode();               //设置定时器1为定时模式
    TIMER1_12TMode();                   //设置定时器1为12T模式
    TIMER1_Mode0();                     //设置定时器1为模式0 (16位自动重载模式)
    TIMER1_DisableGateINT1();         //禁止定时器1门控
    TIMER1_SetIntPriority(0);         //设置中断为最低优先级
    TIMER1_EnableInt();               //使能定时器1中断
    TIMER1_SetPrescale(T1_PSCR);      //设置定时器1的8位预分频
    TIMER1_SetReload16(T1_RELOAD);      //设置定时器1的16位重载值
    TIMER1_Run();                     //定时器1开始运行
}

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

////////////////////////////////////////
// 等待USB配置完成函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void USBLIB_WaitConfiged(void)
{
    while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
}

////////////////////////////////////////
// USB设备接收数据处理程序
// 入口参数: 无
// 函数返回: 无
// bUsbOutReady:USB设备接收数据标志位
// OutNumber:USB设备接收到的数据长度
// UsbOutBuffer:保存USB设备接收到的数据
////////////////////////////////////////
void USBLIB_OUT_Done(void)
{
    if (bUsbOutReady)                   //查询是否有接收到数据
    {
      USB_SendData(UsbOutBuffer, OutNumber); //原路返回, 用于测试
      usb_OUT_done();               //当前包的数据处理完成
    }
}




神农鼎 发表于 2025-4-7 13:20:23


利用 AiCube@AIapp-ISP V6.95M,
智能配置开发工具启动程序框架自动生成器,实现如下的实验:
32位8051单片机入门的第一个完整的C语言程序,printf_usb("Hello World !\r\n")
https://v.stcai.com/sv/426d0d7d-1963d548feb/426d0d7d-1963d548feb.mp4
AiCube 实验一:直接 printf_usb("Hello World !\r\n")
32位8051单片机入门的第一个完整的C语言程序

AiCube 实验二:查询方式,查询到电脑命令后,
                           printf_usb("Hello World !\r\n")或其他

AiCube 实验三:中断方式,单片机USB中断接收服务函数收到命令后,
                           printf_usb("Hello World !\r\n")或其他



以下是纯手敲代码:
实验一:printf_usb("Hello World !\r\n"),第一个完整的C语言程序
实验二: 查询方式,查询到电脑命令后,printf_usb("Hello World !\r\n")或其他
实验三: 中断方式,单片机USB中断接收服务函数收到命令后,
                            printf_usb("Hello World !\r\n")或其他

https://v.stcai.com/sv/6707e7ef-1960e65e764/6707e7ef-1960e65e764.mp4

神农鼎 发表于 2025-4-7 14:59:16

RTC的演示程序,AiCube 搭建


















////////////////////////////////////////
// 文件名称: main.c
// 文件描述:
// 文件版本: V1.0
// 修改记录:
//   1. (2025-04-07) 创建文件
////////////////////////////////////////

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

bit fAlarm = 0;                        //RTC闹钟查询标志,在中断程序中设置,主循环中查询并清除
bit fDay = 0;                        //RTC天查询标志,在中断程序中设置,主循环中查询并清除
bit fHour = 0;                        //RTC小时查询标志,在中断程序中设置,主循环中查询并清除
bit fMinute = 0;                //RTC分钟查询标志,在中断程序中设置,主循环中查询并清除
bit fSecond = 0;                //RTC秒钟查询标志,在中断程序中设置,主循环中查询并清除

////////////////////////////////////////
// 项目主函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void main(void)
{
    SYS_Init();

    while (1)
    {
                if (fAlarm)                     //判断闹钟查询标志
      {
            fAlarm = 0;               //清除闹钟查询标志
            printf_usb("闹钟中断\r\n");
      }
      
      if (fDay)                     //判断天查询标志
      {
            fDay = 0;                   //清除天查询标志
            printf_usb("RTC天中断\r\n");
      }
      
      if (fHour)                      //判断小时查询标志
      {
            fHour = 0;                  //清除小时查询标志
            printf_usb("RTC小时中断\r\n");
      }
      
      if (fMinute)                  //设置分钟查询标志
      {
            fMinute = 0;                //清除分钟查询标志
            printf_usb("RTC分钟中断\r\n");
      }
      
      if (fSecond)                  //设置秒查询标志
      {
            fSecond = 0;                //清除秒查询标志
            printf_usb("RTC秒中断\r\n");
            printf_usb("20%d-%d-%d %d:%d:%d\r\n", RTC_ReadYear(),
                                                                                                  RTC_ReadMonth(),
                                                RTC_ReadDay(),
                                                RTC_ReadHour(),
                                                RTC_ReadMinute(),
                                                RTC_ReadSecond());
      }
      USBLIB_OUT_Done();            //查询方式处理USB接收的数据
    }
}

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

    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口为准双向口模式

    RTC_Init();                         //RTC初始化
    USBLIB_Init();                      //USB库初始化

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

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

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

////////////////////////////////////////
// RTC中断服务程序
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void RTC_ISR(void) interrupt RTC_VECTOR
{
    if (RTC_CheckAlarmFlag())        //判断是否是RTC闹钟中断
    {
      RTC_ClearAlarmFlag();        //清除中断请求标志位
      fAlarm = 1;                                //设置闹钟查询标志
    }

    if (RTC_CheckDayFlag())                //判断是否是RTC天中断
    {
      RTC_ClearDayFlag();         //清除中断请求标志位
      fDay = 1;               //设置天查询标志
    }

    if (RTC_CheckHourFlag())    //判断是否是RTC小时中断
    {
      RTC_ClearHourFlag();    //清除中断请求标志位
      fHour = 1;            //设置小时查询标志
    }

    if (RTC_CheckMinuteFlag())//判断是否是RTC分钟中断
    {
      RTC_ClearMinuteFlag();//清除中断请求标志位
      fMinute = 1;            //设置分钟查询标志
    }

    if (RTC_CheckSecondFlag())//判断是否是RTC秒中断
    {
      RTC_ClearSecondFlag();//清除中断请求标志位
      fSecond = 1;            //设置秒查询标志
    }
}


////////////////////////////////////////
// RTC初始化函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void RTC_Init(void)
{
    CLK_X32K_Enable();                  //启动外部32768晶振
    CLK_X32K_FullGain();                //振荡器高增益
    CLK_X32K_WaitStable();            //等待振荡器稳定

    RTC_CLK_X32K();                     //RTC使用外部32768当作时钟源

    RTC_SetAlarmHour(7);                //设置RTC闹钟的小时
    RTC_SetAlarmMinute(0);            //设置RTC闹钟的分钟
    RTC_SetAlarmSecond(0);            //设置RTC闹钟的秒
    RTC_SetAlarmSSecond(0);             //初始化RTC闹钟的次秒

    RTC_SetYear(25);                  //设置RTC的年
    RTC_SetMonth(4);                  //设置RTC的月
    RTC_SetDay(7);                      //设置RTC的日
    RTC_SetHour(13);                  //设置RTC的小时
    RTC_SetMinute(18);                  //设置RTC的分钟
    RTC_SetSecond(40);                  //设置RTC的秒
    RTC_SetSSecond(0);                  //初始化RTC的次秒

    RTC_Run();                        //启动RTC
    RTC_SyncInitial();                  //同步RTC的初始值
    while (RTC_IsSyncing());            //等待同步完成

    RTC_SetIntPriority(0);            //设置中断为最低优先级
    RTC_EnableAlarmInt();               //使能RTC闹钟中断
    RTC_EnableDayInt();               //使能RTC天中断
    RTC_EnableHourInt();                //使能RTC小时中断
    RTC_EnableMinuteInt();            //使能RTC分钟中断
    RTC_EnableSecondInt();            //使能RTC秒中断
}

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

////////////////////////////////////////
// 等待USB配置完成函数
// 入口参数: 无
// 函数返回: 无
////////////////////////////////////////
void USBLIB_WaitConfiged(void)
{
    while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
}

////////////////////////////////////////
// USB设备接收数据处理程序
// 入口参数: 无
// 函数返回: 无
// bUsbOutReady:USB设备接收数据标志位
// OutNumber:USB设备接收到的数据长度
// UsbOutBuffer:保存USB设备接收到的数据
////////////////////////////////////////
void USBLIB_OUT_Done(void)
{
    if (bUsbOutReady)                   //查询是否有接收到数据
    {
      USB_SendData(UsbOutBuffer, OutNumber); //原路返回, 用于测试
      usb_OUT_done();               //当前包的数据处理完成
    }
}



草木灰06 发表于 2025-4-8 14:30:44

学习了 收藏

jackfangxq 发表于 2025-4-8 16:13:46

神农鼎 发表于 2025-4-7 13:20
实验一:printf_usb("Hello World !\r\n"),第一个完整的C语言程序
实验二: 查询方式,查询到电脑命令后, ...

请问手册中的程序代码怎么复制粘贴的?谢谢

神农鼎 发表于 2025-4-8 20:37:27

jackfangxq 发表于 2025-4-8 16:13
请问手册中的程序代码怎么复制粘贴的?谢谢

QQ或微信截图工具中,有个【转文字】功能

神农鼎 发表于 2025-4-11 19:45:30

汇编语言 实验
14.14深圳大学 I/O 口实验--位操作模式读取按键状态并点灯




14.14.6实验1: 位操作,用USB直接仿真来调试










;IO模式读取按键状态并点灯(位操作)
$INCLUDE(AI8051U.INC)       ;包含AI8051U的头文件

;------------------------------------------------

    ORG   0000H         ;程序复位地址

RESET:

    SETB    EAXFR         ;允许访问扩展的特殊寄存器,XFR
    MOV   WTST,#00H       ;设置取程序代码等待时间,赋值为 0 表示不等待,程序以最快速度运行
    MOV   CKCON,#00H      ;设置访问片内的 xdata 速度,赋值为 0 表示用最快速度访问,不增加额外的等待时间

    MOV   P0M0,#38H       ;设置P03、P04为推挽输出,P05为开漏输出,其余为准双向口模式
    MOV   P0M1,#20H
    MOV   P1M0,#00H       ;设置 P1 口为准双向口模式
    MOV   P1M1,#00H
    MOV   P2M0,#00H       ;设置 P2 口为准双向口模式
    MOV   P2M1,#00H
    MOV   P3M0,#30H       ;P30、P31为高阻输入,P32为准双向口、P33为高阻输入、P34和P35为开漏输出
    MOV   P3M1,#3BH
    MOV   P4M0,#00H       ;设置 P4 口为准双向口模式
    MOV   P4M1,#00H
    MOV   P5M0,#00H       ;设置 P5 口为准双向口模式
    MOV   P5M1,#00H
    MOV   P6M0,#00H       ;设置 P6 口为准双向口模式
    MOV   P6M1,#00H
    MOV   P7M0,#00H       ;设置 P7 口为准双向口模式
    MOV   P7M1,#00H

    MOV   WR0,#WORD2 P3PU ;打开P33、P34、P35的内部上拉电阻,并且仅修改这三个I/O的上拉电阻打开状态
    MOV   WR2,#WORD0 P3PU
    MOV   A,#38H
    MOV   @DR0,R11

    LCALL   DELAY1MS      ;延时1ms,等待IO口电平稳定,因为前面刚改变了模式
                            ;立刻读可能会读到错误的电平,所以需要先等待电平变化稳定后再读
    CLR   P40             ;打开LED部分的供电

;------------------------------------------------

MAINLOOP:

    JNB   P3.2,P32ISLOW   ;判断P32的电平
P32ISHIGH:
    SETB    P0.2            ;P32为高电平,则LED02灭
    SJMP    CHECKP33      ;跳转到判断P33
P32ISLOW:
    CLR   P0.2            ;P32为低电平,则LED02亮

CHECKP33:
    JNB   P3.3,P33ISLOW   ;判断P33的电平
P33ISHIGH:
    SETB    P0.3            ;P33为高电平,则LED03灭
    SJMP    CHECKP34      ;跳转到判断P34
P33ISLOW:
    CLR   P0.3            ;P33为低电平,则LED03亮

CHECKP34:
    JNB   P3.4,P34ISLOW   ;判断P34的电平
P34ISHIGH:
    SETB    P0.4            ;P34为高电平,则LED04灭
    SJMP    CHECKP35      ;跳转到判断P35
P34ISLOW:
    CLR   P0.4            ;P34为低电平,则LED04亮

CHECKP35:
    JNB   P3.5,P35ISLOW   ;判断P35的电平
P35ISHIGH:
    SETB    P0.5            ;P35为高电平,则LED05灭
    SJMP    MAINLOOP      ;跳回到主循环开始的地方继续运行程序
P35ISLOW:
    CLR   P0.5            ;P35为低电平,则LED05亮

    SJMP    MAINLOOP      ;跳回到主循环开始的地方继续运行程序

;------------------------------------------------

DELAY1MS:                                ;@40.000MHz
        PUSH        DR0
        MOV                WR0,#0
        MOV                WR2,#9998
NEXT:
        DEC                DR0,#1
        JNE                NEXT
        POP                DR0
        RET

;------------------------------------------------

    END
页: 1 2 3 [4] 5 6
查看完整版本: 深圳大学《单片机原理及接口技术》上机实验演示视频@Ai8051U