垂柳工作室 发表于 2025-9-16 17:42:38

AI8051U单片机学用打卡 | 到这步可直接要 【免费+包邮送】的AI8051U实验箱

新学期伊始,不忘助力国产替代初心,手头没有试验箱,先用“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义放在附件可下载。 第一节,搭建学用环境 一、下载必要软件工具1. 下载AI 8051U使用手册,下载地址:https://www.stcaimcu.com/data/download/Datasheet/AI8051U.pdf2. 下载安装pdf查看工具,推进下载wps办公软件,WPS办公软件下载地址:https://www.wps.cn/3. 打开上面下载AI 8051U使用手册,参考第二章内容和步骤,下载安装keil开发工具。file:////tmp/wps-lyj/ksohtml/wpsW1GNOV.jpg4. 下载安装STC烧录工具,下载地址:https://www.stcaimcu.com/data/download/Tools/AiCube-ISP-v6.96C.zip5. 下载并解压AI 8051U 试验箱参考学习代码包,下载地址:https://www.stcaimcu.com/data/download/DemoCode/AI8051U-DEMO-CODE-V1.2.zip二、设置烧录工具1. 打开STC烧录工具,参考AI 8051U使用手册第二章第五节,添加型号和头文件,参考第二章第七节新建一个32位8051项目,如下图。file:////tmp/wps-lyj/ksohtml/wpskGPgn2.jpg2. keil开发工具设置,参考AI 8051U使用手册第二章第七节2.2部分设置各个参数。file:////tmp/wps-lyj/ksohtml/wpsYGpOg9.jpg三、创建第一个流水灯程序1. 复制AI 8051U 试验箱参考学习代码包中流水灯main.c里代码到keil编辑栏main.c中,file:////tmp/wps-lyj/ksohtml/wpskYk6bg.jpg并参考如下代码修改:#include "AI8051U.h"typedef unsigned char u8;typedef unsigned int u16;typedef unsigned long u32; #define MAIN_Fosc      24000000ULvoiddelay_ms(u8 ms);void main(void){    WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快    EAXFR = 1; //扩展寄存器(XFR)访问使能    CKCON = 0; //提高访问XRAM速度     P2M1 = 0x00;   P2M0 = 0x00;   //设置擎天柱p2端口为准双向口        while(1)    {      P20 = 0; //擎天柱LED 1点亮      delay_ms(250);      P20 = 1; //擎天柱LED 1熄灭       P21 = 0; //擎天柱LED 2点亮      delay_ms(250);      P21 = 1; //擎天柱LED 2熄灭       P22 = 0; //擎天柱LED 3点亮      delay_ms(250);      P22 = 1; //擎天柱LED 3熄灭       P23 = 0; //擎天柱LED 4点亮      delay_ms(250);      P23 = 1; //擎天柱LED 4熄灭       P24 = 0; //擎天柱LED 5点亮      delay_ms(250);      P24 = 1; //擎天柱LED 5熄灭       P25 = 0; //擎天柱LED 6点亮      delay_ms(250);      P25 = 1; //擎天柱LED 6熄灭       P26 = 0; //擎天柱LED 7点亮      delay_ms(250);      P26 = 1; //擎天柱LED 7熄灭       P27 = 0; //擎天柱LED 8点亮      delay_ms(250);      P27 = 1; //擎天柱LED 8熄灭    }} voiddelay_ms(u8 ms){   u16 i;   do{          i = MAIN_Fosc / 6000;          while(--i);   }while(--ms);}3. 编译下载到擎天柱。先参考下图,点击编译生成芯片烧录文件。file:////tmp/wps-lyj/ksohtml/wps4Zhi0m.jpg2. 用数据线把擎天柱连接到电脑,如下图,同时按下A(p32)和B(电源开关)两个键,先松B键再松A键。file:////tmp/wps-lyj/ksohtml/wpsyRnnQt.png烧录工具扫描串口会出现“USB-Write”字样,然后对照下图,红框选择编译的文件,最后按下“下载/编程”按钮烧录程序,擎天柱LED等流动起来了。file:////tmp/wps-lyj/ksohtml/wpsuZQ3Rz.jpg

