找回密码
 立即注册
查看: 116|回复: 0

【实验箱已收到】学习官方AI8051U|打卡

[复制链接]
  • 打卡等级:常住居民II
  • 打卡总天数:81
  • 最近打卡:2025-06-05 07:27:24
已绑定手机

3

主题

22

回帖

469

积分

中级会员

积分
469
发表于 2025-3-27 22:06:41 | 显示全部楼层 |阅读模式
感谢官方 免费+包邮 Ai8051U 实验箱。
借此实验箱学习一下 Ai8051U 的进阶操作,
在本贴记录一下学习过程。
801.jpg
第八集 定时器周期性任务调度
本集前面的小任务很简单,跟着做就能完成,也很好理解
重头戏是对结构体的学习,这是我之前没接触过的,这里做个笔记记录以下。
什么是结构体
结构体‌Struct‌)是编程语言中一种‌复合数据类型‌,用于将多个不同类型的数据组合成一个逻辑 整体。它允许你将相关的变量聚合在一起,形成一个自定义的数据结构,方便统一管理和操作。
结构体的核心价值
数据聚合:将分散的变量整合成一个逻辑实体。
代码可读性:用 stu.age 比用 age_array 更直观。
函数参数传递:可以一次性传递整个结构体,而非多个分散的参数。
结构体的定义方式‌:
使用关键字(如 struct)定义结构体类型。
包含多个成员变量(字段),每个成员可以是不同的数据类型(如 int, float, 字符串等)。
‌示例(本集的程序‌:
typedef struct
{
u8 Run;               //任务状态:Run/Stop
u16 TIMCount;         //定时计数器
u16 TRITime;          //重载计数器
void (*TaskHook) (void); //任务函数
} TASK_COMPONENTS;
struct 的作用
定义自定义数据类型:struct 可以将多个不同类型的变量组合成一个新的复合数据类型。
数据封装:将逻辑相关的数据组织在一起。
内存管理:结构体成员在内存中连续存储。

typedef 的作用
       是将TASK_COMPONENTS定义成结构体类型别名,它的核心作用是简化变量声明。
定义类型后,可以直接用TASK_COMPONENTS声明变量,无需重复写struct 关键字。
因此TASK_COMPONENTS 是类型名(类似 int、float)。而且这是一个自定义的类型别名,可以改成任何合法的,方便记忆的标识符。


static TASK_COMPONENTS Task_Comps[]=
{
//状态  计数  周期  函数
{0, 300,  300,  LED0_Blink},     
    {0, 600,  600,  LED1_Blink},   
    {0, 900,  900,  LED2_Blink},      
};
这里是用类型别名TASK_COMPONENTS声明了一个数组变量Task_Comps[],
这里对3个数组元素初始化用大括号分开,每个数组元素内有四个结构体成员分别与开始定义的结构体对应。
比如{0, 300,  300,  LED0_Blink},
第一个“0”    对应结构体成员“u8 Run”
第二个“300”   对应结构体成员“u16 TIMCount”
第三个“300”   对应结构体成员“u16 TRITime”
第四个“LED0_Blink” 对应结构体成员void (*TaskHook) (void);
“LED0_Blink” 是一个在其他地方声明过的执行函数。
它在其他地方是这样的
//u8 State1=0;
void LED0_Blink(void)
{
// State1=!State1;
// P00=State1;
P00=!P00;
}
static 的作用:
作用域限制:
Task_Comps 数组被声明为 static,表示它的作用域仅限于当前源文件(其他文件无法通过 extern 访问它)。
这是模块化编程中常见的封装手段,防止全局变量被意外修改。(这些内容是我用deepseek搜索得到的,我现在还没理解这里的意思,以后有机会再搞明白)

u8 Tasks_Max = sizeof(Task_Comps)/sizeof(Task_Comps[0]);
这段代码的作用是 动态计算数组长度
作用:计算整个数组 Task_Comps 占用的内存字节数。
如果 Task_Comps 是包含 3 个 TASK_COMPONENTS 结构体的数组,且单个结构体占 10 字节,
则:
sizeof(Task_Comps) = 3 * 10 = 30 字节
sizeof(Task_Comps[0])
作用:计算数组第一个元素占用的内存字节数(即单个元素的字节大小)。
单个 TASK_COMPONENTS 结构体占 10 字节:
sizeof(Task_Comps[0]) = 10 字节
除法运算 sizeof(...) / sizeof(...)
作用:用数组总字节数除以单个元素字节数,得到数组的实际元素个数。
Tasks_Max = 30 / 10 = 3,
所以最终变量Tasks_Max被赋值为3。

void Task_Marks_Handler_Callback(void)
{
    u8 i;
    for(i=0; i<Tasks_Max; i++)
    {
        if(Task_Comps.TIMCount)      /* 如果时间不为0 */
        {
            Task_Comps.TIMCount--;   /* 时间计数器递减 */
            if(Task_Comps.TIMCount == 0) /* 如果时间到了 */
            {
                /*重载计数器值 */
                Task_Comps.TIMCount = Task_Comps.TRITime;  
                Task_Comps.Run = 1;      /* 任务运行状态置1 */
            }
        }
    }
}
这段代码是用来操作数组Task_Comps[0]用的,每当该程序被执行时通过for循环遍历数组每个元素,通过if判断结构体中TIMCount是否为0,如果不为0,则将TIMCount 减1,
如果已经为0则将Run 置1,并且将TRITime赋值给TIMCount ,重装载倒数值。
所以函数声明后放在1ms定时器中断函数中执行,每当定时器中断时执行。
void Task_Pro_Handler_Callback(void)
{
    u8 i;
    for(i=0; i<Tasks_Max; i++)
    {
        if(Task_Comps.Run) /* 检测任务状态,如果为1 则运行IF内语句 */
        {
            Task_Comps.Run = 0;      /* 将任务状态位置零 0 */
            Task_Comps.TaskHook();   /* 运行程序 */
        }
    }
}
这段代码是用来执行任务的,通过for循环遍历数组每个元素,通过if判断结构体中Run 是否为1,如果为1则执行if中的语句,将任务状态位Run 置0,并运行程序。如果Run不为0 则不执行if语句。




回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-6-18 02:25 , Processed in 0.163794 second(s), 49 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表