yngyng 发表于 2025-2-3 07:05:30

学习《8051U深度入门到32位51大型实战教学视频》

第一集
学习本集,感受到了Ai8051u这个仿真实验板的强大功能!也感受到了新型高速单片机带来的极致体验效果。
希望在这里,通过国芯论坛,通过冲哥的视频教程,能学习到更好的硬件编程方法,和创造更有实用价值的制作。
哪怕梦想让我们拼的遍体鳞伤,这一次我们也要勇往直前!
谢谢冲哥送出的这勉励话语,我将让其陪伴左右,警醒自己!提升自己!

yngyng 发表于 2025-2-3 07:14:08

第二集介绍了AI8051U实验箱的各个硬件模块;编程软件、程序下载软件的下载与安装;简要介绍了软件的基本操作,如何添加头文件及如何加入扩展功能等的操作。


yngyng 发表于 2025-2-3 07:21:36



第三集

课程开始,冲哥就讲解了keil软件的启动和工程的建立!搭建了一个基本的软件代码框架。

介绍了 GPIO

就拿P00来说,P00有4中状态,
假如P0组的引脚只有两种状态,那么仅需要P0M0就够用了,P0M0是一个字节(8位),即二进制为 0000 0000,其中每一位标志一个引脚状态,如下:
0:表示“准双向口”
1:表示“推挽输出”
举例 P0M0为 0100 0000 则表示 P06 为 “推挽输出”,其他7个都是“准双向口”。



yngyng 发表于 2025-2-3 09:49:35

第4集 USB不停电下载



上代码
#include "ai8051u.h" //调用头文件
#include "stc32_stc8_usb.h"
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";

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();   
    IE2 |= 0x80;                                    //使能USB中断
    EA = 1;
      
      while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置


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




yngyng 发表于 2025-2-3 10:03:52

第5集 C语言基础



本集让我重新温习了一遍C语言

老师讲解了 printf, 实现USB-CDC串口发送。

上代码


#include "ai8051u.h"      //调用头文件
#include "stc32_stc8_usb.h" //调用头文件

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

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";

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) // 如果接收到了数据
      {
            printf("Ai8051U真强大\r\n");
            usb_OUT_done(); //
      }
    }
}


运行效果图


yngyng 发表于 2025-2-3 10:15:23

第6集 IO输入输出


首先讲解了 GPIO 的概念。1 高电平 0 低电平



   GPIO(General Purpose I/O Ports)意思为通用输入/输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态-是高电平或是低电平。
   高电平就是指接近于电源正极电压的电平;也叫逻辑“1”; VDD最大电压不能超过5.5V。上限溢出允许0.3v内.
   单片机输出高电平就是输出VCC电压,输出低电平就是输出GND的电压。
   四种模式:准双向口、推挽输出、高阻输出、开漏模式。 灌电流(电源到管脚串电阻尽量大于1K,不小于470欧)和拉电流(管脚到Gnd,推挽/强上拉)的讲解
   单片机电压3.3V,施密特触发器,低电平不能高于0.99V,高电平不能低于1.18V。

通过按键来检测io状态
按键消抖。延时20ms


#include "ai8051u.h"      //调用头文件
#include "stc32_stc8_usb.h" //调用头文件
#include "intrins.h"      //d调用头文件

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

#define u8 unsigned 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 = "@STCISP#";

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("state:%d\r\n", (int)state);

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



yngyng 发表于 2025-2-3 11:39:19

第七集 定时器


本集开始讲解Ai8051U最重要的数字外设之一: 定时器。


Ai8051U 系列单片机内部设置了 6 个 24 位定时器/计数器(8 位预分频+16 位计数)。6 个 16 位定时器 T0、T1、T2、T3、T4 和 T11 都具有计数方式和定时方式两种工作方式。



上代码,用定时器实现了3个小任务:

#include "ai8051u.h"      //调用头文件
#include "stc32_stc8_usb.h" //调用头文件
#include "intrins.h"      //d调用头文件

#define u8 unsigned 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 = "@STCISP#";

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_OUT_done(); //
      }

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

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

      // 任务2:灯按一下点亮三秒后熄灭。
      if (P32 == 0) // 判断P32按钮是否按下
      {
            Delay20ms(); // 延时20ms消抖
            if (P32 == 0)
            {
                printf("按键按下次数\xfd:%d 次\r\n", (int)count);
                count++;
                P00 = 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; // 关闭定时器
                  P00 = 1;
                  P01 = 1;
                }
                while (P32 == 0)
                  ; // 等待P32松开
            }
      }
    }
}

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

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

    P00 = state;
    P01 = !state;
}



