找回密码
 立即注册
查看: 352|回复: 10

AI8051U学习手记 | 再次感谢STC免费提供的AI8051U最小系统板和冲哥的优质教程

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-12-05 16:55:51
已绑定手机

2

主题

9

回帖

70

积分

注册会员

积分
70
发表于 2025-11-6 12:09:27 | 显示全部楼层 |阅读模式

一、认识AI8051

最近上STC论坛查资料,突然发现主页有学习AI8051送最小核心板的活动,申请了一张学习精进一下自己。

1.AI8051特点

阅读官方文档可以总结如下特点:

  1. 双核兼容架构:支持 8 位与 32 位双指令集
  2. 硬件加速能力内置 TFPU(三角函数浮点运算器),可快速处理 FFT、语音识别等复杂算法,无需额外 DSP。
  3. 丰富存储与外设:集成 34KB SRAM、64KB Flash,支持 ISP/IAP;外设含 12 位 ADC、16 位 PWM、USB 2.0、CAN/LIN 总线等,可直接驱动显示屏、音频设备
  4. 开发便捷性兼容 Keil C51/C251 ,内置 USB 接口,自身就是仿真器
  5. 可靠性:低功耗,抗干扰能力强,性价比突出,仅1.9元一片,最小系统板8元包邮。

2.AI8051擎天柱最小系统板

收到的开发板有两处未焊接元器件,虽然测试后发现并没有什么影响,但是本着打破砂锅问到底的精神去看了原理图发现如下:

a15ad856-af48-4e90-8cbe-aa6267055805.png

Pastedimage20251106115830.png补焊后效果如下:
2b5fafb7e824b267416d8fdad94569ea1.jpg

参考资料:

AI8051U 《单片机原理及应用》 《实验指导书》

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

回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-12-05 16:55:51
已绑定手机

2

主题

9

回帖

70

积分

注册会员

积分
70
发表于 2025-11-6 12:25:08 | 显示全部楼层

实验箱已安排 | AI8051U学习手记 | 感谢宏晶和冲哥提供的宝贵学习机会

二、环境配置

AI8051的Keil环境配置十分简单,确保Keil MDK,C51,C251正确安装,通过AICude-ISP一键添加型号、头文件、仿真器驱动到Keil即可。

1.下载Keil

点击Keil Product Downloads进入keil官网下载界面后,逐个点击下载按照指引安装即可。
0f6e3433-3541-483a-b97e-4c9cab6334cc.png

2.下载AICube-ISP

点击深圳国芯人工智能有限公司-工具软件进入STC官网下载界面后,点击下载按照指引安装即可。

6ec24872-acac-4355-ab5f-78158b93f6ed.png

3.一键添加型号、头文件、仿真器驱动到Keil

确保Keil安装正确后,确保Keil关闭后,打开AICube-ISP,进入Keil仿真设置一键导入。

128f9f00-f301-40ea-84a5-6ca106e519fc.png
引用官方提示:

1、添加前请先关闭Keil软件,请务必先关闭Keil软件,否则会导致添加失败
2、添加MCU选型数据库文件到 Keil安装路径下的UV2(或UV3\或UV4\取决于Keil的版本)目录中
3、安装仿真器的驱动程序到Keil安装路径下的C51\目录中
4、复制8051头文件到Keil安装路径下的C51\INC\STC\目录中
5、复制80251头文件到Keil安装路径下的C251\INC\STC\目录中
6、请确认Keil的安装目录下有C51目录和C251目录。请确认Keil的安装目录下有且仅有UV2、UV3、UV4目录中的一个存在

回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:266
  • 最近打卡:2025-12-16 08:29:17

812

主题

1万

回帖

2万

积分

管理员

积分
21267
发表于 2025-11-6 12:57:36 | 显示全部楼层
要 做到 USB不停电下载
要 尝试 图形化配置外设
推荐优先看printf_usb("Hello World !\r\n")及usb不停电下载, 演示视频链接
www.STCAI.com
下载 最新的 AiCube-ISP-V6.96E 或以上版本软件 !
下载 最新的 USB库函数,永远用最新的 USB库函数 !
下载 最新的 用户手册 !

下载 最新的 上机实践指导书 !



