silas3082 发表于 2024-12-12 23:25:23

Ai8051U 实验箱 学习开始打卡

<p><strong>感谢官方提供的Ai8051U擎天柱开发板和实验箱,到手后立马迫不及待的烧录学习了</strong></p>
<p><img src="data/attachment/forum/202412/14/103244olsesteobbe6l76w.jpg" alt="1000001595.jpg" title="1000001595.jpg" /></p>
<p><strong>学习了冲哥的《8051U深度入门到32位51大型实战教学视频》,收获颇多,对于我这种小白来说简直是手把手教学。</strong></p>
<h2>第三集 点亮第一颗LED</h2>
<h3>已成功烧录代码点亮,代码比较简单,容易理解</h3>
<pre><code>#include &quot;ai8051u.h&quot;                //调用头文件

//注意:擎天柱的LED端口在P2,且没有三极管的电源控制,所以只要控制P2端口即可
void main(void)
{
        P2M0 = 0;                //P2端口(P20-P27)为准双向口
        P2M1 = 0;

        while(1)
        {
                P20 = 0;        //P20端口输出0V
                P21 = 0;        //P21端口输出0V
        }
}
</code></pre>
<h2>第四集 USB不停电下载</h2>
<p>实现了开发板不停电下载,免去了反复按电源键和p3.2按键的麻烦,非常实用。</p>
<pre><code>#include &quot;ai8051u.h&quot;                        //调用头文件
#include &quot;stc32_stc8_usb.h&quot;                //调用头文件

//注意:擎天柱的LED端口在P2,且没有三极管的电源控制,所以只要控制P2端口即可,本节课程的其余内容(USB不停电下载)均通用!

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = &quot;@STCISP#&quot;;

void main(void)
{
    P_SW2 |= 0x80;                //B7位写1,使能访问XFR

    P0M1 = 0x00;   P0M0 = 0x00;
    P1M1 = 0x00;   P1M0 = 0x00;
    P2M1 = 0x00;   P2M0 = 0x00;
    P3M1 = 0x00;   P3M0 = 0x00;
    P4M1 = 0x00;   P4M0 = 0x00;
    P5M1 = 0x00;   P5M0 = 0x00;
    P6M1 = 0x00;   P6M0 = 0x00;
    P7M1 = 0x00;   P7M0 = 0x00;

        usb_init();                                     //USB CDC 接口配置

    IE2 |= 0x80;                                    //使能USB中断
    EA = 1;                                                                                        //IE |= 0X80;

        while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置

        while(1)
        {

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

                P20 = 0;                                        //P00端口输出0V
                P22 = 0;                                        //P02端口输出0V

        }
}
</code></pre>
<h2>第五集 C语言基础</h2>
<p>使用print语句,可以随时查看程序运行情况,方便调试及与单片机交互</p>
<pre><code>#include &quot;ai8051u.h&quot;                        //调用头文件
#include &quot;stc32_stc8_usb.h&quot;                //调用头文件

//注意:擎天柱的LED端口在P2,且没有三极管的电源控制,所以只要控制P2端口即可,本节课程的其余内容(C语言测试)均通用!

#define u8unsigned char                //8位无符号变量(0-255)
#define u16 unsigned int                //16位无符号变量(0-65535)

u8 X = 200;
u8 Y = 10;

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = &quot;@STCISP#&quot;;

void main(void)
{
    P_SW2 |= 0x80;                //B7位写1,使能访问XFR

    P0M1 = 0x00;   P0M0 = 0x00;
    P1M1 = 0x00;   P1M0 = 0x00;
    P2M1 = 0x00;   P2M0 = 0x00;
    P3M1 = 0x00;   P3M0 = 0x00;
    P4M1 = 0x00;   P4M0 = 0x00;
    P5M1 = 0x00;   P5M0 = 0x00;
    P6M1 = 0x00;   P6M0 = 0x00;
    P7M1 = 0x00;   P7M0 = 0x00;

        usb_init();                                     //USB CDC 接口配置

    IE2 |= 0x80;                                    //使能USB中断
    EA = 1;                                                                                        //IE |= 0X80;

        while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置

        while(1)
        {

      if (bUsbOutReady)                                                        //如果接收到了数据
      {
            //USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
   
                        if( X &amp;&amp; Y )        //如果条件为真,输出什么
                        {
                                printf(&quot;条件为真\r\n&quot;);
                        }
//                        else
//                        {
//                                printf(&quot;条件为假\r\n&quot;);
//                        }

//                        printf(&quot;X / Y = %u \r\n&quot;,(u16)(X/Y));

//                        printf(&quot;X %% Y = %u \r\n&quot;,(u16)(X%Y));

            usb_OUT_done();                                                        //
      }


        }
}
</code></pre>
<h2>第六集 I/O输入输出</h2>
<p>冲哥用了3个小任务,以实例的形式,介绍了通过检测按键,控制led的亮和灭</p>
<pre><code>#include &quot;ai8051u.h&quot;                        //调用头文件
#include &quot;stc32_stc8_usb.h&quot;                //调用头文件
#include &quot;intrins.h&quot;                        //d调用头文件

//注意:擎天柱的LED端口在P2,且没有三极管的电源控制,所以只要控制P2端口即可,按键通用,本节课程的其余内容均通用!

#define u8unsigned char                //8位无符号变量(0-255)
#define u16 unsigned int                //16位无符号变量(0-65535)

u8 state = 0;                                        //初始状态

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = &quot;@STCISP#&quot;;

