vndolztn 发表于 2024-12-26 22:46:01

AI8051U学习打卡

我的AI8051学习实战
第一集
1.首先是安装编译环境,这里我们选择C251,官网的调查问卷我们可以随便填写,之后就可以跳转到下载页面


2.确保均为全英文路径后安装到D盘,尽量避开系统盘以防重装系统导致的文件丢失,打开keil软件选择图中选项,然后复制CID到keygen CID处得到破解代码,最后到图2所示红圈处点击Add Lic,便破解成功与我图中一样即可。


最后也是尝试了一下硬件USB下载程序的快乐,可以说很轻松,直接节省了一个CH340及其外围电路节省成本的同时还能压缩元件布局。

vndolztn 发表于 2024-12-27 15:38:53

<p>第二集 点亮一颗LED</p>
<p>按照《8051U深度入门到32位51大型实战教学视频》</p>
<p>6.5新建与设置超64K程序代码的项目(Source)模式</p>
<p><img src="data/attachment/forum/202412/27/151917ry9zbbhzyi3n0rhu.png" alt="1735283953495.png" title="1735283953495.png" /></p>
<p>通过读取手册可以得知:</p>
<p>AI8051U目前只支持Source模式,由于中断的压栈与出栈都是4字节建议选中 4Byte Intemupt Frame Size</p>
<p>并且Memory Model选择为XSmall模式,首先AI8051U逻辑地址为FF:0000H~FF:FFFFH,必须使用24位地址线才能正确访问,默认常量类型必须使用&quot;far&quot;类型,指针变量为4字节。</p>
<p>Memory Model模式区别:</p>
<p>XSmall模式将变量定义在内部RAM也就是edata中,单时钟存取,访问速度快,且有2k的edata供使用。</p>
<p>Small模式也是默认将变量定义在内部RAM(data)中,而data默认只有128字节,超过128字节会报错</p>
<p>Large模式虽然能够正确访问全部的16M寻址空间,但是该模式默认将变量定义在内部扩展RAM(xdata)里,存取需要2~3个时钟,访问速度慢。</p>
<p>故设置为XSmall模式</p>
<p>Code RomSize模式区别:</p>
<p>Small模式: 跳转/调用指令为AJMP/ACALL ,单个函数/模块/文件的代码大小为 2K ,总代码大小为 2K</p>
<p>Medium模式: 内部模块代码使用为AJMP/ACALL ,外部模块代码使用为LJMP/LCALL,单个函数/模块/文件的代码大小为 2K ,总代码大小为 64K</p>
<p>Compact模式: 跳转/调用指令为LCALL/AJMP ,单个函数/模块/文件的代码大小为 2K ,总代码大小为64K</p>
<p>Large模式: 跳转/调用指令为LCALL/AJMP ,单个函数/模块/文件的代码大小为 64K ,总代码大小为64K</p>
<p>Huge模式: 内部模块代码使用为LJMP/ECALL ,外部模块代码使用为EJMP/ECALL,单个函数/模块/文件的代码大小为 2K ,总代码大小为 64K。(多文件项目中,文件内部的代码为内部模块代码,其他文件的代码为外部模块代码)</p>
<p>这里设置为 Large模式</p>
<p>终于到了代码环节,这里必须得搞明白AI8051U的端口定义!</p>
<p>比方说:</p>
<p>我们可以把P0M0、P0M1理解为一个8位的变量,他可以对0~7位进行二进制的操作,赋予0或者是1</p>
<p>P0M0中的P0指的是端口P0,M0指的是P0.0</p>
<p>P0M1中的P0指的是端口P0,M1指的是P0.0</p>
<p>P1M0中的P1指的是端口P1,M0指的是P1.0</p>
<p>P1M1中的P1指的是端口P1,M1指的是P1.0</p>
<p>那么P0.0的引脚模式就是由这个P0M0与P0M1的第0位的状态共同决定的</p>
<p>那么P1.0的引脚模式就是由这个P1M0与P1M1的第0位的状态共同决定的</p>
<p><img src="data/attachment/forum/202412/27/155832hnknomp2axo7p3ns.png" alt="1735286304900.png" title="1735286304900.png" /></p>
<p>#include &quot;ai8051u.h&quot; //调用头文件</p>
<p>void main(void)<br />
{</p>
<pre><code>P2M0 = 0x00;
P2M1 = 0x00;




while(1)
{


        P2 = 0X00;
}
</code></pre>
<p>}</p>
<p>前面我们知道了P2M0、P2M1是8位变量,这里赋值的方式为16进制,相当于0000      0000   也就是0~7的引脚设置为   准双向口</p>
<p>程序执行为 先将P2的0~7位设置为准双向口,之后无限将P2的0 ~ 7位拉低,由于在板子上LED灯与电阻串联,一端在高电平上,而另一端在我们的单片机AI8051U上,也就是通过单片机控制引脚来决定LED灯是否发光</p>
<p>电流的产生总是从高电平流向低电平,所以我们的8个LED灯均会发光</p>
<p><img src="data/attachment/forum/202412/27/161354uj6z7lxv67jgz642.jpg" alt="5df10fe43302d52cc3a8cf9dd4a4224.jpg" title="5df10fe43302d52cc3a8cf9dd4a4224.jpg" /></p>

