zzgpu 发表于 2025-2-2 15:27:11

打卡学习《Ai8051U深度入门大型实战视频》


第一集:讲解了8051U的新功能

突出介绍了Ai8051U的强大功能


zzgpu 发表于 2025-2-2 15:44:38

第二集


讲解了Ai8051U实验箱硬件和软件开发工具




软件下载工具





zzgpu 发表于 2025-2-3 13:28:32

第三集 点亮第一颗LED

从本讲开始要写实际的代码了。

相对来说,代码比较简单,容易理解,有C语言基础就行。
#include "ai8051u.h"                //调用头文件

void main(void)
{
      P2M0 = 0;                //P2端口(P20-P27)为准双向口
      P2M1 = 0;

      while(1)
      {
                P20 = 0;      //P20端口输出0V
                P27 = 0;      //P27端口输出0V
      }
}

zzgpu 发表于 2025-2-3 13:34:40

第四集 USB不停电下载

上一讲中的代码下载,需要反复按电源键和p3.2按键才能正常下载。
本讲实现了开发板不停电下载,免去了反复按键的麻烦,非常实用。提高了开发效率。


要实现这个功能,就需要调用官方提供的usb库。要将这个库加入项目中。


上代码:



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

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

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

    // ...

    usb_init(); // 初始化 USB CDC 接口配置

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

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

    while (1)
    {

      if (bUsbOutReady)
      {
            usb_OUT_done();
      }

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



zzgpu 发表于 2025-2-3 13:39:19

第五集 C语言基础

使用STC-USB库实现的printf函数,可以直接与上位机通信,方便调试及与单片机交互。
代码:
#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

    // ...

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

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

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

    while (1)
    {

      if (bUsbOutReady) // 如果接收到了数据
      {
            printf("向上位机发送的信息\r\n");    // 发送消息给上位机
            usb_OUT_done();
      }
    }
}



zzgpu 发表于 2025-2-3 13:48:18

第六集 I/O输入输出


本集简要介绍了GPIO,高电平、低电平的概念。
并通过将按键接入IO端口进行了讲解。最后用3个小任务,以实例的形式介绍了通过检测按键,控制led的亮和灭。
上代码:
#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; // 初始状态

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速度

    // ...

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

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

    P40 = 0;

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

    while (1)
    {

      if (bUsbOutReady) // 如果接收到了数据
      {
            usb_OUT_done(); //
      }

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

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

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

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



zzgpu 发表于 2025-2-3 14:15:28

第七集 定时器


在本集中,冲哥给我们讲解的单片机的重要部件之一:定时器。那什么是定时器,能干什么?翻阅数据手册:

Ai8051U 系列单片机内部设置了 6 个 24 位定时器/计数器(8 位预分频+16 位计数)。6 个 16 位定时器 T0、T1、T2、T3、T4 和 T11 都具有计数方式和定时方式两种工作方式。
定时器/计数器 0 有 4 种工作模式:模式 0(16 位自动重装载模式),模式 1(16 位不可重装载模式),模式 2(8 位自动重装模式),模式 3(不可屏蔽中断的 16 位自动重装载模式)。定时器/计数器 1 除模式 3 外,其他工作模式与定时器/计数器 0 相同。T1 在模式 3 时无效,停止计数。定时器 T2 的工作模式固定为 16 位自动重装载模式。T2 可以当定时器使用,也可以当串口的波特率发生器和可编程时钟输出。定时器 3、定时器 4、定时器 11 与定时器 T2 一样,它们的工作模式固定为 16 位自动重装载模式。T3/T4可以当定时器使用,也可以当串口的波特率发生器和可编程时钟输出。定时器 11 的工作模式固定为 16位自动重装载模式。T11 可以当定时器使用,也可编程时钟输出。
在实际项目中,STC-ISP工具给我们提供了一个便捷工具,帮助我们快速计算定时数据:

①:在下载软件中选择“定时器计算器”功能页,进定时器代码生成界面
②:设置系统工作频率(单位:MHz)
③:设置定时时间长度(单位:毫秒/微秒)
④:选择目标定时器,并设置定时器工作模式
⑤:选择是否需要使能定时器中断
⑥:手动生成 C 代码或者 ASM 代码,复制范例


最后,通过3个小任务给出了具体应用实例:

// 任务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松开
                        }
                }




zzgpu 发表于 2025-2-3 14:35:41

第八集 周期性调度任务


本集接续上一集,用定时器来实现周期性的任务调度,避免了用循环方法,释放单片机资源,提高系统响应速度,改善用户体验。

通过实现三个任务,冲哥深入浅出地讲解了如何用定时器来周期性地调度这些任务:

