找回密码
 立即注册
查看: 583|回复: 24

STC32G系列,备战2025全国大学生智能车竞赛学习贴

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2026-01-20 17:19:10
已绑定手机

3

主题

32

回帖

91

积分

注册会员

积分
91
发表于 2026-1-20 17:19:10 | 显示全部楼层 |阅读模式
本贴作为2025年,备战智能车竞赛的STC32G系列实验箱与相关例程的记录贴
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2026-01-20 17:19:10
已绑定手机

3

主题

32

回帖

91

积分

注册会员

积分
91
发表于 2026-1-20 17:22:44 | 显示全部楼层

STC32G第一课笔记 —— 单片机是啥?咋入门?

春哥(令狐大侠)视频


一、单片机

  • 里面塞了 CPU、内存、输入输出口,能写程序控制
  • 长得各式各样:有40脚的、20脚的、最少还有8脚的(STC真有5-6脚的!)
  • 功能:读电压、输出信号、计时、算数、通信……反正能干很多有规律的控制类事情

二、为啥用 STC32G

  • 32位的!性能强很多,引脚也多
  • 价格差不多,但功能强不少,性价比高
  • 资料全,官网(stcai.com)能下手册、工具、案例,还能打电话问技术支持
  • 实验箱挺好用,上面有按键、数码管、各种模块,后面课程都基于这个讲(用核心板也行,就是接线麻烦点)
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2026-01-20 17:19:10
已绑定手机

3

主题

32

回帖

91

积分

注册会员

积分
91
发表于 2026-1-20 17:28:35 | 显示全部楼层

1. STC-ISP软件下载与安装

  • 功能:下载STC全系列单片机程序,集成虚拟显示、范例程序、定时器生成、USB驱动安装等。
  • 下载方式:通过官方链接下载最新版本,支持高版本向下兼容。
  • 安装:解压后双击即可使用,无需安装。

2. STC32G手册下载

  • 手册功能:详细概述所有功能模块。
  • 下载方式:
    • 在STC-ISP软件内直接下载(资料下载 → 用户手册)
    • 在官网“芯片手册”栏目中下载STC32G系列手册
  • 手册大小:约1000多页,建议配合PDF阅读器使用。

3. PDF阅读器推荐与使用

  • 推荐阅读器:福昕阅读器(Foxit Reader)或WPS
  • 主要使用功能:
    • 目录索引快速跳转
    • 书签功能按模块查找(如IO口、定时器等)
    • Ctrl + F 快速搜索关键词
    • 支持缩放、分屏查看

4. C251开发环境搭建

  • 安装步骤:
    1. 下载C251安装包(官网或手册内提供链接)
    2. 双击安装,按默认路径安装(建议安装在Keil目录下以便兼容)
    3. 安装完成后,在Keil中添加C251头文件路径(点击“添加头文件”按钮)
    4. 验证安装:打开工程编译无报错

5. 程序包下载

  • 内容:包含丰富的范例程序(如跑马灯、数码管显示等)
  • 下载方式:
    • STC-ISP软件内下载:资料下载 → 软件库函数及范例程序 → STC32G实验箱程序
    • 官网下载:应用方案 → STC32G实验箱 → 代码下载

6. 程序编译与下载

编译步骤:

  1. 打开范例工程(如跑马灯工程)
  2. 点击编译按钮,确认“0错误,0警告”
  3. 若提示“未检测到芯片”,需在Keil中正确添加C251头文件路径

下载步骤(USB下载模式):

  1. 连接开发板与电脑(USB线)
  2. 进入下载模式:
    • 按住P3.2按键(INT0)
    • 按下电源按键(ON/OFF)并松开
    • 松开P3.2按键
  3. 在STC-ISP中选择对应芯片型号(如STC32G12K128)
  4. 选择编译好的.hex文件
  5. 设置时钟频率(需与程序内设置一致,如24MHz)
  6. 点击“下载”按钮,等待完成
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2026-01-20 17:19:10
已绑定手机

3

主题

32

回帖

91

积分