上面是 小李 演示:Ai8051U, printf_usb("Hello World !\r\n")及usb不停电下载@AiCube之图形化程序自动生成


上面是 小赵 演示:Ai8051U, printf_usb("Hello World !\r\n")及usb不停电下载@AiCube之图形化程序自动生成
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-12-05 16:55:51
已绑定手机

2

主题

9

回帖

70

积分

注册会员

积分
70
发表于 2025-11-6 16:18:45 | 显示全部楼层

三、LED跑马灯

首先感谢管理员大大提供的USB不停电下载与图形化配置外设教程,学习内容将在后续的打卡中体现~

LED跑马灯、闪光灯是许多开发板的第一个例程,既方便学习者学习搭建程序模板,也便于检测开发板好坏。

1.下载例程

官方的AICube-IDF提供了便捷的资料下载接口,点击跳转浏览器下载即可。

3.1.1AICube-ISP下载例程.png

2.打开例程

解压后会获得如下几个文件夹,为充分发挥AI8051的强大性能,直接选择32位例程即可。
![[3.2.1 例程内容.png]]
双击打开\AI8051U-DEMO-CODE-V1.2\Ai8051U-32Bit\01-用P0口做跑马灯\C语言\sample.uvproj即可通过Keil查看、修改、编译工程。

3.2.2跑马灯例程Keil界面.png

3.修改并编译下载例程

例程中最上部的说明往往格外重要。本例程我们主要可以获取两个信息,例程使用 P0 口驱动LED灯,时钟 24 MHZ

3.3.1例程说明.png
通过观察开发板或原理图可以发现,原厂的LED是焊接在 P20 - P27 上的,这意味着我们实际需要使用的是 P2 口
3.3.2开发板的LED.png
因此,我们需要修改程序,当然在 P00-P07 补焊一排LED灯理论上也是可以的。
主要修改的地方有这两处。

1.修改P2M0为0xff推挽输出,并将P0M0改为0X00准双向口。

3.3.3引脚配置.png

2.将驱动LED的端口从 P00-P07 改为 P20-P27

3.3.4程序修改.png

3.确保Keil输出hex文件打开后,点击Rebuild编译。

3.3.5配置HEX输出并编译.png

4.使用AICube-ISP烧录程序

打开编译好的HEX文件

3.3.6导入编译好的文件.png
配置时钟为24Mhz

3.3.7配置时钟.png
开发板用USB连接电脑后,按住开发板的P32 INTO按键,点击一下POWER按键,串口显示如图即可点击下载烧录。

3.3.8开发板烧录按键.png

3.3.9连接串口并烧录.png
点击后,等待出现操作成功字样,开发板LED会自动开启跑马灯效果。

11月6日.gif

也可以试试流水灯效果

while(1)
{
    led_mask = 0x00;  
  
    for(i = 0; i < 8; i++) 
        {
            led_mask |= (1 << i);
            P2 = ~led_mask;
            delay_ms(250);
        }
        delay_ms(500); 
        P2 = 0xFF;
        delay_ms(500);
}
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:266
  • 最近打卡:2025-12-16 08:29:17

812

主题

1万

回帖

2万

积分

管理员

积分
21267
发表于 2025-11-6 21:20:47 | 显示全部楼层
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-12-05 16:55:51
已绑定手机

2

主题

9

回帖

70

积分

注册会员

积分
70
发表于 2025-11-7 13:36:23 | 显示全部楼层

四、USB串口输出

1. 通过AiCube-ISP进入AICube

4.1.1打开AICube.png

2. 创建AICube项目

4.2.1创建AICube项目.png

3.配置USB通信串行总线并生成Keil项目

勾选USB,通信串行总线,确保设置如图后,点击绿色按钮或按下F5快捷键,将自动创建并打开Keil项目。

4.3.1设置通信串行总线并生成Keil项目.png
生成项目打开主函数后如图所示

4.3.2生成的Keil项目.png
直接编译确保模板被正确创建

4.3.3编译模板.png

4.添加代码到模板并编译

通过注释关闭 USBLIB_OUT_Done(),并在相应位置中添加 printf_usb("Hello_World\r\n");,编译完成后使用AICube-ISP下载即可(建议将IRC频率设置为40Mhz),此处不再赘述。

4.4.1添加代码到模板并编译.png

