核心原理
要实现LED一秒亮灭一次,需要完成两个基本步骤:

(图片来源网络,侵删)
- 控制LED引脚:将连接LED的引脚设置为高电平(点亮)或低电平(熄灭)。
- 产生延时:在亮和灭之间插入一个大约1秒的延时,让LED的状态保持足够长的时间的时间。
核心C语言代码(伪代码/逻辑)
这是最核心的逻辑,不依赖于任何特定的硬件平台。
#include <stdio.h> // 如果是PC端模拟,可能需要这个
// 定义LED的状态
#define LED_ON 1
#define LED_OFF 0
// 假设我们有一个函数来控制LED
void control_led(int state) {
// 在实际硬件上,这里会操作寄存器来设置引脚电平
// GPIOA->ODR |= (1 << 5); // 点亮PA5引脚
// GPIOA->ODR &= ~(1 << 5); // 熄灭PA5引脚
printf("LED State: %s\n", state == LED_ON ? "ON" : "OFF");
}
// 假设我们有一个延时函数
void delay_1_second(void) {
// 在实际硬件上,这里是一个精确的延时函数,通常使用定时器
// 使用systick定时器或普通定时器
// PC端模拟可以用简单的循环或库函数
for(int i = 0; i < 100000000; i++); // 这是一个非常粗糙的延时,仅用于演示
}
int main() {
while(1) { // 无限循环
control_led(LED_ON); // 点亮LED
delay_1_second(); // 保持点亮1秒
control_led(LED_OFF); // 熄灭LED
delay_1_second(); // 保持熄灭1秒
}
return 0;
}
完整示例:基于STM32 HAL库(使用Keil或STM32CubeIDE)
这是一个非常常见的嵌入式平台示例,我们使用STM32的标准库HAL,它抽象了底层的寄存器操作,使代码更简洁。
硬件准备:
- 一块STM32开发板(如STM32F103C8T6 "Blue Pill")
- 一个LED(通常开发板上已自带,例如连接到PC13引脚)
- 杜邦线(如果需要外接LED)
代码实现:

(图片来源网络,侵删)
#include "main.h" // STM32生成的头文件
// 在 main.c 中实现
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
// 延时函数,使用systick定时器实现精确延时
// 在STM32 HAL中,通常使用HAL_Delay()函数,它基于SysTick
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
// 这个回调函数通常用于更复杂的定时器中断
// 对于简单的1秒延时,直接使用HAL_Delay()是最方便的
}
int main(void)
{
// HAL库初始化
HAL_Init();
// 配置系统时钟
SystemClock_Config();
// 初始化GPIO
MX_GPIO_Init();
while (1)
{
// 点亮LED
// 假设LED连接在PC13,低电平点亮
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // RESET = 0, 点亮
HAL_Delay(1000); // 延时1000毫秒 = 1秒
// 熄灭LED
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // SET = 1, 熄灭
HAL_Delay(1000); // 延时1秒
}
}
// GPIO初始化函数(由STM32CubeMX生成)
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 使能GPIOC时钟
__HAL_RCC_GPIOC_CLK_ENABLE();
// 配置PC13引脚
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
// 系统时钟配置函数(由STM32CubeMX生成)
void SystemClock_Config(void)
{
// ... (此函数通常由CubeMX生成,内容较长,一般无需手动修改)
}
代码解释:
HAL_Init(): 初始化HAL库。SystemClock_Config(): 配置系统时钟,这是所有外设运行的基础。MX_GPIO_Init(): 初始化GPIO(通用输入输出)端口,这里我们将PC13引脚配置为推挽输出模式。HAL_GPIO_WritePin(): 这是HAL库提供的函数,用于设置引脚的电平。GPIO_PIN_RESET(或GPIO_PIN_0) 表示低电平。GPIO_PIN_SET(或GPIO_PIN_1) 表示高电平。- 注意:很多开发板的LED是低电点亮的,所以用
RESET来点亮。
HAL_Delay(1000): 这是HAL库提供的毫秒级延时函数,参数单位是毫秒。1000就是1秒,这个函数是基于SysTick定时器实现的,非常精确。
完整示例:基于Arduino (AVR)
Arduino平台极大地简化了开发过程,其核心也是C/C++。
硬件准备:
- 一块Arduino开发板(如Arduino Uno)
- 一个LED(或使用板载L13 LED)
- 一个220Ω电阻(如果外接LED)
- 面包板和杜邦线
代码实现:
// 定义LED连接的引脚
const int ledPin = 13; // 大多数Arduino板载LED都连接在13号引脚
void setup() {
// 初始化LED引脚为输出模式
pinMode(ledPin, OUTPUT);
}
void loop() {
// 点亮LED
digitalWrite(ledPin, HIGH); // HIGH 表示高电平,点亮LED
delay(1000); // 延时1000毫秒 (1秒)
// 熄灭LED
digitalWrite(ledPin, LOW); // LOW 表示低电平,熄灭LED
delay(1000); // 延时1秒
}
代码解释:
const int ledPin = 13;: 定义一个常量,表示LED连接的数字引脚。setup():setup函数只在程序开始时运行一次,这里我们用pinMode(ledPin, OUTPUT)将ledPin设置为输出模式。loop():loop函数会无限循环执行,这是Arduino程序的主体。digitalWrite(ledPin, HIGH): 向ledPin写入高电平,点亮LED。delay(1000): Arduino内置的延时函数,参数单位是毫秒。digitalWrite(ledPin, LOW): 向ledPin写入低电平,熄灭LED。delay(1000): 再次延时1秒。
总结与对比
| 特性 | 原生C (STM32 HAL) | Arduino |
|---|---|---|
| 抽象层级 | 较低,需要理解外设和库函数 | 非常高,封装了所有底层细节 |
| 代码复杂度 | 相对复杂,需要初始化多个部分 | 极其简单,setup和loop结构清晰 |
| 适用场景 | 专业嵌入式开发,需要精确控制和优化 | 快速原型开发,教学,爱好项目 |
| 核心函数 | HAL_GPIO_WritePin(), HAL_Delay() |
digitalWrite(), delay() |
| 学习曲线 | 陡峭 | 平缓 |
对于初学者来说,从Arduino开始是理解这个概念最快、最简单的方式,当你需要更底层的控制和更高的性能时,再转向STM32等原生C开发。