任务1:用一个定时器实现这个任务。LED1实现0.3秒取反一次,LED2实现0.6秒取反一次,LED3 0.9秒取反一次
任务2:数组点亮LED,实现流水灯
任务3:按键按一下,LED通过数组移动一下;


在代码实现中,通过数组的方式来定义任务:
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);

void Task_Pro_Handler_Callback(void)
{
    u8 i;
    for (i = 0; i < Tasks_Max; i++)
    {
      if (Task_Comps.Run) /* If task can be run */
      {
            Task_Comps.Run = 0;    /* Flag clear 0 */
            Task_Comps.TaskHook(); /* Run task */
      }
    }
}


zzgpu 发表于 2025-2-3 14:57:42

第九集 数码管


本集讲解了

1.数码管介绍
2.数码管显示原理
3.数码管静态显示
4.数码管动态显示
5.虚拟显示——LED和数码管

八段数码管由8个发光二极管构成,通过不同的组合可用来显示数字0~9、字符A~F和小数点“.”。分为共阳极和共阴极两种结构。






如果静态显示8位数码管,至少需要占用8*8+3位IO端口,非常浪费宝贵的端口资源。
在实际的项目中,多采用动态显示模式。利用人眼的视觉暂留原理,逐位动态扫描显示,可以达到多位视觉上同时显示的效果。
在实际的实现中,还需要注意消隐,改善视觉效果。

代码:
void Send_595(u8 dat)
{
      u8 i;

      for (i = 0; i < 8; i++)
      {
                dat <<= 1;                // DAT = (DAT<<1);      //CY
                HC595_SER = CY; // 先把数据写到引脚上
                HC595_SCK = 1;      // 输出上升沿的时钟信号
                HC595_SCK = 0;
      }
}

void Display_Seg(u8 HC595_1, u8 HC595_2)
{
      Send_595(HC595_1); // 数码管段码输出高电平点亮
      Send_595(HC595_2); // 数码管位码      低电平点亮

      HC595_RCK = 1; // 数据输出
      HC595_RCK = 0;
}

void Seg_Task(void)
{
      u8 num = 0;
      if (Seg_no == 0) // 小时十位
      {
                num = shi / 10;
                Display_Seg(SEG_NUM, ~T_NUM); // 数码管刷段码和位码
      }
      else if (Seg_no == 1) // 小时的个位
      {
                num = shi % 10;
                Display_Seg(SEG_NUM, ~T_NUM); // 数码管刷段码和位码
      }
      else if (Seg_no == 2) // 第一个横杠
      {
                Display_Seg(SEG_NUM, ~T_NUM); // 数码管刷段码和位码
      }
      else if (Seg_no == 3) // 分钟的十位
      {
                num = fen / 10;
                Display_Seg(SEG_NUM, ~T_NUM); // 数码管刷段码和位码
      }
      else if (Seg_no == 4)
      {
                num = fen % 10;
                Display_Seg(SEG_NUM, ~T_NUM); // 数码管刷段码和位码
      }
      else if (Seg_no == 5)
      {
                Display_Seg(SEG_NUM, ~T_NUM); // 数码管刷段码和位码
      }
      else if (Seg_no == 6)
      {
                num = miao / 10;
                Display_Seg(SEG_NUM, ~T_NUM); // 数码管刷段码和位码
      }
      else if (Seg_no == 7)
      {
                num = miao % 10;
                Display_Seg(SEG_NUM, ~T_NUM); // 数码管刷段码和位码
      }
      else
      {
      }
      Seg_no++;
      if (Seg_no > 7)
                Seg_no = 0;
}


zzgpu 发表于 2025-2-3 16:39:53

<h2>第十集 虚拟LED数码管</h2>
<p>手上只有擎天柱的朋友有福了!AIAPP-ISP提供了虚拟功能!</p>
<p>先准备好三件套:</p>
<p><img src="data/attachment/forum/202502/03/164342i3nszautsmviamwn.png" alt="图片1.png" title="图片1.png" /></p>
<p>isp提供的虚拟功能为快速调试提供了便利条件。</p>
<ol>
<li>虚拟显示——LED</li>
</ol>
<p><img src="data/attachment/forum/202502/03/165016xi86nvrvlzi6tngr.png" alt="11.PNG" title="11.PNG" /></p>
<p>2 虚拟显示——数码管</p>
<p><img src="data/attachment/forum/202502/03/165027waqga2qlql0sa2hr.png" alt="22.PNG" title="22.PNG" /></p>
<p>3 虚拟键盘</p>
<p><img src="data/attachment/forum/202502/03/165052h1k1kktx2epn6vkp.png" alt="33.PNG" title="33.PNG" /></p>
页: [1] 2
查看完整版本: 打卡学习《Ai8051U深度入门大型实战视频》