5.打开串口助手监听串口

设置合适的COM口,波特率使用默认的115200即可,打开串口后显示如下内容。

4.5.1串口输出效果.png

回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-12-05 16:55:51
已绑定手机

2

主题

9

回帖

70

积分

注册会员

积分
70
发表于 2025-11-8 20:59:52 | 显示全部楼层

五、USB免下电下载

很方便的功能

1.创建工程模板

参照USB串口输出部分使用AICube一键生成工程模板。

2.在生成的工程main.c中添加如下内容

添加如下内容并编译

5.2.1添加代码.png

3.烧录程序

此时打开AICube-ISP仍是如下状态,按照之前的方法进行烧录即可

5.3.1烧录程序.png
烧录成功后串口信息如下,此时即可不断电直接烧录。

5.3.2成功效果.png

4.运行程序

此时通过串口助手即可与单片机通讯。
根据代码易得,发送6,7会反馈不同的信息。

5.4.1运行程序.png

回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:266
  • 最近打卡:2025-12-16 08:29:17

812

主题

1万

回帖

2万

积分

管理员

积分
21267
发表于 2025-11-9 16:00:06 | 显示全部楼层
USB通信 都搞定了,建议直接申请 AI8051U 实验箱,

尝试 用 AiCube 图形化实现 各外设的 功能实现

点评

好的,已申请  发表于 2025-11-10 17:41
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-12-05 16:55:51
已绑定手机

2

主题

9

回帖

70

积分

注册会员

积分
70
发表于 2025-11-9 22:10:02 | 显示全部楼层

六、嵌入式C语言基础

1、USB-CDC串口printf函数实现

1.1 功能概述

printf函数是开发调试的核心工具,可通过USB-CDC串口快速打印变量值和调试信息,实现"免冷启动下载"调试。

1.2 启用步骤

  1. 打开USB库配置文件
  2. 找到printf宏定义位置(通常在第6行附近)
  3. 移除行首的反斜杠 \ 以启用功能
  4. 重新编译工程

常见问题排查

  • 配置文件选项错误
  • liba库文件未正确添加
  • 误删关键系统文件

1.3 printf重定向原理

工程中printf被重定向为 define宏替换:

// 示例:printf被重定向到USB输出函数
#define printf  USB_Printf_HID

define的作用:在预处理阶段,将代码中所有 printf替换为 USB_Printf_HID

1.4 格式化字符串语法

1.4.1 基本结构

printf("格式控制字符串", 参数列表);

1.4.2 字符类型

  1. 普通字符:原样输出

    printf("Hello World\n");  // 输出:Hello World(并换行)
    
  2. 转换说明:以 %开头,用于插入变量值

    • %s:输出字符串
    • %d:以十进制整数形式输出
    • %u:无符号十进制整数
  3. 转义字符

    • \n:换行符(Newline)
    • \t:水平制表符(Tab,通常=4个空格)
    • \\:输出反斜杠本身
    • %%:输出百分号本身(转义)

1.4.3 参数数量规则

N个转换说明符 = N+1个参数(格式字符串本身算第一个参数)

// 正确示例:3个%对应3个额外参数,共4个参数
printf("今天是%d年%d月%d日", 2025, 11, 9);  // 输出:今天是2025年11月9日

1.4.4 实战示例

// 接收到数据后原样返回并打印自定义信息
if (接收标志) {
    USB_SendData(接收缓冲区);  // 原路返回数据
    printf("STC YYDS\n");       // 打印自定义字符串
    清空接收区();
}

1.5 串口调试技巧

1.5.1 文本模式 vs 十六进制模式

  • 文本模式:直接显示ASCII字符
  • 十六进制模式:将每个字符转换为HEX值显示

示例:

文本模式显示:STC YYDS
十六进制模式:53 54 43 20 59 59 44 53
(53='S', 54='T', 43='C', 20='空格', 59='Y', 44='D')

应用场景:调试数值变量时,十六进制模式更直观。

1.5.2 免冷启动下载配置

  1. 下载软件中勾选三个关键选项(自动下载相关)
  2. 选择生成的 .obj文件
  3. 选择24MHz主频
  4. 识别USB-CDC虚拟串口号(如COM3)
  5. 波特率任意设置(USB-CDC不受波特率限制)