垂柳工作室 发表于 2025-9-16 23:33:20

新学期伊始,不忘助力国产替代初心,手头没有试验箱,先用“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义(适合有c语言基础的同学)。 单片机(Single-Chip Microcomputer),又称微控制单元(MCU),是一种将中央处理器(CPU)、存储器(包括ROM和RAM)、输入/输出(I/O)接口、定时器/计数器、中断系统等主要计算机组件电路元件集成在一块芯片上,并且可以用代码控制的微型计算机系统。上节课提到的P2端口就是单片机输入/输出(I/O)接口,代码就是控制单片机的指令。学习单片机需要硬件电路和编程基础,零基础的同学在跟随着学习之外,抽空补习一点相关知识,建议遇到了哪儿就学哪儿,带着问题学,后期我们将实践PCB电路板,另外自行准备相关基础工具,比如电洛铁、万用表等。 第二节,实现不停电下载1.利用烧录工具AICube助手自动生成代码。打开STC烧录工具,参考下图红框,三个步骤设置:file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml6640/wps1.jpg 注意文件名最好都用英文,避免出现乱码,点击确定后,工具软件自动生成代码,并自动关联keil启动打开代码,stc工程师真牛!file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml6640/wps2.jpg 一个是main.c另一个是usb库文件2. Main.c文件去掉绿色注释后的代码如下:#include "config.h"                     //默认已包含stdio.h、intrins.h等头文件 void main(void){    SYS_Init();    while (1)    {      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口为准双向口模式    delay_ms(1);    USBLIB_Init();                      //USB库初始化    delay_ms(1);    EnableGlobalInt();                  //使能全局中断} void delay_us(uint16_t us){    do    {      NOP(34);                        //(MAIN_Fosc + 500000) / 1000000 - 6    } while (--us);} void delay_ms(uint16_t ms){    uint16_t i;    do    {      i = MAIN_Fosc / 6000;      while (--i);    } while (--ms);} void USBLIB_Init(void){    usb_init();                         //初始化USB模块    USB_SetIntPriority(0);            //设置中断为最低优先级    set_usb_ispcmd("@STCISP#");         //设置USB不停电下载命令} void USBLIB_WaitConfiged(void){    while (DeviceState != DEVSTATE_CONFIGURED) //等待USB完成配置      WDT_Clear();                  //清看门狗定时器 (防止硬件自动使能看门狗)} void USBLIB_OUT_Done(void){    if (bUsbOutReady)                   //查询是否有接收到USB主机发送数据    {               USB_SendData(UsbOutBuffer, OutNumber); //原路返回, 用于测试            usb_OUT_done();               //当前包的数据处理完成,通知USB主机可以发送下一包数据    }}3. 添加流水灯代码:在上方主函数void main(void)里面“USBLIB_OUT_Done();”下一行添加上节课代码:P20 = 0;//擎天柱LED 1点亮      delay_ms(250);      P20 = 1;//擎天柱LED 1熄灭P22 = 0;//擎天柱LED 3点亮      delay_ms(250);      P22 = 1;//擎天柱LED 3熄灭4. 编译好后按照下图设置,还得按上节课方法,同时按下擎天柱p32键(A键)和电源开关(B键)后,先松开电源开关,再松开p32键,烧录程序扫描到USB—Writer后点击“下载/编程”按钮把程序烧录到擎天柱后,LED1和LED3闪烁,实现了可以不断电自动下载。file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml6640/wps3.jpg file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml6640/wps4.png 这种方法方便,将来有利于提高开发效率,值得提倡使用,但不利于初学者学习,可能看了一头雾水。作为初学者建议要学习理解其中原理。STC单片机的不断电自动下载功能是一种基于芯片内部ISP监控区的特殊编程技术,它通过软件复位机制触发单片机从ISP监控区启动,从而实现程序更新的无缝操作。这项技术巧妙地解决了传统下载方式需要频繁断电的痛点,显著提升了开发效率和系统可靠性。STC单片机采用双启动区设计,包含两个关键程序存储区域:用户程序区和ISP监控区。ISP监控区是STC单片机出厂前已固化好的引导程序,负责接收上位机指令并执行存储器擦写操作。具体可参考学习芯片手册2.36.4章节。file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml6640/wps5.jpgfile:///C:/Users/Administrator/AppData/Local/Temp/ksohtml6640/wps6.jpg 参考芯片手册351页,USB范例程序,和手册第1005页,细心同学会发现,冲哥视频中代码有自定义三行代码,主要是ubs库版本问题。20250319以后的USB库就不需要自定义三行代码。file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml6640/wps7.jpgfile:///C:/Users/Administrator/AppData/Local/Temp/ksohtml6640/wps8.jpg 至于usb库文件有兴趣同学可自行找USB专题章节深入研究学习。