void Delay20ms(void)        //@24.000MHzDelay20ms();
{
        unsigned long edata i;

        _nop_();
        _nop_();
        i = 119998UL;
        while (i) i--;
}


void main(void)
{
    WTST = 0;                                                                                //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1;                                                                                 //扩展寄存器(XFR)访问使能
    CKCON = 0;                                                                                 //提高访问XRAM速度

    P0M1 = 0x00;   P0M0 = 0x00;
    P1M1 = 0x00;   P1M0 = 0x00;
    P2M1 = 0x00;   P2M0 = 0x00;
    P3M1 = 0x00;   P3M0 = 0x00;
    P4M1 = 0x00;   P4M0 = 0x00;
    P5M1 = 0x00;   P5M0 = 0x00;
    P6M1 = 0x00;   P6M0 = 0x00;
    P7M1 = 0x00;   P7M0 = 0x00;

        usb_init();                                     //USB CDC 接口配置

    IE2 |= 0x80;                                    //使能USB中断
    EA = 1;                                                                                        //IE |= 0X80;

        while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置

        while(1)
        {

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

//                //任务1:按下P32按钮灯亮,松开P32按钮灯灭;
//                if( P32 == 0 )                                                                //判断P32按钮是否按下
//                {
//                        P20 = 0;
//                }
//                else
//                {
//                        P20 = 1;
//                }
//

                //任务2:按下P32按钮灯灭,松开P32按钮灯亮;
//                if( P32 == 1 )                                                                //判断P32按钮是否按下
//                {
//                        P20 = 0;
//                }
//                else
//                {
//                        P20 = 1;
//                }

                //任务3:按一下灯亮,按一下灯灭
                if( P32 == 0 )                                                                //判断P32按钮是否按下
                {
                        Delay20ms();                                                        //延时20ms消抖
                        if( P32 == 0 )
                        {
                                state = !state;                                                //变量取反 0 1 0 1 0 1
                                P20 = state;
                                printf(&quot;state:%d\r\n&quot;,(int)state);

                                while( P32 == 0 );                                        //等待P32松开

                        }
                }


        }
}
</code></pre>
<h2>第七集 定时器中断</h2>
<p>也是通过3个小任务,介绍了定时器的使用。</p>
<pre><code>#include &quot;ai8051u.h&quot;                        //调用头文件
#include &quot;stc32_stc8_usb.h&quot;                //调用头文件
#include &quot;intrins.h&quot;                        //d调用头文件

//注意:擎天柱的LED端口在P2,且没有三极管的电源控制,所以只要控制P2端口即可,按键通用,本节课程的其余内容均通用!

#define u8unsigned char                //8位无符号变量(0-255)
#define u16 unsigned int                //16位无符号变量(0-65535)

u8 state = 0;                                        //初始状态
u8 Run_State = 0;                                //运行状态

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = &quot;@STCISP#&quot;;

void Delay20ms(void)        //@24.000MHzDelay20ms();
{
        unsigned long edata i;

        _nop_();
        _nop_();
        i = 119998UL;
        while (i) i--;
}
void Timer0_Init(void);                //3秒@24.000MHz                //函数声明

void main(void)
{
        int count=1;                                                                        //按键计数变量

    WTST = 0;                                                                                //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1;                                                                                 //扩展寄存器(XFR)访问使能
    CKCON = 0;                                                                                 //提高访问XRAM速度

    P0M1 = 0x00;   P0M0 = 0x00;
    P1M1 = 0x00;   P1M0 = 0x00;
    P2M1 = 0x00;   P2M0 = 0x00;
    P3M1 = 0x00;   P3M0 = 0x00;
    P4M1 = 0x00;   P4M0 = 0x00;
    P5M1 = 0x00;   P5M0 = 0x00;
    P6M1 = 0x00;   P6M0 = 0x00;
    P7M1 = 0x00;   P7M0 = 0x00;

        usb_init();                                     //USB CDC 接口配置

    IE2 |= 0x80;                                    //使能USB中断
//        Timer0_Init();                                                                        //定时器初始化

    EA = 1;                                                                                        //IE |= 0X80;

        P40 = 0;

        while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置

        while(1)
        {

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

                //任务1:
//                if( P32 == 0 )                                                                //判断P32按钮是否按下
//                {
//                        Delay20ms();                                                        //延时20ms消抖
//                        if( P32 == 0 )
//                        {
//                                printf(&quot;按键按下次数\xfd:%d 次\r\n&quot;,(int)count);
//                                count++;
//
//                                while( P32 == 0 );                                        //等待P32松开
//
//                        }
//                }

//                //任务2:灯按一下点亮三秒后熄灭。
                if( P32 == 0 )                                                                //判断P32按钮是否按下
                {
                        Delay20ms();                                                        //延时20ms消抖
                        if( P32 == 0 )
                        {
//                                printf(&quot;按键按下次数\xfd:%d 次\r\n&quot;,(int)count);
//                                count++;
                                P20 = 0;
                                Timer0_Init();
                                while( P32 == 0 );                                        //等待P32松开

                        }
                }

//
                //任务3:救护车灯控制器,按下报警按钮,红蓝交替闪烁(LED1和LED2              表示红和蓝灯),再按一下报警按钮,红蓝灯停止。
                if( P32 == 0 )                                                                //判断P32按钮是否按下
                {
                        Delay20ms();                                                        //延时20ms消抖
                        if( P32 == 0 )
                        {
                                Run_State = !Run_State;                                //运行状态取反

                                if( Run_State==1 )                                        //运行
                                {
                                        Timer0_Init();
                                }
                                else
                                {
                                        TR0 = 0;                                                //关闭定时器
                                        P20 = 1;
                                        P21 = 1;
                                }
                                while( P32 == 0 );                                        //等待P32松开

                        }
                }

        }
}