警告:printf不宜放在无延时的循环外部,可能导致系统崩溃。

2、数的进制系统

2.1 进制转换方法

通用公式

任意N进制数 → 十进制:

数值 = 每位数字 × N^位权 的总和

2.1.1 二进制 → 十进制

示例:1011b

1×2³ + 0×2² + 1×2¹ + 1×2⁰ = 8 + 0 + 2 + 1 = 11

2.1.2 十六进制 → 十进制

示例:0x3A4

3×16² + 10×16¹ + 4×16⁰ = 768 + 160 + 4 = 932

2.2 快捷转换工具

推荐使用程序员计算器

  • 十进制83 → 十六进制0x53
  • 十六进制0x53 → 十进制83

2.3 十六进制对照表(必须熟记)

十进制 十六进制 十进制 十六进制
0 0x0 8 0x8
1 0x1 9 0x9
2 0x2 10 0xA
3 0x3 11 0xB
4 0x4 12 0xC
5 0x5 13 0xD
6 0x6 14 0xE
7 0x7 15 0xF

3、C语言基本数据类型

3.1 类型长度与范围(32位编译器)

类型 位数 有符号范围 无符号范围 常用宏定义
char 8 -128 ~ 127 0 ~ 255 int8_t / U8
short 16 -32768 ~ 32767 0 ~ 65535 int16_t / U16
int 16/32 依赖编译器 0 ~ 65535/2³²-1 int / U32
long 32 -2³¹ ~ 2³¹-1 0 ~ 2³²-1 int32_t
float 32 IEEE 754浮点 - float
double 64 IEEE 754浮点 - double