西西研究员 发表于 2025-9-17 08:33:57

推荐优先看的 printf_usb("Hello World !\r\n")及usb不停电下载, 演示视频链接
https://v.stcai.com/sv/1c5eec2-197fcd9b766/1c5eec2-197fcd9b766.mp4
https://v.stcai.com/sv/1fce8086-197cf2b9dd4/1fce8086-197cf2b9dd4.mp4

西西研究员 发表于 2025-9-19 13:59:15

新学期伊始,不忘助力国产替代初心,手头没有试验箱,先用“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义(适合有c语言基础的同学)。

单片机(Single-Chip Microcomputer),又称微控制单元(MCU),是一种将中央处理器(CPU)、存储器(包括ROM和RAM)、输入/输出(I/O)接口、定时器/计数器、中断系统等主要计算机组件电路元件集成在一块芯片上,并且可以用代码控制的微型计算机系统。
上节课提到的P2端口就是单片机输入/输出(I/O)接口,代码就是控制单片机的指令。学习单片机需要硬件电路和编程基础,零基础的同学在跟随着学习之外,抽空补习一点相关知识,建议遇到了哪儿就学哪儿,带着问题学,后期我们将实践PCB电路板,另外自行准备相关基础工具,比如电洛铁、万用表等。

第二节,实现不停电下载
1.利用烧录工具AICube助手自动生成代码。打开STC烧录工具,参考下图红框,三个步骤设置:
file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml3188/wps1.jpg
注意文件名最好都用英文,避免出现乱码,点击确定后,工具软件自动生成代码,并自动关联keil启动打开代码,stc工程师真牛!
file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml3188/wps2.jpg
一个是main.c另一个是usb库文件
2. Main.c文件去掉绿色注释后的代码如下:
#include "config.h"                     //默认已包含stdio.h、intrins.h等头文件