yngyng 发表于 2025-2-3 13:16:02

<h2>第八集 定时器周期性调度任务</h2>
<p>学完本集,主要有二点收获:</p>
<ol>
<li>代码的模块化管理</li>
<li>任务的合理分解</li>
</ol>
<p>随着功能的增加,代码量也直线上升,如何组织代码很关键,对以后的需求变化影响至关重要。</p>
<pre><code>main.c         主模块
└─user
    ├─io.c       io功能
    ├─config.c   配置
    └─task.c   任务
</code></pre>
<p>主模块就显得非常简洁明了</p>
<pre><code class="language-c">#include &quot;config.h&quot;
#include &quot;task.h&quot;
#include &quot;io.h&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_OUT_done(); //
                }
                Task_Pro_Handler_Callback(); // 执行功能函数
        }
}
</code></pre>
<p>具体任务分解到了任务模块中</p>
<pre><code class="language-c">#include &quot;task.h&quot;
#include &quot;io.h&quot;

static TASK_COMPONENTS Task_Comps[] = {
    // 状态计数周期函数
    {0, 300, 300, LED0_Blink}, /* task 1 Period: 300ms */
    {0, 600, 600, LED1_Blink}, /* task 1 Period: 600ms */
    {0, 900, 900, LED2_Blink}, /* task 1 Period: 600ms */
    {0, 10, 10, KEY_Task},   /* task 1 Period: 600ms */
};

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>

yngyng 发表于 2025-2-3 15:21:42

<h2>第九集 数码管</h2>
<p>LED数码管由8个发光二极管构成,通过不同的组合可用来显示数字0~9、字符A~F和小数点“.”。分为共阳极和共阴极两种结构。</p>
<p>AIapp-ISP 工具提供了虚拟显示功能,极大地方便了开发调试。</p>
<p><img src="data/attachment/forum/202502/03/152202yw3baurdwuu3trbg.png" alt="1.PNG" title="1.PNG" /></p>
<p><img src="data/attachment/forum/202502/03/152240ln585k65n1n8nuoe.png" alt="image.png" title="image.png" /></p>
<p>代码</p>
<pre><code class="language-C">u8 SEG_NUM[] =
        {
                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*/
};

void SEG_PC(void)
{
        u8 cod;

        cod = SEG_NUM; // 小时的十位数的数码管段码
        cod = SEG_NUM;
        cod = SEG_NUM; // 数码管刷段码和位码

        cod = SEG_NUM; // 分钟
        cod = SEG_NUM;
        cod = SEG_NUM; // 数码管刷段码和位码

        cod = SEG_NUM; // 分钟
        cod = SEG_NUM;

        SEG7_ShowCode(cod);
}
</code></pre>

yngyng 发表于 2025-2-3 15:24:42

<h2><a href="https://www.stcaimcu.com/forum.php?mod=attachment&amp;aid=NzY0ODV8Njc0NzZmZTF8MTczODU2MTg2M3wzNjc4NHwxMTkwMg%3D%3D">第十集 虚拟LED数码管</a></h2>
<p>准备好三件套</p>
<p><img src="data/attachment/forum/202502/03/165241avq2i76c7a6lia3a.png" alt="图片1.png" title="图片1.png" /></p>
<p>isp提供的虚拟功能为快速调试提供了便利条件。</p>
<ol>
<li>虚拟显示——LED</li>
</ol>
<p><img src="data/attachment/forum/202502/03/165241lydf1oqv7v0vo7b7.png" alt="11.PNG" title="11.PNG" /></p>
<p>2 虚拟显示——数码管</p>
<p><img src="data/attachment/forum/202502/03/165241g4rykx8k48rx4u4y.png" alt="22.PNG" title="22.PNG" /></p>
<p>3 虚拟键盘</p>
<p><img src="data/attachment/forum/202502/03/165241kj7z9aiol7jz8a7j.png" alt="33.PNG" title="33.PNG" /></p>
页: [1]
查看完整版本: 学习《8051U深度入门到32位51大型实战教学视频》