注册会员

积分
91
发表于 2026-1-20 17:31:31 | 显示全部楼层

《STC32G单片机开发教程》第四集课程笔记:建立工程与点亮第一颗LED(上)

一、目标

  • 掌握LED点亮的基本原理(高低电平与IO口控制)
  • 学会在Keil中新建STC32G工程
  • 编写代码点亮实验箱上的第一颗LED
  • 了解并配置自动下载功能

二、LED点亮原理与硬件分析

1. LED点亮基本条件

  • LED(发光二极管)需要正向电压差才能发光
  • 实验中:正极接5V(高电平),负极接0V(低电平)时LED点亮
  • 在单片机中,用“高低电平”代替具体电压值
    • 高电平 = 接近VCC电压(如5V)
    • 低电平 = 接近GND电压(0V)
    • 常用表示:1 = 高电平,0 = 低电平

2. 单片机IO口(GPIO)

  • GPIO = General Purpose Input/Output(通用输入输出端口)
  • 每个引脚可以配置为:
    • 输入:读取外部电平(高/低)
    • 输出:向外输出电平(高/低)
  • 引脚命名Px.y(如P4.0、P6.1)
    • Px:端口组(如P0、P4、P6)
    • y:组内引脚编号(0~7,每组最多8个引脚)
  • 操作方式
    • 单独操作:控制单个引脚(如P4.0)
    • 批量操作:控制整个端口组(如P4全部8个引脚)

3. 实验箱LED电路分析

  • 开发板上8个LED通过三极管驱动
  • 点亮条件(以LED4为例)
    1. P4.0输出低电平 → 三极管导通
    2. P6.4输出低电平 → LED形成压差,点亮
  • 原理图要点
    • LED正极通过电阻接到VCC(5V)
    • LED负极接到单片机引脚(P6.4)
    • 三极管基极接到P4.0,控制整个LED组的供电

三、新建Keil工程步骤