void main(void)
{
    SYS_Init();
    while (1)
    {
      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口为准双向口模式
    delay_ms(1);
    USBLIB_Init();                      //USB库初始化
    delay_ms(1);
    EnableGlobalInt();                  //使能全局中断
}

void delay_us(uint16_t us)
{
    do
    {
      NOP(34);                        //(MAIN_Fosc + 500000) / 1000000 - 6
    } while (--us);
}

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

void USBLIB_Init(void)
{
    usb_init();                         //初始化USB模块
    USB_SetIntPriority(0);            //设置中断为最低优先级
    set_usb_ispcmd("@STCISP#");         //设置USB不停电下载命令
}

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

void USBLIB_OUT_Done(void)
{
    if (bUsbOutReady)                   //查询是否有接收到USB主机发送数据
    {         
      USB_SendData(UsbOutBuffer, OutNumber); //原路返回, 用于测试      
      usb_OUT_done();               //当前包的数据处理完成,通知USB主机可以发送下一包数据
    }
}
3. 添加流水灯代码:
在上方主函数void main(void)里面“USBLIB_OUT_Done();”下一行添加上节课代码:
P20 = 0;//擎天柱LED 1点亮
      delay_ms(250);
      P20 = 1;//擎天柱LED 1熄灭
P22 = 0;//擎天柱LED 3点亮
      delay_ms(250);
      P22 = 1;//擎天柱LED 3熄灭
4. 编译好后按照下图设置,还得按上节课方法,同时按下擎天柱p32键(A键)和电源开关(B键)后,先松开电源开关,再松开p32键,烧录程序扫描到USB—Writer后点击“下载/编程”按钮把程序烧录到擎天柱后,LED1和LED3闪烁,实现了可以不断电自动下载。
file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml3188/wps3.jpg

file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml3188/wps4.png
这种方法方便,将来有利于提高开发效率,值得提倡使用,但不利于初学者学习,可能看了一头雾水。作为初学者建议要学习理解其中原理。STC单片机的不断电自动下载功能是一种基于芯片内部ISP监控区的特殊编程技术,它通过软件复位机制触发单片机从ISP监控区启动,从而实现程序更新的无缝操作。这项技术巧妙地解决了传统下载方式需要频繁断电的痛点,显著提升了开发效率和系统可靠性。
STC单片机采用双启动区设计,包含两个关键程序存储区域:用户程序区和ISP监控区。ISP监控区是STC单片机出厂前已固化好的引导程序,负责接收上位机指令并执行存储器擦写操作。具体可参考学习芯片手册2.36.4章节。
file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml3188/wps5.jpg

file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml3188/wps6.jpg
参考芯片手册351页,USB范例程序,和手册第1005页,细心同学会发现,冲哥视频中代码有自定义三行代码,主要是ubs库版本问题。20250319以后的USB库就不需要自定义三行代码。
file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml3188/wps7.jpg

file:///C:/Users/Administrator/AppData/Local/Temp/ksohtml3188/wps8.jpg
至于usb库文件有兴趣同学可自行找USB专题章节深入研究学习。

西西研究员 发表于 2025-9-19 13:59:53

新学期伊始,不忘助力国产替代初心,手头没有试验箱,先用“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义。
第三节,定时器周期性调度任务
本节课主要任务是移植AI8051U试验箱代码27通过定时器周期性调度任务综合例程,温习一下单片机的定时器,解析一下程序代码。
一、学习内容
1. 定时器。什么为定时器,20250825版本的AI8051U芯片手册在第十七章介绍定时器,AI8051U芯片内置6个定时器(T0、T1、T2、T3、T4、T11),建议认真学习T0、T11两个定时器就够了,其他类似。

2. 定时器工作三部曲:
一是‌初始化配置‌:通过控制寄存器设置工作模式、时钟源和预分频器参数。
二是‌启动计数‌:计数器从初值开始,对时钟信号进行递增或递减计数。
三是‌溢出处理‌:当计数值达到上限(如16位计数器为65535)时,产生溢出中断或自动重载初值,循环执行,下图就是计时器工作示意图。‌‌

3. 学会查阅AI 8051U使用手册掌握定时器寄存器设置。本节课涉及T0定时器,查阅WTST、EAXFR、CKCON、P2M1、P2M0、AUXR、TH0、THL、ET0、TR0、EA。以AUXR为例,


二、代码移植与解析
1. 代码移植
拷贝上节课不停电可自动下载例程,打开AI8051U试验箱代码27通过定时器周期性调度任务综合例程代码,移植相关代码,只有一个man.c和usb_cdc_32.LIB两个文件。

2. 解析代码
man.c的代码如下:
#include "AI8051U.h" //引用AI8051U头文件,里面定义寄存器、引脚等等
#include "ai_usb.h" //引用USB库函数,实现不停电自动下载等
#define MAIN_Fosc      24000000UL //定义主时钟为24兆赫兹
#define Timer0_Reload   (MAIN_Fosc / 1000) //定义定时器重载值
//为了区别讲解第二节课不停电自动下载例程,特意引用20250319以前版本USB库函数,所以得自定义下面三行代码
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";   //设置自动复位到ISP区的用户接口命令
//定义任务调用结构体
typedef struct
{
u8 Run;               //任务状态:Run/Stop
u16 TIMCount;         //定时计数器
u16 TRITime;          //重载计数器
void (*TaskHook) (void); //任务函数,这里是传递函数地址,是指针、实参
} TASK_COMPONENTS;
//申明闪LED函数,具体函数放在主函数void main(void)后面
void ShowLed(void);
//定义任务函数
static TASK_COMPONENTS Task_Comps[]=
{
//状态计数周期函数   
    {0, 500, 500, ShowLed},          //闪LED任务初始不亮,间隔500毫秒,周期500毫秒,任务函数名ShowLed
    /* 有新任务,先申明定义任务,再对照上面参数往下添加 */
};
//计算任务个数。Task_Comps是任务数组,Task_Comps是第一个任务,sizeof(Task_Comps)是计算总任务占用内存字节数,sizeof(Task_Comps) 是计算单个任务占用内存字节数,由于每个任务数据格式一样,所以Tasks_Max就是记录任务总个数。
u8 Tasks_Max = sizeof(Task_Comps)/sizeof(Task_Comps);
/*************本地函数声明    **************/
void Timer_config(void);
void Task_Marks_Handler_Callback(void);
void Task_Pro_Handler_Callback(void);
/******************** 主函数 **************************/
void main(void)
{
    WTST = 0;   //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度
    P2M1 = 0x00; //设置为准双向口
P2M0 = 0x00;
Timer_config(); //启动定时器
usb_init();   //初始化USB
EA = 1;      //打开总中断
    while(1)
    {
      if( DeviceState != DEVSTATE_CONFIGURED ) //
continue;
if( bUsbOutReady )
{
usb_OUT_done();
}
Task_Pro_Handler_Callback();
    }
}
//========================================================================
// 函数: Task_Pro_Handler_Callback
// 描述: 任务处理回调函数.
// 参数: None.
// 返回: None.
//========================================================================
void Task_Pro_Handler_Callback(void)
{
    u8 i;
    for(i=0; i<Tasks_Max; i++)
    {
      if(Task_Comps.Run) /* If task can be run */
      {
            Task_Comps.Run = 0;      /* Flag clear 0 */
            Task_Comps.TaskHook();   /* Run task */
      }
    }
}
//========================================================================
// 函数: Task_Handler_Callback
// 描述: 任务标记回调函数.
// 参数: None.
// 返回: None.
//========================================================================
void Task_Marks_Handler_Callback(void)
{
    u8 i;
    for(i=0; i<Tasks_Max; i++)
    {
      if(Task_Comps.TIMCount)      /* If the time is not 0 */
      {
            Task_Comps.TIMCount--;   /* Time counter decrement */
            if(Task_Comps.TIMCount == 0) /* If time arrives */
            {
                /*Resume the timer value and try again */
                Task_Comps.TIMCount = Task_Comps.TRITime;
                Task_Comps.Run = 1;      /* The task can be run */
            }
      }
    }
}
//========================================================================
// 函数: Timer_config
// 描述: 定时器配置
// 参数: none.
// 返回: none.
void Timer_config(void)
{
    AUXR = 0x80;    //Timer0 set as 1T, 16 bits timer auto-reload,
    TH0 = (u8)(Timer0_Reload / 256);
    TL0 = (u8)(Timer0_Reload % 256);
    ET0 = 1;      //Timer0 interrupt enable
    TR0 = 1;      //Tiner0 run
}
//========================================================================
// 函数: Timer0_ISR_Handler
// 描述: Timer0中断函数.
// 参数: none.
// 返回: none.
//========================================================================
void Timer0_ISR_Handler (void) interrupt TMR0_VECTOR //进中断时已经清除标志
{
Task_Marks_Handler_Callback(); //任务标记回调函数
}
void ShowLed(void)
{
P20 =!P20;
P23 =!P23;
}
本例程是开启了定时器,主函数man循环不断调用Task_Pro_Handler_Callback(),循环判断任务体数组各任务成员属性Task_Comps.Run状态,状态为可运行(即可为1),将状态设置为不可运行,即Task_Comps.Run = 0,然后调用运行任务函数,本实例任务是闪LED灯,Task_Comps.TaskHook()这句就是调用 ShowLed()函数。ShowLed()函数是让擎天柱P20、P23两个LED灯同时闪烁。
定时器是1毫秒自动调用一次Task_Marks_Handler_Callback()函数,循环判断任务体数组各任务成员属性Task_Comps.TIMCount值是否大于0,TIMCount大于0就减1,直到TIMCount等于0时,将任务可运行标志设置为可运行即Task_Comps.Run=1,把任务周期值重新赋值给任务计数器,即Task_Comps.TIMCount = Task_Comps.TRITime。

垂柳工作室 发表于 2025-9-19 14:57:47

新学期伊始,不忘助力国产替代初心,手头没有试验箱,先用“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义。第四节,自动生成多文件项目代码,温习C/C++语言本节课任务是学用AICube自动生成程序,温习c语言变量作用域一、更新STC烧录工具和USB库,自动生成项目文件1. 下载资料。STC烧录工具最新版是AiCube-ISP-V6.96C,USB最新库文件是20250716版;AiCube-ISP-V6.96C下载地址:https://www.stcaimcu.com/data/download/Tools/AiCube-ISP-v6.96C.zip2. 更新更新keil头文件。解压运行烧录工具(AiCube-ISP-V6.96C.exe),按下图顺序操作找到keil安装目录(keil_v5),更新头文件。https://www.stcaimcu.com/data/attachment/forum/202509/19/130632s23fkk731e0l2uu1.png
3. 打开AiCube自动生成项目代码。参考下图顺序,点击启动烧录工具AiCube.设置好单片机型号、项目名称、保存路径,这里项目类型设置为多代码文件项目。https://www.stcaimcu.com/data/attachment/forum/202509/19/130633fueesyrqee8u4gr8.png
点击确定后,勾选USB,通用串行总线和TIMER0,定时器0选相框,USB库函数设置“与printf函数关联”为是。https://www.stcaimcu.com/data/attachment/forum/202509/19/130633o44acta44gtltnt6.png
定时器0开启中断使能,如下图,点击自动生成代码按钮弹出提示项目创建成功提示,再点确定后会关联启动keil打开所生成的项目文件。https://www.stcaimcu.com/data/attachment/forum/202509/19/130633b1shb1gq8o1y9q11.png
AiCube自动生成的项目包含三个c文件和usb库,查看各个文件内容,发现大量注释,分门别类提示放置用户的变量、函数,包含头文件等等,点击编译,编译器提示0错误0警告。足见AiCube功能强大方便。在看代码时,遇到不清楚函数、变量等,可鼠标右键点击追溯函数、变量定义,具体操作参考下图。https://www.stcaimcu.com/data/attachment/forum/202509/19/130634ey2227dlft2wz6z2.png
二、温习验证c语言变量生命周期1. 移植AI8051U实验箱多任务代码。个人觉得官方推荐的实验箱代码:27-通过定时器周期性调度任务综合例程相当好。先拷贝其中Sources\src\Task.c和Sources\inc\Task.h到demo项目相应目录下。对照我刚才AiCube自动生成的项目,Task.c拷贝到G:\STCproject\AI8051U_PROJECT\demo\Sources\目录下,Task.h拷贝到G:\STCproject\AI8051U_PROJECT\demo\Sources\inc目录,下,路径可参考下图。https://www.stcaimcu.com/data/attachment/forum/202509/19/130634auxtnxbxthbxexux.png
2. 将Task.c添加到项目中。展开demo,鼠标右键点击AiCube添加现存文件task.c,参考下图操作。https://www.stcaimcu.com/data/attachment/forum/202509/19/130634cnwcalbj9ljwwa3b.png
3. 主函数添加代码。main.c文件要在13行#include "config.h"下面添加一句,#include "Task.h",即包含了Task.c的头文件,在第49行“在此添加主函数中用户主循环代码”下一行添加任务处理回调函数Task_Pro_Handler_Callback();备注:Task.c任务函数功能请参考上一节课解析。https://www.stcaimcu.com/data/attachment/forum/202509/19/130635x9biinitenqci60q.png
4. 添加任务函数和变量。task.c文件添加一个数组变量,这里就拷贝27-通过定时器周期性调度任务综合例程app_Display.c文件的t_dispiay[]标准字库数组,定义一个用于验证变量display_index,再定义一个任务函数Test_Demo()驱动擎天柱p2端口led灯。task.h文件申明一下任务函数Test_Demo();timer.c文件第13行#include "config.h"下面添加一句,#include "Task.h";在第61行下面添加一句任务标记回调函数:Task_Marks_Handler_Callback();5. 烧录验证。编译烧录看到擎天柱LED在闪烁,说明task.c文件display_index变量是全局变量,生命周期是程序运行到结束。三、分析理解Keil多文件项目中变量生命周期在C/C++语言中,变量的作用域和链接性是两个独立但相互关联的概念。变量display_index在task.c文件中定义为全局变量,具有外部链接性,只要通过适当的声明,可以在程序的任何地方被访问 。1.作用域(Scope):决定变量在源代码中可见的范围。全局变量在文件顶层定义,作用域为整个文件,函数内部定义的变量作用域仅限于该函数内。2.链接性(Storage Class):决定变量在不同编译单元间的可见性,外部链接(external linkage):默认情况下,未使用static关键字修饰的全局变量具有外部链接性,可在程序各处访问。3.内部链接 internal linkage:使用static关键字修饰的全局变量仅在当前文件内可见。task.c文件中的全局变量display_index没有使用static关键字修饰,因此它具有外部链接性。这使得即使主函数main.c文件未在头文件中声明extern int display_index,也能通过调用task.c文件中的函数Test_Demo()间接访问和修改display_index的值。因为函数Test_Demo()在定义时已经能够访问task.c文件中的全局变量display_index,且函数Test_Demo()的实现代码与display_index的存储位置已建立直接关联。函数Test_Demo()作为task.c文件的接口,封装了对全局变量display_index的操作。其核心机制在于函数封装作用,当主函数main.c文件调用Test_Demo()时,实际执行的是task.c文件中已绑定display_index变量地址的函数代码。函数Test_Demo()的作用域包含task.c文件的所有全局变量,因此可以直接访问和修改display_index的值,无需额外声明。这种机制是C/C++语言设计的基本特性之一,它允许通过函数封装实现对全局状态的修改,同时保持代码的模块化和可维护性。附件内容:课件讲义、程序源代码、擎天柱验证视频

垂柳工作室 发表于 2025-9-21 12:28:39

新学期伊始,不忘助力国产替代初心,手头没有试验箱,先用“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义。
第五节,学用调试仿真接口(擎天柱LED_DIP40)本节课主要任务是用擎天柱配合烧录工具cdc/hid串口助手,验证理解仿真接口擎天柱LED的指令意思,尝试调用封装接口函数。一、准备验证工作。拷贝上节课04自动生成代码AiCube,连接擎天柱到电脑上。由于上节课烧录到擎天柱的代码包含打开USB-CDC功能,打开烧录工具会多一个串口,我这里显示是(COM6)USB-CDC(如下图)。鼠标点击菜单“调试仿真接口”找到并鼠标左键点击打开“擎天柱-LED-DIP40(4)”,再鼠标左键点击“调试仿真接口”菜单“接口协议及帮助”,鼠标左键点击打开“DIP40封装LED接口”,学习功能1-4。 二、验证DIP40各功能指令。1. 功能1控制DIP40的指定管脚输出低电平
字节数1234567
命令格式:4CH45H44H28HO2H00HPx
命令注解命令头后面有效数据长度固定为00H端口的状态数据
   px的注解一览表
px位数Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
px位解析固定为0管脚的组,作为高字节管脚的位,作为低字节
计算时注意:Bit6、Bit5、Bit4、Bit3作为一个字节计算示例1末位px解析表
px位数Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
03H00000011
px位解析固定为0值为0指定P0端口值为3指定P0端口第3管脚
示例2末位px解析表
px位数Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
25H00100101
px位解析固定为0值为4指定P4端口值为5指定P4端口第5管脚
组:Bit6、Bit5、Bit4、Bit3二进制值:0 1 0 0换算十六进制值为4;位:Bit2、Bit1、Bit0二进制值:1 0 1换算十六进制值为5;验证:设置点亮P5.7
P5.7位数Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
2FH00101111
固定为0值为5指定P5端口值为7指定P5端口第7管脚
STC工程师封装了LED40_ClrBit函数,在ai_usb.h中申明,函数有两个参数,第一个参数是指定端口,第二个参数指定端口引脚LED40_ClrBit(0, 3);    //设置P0.3口输出低电平LED40_ClrBit(4, 5);    //设置P4.5口输出低电平2. 功能2控制DIP40的指定管脚输出高电平控制命令除了px的bit7:固定为1外,其他的跟上面“控制DIP40的指定管脚输出低电平”一模一样,STC工程师封装函数名LED40_SetBit,可直接调用。LED40_SetBit(4, 5);    //设置P4.5口输出高电平3. 功能3控制DIP40的各个管脚上LED的状态。
字节数1234567
命令格式:4CH45H44H28HO2Hx1Px
命令注解命令头后面有效数据长度屏蔽位端口的状态数据
第6字节x1:
x1位数Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
x1位解析固定为0P5P4P3P2P1P0
验证命令结论:最好单独设置每个端口,一次设置多个端口有异常。比如:在CDC/HID串口助手发送HEX格式数据4CH 45H 44H 28H 02H 3FH 00H;DIP40的LED全部亮了,再发送4CH 45H 44H 28H 02H 3FH FFH只有P0端口熄灭,其他等依然亮着(如下图)。但是,STC工程师封装函数名LED40_SetPort,可直接调用。LED40_SetPort(0, 0x55);    //设置P0口输出55H
4. 功能4 控制DIP40的各个管脚上LED的状态 命令格式: 4CH 45H 44H 28H x1 x2 px ...
字节数1234567
命令格式:4CH45H44H28Hx1X2Px
命令注解命令头后面有效数据长度屏蔽位端口的状态数据
第五字节x1指定后面有效数长度第六字节x2指定P0~P5端口的屏蔽位,哪位值等于1就指定对应端口,比如Bit0值等1时指定P0端口。
X2位数Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
X2位解析固定为0不用P5P4P3P2P1P0
验证指令:让DIP40的LED全熄灭,可在CDC/HID串口助手发送HEX格式数据4CH 45H 44H 28H 07H 3FH FFH FFH FFH FFH FFH FFH让DIP40的LED全亮,可在CDC/HID串口助手发送HEX格式数据4CH 45H 44H 28H 07H 3FH 00H 00H 00H 00H 00H 00HSTC工程师封装函数名LED40_SendData,可直接调用,函数有两个参数,第一个参数设置数组,第二参数指定数组长度。数组第一个值是x2指定P0~P5端口的屏蔽位,数组第二个值是指定端口状态。三、调用第三功能,让DIP40的LED与擎天柱同步显示任务函数:static TASK_COMPONENTS Task_Comps[]={//状态计数周期函数{0, 2000, 2000, Test_Demo}};测试函数:void Test_Demo(void){ P2 = t_display; LED40_SetPort(2, t_display); if(++display_index >= 40)display_index = 0;}

垂柳工作室 发表于 2025-9-21 12:35:11

请教大佬一下,如上贴子,把wps表格复制粘贴到论坛贴后,表格变形了,线条也不显示了,这个问题如何解决。谢谢

神农鼎 发表于 2025-9-21 15:57:13



论坛发帖 专业编辑器, Markdown 使用语法参考 - TinyML,Ai8051U 人工智能 开山之作,AI手写计算器 国芯人工智能技术交流网站 - AI32位8051交流社区

神农鼎 发表于 2025-9-21 15:58:05

垂柳工作室 发表于 2025-9-21 12:28
新学期伊始,不忘助力国产替代初心,手头没有试验箱,先用“擎天柱”带领大一同学,跟随冲哥视频,学用STC...
到这步,可以直接跟 客服 要 【免费+包邮送】的 AI8051U实验箱
页: [1] 2
查看完整版本: AI8051U单片机学用打卡 | 到这步可直接要 【免费+包邮送】的AI8051U实验箱