【实验箱已收到】学习官方AI8051U|打卡
感谢官方 免费+包邮 的 Ai8051U 实验箱。借此实验箱学习一下 Ai8051U 的进阶操作,
在本贴记录一下学习过程。 第八集 定时器周期性任务调度 本集前面的小任务很简单,跟着做就能完成,也很好理解重头戏是对结构体的学习,这是我之前没接触过的,这里做个笔记记录以下。 什么是结构体结构体(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);这段代码的作用是 动态计算数组长度作用:计算整个数组 Task_Comps 占用的内存字节数。
如果 Task_Comps 是包含 3 个 TASK_COMPONENTS 结构体的数组,且单个结构体占 10 字节,则:sizeof(Task_Comps) = 3 * 10 = 30 字节sizeof(Task_Comps)作用:计算数组第一个元素占用的内存字节数(即单个元素的字节大小)。单个 TASK_COMPONENTS 结构体占 10 字节:sizeof(Task_Comps) = 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用的,每当该程序被执行时通过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语句。
页:
[1]