关键提示:32位编译器默认不支持64位变量,使用 double需在文件头添加特殊编译指令(如 #pragma pack(8))。

3.2 变量定义语法

数据类型 变量名;

示例:

unsigned char x;    // 定义无符号字符变量x(0-255)
int y;              // 定义整型变量y

3.3 类型简化技巧(宏定义)

使用 define简化复杂类型声明:

#define U8  unsigned char    // 定义U8代替unsigned char
#define U16 unsigned int     // 定义U16代替unsigned int

// 后续可简洁定义变量
U8 x = 20;    // 等效于 unsigned char x = 20;
U16 y = 1000; // 等效于 unsigned int y = 1000;

3.4 变量作用域规则

// 全局变量:定义在最外层大括号,整个文件可见
U8 global_var = 100;

void function() {
    // 局部变量:仅在本大括号内有效
    U8 local_var = 50;
  
    if (1) {
        U8 inner_var = 10;  // 仅在if块内有效
    }
    // inner_var在此已失效
}

核心原则:大括号 {}界定变量生命周期。

4、C语言常用运算符

4.1 算术运算符

运算符 说明 示例(X=20, Y=10) 结果
+ 加法 X + Y 30
- 减法 X - Y 10
* 乘法 X * Y 200
/ 整数除法 X / Y 2
% 取模(余数) X % Y 0
++ 自增 X++ → X=21 -
-- 自减 X-- → X=19 -

关键特性

  • 除法 /结果只保留整数部分
  • 取模 %获取除法余数
  • 避免溢出:8位×8位可能溢出,建议强制转换为16位
U8 x = 200, y = 10;
U16 result = (U16)x * y;  // 强制转换防止溢出
// 错误示例:U8 result = x * y; // 结果会错误(2000>255)

4.2 关系运算符

运算符 说明 示例(X=20, Y=10) 结果
== 等于 X == Y 假(0)
!= 不等于 X != Y 真(1)
> 大于 X > Y 真(1)
< 小于 X < Y 假(0)
>= 大于等于 X >= Y 真(1)
<= 小于等于 X <= Y 假(0)

核心原则:结果为真(1)假(0),0为假,非0为真。

4.3 逻辑运算符

运算符 说明 示例(A=5, B=10) 结果
&& 逻辑与 (A>0) && (B>0) 真(1)
` ` 逻辑或
! 逻辑非 !A 假(0)

运算规则

  • &&:两边都为真才是真
  • ||:一边为真就是真
  • !:真变假,假变真

4.4 位运算符

运算符 说明 示例(按位操作)
& 按位与 0101 & 1100 = 0100
` ` 按位或
^ 按位异或 0101 ^ 1100 = 1001
~ 按位取反 ~0101 = 1010
<< 左移 0101 << 1 = 1010(低位补0)
>> 右移 0101 >> 1 = 0010(高位补0)

记忆口诀

  • 按位与 &全1为1,有0为0
  • 按位或 |有1为1,全0为0
  • 按位异或 ^相同为0,相异为1

4.5 赋值运算符

运算符 等价形式 示例
= 直接赋值 C = A + B
+= C = C + A C += A
-= C = C - A C -= A
*= C = C * A C *= A
/= C = C / A C /= A
%= C = C % A C %= A

4.6 条件运算符

条件 ? 表达式1 : 表达式2

逻辑:条件为真执行表达式1,否则执行表达式2。

4.7 if-else控制结构

if (条件表达式) {
    // 条件为真(非0)时执行
    printf("条件为真\n");
} else {
    // 条件为假(0)时执行
    printf("条件为假\n");
}

关键要点

  • 条件可以是任意表达式(算术、关系、逻辑运算)
  • else必须与if配对使用,不能单独存在
  • 代码块需用英文大括号 {}包围
  • 遵循缩进原则提高可读性

5、注意事项

5.1 数据溢出陷阱

// 错误示例:8位变量溢出
U8 x = 200;      // 最大值255
U8 y = 10;
U8 result = x * y;  // 200*10=2000 > 255,结果错误为208

// 正确做法:强制类型转换
U16 result = (U16)x * y;  // 使用16位变量存储

溢出特征:当计算结果超过变量类型最大值时,高位数据丢失,无法恢复。

5.2 调试技巧总结

  1. printf定位:在关键位置打印变量值
  2. 十六进制模式:调试数值变量更直观
  3. 格式符组合%d整数、%u无符号、%s字符串必须掌握
  4. 转义字符\n换行、\t制表符规范输出格式
知识点 核心内容 常见错误
printf 重定向到USB-CDC,格式符%对应参数 中文引号、参数数量不匹配
进制转换 2^位权求和,熟记0-F对照 忘记16的幂次计算
数据类型 U8=8位, U16=16位, 注意范围 溢出导致数据错误
运算符 /取整, %取余, &&||逻辑, &|位运算 混淆逻辑与位运算
if语句 0为假, 非0为真, else配if 使用中文符号, 作用域混乱
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-12-05 16:55:51
已绑定手机

2

主题

9

回帖

70

积分

注册会员

积分
70
发表于 2025-11-10 17:39:50 | 显示全部楼层

七、GPIO与按键

1、认识GPIO:从点灯开始

GPIO是通用输入输出端口的缩写,说白了就是能控制高低电平的引脚。

1.1 高低电平不是想多高就多高

电压极限参数(划重点!)

  • VCC对地电压最大 5.5V(实测我的实验箱是3.3V供电)
  • IO口电压不能超过 VCC + 0.3V
    • 3.3V供电时,IO口别超过3.6V
    • 5V供电时,IO口别超过5.3V

1.2 GPIO的四种工作模式

模式 我的理解 应用场景
准双向口 能进能出,但输出电流小(拉电流只有μA级) 最常用,默认就是这个
推挽输出 输出能力贼强,灌电流拉电流都能到20mA 驱动LED、蜂鸣器
高阻输入 只读模式,相当于悬空 读模拟信号
开漏输出 只能输出低电平,高电平靠外部上拉 I2C通信

这里有个坑:准双向口的拉电流很小,想直接驱动LED亮度不够,得用推挽输出或者像实验箱那样用灌电流方式(LED负极接IO口)。

1.3 施密特触发器:电平判定的"缓冲带"

输入电平判定标准(3.3V供电)

  • 低电平:必须 < 0.99V (开了施密特触发器的情况下)
  • 高电平:必须 > 1.09V

这个"滞后效应"就是施密特触发器的作用,防止电压在阈值附近抖动造成误判。AI8051U上电默认是开启施密特触发器的,所以直接按手册的0.99V/1.09V判断就行。


2、按键检测:从理论到代码

2.1 按键电路其实很简单

实验箱上的按键电路长这样:

VCC ──[10kΩ上拉电阻]──┬── P32
                      │
                     [按键]
                      │
                     GND

没按下时,P32被上拉电阻拉到高电平(3.3V);按下后,直接接地变成低电平(0V)。所以检测按键就是判断IO口是不是等于0。

2.2 第一个任务:按下亮,松开灭

照着视频敲的第一版代码:

void main() {
    P40 = 0;  // 打开LED总开关(这个坑后面讲)
  
    while(1) {
        if (P32 == 0) {   // 按键按下
            P00 = 0;      // LED亮
        } else {
            P00 = 1;      // LED灭
        }
    }
}

2.3 第二个任务:按下灭,松开亮

这个简单,把 if-else里的内容互换就行。

// 方式一:直接取反
P00 = !P00;  // 原来是0变1,是1变0

// 方式二:条件判断
if (P32 == 0) {
    P00 = 1;   // 按下灭
} else {
    P00 = 0;   // 松开亮
}

两种方式效果一样,但方式一更简洁。


4、按键消抖:

4.1 现象:按一下灯闪个不停

写到第三个任务"按一下切换状态"时,问题出现了。我的代码:

U8 state = 0;

void main() {
    while(1) {
        if (P32 == 0) {
            state = !state;  // 状态取反
            P00 = state;
        }
    }
}

结果按一下按钮,灯疯狂闪烁,用串口打印发现 state在0和1之间乱跳。这就是按键抖动

4.2 消抖方案:延时+二次确认

正确的消抖流程应该是:

  1. 检测到按键按下(低电平)
  2. 延时20ms(跳过抖动期)
  3. 再次检测,如果还是按下,才认为是有效按键
  4. 执行操作后,等待按键松开
void main() {
    // 初始化代码...
  
    while(1) {
        if (P32 == 0) {          // 第一次检测
            delay_ms(20);        // 消抖延时
            if (P32 == 0) {      // 第二次确认
                state = !state;
                P00 = state;
            
                while(P32 == 0); // 等待松开(这个最关键!)
            }
        }
    }
}

4.3 延时函数怎么来?

步骤

  1. 打开AICube-ISP → 工具 → 软件延时计算器
  2. 系统主频:24MHz(必须和工程一致)
  3. 延时时间:20毫秒
  4. 指令集:AR32(32位选这个,8位选AR8)
  5. 点击生成C代码

生成的函数长这样:

void delay_ms(unsigned int ms) {
    // 一堆汇编指令,反正很准
}

重要提醒:使用前必须在 main()开头加三行配置:

WTST = 0;    // 设置指令延时参数最小
EAXFR = 1;   // 扩展XFR访问使能
CKCON = 0;   // 提高XRAM访问速度

这三行在官方例程里都有,直接复制就行。


4、三个任务完整代码

任务1:按下亮,松开灭

#include "AI8051U.H"

void main() {
    // 初始化三件套
    WTST = 0;
    EAXFR = 1;
    CKCON = 0;
  
    P40 = 0;  // 打开LED开关
  
    while(1) {
        if (P32 == 0) {   // 按下
            P00 = 0;      // 亮
        } else {          // 松开
            P00 = 1;      // 灭
        }
    }
}

任务2:按下灭,松开亮

// 只改if-else内部
if (P32 == 0) {
    P00 = 1;  // 按下灭
} else {
    P00 = 0;  // 松开亮
}

任务3:按一下切换(带消抖)

#include "AI8051U.H"
#include "intrins.h"  // 包含nop

#define U8 unsigned char

U8 state = 0;

// 延时函数声明
void delay_ms(unsigned int ms);

void main() {
    // 初始化三件套
    WTST = 0;
    EAXFR = 1;
    CKCON = 0;
  
    P40 = 0;  // 打开LED开关
  
    while(1) {
        if (P32 == 0) {          // 检测按下
            delay_ms(20);        // 消抖
            if (P32 == 0) {      // 确认按下
                state = !state;  // 状态翻转
                P00 = state;     // 更新LED
          
                // 等待松开(防止连击)
                while(P32 == 0);
            }
        }
    }
}

// 生成的延时函数
void delay_ms(unsigned int ms) {
    // 自动生成的代码,别手打
}
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-12-16 10:33 , Processed in 0.133111 second(s), 86 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表