//void Timer0_Init(void)                //3秒@24.000MHz        函数定义
//{
//        TM0PS = 0x5B;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
//        AUXR &amp;= 0x7F;                        //定时器时钟12T模式
//        TMOD &amp;= 0xF0;                        //设置定时器模式
//        TL0 = 0x3F;                                //设置定时初始值
//        TH0 = 0x01;                                //设置定时初始值
//        TF0 = 0;                                //清除TF0标志
//        TR0 = 1;                                //定时器0开始计时
//        ET0 = 1;                                //使能定时器0中断
//
//        //TM0PS = 91
//        //12T                 /12
//        // THO-TL0 = 319
//
//}

void Timer0_Init(void)                //500毫秒@24.000MHz
{
        TM0PS = 0x0F;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
        AUXR &amp;= 0x7F;                        //定时器时钟12T模式
        TMOD &amp;= 0xF0;                        //设置定时器模式
        TL0 = 0xDC;                                //设置定时初始值
        TH0 = 0x0B;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时
        ET0 = 1;                                //使能定时器0中断
}

void Timer0_Isr(void) interrupt 1                //3秒执行一次
{
        state = !state;

        P20 = state;
        P21 = !state;
}

</code></pre>
<p>在此基础上,我想实现10秒的倒计时,修改了一下代码,顺利实现:</p>
<pre><code>#include &quot;ai8051u.h&quot;                        //调用头文件
#include &quot;stc32_stc8_usb.h&quot;                //调用头文件
#include &quot;intrins.h&quot;                        //d调用头文件

//注意:擎天柱的LED端口在P2,且没有三极管的电源控制,所以只要控制P2端口即可,按键通用,本节课程的其余内容均通用!

#define u8unsigned char                //8位无符号变量(0-255)
#define u16 unsigned int                //16位无符号变量(0-65535)

u8 state = 0;                                        //初始状态
u8 Run_State = 0;                                //运行状态
u8 numb=10;                //10秒计数


char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = &quot;@STCISP#&quot;;

void Delay20ms(void)        //@24.000MHzDelay20ms();
{
        unsigned long edata i;

        _nop_();
        _nop_();
        i = 119998UL;
        while (i) i--;
}
void Timer0_Init(void);                //3秒@24.000MHz                //函数声明

void main(void)
{
        int count=1;                                                                        //按键计数变量

    WTST = 0;                                                                                //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1;                                                                                 //扩展寄存器(XFR)访问使能
    CKCON = 0;                                                                                 //提高访问XRAM速度

    P0M1 = 0x00;   P0M0 = 0x00;
    P1M1 = 0x00;   P1M0 = 0x00;
    P2M1 = 0x00;   P2M0 = 0x00;
    P3M1 = 0x00;   P3M0 = 0x00;
    P4M1 = 0x00;   P4M0 = 0x00;
    P5M1 = 0x00;   P5M0 = 0x00;
    P6M1 = 0x00;   P6M0 = 0x00;
    P7M1 = 0x00;   P7M0 = 0x00;

        usb_init();                                     //USB CDC 接口配置

    IE2 |= 0x80;                                    //使能USB中断
//        Timer0_Init();                                                                        //定时器初始化

    EA = 1;                                                                                        //IE |= 0X80;

        P40 = 0;

        while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置

        while(1)
        {

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

            usb_OUT_done();                                                        //
      }



                //任务2-1:灯按一下打印10秒倒计时。
                if( P32 == 0 )                                                                //判断P32按钮是否按下
                {
                        Delay20ms();                                                        //延时20ms消抖
                        if( P32 == 0 )
                        {
                                Timer0_Init();

                                while( P32 == 0 );                                        //等待P32松开

                        }
                }


        }
}




void Timer0_Isr(void) interrupt 1
{
        numb--;       //每一秒计数减1;
        printf(&quot;10秒倒计时:%d \r\n&quot;,(u8)numb);    //每一秒打印输出
        if(numb==0){          //当倒计时结束,关闭定时器
        TR0 = 0;
        }
}

void Timer0_Init(void)                //1秒@24.000MHz
{
        TM0PS = 0x1E;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
        AUXR &amp;= 0x7F;                        //定时器时钟12T模式
        TMOD &amp;= 0xF0;                        //设置定时器模式
        TL0 = 0xFC;                                //设置定时初始值
        TH0 = 0x03;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时
        ET0 = 1;                                //使能定时器0中断
}


</code></pre>
<p><img src="data/attachment/forum/202412/12/232517mtgt5m9hb9ih5k3l.png" alt="image.png" title="image.png" /></p>
<p>目前就学到这里,后期继续学习。</p>

zhange 发表于 2024-12-13 08:50:54

<p>加油...</p>

silas3082 发表于 2024-12-13 14:36:35

