【30】单片机编程核心技巧:Switch驱动的定时中断跑马灯
七律 · 逐光
状态为魂控时光,定时中断显锋芒。
步骤变量定乾坤,八灯流转若飞霜。
电光石火随心转,程序逻辑自分明。
单片机中真王者,一招一式定乾坤。
摘要
本文以STC8H单片机为例,通过Switch语句结合定时中断实现8个LED的跑马灯效果,系统阐述其状态机设计原理、步骤变量管理及代码实现。Switch语句通过控制核心步骤变量(run_step
),将复杂逻辑分解为有序状态,结合定时中断实现精准的LED流动周期控制,展现了其作为“编程战斗机”的高效性与扩展性。
引言
Switch语句是单片机编程中的“战斗机”,通过步骤变量(如run_step
)可将复杂流程分解为多个可管理的状态。本文以8个LED的跑马灯为例,通过Switch语句驱动状态机,并结合定时中断实现精准的时间控制,为开发者提供可复用的编程范式。
1. Switch语句的核心地位
1.1 定时中断与Switch的协同作用
跑马灯需要精确控制LED的流动周期,Switch语句通过以下方式实现:
- 步骤变量控制:
run_step
的值决定当前点亮的LED编号(0~7)。 - 定时中断计数:通过定时器中断更新计数器
led_cnt
,实现精准时间控制。 - 状态迁移:每个
case
分支通过条件判断切换状态,形成循环流动效果。
1.2 步骤变量的定义规范
- 命名规则:统一后缀为
_step
(如run_step
),明确其作为程序控制核心的角色。 - 作用:通过修改
run_step
的值,可无缝切换LED的点亮位置,实现逻辑流转。
2. 状态机设计与Switch实现
2.1 状态机结构
跑马灯程序通过8个状态实现LED的逐个点亮:
- **状态07**:分别对应LED1LED8的点亮。
- 状态迁移逻辑:
- 每个状态通过计数器
led_cnt
控制LED的亮灯时长(如LED_ON_TIME
)。 - 达到阈值后,关闭当前LED,开启下一LED,并更新
run_step
。
- 每个状态通过计数器
2.2 代码实现
#include <stc8.h>
// 定义LED引脚(P1.0~P1.7)
#define LED_PORT P1
#define LED_PINS 8 // LED数量
// 定义LED亮灯时间(单位:中断次数)
#define LED_ON_TIME 1000 // 每个LED亮灯1秒(假设中断周期为1ms)
// 步骤变量(核心控制变量)
unsigned char run_step = 0;
unsigned long led_cnt = 0;
// 定时器1中断服务函数
void timer1_isr() interrupt 3 {
TH1 = 0xFC; // 重装定时器初值(1ms中断周期)
TL1 = 0x00;
led_cnt++; // 计数器递增
}
void main() {
// 初始化IO口(P1.0~P1.7为推挽输出)
P1M0 = 0xFF; // 设置P1所有引脚为推挽模式
P1M1 = 0x00;
// 定时器1配置(1ms中断周期)
TMOD |= 0x01; // 设置定时器1为模式1(16位)
TH1 = 0xFC; // 初值计算:系统时钟11.0592MHz,定时1ms
TL1 = 0x00;
ET1 = 1; // 使能定时器1中断
EA = 1; // 全局中断使能
TR1 = 1; // 启动定时器
// 初始状态:所有LED灭
LED_PORT = 0x00;
while(1) {
// Switch语句驱动状态机(核心代码)
switch(run_step) {
case 0: // LED1亮
if(led_cnt > LED_ON_TIME) {
led_cnt = 0;
LED_PORT = 0x01; // 只点亮LED1(P1.0)
run_step = 1; // 进入下一状态
}
break;
case 1: // LED2亮
if(led_cnt > LED_ON_TIME) {
led_cnt = 0;
LED_PORT = 0x02; // 只点亮LED2(P1.1)
run_step = 2;
}
break;
case 2: // LED3亮
if(led_cnt > LED_ON_TIME) {
led_cnt = 0;
LED_PORT = 0x04; // 只点亮LED3(P1.2)
run_step = 3;
}
break;
case 3: // LED4亮
if(led_cnt > LED_ON_TIME) {
led_cnt = 0;
LED_PORT = 0x08; // 只点亮LED4(P1.3)
run_step = 4;
}
break;
case 4: // LED5亮
if(led_cnt > LED_ON_TIME) {
led_cnt = 0;
LED_PORT = 0x10; // 只点亮LED5(P1.4)
run_step = 5;
}
break;
case 5: // LED6亮
if(led_cnt > LED_ON_TIME) {
led_cnt = 0;
LED_PORT = 0x20; // 只点亮LED6(P1.5)
run_step = 6;
}
break;
case 6: // LED7亮
if(led_cnt > LED_ON_TIME) {
led_cnt = 0;
LED_PORT = 0x40; // 只点亮LED7(P1.6)
run_step = 7;
}
break;
case 7: // LED8亮
if(led_cnt > LED_ON_TIME) {
led_cnt = 0;
LED_PORT = 0x80; // 只点亮LED8(P1.7)
run_step = 0; // 重置状态,循环开始
}
break;
}
}
}
2.3 关键代码解析
- 步骤变量控制:
run_step
的值决定当前点亮的LED编号,如case 0
对应LED1。 - 定时中断计数:通过定时器1中断每1ms触发一次,更新
led_cnt
。 - 状态迁移逻辑:每个
case
分支通过条件判断切换状态,形成循环流动。
3. 实验验证
3.1 硬件连接
- LED配置:
- 8个LED的阳极分别通过
510Ω
电阻连接至 P1.0~P1.7 引脚。 - 所有LED阴极接地。
- 8个LED的阳极分别通过
3.2 预期结果
- LED依次从 P1.0 到 P1.7 逐个点亮,形成流动效果。
- 每个LED亮灯时长为
LED_ON_TIME=1000
(假设中断周期为1ms
,即1秒)。
4. 扩展应用
Switch语句的“战斗机”特性可扩展至复杂场景:
- 多LED控制:通过增加
case
分支实现更多LED的流动效果。 - 动态模式切换:通过修改步骤变量
run_step
实现正反向流动、加速/减速等模式。 - 组合控制:结合传感器输入(如按键)动态改变流动方向或速度。
5. 结论
Switch语句通过控制核心步骤变量(run_step
),将复杂逻辑分解为有序状态,结合定时中断实现精准时间控制,是单片机程序的灵魂与支点。本文通过8个LED的跑马灯案例,验证了其高效性与可扩展性,开发者可基于此范式快速构建多状态控制程序,实现“以Switch为支点,撬动程序设计”的目标。
附录:STC8H定时器配置说明
-
定时器1配置:
-
TMOD |= 0x01
:设置定时器1为模式1(16位定时)。 -
TH1 = 0xFC; TL1 = 0x00
:初值计算公式:
初值 = 65536 − 系统时钟 定时周期 × 12 \text{初值} = 65536 - \frac{\text{系统时钟}}{\text{定时周期} \times 12} 初值=65536−定时周期×12系统时钟( 此 处 系 统 时 钟 为 11.0592 M H z , 定 时 1 m s ) 。 (此处系统时钟为11.0592MHz,定时1ms)。 (此处系统时钟为11.0592MHz,定时1ms)。
-
-
中断使能:
ET1 = 1
:使能定时器1中断。EA = 1
:全局中断使能。