vndolztn 发表于 2024-12-27 20:45:11

<p>第三集    不停电USB下载</p>
<p>1.<a href="https://www.stcai.com/gjrj">深圳国芯人工智能有限公司-工具软件</a>下载好USB库</p>
<p>2.选择查询模式STC-CDC范例程序-&gt; stc32g_cdc_query_demo将stc_usb_cdc_32g.LIB、stc32_stc8_usb.h这俩个文件放入我们上节课的点灯程序中</p>
<p><img src="data/attachment/forum/202412/27/204603jzxqmebehtjc857d.png" alt="1735303551270.png" title="1735303551270.png" /><br />
<img src="data/attachment/forum/202412/27/204620wnwdgrz4wr7gw8of.png" alt="1735303576066.png" title="1735303576066.png" /><br />
<img src="data/attachment/forum/202412/27/204636c6pp15pv7utsztvt.png" alt="1735303592080.png" title="1735303592080.png" /></p>
<p><img src="data/attachment/forum/202412/27/204657azbvkkshkpt7kuyw.png" alt="1735303613030.png" title="1735303613030.png" /></p>
<p>3.进行不停电USB下载代码的移植,可以看到官方的头文件是STC32G,而我们是AI8051U</p>
<p>将stc_usb_cdc_32g.LIB加入到文件工程下,在mian.c文件中#include“stc32_stc8_usb.h”这样我们第一步完成了。</p>
<p>第二步、将以下变量声明,并对在mian函数中添加P_SW2 |= 0x80;这一步是在保持原有P_SW2各个位不变的情况下,将最高位置1,否则我们将无法使用特殊功能寄存器。</p>
<p>char *USER_DEVICEDESC = NULL;<br />
char *USER_PRODUCTDESC = NULL;<br />
char *USER_STCISPCMD = &quot;@STCISP#&quot;;</p>
<p><img src="data/attachment/forum/202412/27/205505jr9rn3s22ejsktek.png" alt="1735304096148.png" title="1735304096148.png" /></p>
<p><img src="data/attachment/forum/202412/27/205631bi2a1bbbiv9atmdv.png" alt="1735304184917.png" title="1735304184917.png" /></p>
<p>第三步、初始化usb_init();</p>
<p>IE2 |= 0x80;将IE2的最高位拉高,以便打开USB中断允许位。</p>
<p>EA=1,将EA拉高,以便打开中断控制,如图所示。</p>
<p><img src="data/attachment/forum/202412/27/205854v3mlldzvr0mrrovd.png" alt="1735304317731.png" title="1735304317731.png" /></p>
<p><img src="data/attachment/forum/202412/27/210126v0ra9mhnhsz8k96e.png" alt="1735304478485.png" title="1735304478485.png" /></p>
<p>第四步、在main函数添加      while(DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置</p>
<p>打开stc32_stc8_usb.h我们可以在35行找到#define DEVSTATE_CONFIGURED   4</p>
<p>也就是说如果DeviceState返回的值为4,while循环条件不满足跳出循环,说明UBS配置完成了可以进行正常的程序运行。</p>
<p>第五步、在while循环中添加 这一段代码的意思是   USB不管接收到什么都会将接收到的代码发送回去</p>
<p>因为stc32_stc8_usb.h 声明了许多的函数,我们没有调用变回报错L57的错误</p>
<p><img src="data/attachment/forum/202412/27/211240kk4ee3ihda4hq43d.png" alt="1735305156372.png" title="1735305156372.png" /></p>
<video controls="controls" src="forum.php?mod=attachment&amp;aid=77369"></video>
<p>以下为代码展示</p>
<p>#include &quot;ai8051u.h&quot; //调用头文件<br />
#include &quot;stc32_stc8_usb.h&quot; //调用头文件</p>
<p>char *USER_DEVICEDESC = NULL;<br />
char *USER_PRODUCTDESC = NULL;<br />
char *USER_STCISPCMD = &quot;@STCISP#&quot;;</p>
<p>void main(void)<br />
{<br />
P_SW2 |= 0x80;</p>
<pre><code>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;


        usb_init();
        IE2 |= 0x80;
EA = 1;
        while(DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置
while(1)
{


        P2 = 0x70;

          if (bUsbOutReady)
    {
      USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)

      usb_OUT_done();
    }
}
</code></pre>
<p>}</p>

vndolztn 发表于 2024-12-27 23:48:45

<p>第四集、C语言基础</p>
<p>1.使用printf函数</p>
<p>由于版本的更新,现在用PRINTF_USB来进行重定向。</p>
<p>在97行存在一个</p>
<p>#elif defined PRINTF_HID || defined PRINTF_USB</p>
<p>#define printfprintf_usb</p>
<p>这一段的代码意思是如果当你使能defined PRINTF_HID或者是defined PRINTF_USB 时,printf 相当于是printf_usb,便实现了重定向的过程。</p>
<p><img src="data/attachment/forum/202412/27/234458jrfc6zmxd6zuwmb7.png" alt="1735314292465.png" title="1735314292465.png" /></p>
<p><img src="data/attachment/forum/202412/27/234554z0q71nz9jjtn0xdy.png" alt="1735314348986.png" title="1735314348986.png" /></p>
<p>那么就让我们尝试一下AI8050U的printf函数吧。</p>
<p>这个不断电下载相当舒适,节省时间开发,这一点要点赞。</p>
<p>那么printf函数也是非常合适,中英文字符支持的同时也能支持转换。</p>
<video controls="controls" src="forum.php?mod=attachment&amp;aid=77404"></video>
<p>#include &quot;ai8051u.h&quot; //调用头文件<br />
#include &quot;stc32_stc8_usb.h&quot; //调用头文件</p>
<p>char *USER_DEVICEDESC = NULL;<br />
char *USER_PRODUCTDESC = NULL;<br />
char *USER_STCISPCMD = &quot;@STCISP#&quot;;</p>
<p>void main(void)<br />
{<br />
int a = 50;<br />
int b = 5;</p>
<pre><code>        P_SW2 |= 0x80;

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;


        usb_init();
        IE2 |= 0x80;
EA = 1;
        while(DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置
while(1)
{


        P2 = 0x00;

          if (bUsbOutReady)
    {
      //USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
      printf(&quot;你好世界\r\n&quot;);
                                  printf(&quot;a+b= %d                a/b= %d                \r\n&quot;,a+b,a/b);
                               
      usb_OUT_done();
    }
}
</code></pre>
<p>}</p>

vndolztn 发表于 2024-12-28 15:49:28

<p>第五集 I/O输入输出</p>
<p>GPIO(General Purpose Input Output,通用输入输出)是嵌入式系统中常见的接口。它允许微控制器或单片机直接控制和监测外部设备的状态。可以通过输入高低电平或者通过它们读入引脚的状态-是高电平或者是低电平。</p>
<p>高电平:接近于电源正极的电压,也称为逻辑‘1’</p>
<p>低电平:接近于GND的电压,也称为逻辑‘0’</p>
<p>单片机输出高电平就是输出VCC的电压,输出低电压就是输出GND的电压。</p>
<p>单片机VDD端极限电压为5.5V,则其他IO对地电压等于5.5+0.3=5.8V。</p>
<p>单片机VDD端极限电压为3.3V,则其他IO对地电压等于3.3+0.3=3.6V。</p>
<p>灌电流可以看作向IO口流入电流。</p>
<p>拉电流可以看作IO向外部输出电流。</p>
<p><img src="data/attachment/forum/202412/28/155140zzukicmuwnjk6pni.png" alt="1735372291533.png" title="1735372291533.png" /></p>
<p><img src="data/attachment/forum/202412/28/155249poosa1ga1joaclcv.png" alt="1735372362070.png" title="1735372362070.png" /></p>
<p>打开手册可以看到电压不同导致施密特开关的电压也是不同的,在5V电压下低电平不能高于1.32V,高电平不能低于1.48V,在5V电压下低电平不能高于0.99V,高电平不能低于1.07V。</p>
<p>上电默认使能施密特触发。</p>
<p><img src="data/attachment/forum/202412/28/155456z29y3ds6skkd62rt.png" alt="1735372485993.png" title="1735372485993.png" /></p>
<p><img src="data/attachment/forum/202412/28/155528dv611r6lbmjrft41.png" alt="1735372518973.png" title="1735372518973.png" /></p>
<p>由于擎天柱板的P2端口为LED灯,故修改。</p>
<video controls="controls" src="forum.php?mod=attachment&amp;aid=77652"></video>
<video controls="controls" src="forum.php?mod=attachment&amp;aid=77653"></video>
<video controls="controls" src="forum.php?mod=attachment&amp;aid=77654"></video>
<video controls="controls" src="forum.php?mod=attachment&amp;aid=77655"></video>
<video controls="controls" src="forum.php?mod=attachment&amp;aid=77656"></video>
<p>#include &quot;ai8051u.h&quot; //调用头文件<br />
#include &quot;stc32_stc8_usb.h&quot; //调用头文件        <br />
#include &quot;intrins.h&quot;</p>
<p>#define u8                 unsigned char<br />
#define u16   unsigned int</p>
<p>char *USER_DEVICEDESC = NULL;<br />
char *USER_PRODUCTDESC = NULL;<br />
char *USER_STCISPCMD = &quot;@STCISP#&quot;;<br />
u8 state = 0;<br />
u8 i = 0;</p>
<p>void Delay20ms(void)        //@24.000MHz<br />
{<br />
unsigned long edata i;</p>
<pre><code>_nop_();
_nop_();
i = 119998UL;
while (i) i--;
</code></pre>
<p>}</p>
<p>void main(void)<br />
{<br />
WTST= 0;<br />
EAXFR = 1;<br />
CKCON = 0;</p>
<pre><code>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;


        usb_init();
        IE2 |= 0x80;
EA = 1;
        while(DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置
while(1)
{




          if (bUsbOutReady)
    {
      //USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)

                               
      usb_OUT_done();
    }
                        //任务1        按下P32发光 松开P32灭
</code></pre>
<p>//                                if(P32 == 0)<br />
//                                {<br />
//                                        P20 = 0;<br />
//                        <br />
//                                }<br />
//                                else<br />
//                                {<br />
//                                        P20 = 1;<br />
//                                }<br />
//任务2        按下P32灭 松开P32亮<br />
//                                if(P32 == 0)<br />
//                                {<br />
//                                        P20 = 1;<br />
//                        <br />
//                                }<br />
//                                else<br />
//                                {<br />
//                                        P20 = 0;<br />
//                                }<br />
//任务3 按一下亮,按一下灭。<br />
//                                if(P32 == 0)<br />
//                                {<br />
//                                        Delay20ms();<br />
//                                        if(P32 == 0)<br />
//                                        {<br />
//                                                state = !state;<br />
//                                                P20 = state;<br />
//                                                while(P32 == 0);<br />
//                                <br />
//                                        }<br />
//                                <br />
//                        <br />
//                                }<br />
//课后作业1<br />
//                                if(P32 == 0)<br />
//                                {<br />
//                                Delay20ms();<br />
//                                        if(P32 == 0)<br />
//                                        {<br />
//                                                P20 = 1;<br />
//                                                while(P32 == 0);<br />
//                                <br />
//                                        }<br />
//                        <br />
//                                }<br />
//                                  else if(P33 == 0)<br />
//                                {<br />
//                                Delay20ms();<br />
//                                        if(P33 == 0)<br />
//                                        {<br />
//                                                P20 = 0;<br />
//                                                while(P33 == 0);<br />
//                                <br />
//                                        }<br />
//                        <br />
//                                }                <br />
//课后作业2<br />
if(P32 == 0)<br />
{<br />
Delay20ms();<br />
if(i&gt;8)<br />
{<br />
i = 0;<br />
}<br />
if(P32 == 0)<br />
{<br />
P2 = 0xff &lt;&lt; i ;<br />
i++;<br />
while(P32 == 0);</p>
<pre><code>                                }
               
                        }
               
}
</code></pre>
<p>}</p>

vndolztn 发表于 2024-12-28 21:40:43

<p>第六集、定时器中断</p>
<p>通过AIapp-ISP-v6.95C 选择定时器计数器,时钟频率选24Mhz、定时器0、24位自动重载、12T、定时长度为3秒</p>
<p>使能定时器中断。<br />
<img src="data/attachment/forum/202412/28/214036i0tgada2z1bjh0e1.png" alt="1735393232466.png" title="1735393232466.png" /></p>
<p>将代码粘贴置keil5后,打开手册可以得知,TM0PS可调节定时器0的时钟,如果TM0PS=0,则直接为系统时钟频率,TM0PS = 0x5B;也就是TM0PS=91;说明24Mhz/91 ≈263,736Khz</p>
<p>AUXR &amp;= 0x7F;也就是01111111 将最高位置0其它位保持不变,结合手册我们得知CPU时钟为12分频。</p>
<p>TMOD &amp;= 0xF0;也就是1111 0000 高四位保持不变,低四位全部置0,集合手册我们得知</p>
<p>T0_C/T:置0用作对内部系统时钟进行计数,置1用作计数器对P3.4外部脉冲进行计数。</p>
<p>当GATE=0 ,若TR0=1,则定时器计数。</p>
<p>TL0 = 0x3F;TH0 = 0x01;说明初始值为319。</p>
<p>TF0 = 0;        清除TF0标志</p>
<p>TR0 = 1;        定时器0开始计时</p>
<p>ET0 = 1;        使能定时器0中断</p>
<p><img src="data/attachment/forum/202412/28/220139gyyzddyv73g3vos9.png" alt="1735394491387.png" title="1735394491387.png" /></p>
<p><img src="data/attachment/forum/202412/28/220154ssla3g8sh8zsgl3r.png" alt="1735394507963.png" title="1735394507963.png" /></p>
<p><img src="data/attachment/forum/202412/28/220506gem9ejtmk99388sb.png" alt="1735394699141.png" title="1735394699141.png" /></p>
<p><img src="data/attachment/forum/202412/28/221048oy231zyn9nvzyb5z.png" alt="1735395042349.png" title="1735395042349.png" /></p>
<p><img src="data/attachment/forum/202412/28/221616mjpffvvphqipq1fi.png" alt="1735395369874.png" title="1735395369874.png" /></p>
<p><img src="data/attachment/forum/202412/28/221839hivizpdh5hkov8id.png" alt="1735395513632.png" title="1735395513632.png" /></p>
<p>(91+1) * (65536-319) * 12 / 24000000</p>
<p>71999568   ÷   24000000 约等于2.99将近3秒了</p>
<p><img src="data/attachment/forum/202412/28/222043g1nzizrkrflzlnur.png" alt="5d8e1ac7567d5353b9bd9f2fae53221.png" title="5d8e1ac7567d5353b9bd9f2fae53221.png" /></p>
<video controls="controls" src="forum.php?mod=attachment&amp;aid=77795"></video>

vndolztn 发表于 2024-12-29 22:06:50

<p>第七集、定时器周期性调度任务</p>
<p>typedef struct<br />
{<br />
u8 Run;               //任务状态:Run/Stop<br />
u16 TIMCount;         //定时计数器<br />
u16 TRITime;          //重载计数器<br />
void (*TaskHook) (void); //任务函数<br />
} TASK_COMPONENTS;</p>
<p>代码理解如下:创建TASK_COMPONENTS结构体包含四个成员,为之后的调度做准备。</p>
<p>static TASK_COMPONENTS Task_Comps[]=<br />
{<br />
//状态计数周期函数</p>
<p>{0, 300,   300,   LED0_Blink},      /* task 1 Period: 300ms <em>/<br />
{0, 600,   600,   LED1_Blink},      /</em> task 1 Period: 600ms <em>/<br />
{0, 900,   900,   LED2_Blink},      /</em> task 1 Period: 600ms <em>/<br />
{0, 10,    10,    KEY_Task},      /</em> task 1 Period: 600ms */<br />
};</p>
<p>代码理解如下:静态结构体成员赋给Task_Comps的数组,一共有四个元素,每个元素都进行了初始化,也就是创造了四个任务。</p>
<p>u8 Tasks_Max = sizeof(Task_Comps)/sizeof(Task_Comps);</p>
<p>代码理解如下:通过总大小除以单个元素的大小来得出一共有多少个任务</p>
<p>//========================================================================<br />
// 函数: Task_Handler_Callback<br />
// 描述: 任务标记回调函数.<br />
// 参数: None.<br />
// 返回: None.<br />
// 版本: V1.0, 2012-10-22<br />
//========================================================================<br />
void Task_Marks_Handler_Callback(void)<br />
{<br />
u8 i;<br />
for(i=0; i&lt;Tasks_Max; i++)<br />
{<br />
if(Task_Comps.TIMCount)      /* If the time is not 0 <em>/<br />
{<br />
Task_Comps.TIMCount--;   /</em> Time counter decrement <em>/<br />
if(Task_Comps.TIMCount == 0) /</em> If time arrives */<br />
{<br />
/*Resume the timer value and try again <em>/<br />
Task_Comps.TIMCount = Task_Comps.TRITime;<br />
Task_Comps.Run = 1;      /</em> The task can be run */<br />
}<br />
}<br />
}<br />
}</p>
<p>代码理解如下:很明显,让任务运行一定是遵循什么规律的,进入这个函数时for循环使得他对所有任务的计时器-1,如果-1后发现有任务的定时器归零,那么说明延时时间到了,Task_Comps.TIMCount = Task_Comps.TRITime;将该任务的重装载值重新赋给定时计数器,Task_Comps.Run = 1;将他的运行状态置1,为之后的运行做准备。</p>
<p>//========================================================================<br />
// 函数: Task_Pro_Handler_Callback<br />
// 描述: 任务处理回调函数.<br />
// 参数: None.<br />
// 返回: None.<br />
// 版本: V1.0, 2012-10-22<br />
//========================================================================<br />
void Task_Pro_Handler_Callback(void)<br />
{<br />
u8 i;<br />
for(i=0; i&lt;Tasks_Max; i++)<br />
{<br />
if(Task_Comps.Run) /* If task can be run <em>/<br />
{<br />
Task_Comps.Run = 0;      /</em> Flag clear 0 <em>/<br />
Task_Comps.TaskHook();   /</em> Run task */<br />
}<br />
}<br />
}</p>
<p>代码理解如下:任务回调函数,当Task_Comps.Run 为真,先将该任务的运行状态清零,之后进入执行函数,运行该函数的代码。</p>
<p>所谓的执行函数就是Task_Comps数组中每个元素的最后一位成员函数。</p>
<video controls="controls" src="forum.php?mod=attachment&amp;aid=78031"></video>
<video controls="controls" src="forum.php?mod=attachment&amp;aid=78032"></video>
页: [1]
查看完整版本: AI8051U学习打卡