<h2>第八集 定时器周期性调度任务</h2>
<h3>任务1: p32按下,led1循环300ms闪烁,led2循环600ms闪烁,led3循环900ms闪烁</h3>
<p>1.定义了三个计时变量   u16 count_ms = {0,0,0};</p>
<p>2.在定时器void Timer0_Init(void)                //1毫秒@24.000MHz</p>
<p>中断执行函数中,判断计时变量是否到设定时间</p>
<pre><code>for(i=0;i&lt;3;i++){
count_ms++;
if(count_ms&gt;=300){
count_ms=0;
        P20 = !P20;
}
if(count_ms&gt;=600){
count_ms=0;

        P21 = !P21;
}
if(count_ms&gt;=900){
count_ms=0;

        P22 = !P22;
}
}
</code></pre>

silas3082 发表于 2024-12-13 15:25:16

<h3>任务2:p2流水灯</h3>
<p>1.首先定义一个p2口8个led状态的数组:</p>
<pre><code>u8 state={0xFE,// 1111 1110 ,最低位(P20控制的LED)点亮,其余熄灭
0xFD,// 1111 1101 ,次低位(P21控制的LED)点亮,其余熄灭
0xFB,// 1111 1011 ,依次类推
0xF7,
0xEF,
0xDF,
0xBF,
0x7F};
</code></pre>
<p>2.和任务1不同的是,任务1是按下p32按键的时候才启动定时器中断,所以任务1的定时器初始化在if(){XXXX;</p>
<p>Timer0_Init();</p>
<p>}中,此处直接在开机就执行流水灯,所以Timer0_Init();在main函数刚开始</p>
<pre><code>
#include &quot;ai8051u.h&quot;                        //调用头文件
#include &quot;stc32_stc8_usb.h&quot;                //调用头文件
#include &quot;intrins.h&quot;                        //d调用头文件//注意:擎天柱的LED端口在P2,且没有三极管的电源控制,所以只要控制P2端口即可,按键通用,本节课程的其余内容均通用!#define u8unsigned char                //8位无符号变量(0-255)
#define u16 unsigned int                //16位无符号变量(0-65535)u16 count_ms = {0,0,0};                                        //三个计时变量
u8 numb=0;u8 state={0xFE,// 1111 1110 ,最低位(P20控制的LED)点亮,其余熄灭
0xFD,// 1111 1101 ,次低位(P21控制的LED)点亮,其余熄灭
0xFB,// 1111 1011 ,依次类推
0xF7,
0xEF,
0xDF,
0xBF,
0x7F};
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = &quot;@STCISP#&quot;;void Delay20ms(void)        //@24.000MHzDelay20ms();
{
unsigned long edata i;_nop_();
_nop_();
i = 119998UL;
while (i) i--;
_nop_();
_nop_();
i = 119998UL;
while (i) i--;
}
void Timer0_Init(void);                //3秒@24.000MHz                //函数声明void main(void)
{
int count=1;                                                                        //按键计数变量WTST = 0;                                                                                //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1;                                                                                 //扩展寄存器(XFR)访问使能
CKCON = 0;                                                                                 //提高访问XRAM速度

P0M1 = 0x00;   P0M0 = 0x00;
P1M1 = 0x00;   P1M0 = 0x00;
P2M1 = 0x00;   P2M0 = 0x00;
P3M1 = 0x00;   P3M0 = 0x00;
P4M1 = 0x00;   P4M0 = 0x00;
P5M1 = 0x00;   P5M0 = 0x00;
P6M1 = 0x00;   P6M0 = 0x00;
P7M1 = 0x00;   P7M0 = 0x00;

usb_init();                                     //USB CDC 接口配置

IE2 |= 0x80;                                    //使能USB中断
Timer0_Init();                                                                        //定时器初始化

EA = 1;                                                                                        //IE |= 0X80;



while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置

while(1)
{

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

      usb_OUT_done();                                                        //
    }


WTST = 0;                                                                                //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1;                                                                                 //扩展寄存器(XFR)访问使能
CKCON = 0;                                                                                 //提高访问XRAM速度

P0M1 = 0x00;   P0M0 = 0x00;
P1M1 = 0x00;   P1M0 = 0x00;
P2M1 = 0x00;   P2M0 = 0x00;
P3M1 = 0x00;   P3M0 = 0x00;
P4M1 = 0x00;   P4M0 = 0x00;
P5M1 = 0x00;   P5M0 = 0x00;
P6M1 = 0x00;   P6M0 = 0x00;
P7M1 = 0x00;   P7M0 = 0x00;

usb_init();                                     //USB CDC 接口配置

IE2 |= 0x80;                                    //使能USB中断
Timer0_Init();                                                                        //定时器初始化

EA = 1;                                                                                        //IE |= 0X80;



while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置

while(1)
{

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

      usb_OUT_done();                                                        //
    }


//         任务2:p2流水灯
if(count_ms&gt;=300){
count_ms=0;                        P2=state;
                                numb++;

                                if(numb&gt;=8){
                                numb=0;
                                }
                        }
}
                        P2=state;
                                numb++;

                                if(numb&gt;=8){
                                numb=0;
                                }
                        }
}
}void Timer0_Isr(void) interrupt 1
{
u8 i;
for(i=0;i&lt;3;i++){
count_ms++;}

}
}

}
void Timer0_Init(void)                //1毫秒@24.000MHz
{
TM0PS = 0x00;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR &amp;= 0x7F;                        //定时器时钟12T模式
TMOD &amp;= 0xF0;                        //设置定时器模式
TL0 = 0x30;                                //设置定时初始值
TH0 = 0xF8;                                //设置定时初始值
TF0 = 0;                                //清除TF0标志
TR0 = 1;                                //定时器0开始计时
ET0 = 1;                                //使能定时器0中断
}
</code></pre>