1. 创建工程目录

  • 在桌面新建文件夹(如 Demo
  • 用于存放工程文件,便于管理

2. 在Keil中新建工程

  1. 打开Keil软件 → ProjectNew μVision Project
  2. 选择刚才创建的 Demo文件夹
  3. 输入工程名(如 demo)→ 保存
  4. 选择芯片型号
    • 厂商:STC MCU Database
    • 型号:STC32G12K128(根据实际芯片选择)
  5. 点击 OK,跳过提示的运行时环境添加

3. 添加源文件

  1. 点击工具栏 New(或 FileNew)创建新文件
  2. 输入代码后,点击 FileSave
    • 文件名:demo.c(必须是 .c扩展名)
    • 保存到工程文件夹内
  3. 将文件添加到工程
    • Project窗口右键 Source Group 1
    • 选择 Add Existing Files to Group...
    • 双击刚才保存的 demo.c文件

4. 工程配置(生成HEX文件)

  1. 点击 Options for Target(魔术棒图标)
  2. Output选项卡中:
    • 勾选 Create HEX File
    • 可勾选 Debug Information(便于调试)
  3. 点击 OK保存

四、编写点亮LED的代码

1. 代码结构解析

// 1. 寄存器地址定义(sfr)
sfr P4 = 0xC0;      // P4端口地址
sfr P4M0 = 0xB4;    // P4模式寄存器0
sfr P4M1 = 0xB3;    // P4模式寄存器1
sfr P6 = 0xE8;      // P6端口地址
sfr P6M0 = 0xCC;    // P6模式寄存器0
sfr P6M1 = 0xCB;    // P6模式寄存器1

// 2. 引脚位定义(sbit)
sbit P40 = P4^0;    // 三极管控制引脚(P4.0)
sbit P64 = P6^4;    // LED控制引脚(P6.4)

// 3. 主函数
void main()
{
    // 配置P4、P6为准双向口(既能输入也能输出)
    P4M0 = 0x00;
    P4M1 = 0x00;
    P6M0 = 0x00;
    P6M1 = 0x00;
  
    // 控制引脚输出低电平
    P40 = 0;  // 三极管导通
    P64 = 0;  // LED点亮
  
    // 程序主循环(防止程序跑飞)
    while(1);
}

2. 关键概念说明

  • sfr:特殊功能寄存器定义
    • 将芯片内部的寄存器地址(如 0xC0)命名为易记的名称(如 P4
    • 方便后续通过名称操作寄存器,避免记忆复杂地址
  • sbit:位定义
    • 将端口的某个引脚单独命名(如 P4^0命名为 P40
    • 方便单独控制某个引脚
  • 准双向口配置
    • PxM0PxM1寄存器控制IO口模式
    • 同时设为 0x00时,配置为准双向口
    • 准双向口特性:可输入、可输出,驱动能力适中

3. 编译与下载

  1. 编译:点击 Build按钮(或按 F7
    • 显示 0 Error(s), 0 Warning(s)表示编译成功
    • Objects文件夹下生成 demo.hex文件
  2. 下载到单片机
    • 打开STC-ISP软件
    • 选择对应芯片型号
    • 载入 demo.hex文件
    • 进入下载模式(按P3.2 → 按电源键 → 松开电源键 → 松开P3.2)
    • 点击 下载/编程

五、调试技巧与注意事项

1. 代码编写规范

  • 缩进:使用Tab键(建议设置缩进4格)
  • 注释
    • 单行注释:// 注释内容
    • 多行注释:/* 注释内容 */
  • 空行分隔:不同功能模块间用空行分隔,提高可读性
  • 英文符号:代码中的所有符号(分号、括号等)必须为英文符号

2. Keil使用技巧

  • 中文支持:在 EditConfigurationEncoding中选择 GB2312
  • 快速搜索Ctrl + F在当前文件中搜索
  • 工程内搜索:在搜索框选择 In Files可搜索整个工程

3. 常见问题排查

问题现象 可能原因 解决方法
编译错误(红色波浪线) 关键词拼写错误、符号非英文 检查拼写,切换输入法
下载后LED不亮 引脚配置错误、寄存器地址写错 对照手册检查地址,用万用表测电平
无法进入下载模式 按键顺序错误、USB线接触不良 严格按照P3.2→电源键顺序操作
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2026-01-20 17:19:10
已绑定手机

3

主题

32

回帖

91

积分

注册会员

积分
91
发表于 2026-1-20 17:40:59 | 显示全部楼层

STC32G单片机开发课程笔记(第四集)

上节课成功点亮 LED,但每次重新下载程序时,需手动按下开发板上的按钮进入 HID 下载模式。频繁操作不便,影响调试效率。


自动下载(不断电下载)

1. 原理

  • 利用 STC32G 的 “用户程序复位到系统区” 功能。
  • 通过向特殊功能寄存器写入 0x60,触发软件复位,使单片机自动进入 USB 下载模式。

2. 步骤概览

  • 在 STC-ISP 软件中勾选相应选项。
  • 在工程中添加 STC 官方提供的库文件(HID / CDC)。
  • 在代码中调用初始化函数,并设置好 USB 时钟与中断。

四、实现

1. STC-ISP 软件设置

  • 选择单片机型号:STC32G12K128。
  • 勾选 “收到用户命令后复位到监控程序区”
  • 下载模式选择 “USB-HID”
  • 用户命令保持默认(@STCISP#)。

2. 工程代码修改

  • 将官方库文件(如 hid32g.lib)复制到工程目录并添加到项目中。
  • main.c 中添加头文件引用:
    #include "stc.h"
    #include "usb.h"
    
  • main 函数开头调用初始化函数:
    sys_init();   // 系统初始化(含USB时钟设置)
    usb_init();   // USB初始化
    EA = 1;       // 开启总中断
    

3. 关键点说明

  • sys_init() 函数需正确定义(可从官方例程复制),用于设置 IO 口模式和 USB 时钟源。
  • 若函数定义在 main 之后,需在文件开头添加函数声明。

五、CDC 模式实现(虚拟串口模式)

  • 使用 cdc32g.lib 库文件,其他步骤与 HID 模式类似。
  • 成功后会生成一个虚拟串口(如 STC-USB CDC COM5),可通过该串口实现自动下载。
  • 注意:CDC 模式需额外设置 USB 时钟相关寄存器,具体参考官方例程。

  1. 编译错误处理
  • 错误提示“未定义的函数”:检查函数名大小写及是否正确定义。
  • 错误提示“未找到头文件”:检查头文件路径是否添加正确。
  1. 下载失败处理

    • 首次使用自动下载功能时,仍需手动进入下载模式一次。
    • 确认 STC-ISP 中 “收到用户命令后复位” 选项已勾选。
  2. 代码优化

    • 删除重复的 IO 口初始化代码(如 P0M0=0x00; P0M1=0x00;),因其已在 sys_init() 中统一设置。
    • 使用 sbit 定义引脚可提高代码可读性(如 sbit LED = P4^0;)。

七、

一个具备自动下载功能的最小工程应包含:

  • 必要的头文件(stc.husb.h)。
  • sys_init()usb_init() 初始化调用。
  • 总中断开启(EA=1)。
  • 用户功能代码(如 LED 控制)。

八、

  1. IO 口控制

    • 使用 PxM0PxM1 寄存器设置引脚模式(如准双向、推挽输出等)。
    • 直接操作 Px 寄存器可同时控制8个引脚。
  2. sbit 用法

    • 用于定义单个引脚,如 sbit LED = P4^0;
    • 后续可通过 LED=0/1 控制该引脚电平。
  3. include 头文件

    • 使用 #include "xxx.h" 引入自定义头文件(双引号表示优先从当前目录查找)。
  4. 中断控制

    • EA 为总中断开关,置1后 CPU 才能响应中断。
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2026-01-20 17:19:10
已绑定手机

3

主题

32

回帖

91

积分

注册会员

积分
91
发表于 2026-1-20 17:43:48 | 显示全部楼层

C语言printf函数、ASCII码与进制转换


printf

1. 功能说明

  • printf 是C语言标准输出函数,在单片机中可通过USB-CDC虚拟串口输出数据到电脑端,方便调试。
  • 可用于打印字符串、变量值、传感器数据等。

2. 实现步骤

  • main 函数中添加USB通信检测与数据处理代码:
    if(DeviceState != DEVSTATE_CONFIGURED) continue;
    if(bUsbOutReady)
    {
        // 接收到数据后执行
        printf("Hello World\r\n");
        USB_SendData(UsbOutBuffer, OutNumber);
    }
    
  • 编译下载后,通过串口工具发送任意数据(如“1”),即可在接收区看到输出。

3. 输出模式说明

  • HEX模式:显示ASCII码的十六进制值(如 48 65 6C 6C 6F)。
  • 文本模式:直接显示可读字符串(如 Hello World)。

常用格式符

格式符 说明 示例
%d 有符号十进制整数 printf("%d", 100);
%u 无符号十进制整数 printf("%u", 200);
%f 单精度浮点数 printf("%f", 3.14);
%c 单个字符 printf("%c", 'A');
%s 字符串 printf("%s", "Hello");

2. 格式化控制

  • %.2f:保留两位小数(如 11.20)。
  • %3.3f:整数部分占3位,小数部分占3位(如 011.200)。
  • \r\n:Windows系统下的换行符(回车+换行)。

3. 示例:打印温湿度

printf("当前温度:%.2f℃\r\n", 11.2);
printf("当前湿度:%.2f%%\r\n", 55.2);
  • 输出效果:
    当前温度:11.20℃
    当前湿度:55.20%

ASCII码与字符输出

1. ASCII码表

  • 每个字符对应一个十进制值(0~127),如 ‘0’ 对应 48‘A’ 对应 65
  • 十六进制 0x35 对应十进制 53,即字符 ‘5’

2. 字符输出示例

printf("%c", 53);  // 输出字符 '5'
  • 在HEX模式下显示 35,文本模式下显示 5

3. 汉字与多字节字符

  • 汉字通常由两个字节表示(GBK编码),在串口调试中需注意编码格式。

1. 进制表示方法

进制 前缀/示例 说明
十进制 128 逢十进一
十六进制 0x8080H 逢十六进一,09、AF
二进制 0b10000000 逢二进一,仅0和1

2. 进制转换方法

  • 二进制 → 十进制:按权展开求和。
    0b11111111 = 1×2⁷ + 1×2⁶ + ... + 1×2⁰ = 255
    
  • 十进制 → 十六进制:除16取余,逆序排列。
    251 ÷ 16 = 15 余 11 → 0xFB
    
  • 二进制 ↔ 十六进制:4位二进制对应1位十六进制。
    0b1111 1011 → 0xFB
    

3. Windows计算器辅助转换

  • 打开“程序员模式”,支持二进制、十进制、十六进制实时互转。
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2026-01-20 17:19:10
已绑定手机

3

主题

32

回帖

91

积分

注册会员

积分
91
发表于 2026-1-20 17:47:16 | 显示全部楼层

第六集:LED闪烁与花式点灯(上)


1. LED闪烁概念

  • 闪烁:LED一亮一灭的周期性变化
  • 应用场景:闹钟指示灯、汽车示廓灯/危险报警灯
  • 时间单位换算
    • 1秒 = 1000毫秒(ms)
    • 0.5秒 = 500ms

2. 延时函数(delay)的实现

  • 函数名delay_ms
  • 参数:毫秒数(u16 ms
  • 实现原理:通过嵌套循环消耗CPU时间实现“空等”
  • 代码示例
    void delay_ms(u16 ms) {
        do {
            u16 i = MAIN_FOSC / 6000;  // 根据主频计算延时基数
            while (--i);
        } while (--ms);
    }
    

3. 宏定义与类型定义

  • 宏定义(方便修改与阅读):
    #define MAIN_FOSC 24000000UL
    
  • 类型定义(增强可读性):
    typedef unsigned int u16;
    

4. 循环语句对比

循环类型 执行顺序 特点
while(条件) 先判断条件,再执行 条件不满足时可能一次都不执行
do…while(条件) 先执行一次,再判断条件 至少执行一次

5. 自增与自减运算

  • i++:先使用 i的值,再自增
  • ++i:先自增,再使用 i的值
  • i-- / --i 同理

代码实现

LED闪烁核心代码

#include "stc32g.h"
#define MAIN_FOSC 24000000UL

void delay_ms(u16 ms) {
    do {
        u16 i = MAIN_FOSC / 6000;
        while (--i);
    } while (--ms);
}

void main() {
    while (1) {
        P60 = 0;        // 点亮LED
        delay_ms(500);  // 亮500ms
        P60 = 1;        // 熄灭LED
        delay_ms(500);  // 灭500ms
    }
}

多灯闪烁示例

P60 = 0;
P67 = 0;
delay_ms(500);
P60 = 1;
P67 = 1;
delay_ms(500);
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2026-01-20 17:19:10
已绑定手机

3

主题

32

回帖

91

积分

注册会员

积分
91
发表于 2026-1-20 17:49:55 | 显示全部楼层

第六集(下):函数与模块化编程


一、宏定义

  • 作用:用一个名称替代一串数值或代码,便于修改和阅读
  • 语法#define 名称 替换内容
  • 示例
    #define MAIN_FOSC 24000000UL  // 定义主时钟频率
    
  • 注意事项
    • 名称不能是中文,可以是英文、数字、下划线
    • 末尾不加分号
    • 推荐使用大写字母+下划线命名(如 MAIN_FOSC

二、函数的使用

1. 函数使用的三个步骤

步骤 说明 示例
定义 编写函数的具体功能 int Add(int parm1, int parm2) { return parm1 + parm2; }
声明 在调用前声明函数原型(可省略,但推荐) int Add(int parm1, int parm2);
调用 在需要的地方调用函数 result = Add(1, 2);

2. 函数定义详解

返回值类型 函数名(入口参数类型 参数名, ...) {
    // 函数体
    return 返回值;
}
  • 返回值类型:可以是 void(无返回值)、intu16
  • 函数名:避开C语言关键词,不要与其他函数重名
  • 入口参数:可多个,用逗号分隔,需指明类型

3.加法函数

// 函数定义(通常在文件后面或独立文件中)
int Add(int parm1, int parm2) {
    return parm1 + parm2;
}

// 函数声明(通常在文件开头或头文件中)
int Add(int parm1, int parm2);

// 函数调用(在main或其他函数中)
int result = Add(1, 2);

三、模块化编程

① 新建 .c.h 文件

  • 通常一个功能模块对应一对文件
  • 示例:math.cmath.h
  • 命名建议:英文、有含义、避开关键词

② 编写头文件(.h

#ifndef __MATH_H__
#define __MATH_H__

// 函数声明
int Add(int parm1, int parm2);
int Sub(int parm1, int parm2);
int Mul(int parm1, int parm2);

#endif

③ 编写源文件(.c

#include "math.h"

int Add(int parm1, int parm2) {
    return parm1 + parm2;
}

int Sub(int parm1, int parm2) {
    return parm1 - parm2;
}

int Mul(int parm1, int parm2) {
    return parm1 * parm2;
}

④ 在工程中添加模块

  1. 添加引用路径

    • 在Keil中:C251Include Paths
    • 添加模块所在文件夹路径
  2. 添加源文件到工程

    • 双击工程文件列表空白处
    • 选择对应的 .c 文件
  3. 在主文件中包含头文件

    #include "math.h"
    

四、四则运算模块

math.h

#ifndef __MATH_H__
#define __MATH_H__

// 加法
int Add(int parm1, int parm2);

// 减法
int Sub(int parm1, int parm2);

// 乘法
int Mul(int parm1, int parm2);

#endif

math.c

#include "math.h"

int Add(int parm1, int parm2) {
    return parm1 + parm2;
}

int Sub(int parm1, int parm2) {
    return parm1 - parm2;
}

int Mul(int parm1, int parm2) {
    return parm1 * parm2;
}

main.c

#include "STC32G.H"
#include "math.h"
#include "stdio.h"

void main() {
    // 调用模块中的函数
    int result1 = Add(1, 2);
    int result2 = Sub(5, 2);
    int result3 = Mul(5, 3);
  
    // 通过串口输出结果
    printf("Add(1, 2) = %d\n", result1);
    printf("Sub(5, 2) = %d\n", result2);
    printf("Mul(5, 3) = %d\n", result3);
  
    while(1);
}
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2026-01-20 17:19:10
已绑定手机

3

主题

32

回帖

91

积分

注册会员

积分
91
发表于 2026-1-20 17:53:14 | 显示全部楼层

STC32G单片机教程笔记 · 第七集(上):按键点灯


SOS作业

1. 实现效果

  • 三短:快速闪烁3次(200ms亮/200ms灭)
  • 三长:慢速闪烁3次(500ms亮/500ms灭)
  • 三短:快速闪烁3次(200ms亮/200ms灭)
  • 循环:间隔后重复

2. 代码结构

  • 模块化编程:将SOS功能封装在独立文件中
  • 延时函数复用:使用之前编写的 delay_ms函数
  • 头文件保护:防止重复包含

3. 代码

// sos.c 中实现SOS功能
void SOS_LED(void) {
    // 三短
    for(int i=0; i<3; i++) {
        P60 = 0;  // 点亮
        delay_ms(200);
        P60 = 1;  // 熄灭
        delay_ms(200);
    }
  
    // 三长
    for(int i=0; i<3; i++) {
        P60 = 0;
        delay_ms(500);
        P60 = 1;
        delay_ms(500);
    }
  
    // 三短(重复)
    for(int i=0; i<3; i++) {
        P60 = 0;
        delay_ms(200);
        P60 = 1;
        delay_ms(200);
    }
}

按键

1. 按键分类

类型 特点 应用场景
常开按键 常态断开,按下导通 大多数开关按钮
常闭按键 常态导通,按下断开 安全开关、急停按钮
自锁按键 按下保持状态,再按恢复 电源开关
轻触按键 按下导通,松开断开 电子设备控制

2. 按键物理结构

引脚1 ---- 开关 ---- 引脚2
      ↑
   按钮按下时导通

3. 按键电路原理(以实验箱为例)

VCC → 上拉电阻 → 单片机IO口
               ↓
             按键 → GND
  • 未按下:IO口通过上拉电阻接到VCC,检测为高电平
  • 按下:IO口通过按键接地,检测为低电平

4. 开发板按键对应

  • SW17 → P3.2
  • SW18 → P3.3

按键消抖

1. 抖动现象

  • 原因:机械开关接触时物理震动
  • 时间:5-10ms
  • 表现:按下/松开瞬间电压不稳定

2. 消抖方法

  • 硬件消抖:RC电路滤波
  • 软件消抖:延时检测(常用)

3. 软件消抖实现

if(按键 == 0) {          // 初次检测到按下
    delay_ms(10);         // 延时10ms
    if(按键 == 0) {      // 再次确认按下
        // 执行按键功能
    }
}

按键检测与点灯实现

1. 宏定义按键引脚

#define K1 P32  // 按键1,对应P3.2
#define K2 P33  // 按键2,对应P3.3

2. 基础按键检测

// 检测按键是否按下(带消抖)
if(K1 == 0) {           // 第一次检测
    delay_ms(10);       // 消抖延时
    if(K1 == 0) {       // 确认按下
        printf("P32已按下\n");
    }
}

3. 三种按键控制模式

模式1:按下亮,松开灭

if(K1 == 0) {
    delay_ms(10);
    if(K1 == 0) {
        P60 = 0;  // 点亮LED
        printf("P32已按下\n");
    }
} else {
    P60 = 1;  // 松开熄灭
}

模式2:按下灭,松开亮

if(K1 == 0) {
    delay_ms(10);
    if(K1 == 0) {
        P60 = 1;  // 按下熄灭
        printf("P32已按下\n");
    }
} else {
    P60 = 0;  // 松开点亮
}

模式3:按键取反(按一次改变状态)

if(K2 == 0) {
    delay_ms(10);
    if(K2 == 0) {
        P61 = !P61;  // 状态取反
        printf("P33已按下,LED取反\n");
  
        // 等待按键松开
        while(K2 == 0);  // 死循环等待
    }
}
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2026-01-20 17:19:10
已绑定手机

3

主题

32

回帖

91

积分

注册会员

积分
91
发表于 2026-1-20 17:56:01 | 显示全部楼层

第七集:按键控制与流水灯实现

1. 按键控制LED左移

if (K1 == 0) {               // 检测按键按下
    delay_ms(10);            // 消抖
    if (K1 == 0) {
        led_data = (led_data << 1) | 1;  // 左移并补1
        if (led_data == 0xFF) {          // 如果全亮
            led_data = 0xFE;             // 重置
        }
        P6 = led_data;                   // 输出到LED
    }
}

2. 使用数组实现流水灯

u8 led_table[8] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};
u8 index = 0;

while(1) {
    P6 = led_table[index];
    delay_ms(500);
    index++;
    if (index >= 8) index = 0;
}

数组使用注意事项

  • 数组索引从 0 开始,长度为 n 的数组,索引范围为 0 ~ n-1
  • 可通过修改数组元素值改变LED亮灯顺序
  • 数组可灵活实现多种亮灯模式(如间隔亮、分组亮等)

// 定义LED状态表(从右至左逐亮)
u8 led_pattern[8] = {
    0xFE, // 11111110
    0xFD, // 11111101
    0xFB, // 11111011
    0xF7, // 11110111
    0xEF, // 11101111
    0xDF, // 11011111
    0xBF, // 10111111
    0x7F  // 01111111
};
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-2-12 18:02 , Processed in 0.115741 second(s), 87 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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