silas3082 发表于 2024-12-13 15:35:05

<h3>在流水灯的基础上,将led状态的数组数据再反过来,就是先led流水灯左右左右的流动</h3>
<pre><code>u8 state={0xFE,// 1111 1110 ,最低位(P20控制的LED)点亮,其余熄灭
0xFD,// 1111 1101 ,次低位(P21控制的LED)点亮,其余熄灭
0xFB,// 1111 1011 ,依次类推
0xF7,
0xEF,
0xDF,
0xBF,
0x7F,0xBF,0xDF, 0xEF,0xF7,0xFB,0xFD};
</code></pre>

silas3082 发表于 2024-12-13 16:56:59

<h3>任务3:按下p32按钮,led依次右移一位</h3>
<p>这里学习了不使用while(P32==0)这个语句,这样会造成按键按下期间其他任务不执行的情况;</p>
<p>而是改为定时器每10ms执行一次判断p32是否按下,如果按下,则把按键技术变量key_vol加1,当加到5时,即50ms按键都按下,则为按键按下,否则key_vol=0;</p>
<p><img src="data/attachment/forum/202412/13/165343i8x8dg6f0v2glng3.png" alt="videoframe_2561396.png" title="videoframe_2561396.png" /></p>
<p>这样就实现了不同任务互不影响。</p>
<pre><code>#include &quot;ai8051u.h&quot;                        //调用头文件
#include &quot;stc32_stc8_usb.h&quot;                //调用头文件
#include &quot;intrins.h&quot;                        //d调用头文件//注意:擎天柱的LED端口在P2,且没有三极管的电源控制,所以只要控制P2端口即可,按键通用,本节课程的其余内容均通用!#define u8unsigned char                //8位无符号变量(0-255)
#define u16 unsigned int                //16位无符号变量(0-65535)u16 count_ms = {0,0,0};                                        //三个计时变量
u8 numb=0;
u16 key_vol=0;
u8 state={0xFE,// 1111 1110 ,最低位(P20控制的LED)点亮,其余熄灭
0xFD,// 1111 1101 ,次低位(P21控制的LED)点亮,其余熄灭
0xFB,// 1111 1011 ,依次类推
0xF7,
0xEF,
0xDF,
0xBF,
0x7F};
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = &quot;@STCISP#&quot;;void Delay20ms(void)        //@24.000MHzDelay20ms();
{
unsigned long edata i;_nop_();
_nop_();
i = 119998UL;
while (i) i--;
_nop_();
_nop_();
i = 119998UL;
while (i) i--;
​}
void Timer0_Init(void);                //3秒@24.000MHz                //函数声明void main(void)
{
int count=1;                                                                        //按键计数变量WTST = 0;                                                                                //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1;                                                                                 //扩展寄存器(XFR)访问使能
CKCON = 0;                                                                                 //提高访问XRAM速度

P0M1 = 0x00;   P0M0 = 0x00;
P1M1 = 0x00;   P1M0 = 0x00;
P2M1 = 0x00;   P2M0 = 0x00;
P3M1 = 0x00;   P3M0 = 0x00;
P4M1 = 0x00;   P4M0 = 0x00;
P5M1 = 0x00;   P5M0 = 0x00;
P6M1 = 0x00;   P6M0 = 0x00;
P7M1 = 0x00;   P7M0 = 0x00;

usb_init();                                     //USB CDC 接口配置

IE2 |= 0x80;                                    //使能USB中断
Timer0_Init();                                                                        //定时器初始化

EA = 1;                                                                                        //IE |= 0X80;



while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置

while(1)
{

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


WTST = 0;                                                                                //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1;                                                                                 //扩展寄存器(XFR)访问使能
CKCON = 0;                                                                                 //提高访问XRAM速度

P0M1 = 0x00;   P0M0 = 0x00;
P1M1 = 0x00;   P1M0 = 0x00;
P2M1 = 0x00;   P2M0 = 0x00;
P3M1 = 0x00;   P3M0 = 0x00;
P4M1 = 0x00;   P4M0 = 0x00;
P5M1 = 0x00;   P5M0 = 0x00;
P6M1 = 0x00;   P6M0 = 0x00;
P7M1 = 0x00;   P7M0 = 0x00;

usb_init();                                     //USB CDC 接口配置

IE2 |= 0x80;                                    //使能USB中断
Timer0_Init();                                                                        //定时器初始化

EA = 1;                                                                                        //IE |= 0X80;



while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置

while(1)
{

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


​//         任务3:按下p32按钮,led依次右移一位                        if(count_ms&gt;=1000){                     //第一个任务每一秒打印一个hellow world
                        count_ms=0;
                        printf(&quot;当前第%d个led点亮\r\n&quot;,(u16)numb);
                        }
       
       
                        P2=state;

                        if(count_ms&gt;=10){                  //第二个任务按下p32按钮,led依次右移一位
                        count_ms=0;
                                if(P32==0){   
                                key_vol ++;
                                if(key_vol==5){
                                numb ++;
                                        if(numb&gt;=8){
                                        numb=0;
                                        }
                                        }
                                }
                                else{
                                key_vol=0;
                                }
                                }
               
                        }


       
}
                        if(count_ms&gt;=1000){                     //第一个任务每一秒打印一个hellow world
                        count_ms=0;
                        printf(&quot;当前第%d个led点亮\r\n&quot;,(u16)numb);
                        }
       
       
                        P2=state;

                        if(count_ms&gt;=10){                  //第二个任务按下p32按钮,led依次右移一位
                        count_ms=0;
                                if(P32==0){   
                                key_vol ++;
                                if(key_vol==5){
                                numb ++;
                                        if(numb&gt;=8){
                                        numb=0;
                                        }
                                        }
                                }
                                else{
                                key_vol=0;
                                }
                                }
               
                        }


       
}
​void Timer0_Isr(void) interrupt 1
{
u8 i;
for(i=0;i&lt;3;i++){
count_ms++;}

}
}

}
​void Timer0_Init(void)                //1毫秒@24.000MHz
{
TM0PS = 0x00;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR &amp;= 0x7F;                        //定时器时钟12T模式
TMOD &amp;= 0xF0;                        //设置定时器模式
TL0 = 0x30;                                //设置定时初始值
TH0 = 0xF8;                                //设置定时初始值
TF0 = 0;                                //清除TF0标志
TR0 = 1;                                //定时器0开始计时
ET0 = 1;                                //使能定时器0中断
}
</code></pre>
<p>这里补充一下,冲哥教程里没有</p>
<pre><code>if(numb&gt;=8){
numb=0;
</code></pre>
<p>}这一段,会导致超过8之后会出现莫名其妙的问题,这个地方需要给numb重置一下。</p>

silas3082 发表于 2024-12-13 17:21:42

<h3>文件的创建</h3>
<p>这一节介绍了利用.c和.h文件,简化main.c中的代码,使代码看上去更加整洁。</p>
<p>.c文件用来存放函数,并且函数需要在.h文件中声明。.h文件用来放定义的变量,函数声明</p>
<h4><strong>config.c文件</strong></h4>
<pre><code>#include &quot;config.h&quot;void sys_init(void){
WTST = 0;                                                                                //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1;                                                                                 //扩展寄存器(XFR)访问使能
CKCON = 0;                                                                                 //提高访问XRAM速度P0M1 = 0x00;   P0M0 = 0x00;
P1M1 = 0x00;   P1M0 = 0x00;
P2M1 = 0x00;   P2M0 = 0x00;
P3M1 = 0x00;   P3M0 = 0x00;
P4M1 = 0x00;   P4M0 = 0x00;
P5M1 = 0x00;   P5M0 = 0x00;
P6M1 = 0x00;   P6M0 = 0x00;
P7M1 = 0x00;   P7M0 = 0x00;
}
P0M1 = 0x00;   P0M0 = 0x00;
P1M1 = 0x00;   P1M0 = 0x00;
P2M1 = 0x00;   P2M0 = 0x00;
P3M1 = 0x00;   P3M0 = 0x00;
P4M1 = 0x00;   P4M0 = 0x00;
P5M1 = 0x00;   P5M0 = 0x00;
P6M1 = 0x00;   P6M0 = 0x00;
P7M1 = 0x00;   P7M0 = 0x00;
}
​void Timer0_Init(void)                //1毫秒@24.000MHz
{
TM0PS = 0x00;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR &amp;= 0x7F;                        //定时器时钟12T模式
TMOD &amp;= 0xF0;                        //设置定时器模式
TL0 = 0x30;                                //设置定时初始值
TH0 = 0xF8;                                //设置定时初始值
TF0 = 0;                                //清除TF0标志
TR0 = 1;                                //定时器0开始计时
ET0 = 1;                                //使能定时器0中断
}void Delay20ms(void)        //@24.000MHzDelay20ms();
{
unsigned long edata i;_nop_();
_nop_();
i = 119998UL;
while (i) i--;
_nop_();
_nop_();
i = 119998UL;
while (i) i--;
​}
</code></pre>
<p>config.h文件</p>
<pre><code>#ifndef __CONFIG_H
#define __CONFIG_H#include &quot;ai8051u.h&quot;                        //调用头文件
#include &quot;stc32_stc8_usb.h&quot;                //调用头文件
#include &quot;intrins.h&quot;                        //d调用头文件#define u8unsigned char                //8位无符号变量(0-255)
#define u16 unsigned int                //16位无符号变量(0-65535)void sys_init(void);         //函数声明void Timer0_Init(void);void Delay20ms(void);#endif
</code></pre>
<p>main.c</p>
<pre><code>#include &quot;config.h&quot;u16 count_ms = {0,0,0};                                        //三个计时变量
u8 numb=0;
u16 key_vol=0;
u8 state={0xFE,// 1111 1110 ,最低位(P20控制的LED)点亮,其余熄灭
0xFD,// 1111 1101 ,次低位(P21控制的LED)点亮,其余熄灭
0xFB,// 1111 1011 ,依次类推
0xF7,
0xEF,
0xDF,
0xBF,
0x7F};
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = &quot;@STCISP#&quot;;void main(void)
{sys_init();
usb_init();                                     //USB CDC 接口配置
sys_init();
usb_init();                                     //USB CDC 接口配置
​IE2 |= 0x80;                                    //使能USB中断
Timer0_Init();                                                                        //定时器初始化EA = 1;                                                                                        //IE |= 0X80;while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置

while(1)
{

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


while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置

while(1)
{

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


​//         任务3:按下p32按钮,led依次右移一位                        if(count_ms&gt;=1000){                     //第一个任务每一秒打印一个hellow world
                        count_ms=0;
                        printf(&quot;当前第%d个led点亮\r\n&quot;,(u16)numb);
                        }
       
       
                        P2=state;

                        if(count_ms&gt;=10){                  //第二个任务按下p32按钮,led依次右移一位
                        count_ms=0;
                                if(P32==0){   
                                key_vol ++;
                                if(key_vol==5){
                                numb ++;
                                        if(numb&gt;=8){
                                        numb=0;
                                        }
                                        }
                                }
                                else{
                                key_vol=0;
                                }
                                }
               
                        }


       
}
                        if(count_ms&gt;=1000){                     //第一个任务每一秒打印一个hellow world
                        count_ms=0;
                        printf(&quot;当前第%d个led点亮\r\n&quot;,(u16)numb);
                        }
       
       
                        P2=state;

                        if(count_ms&gt;=10){                  //第二个任务按下p32按钮,led依次右移一位
                        count_ms=0;
                                if(P32==0){   
                                key_vol ++;
                                if(key_vol==5){
                                numb ++;
                                        if(numb&gt;=8){
                                        numb=0;
                                        }
                                        }
                                }
                                else{
                                key_vol=0;
                                }
                                }
               
                        }


       
}
​void Timer0_Isr(void) interrupt 1
{
u8 i;
for(i=0;i&lt;3;i++){
count_ms++;}

}
}

}
</code></pre>

silas3082 发表于 2024-12-13 17:23:56

<h3>结构体数组的周期性调度</h3>
<p>本节知识点还是挺多的,而且不是那么容易理解。</p>
<p>1.首先创建了task.c和task.h的文件</p>
<p>在task.c文件中,定义一个结构体:</p>
<pre><code>


static TASK_COMPONENTS Task_Comps[]=
{
   //状态计数周期函数
    {0, 300,   300,   Led0_Blink},/* 300ms执行一次 */
                {0, 600,   600,   Led1_Blink},/* 600ms执行一次 */
                {0, 900,   900,   Led2_Blink},/* 900ms执行一次 */
                {0, 10,   10,   key_task},/* 10ms执行一次 */

        /* Add new task here */
};

</code></pre>
<p>任务标记回调函数:void Task_Marks_Handler_Callback(void),此函数的作用是对结构体中的每一组元素根据计数值进行倒数,当倒数到0时,计数重置为计数周期,并且第一位run置1,从而调用相应的任务执行函数。</p>
<pre><code>void Task_Marks_Handler_Callback(void)
{
    u8 i;
    for(i=0; i&lt;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 */
            }
      }
    }
}

</code></pre>
<p>任务处理回调函数:void Task_Marks_Handler_Callback(void),此函数的作用是当run置一后,执行相应的函数。</p>
<pre><code>void Task_Pro_Handler_Callback(void)
{
    u8 i;
    for(i=0; i&lt;Tasks_Max; i++)
    {
      if(Task_Comps.Run) /* If task can be run */
      {
            Task_Comps.Run = 0;      /* Flag clear 0 */
            Task_Comps.TaskHook();   /* Run task */
      }
    }
}

</code></pre>
<p>完整的task.c</p>
<pre><code>#include &quot;task.h&quot;
#include &quot;io.h&quot;



static TASK_COMPONENTS Task_Comps[]=
{
   //状态计数周期函数
    {0, 300,   300,   Led0_Blink},/* 300ms执行一次 */
                {0, 600,   600,   Led1_Blink},/* 600ms执行一次 */
                {0, 900,   900,   Led2_Blink},/* 900ms执行一次 */
                {0, 10,   10,   key_task},/* 10ms执行一次 */

        /* Add new task here */
};



u8 Tasks_Max = sizeof(Task_Comps)/sizeof(Task_Comps);



//========================================================================
// 函数: Task_Handler_Callback
// 描述: 任务标记回调函数.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2012-10-22
//========================================================================
void Task_Marks_Handler_Callback(void)
{
    u8 i;
    for(i=0; i&lt;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 */
            }
      }
    }
}

//========================================================================
// 函数: Task_Pro_Handler_Callback
// 描述: 任务处理回调函数.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2012-10-22
//========================================================================
void Task_Pro_Handler_Callback(void)
{
    u8 i;
    for(i=0; i&lt;Tasks_Max; i++)
    {
      if(Task_Comps.Run) /* If task can be run */
      {
            Task_Comps.Run = 0;      /* Flag clear 0 */
            Task_Comps.TaskHook();   /* Run task */
      }
    }
}


</code></pre>
<p>在task.h文件中,有结构体声明及回调函数的声明</p>
<pre><code>#ifndef __TASK_H
#define __TASK_H


#include &quot;config.h&quot;

typedef struct
{
        u8 Run;               //任务状态:Run/Stop
        u16 TIMCount;         //定时计数器
        u16 TRITime;          //重载计数器
        void (*TaskHook) (void); //任务函数
} TASK_COMPONENTS;   


void Task_Marks_Handler_Callback(void);
void Task_Pro_Handler_Callback(void);
#endif
</code></pre>
<p>那之前p00每300ms闪烁一次,p01每600ms闪烁一次,p02每900ms闪烁一次为例</p>
<p>增加了io.c和io.h文件,将io口的配置转移到这里。</p>
<p>io.c文件</p>
<pre><code>#include &quot;io.h&quot;


u16 key_vol=0;
void Led0_Blink(void){

        P00=!P00;
}

void Led1_Blink(void){
P01=!P01;
}

void Led2_Blink(void){
P02=!P02;
}

void key_task(void){
if(P32==0){
   key_vol++;
       if(key_vol==5){
       //按键按下的任务
               printf(&quot;按键单机\r\n&quot;);
       }
       }
else{
key_vol=0;
       
}
}
</code></pre>
<p>io.h文件</p>
<pre><code>#ifndef __IO_H
#define __IO_H


#include &quot;config.h&quot;

void Led0_Blink(void);
void Led1_Blink(void);
void Led2_Blink(void);
void key_task(void);

#endif
</code></pre>
<p>main.c</p>
<pre><code>
#include &quot;config.h&quot;
#include &quot;task.h&quot;



char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = &quot;@STCISP#&quot;;



void main(void)
{

        sys_init();
        usb_init();                                     //USB CDC 接口配置

IE2 |= 0x80;                                    //使能USB中断
        Timer0_Init();                                                                        //定时器初始化

EA = 1;                                                                                        //IE |= 0X80;

        P40=0;

        while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置

        while(1)
        {
       
      if (bUsbOutReady)                                                        //如果接收到了数据
      {
            //USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
         
            usb_OUT_done();                                                        //
      }
       
                Task_Pro_Handler_Callback();      //执行函数


                               
                                }
       
               
                       
        }




void Timer0_Isr(void) interrupt 1
{
        Task_Marks_Handler_Callback();      //系统计时

        }



</code></pre>

silas3082 发表于 2024-12-14 15:36:17

<h3>第九集 数码管</h3>
<p>本节使用两个hc595控制8位8段数码管</p>
<p>1.首先,在io.c中创建两个数组,分别存放数码管的段码和位码:</p>
<pre><code>u8 SEG_NUM[]=                           /////数码管位码0-9,A-F,
{
0x3F,       /'0', 0/
0x06,       /'1', 1/
0x5B,       /'2', 2/
0x4F,       /'3', 3/
0x66,       /'4', 4/
0x6D,       /'5', 5/
0x7D,       /'6', 6/
0x07,       /'7', 7/
0x7F,       /'8', 8/
0x6F,       /'9', 9/
0x77,       /'A', 10/
0x7C,       /'B', 11/
0x39,       /'C', 12/
0x5E,       /'D', 13/
0x79,       /'E', 14/
0x71,       /'F', 15/
0x40,       /'-', 16/
0x00,       /' ', 17/
0x80,       /'.', 18/
};u8 T_NUM =                                    //数码管位码
{
0X01,0X02,0X04,0X08,0X10,0X20,0X40,0X80
};
</code></pre>
<p>其中,数码管的位码可以用isp软件-工具-字库生成工具    中找到数码管,直接就可以生成</p>
<p>然后是移位寄存器595端口初始化函数:void init_595(void),先把数据写到引脚上void Send_595(u8 dat),数码管段码输出,数码管位码输出void Display_Seg(u8 HC595_1,HC595_2)</p>
<p>需要显示的数据用void Seg_Task(void)显示。在task.c中,用结构体显示,</p>
<h4>任务2:8位数码管显示12345678</h4>
<pre><code>u8 Seg_no=0;
void Seg_Task(void){


        Display_Seg( SEG_NUMB, ~T_NUM );       //数码管刷新断码和位码
        Seg_no++;
        if(Seg_no&gt;7){
        Seg_no=0;
        }
</code></pre>
<p>task.c中每1ms执行一次Seg_Task</p>
<pre><code>static TASK_COMPONENTS Task_Comps[]=
{
{0, 1,   1,   Seg_Task},/ 1ms执行一次 /
};
</code></pre>
<p>这里容易错的地方是,容易在Seg_Task函数中使用for循环来依次显示1-8位数码管数值,这里不需要再用到for循环,因为在{0, 1,   1,   Seg_Task},中就是每1ms执行一次循环</p>

silas3082 发表于 2024-12-14 15:59:20

<h3>数码管任务3:动态显示时分秒00-00-00</h3>
<p>用到两个函数,Seg_Task用来显示数码管,时间间隔位1ms,CountUp用来每一秒将miao加一,时间间隔为1秒,都是通过任务调度实现</p>
<pre><code>
u8 Seg_no=0;
u8 shi=0;
u8 fen =0;
u8 miao=0;

void Seg_Task(void){


        switch(Seg_no){
                case 0: Display_Seg( SEG_NUMB, ~T_NUM );   break;//小时十位
                case 1: Display_Seg( SEG_NUMB, ~T_NUM );   break;
                case 2: Display_Seg( SEG_NUMB, ~T_NUM );   break;
                case 3: Display_Seg( SEG_NUMB, ~T_NUM );   break;
                case 4: Display_Seg( SEG_NUMB, ~T_NUM );   break;
                case 5: Display_Seg( SEG_NUMB, ~T_NUM );   break;
                case 6: Display_Seg( SEG_NUMB, ~T_NUM );   break;
                case 7: Display_Seg( SEG_NUMB, ~T_NUM );   break;
        }
   
        Seg_no++;
        if(Seg_no&gt;7){
        Seg_no=0;
        }

        }


void CountUp(void){
miao++;
        if(miao&gt;59){
        miao=0;
                fen++;
                if(fen&gt;59){
                fen=0;
                        shi++;
                        if(shi&gt;23){
                        shi=0;
                        }
                }
        }


}



</code></pre>
<p>冲哥用的if esle if语句,我这里用了switch case,实现效果一样</p>
<p><img src="data/attachment/forum/202412/14/160200jl58112w755m42e1.jpg" alt="微信图片_20241214160144.jpg" title="微信图片_20241214160144.jpg" /></p>
页: [1] 2 3 4
查看完整版本: Ai8051U 实验箱 学习开始打卡