好的!下面我基于 STC8H8K64U 的数据手册和官方实验指导书,为你写一个完整的流水灯演示程序。
📌 硬件说明
根据 STC8H8K64U 实验箱/开天斧的典型原理图:
- LED 指示灯接在 P6 口(P6.0~P6.7),低电平点亮
- P4.0 控制 PNP 三极管作为 LED 总电源开关,P4.0 输出 0 时总电源导通
- 如果使用自己的最小系统板,请根据实际硬件调整端口
📝 完整代码(使用定时器中断实现流水灯)
/****************************************************************
* 文件名: main.c
* 功能 : STC8H8K64U 流水灯演示程序
* 使用定时器0 1ms中断,每500ms切换一次流水灯
* 8个LED接P6口(低电平点亮),P4.0为总电源控制(低电平导通)
* 晶振 : 使用内部IRC,建议设置为 11.0592MHz 或 24MHz
****************************************************************/
#include "stc8h.h" // STC8H头文件
#define LED_PORT P6 // LED接P6口
#define LED_PIN_ALL 0xFF // 8位全亮/全灭值
// 流水灯方向定义
#define LEFT_TO_RIGHT 0
#define RIGHT_TO_LEFT 1
// 全局变量
bit dir = LEFT_TO_RIGHT; // 流水灯方向
u8 led_index = 0; // 当前点亮的LED索引(0~7)
u16 timer_count = 0; // 定时器计数
/******************** 毫秒级延时函数(查询方式) *******************/
void delay_ms(u16 ms)
{
u16 i;
for(i = 0; i < ms; i++)
{
// 12MHz下约延时1ms (根据实际主频可微调)
u16 j = 12000 / 12;
while(j--);
}
}
/******************** I/O口初始化 *******************/
void GPIO_init(void)
{
// P6口设置为推挽输出模式(P6M1=0, P6M0=0xFF)
P6M1 = 0x00;
P6M0 = 0xFF;
// P4.0设置为推挽输出
P4M1 = 0x00;
P4M0 = 0x01;
// 初始状态:关闭总电源(P4.0=1),LED全部熄灭(P6=0xFF)
P4 |= 0x01; // P4.0 = 1,关断LED总电源
P6 = 0xFF; // 所有LED熄灭(低电平点亮)
}
/******************** 定时器0初始化 *******************/
// 使用定时器0,模式0(16位自动重装载)
// 时钟频率 = 主频 / 12
// 定时1ms示例:以12MHz主频为例
void Timer0_init(void)
{
// 注意:如果使用24MHz,需要相应调整重装值
// 此处以 12MHz 主频为例:定时1ms
// 计数脉冲 = 12MHz / 12 = 1MHz,计1000次 = 1ms
// 重装值 = 65536 - 1000 = 64536 = 0xFC18
AUXR |= 0x80; // 定时器0时钟1T模式(如果要用1T)
// 此处使用12T模式,更通用
AUXR &= ~0x80; // 定时器0时钟12T模式
TMOD &= 0xF0; // 清除定时器0模式位
TMOD |= 0x00; // 模式0(16位自动重装载)
// 以12MHz主频为例,12T模式,1ms定时
// 实际请根据你的主频用ISP软件中的"定时器计算器"工具自动生成
TL0 = 0x18; // 低字节
TH0 = 0xFC; // 高字节 (65536-1000=64536=0xFC18)
ET0 = 1; // 使能定时器0中断
TR0 = 1; // 启动定时器0
}
/******************** 主函数 *******************/
void main(void)
{
P_SW2 |= 0x80; // 使能访问XFR扩展寄存器(很多新功能需要此设置)
GPIO_init(); // 初始化I/O口
Timer0_init(); // 初始化定时器0
EA = 1; // 开启总中断
// 开启LED总电源
P4 &= ~0x01; // P4.0 = 0,导通PNP三极管
// 主循环:流水灯由定时器中断驱动,主循环可执行其他任务
while(1)
{
// 此处可以放其他任务代码,流水灯由中断自动运行
// 例如:检测按键、串口通信等
}
}
/******************** 定时器0中断服务函数 *******************/
void Timer0_ISR(void) interrupt 1
{
// 每1ms进入一次中断
timer_count++;
// 每500ms切换一次流水灯位置
if(timer_count >= 500)
{
timer_count = 0;
// 根据方向更新索引
if(dir == LEFT_TO_RIGHT)
{
led_index++;
if(led_index >= 8)
{
led_index = 0;
}
}
else // RIGHT_TO_LEFT
{
if(led_index == 0)
{
led_index = 7;
}
else
{
led_index--;
}
}
// 更新LED显示:将对应位置0(点亮),其余置1(熄灭)
// 例: led_index=0 => 0xFE (点亮P6.0)
// led_index=1 => 0xFD (点亮P6.1)
// ...以此类推
LED_PORT = ~(1 << led_index);
}
}
💡 使用说明 & 重要提醒
1️⃣ 关于主频与定时器重装值
上面的代码以 12MHz 主频为例写了定时初值。请根据你实际设置的主频,使用 STC-ISP(AIapp-ISP)下载软件 中的 "定时器计算器" 工具自动生成准确的定时器初值,更省心、更准确:
ISP软件 → 定时器计算器 → 选择"定时器0" → 设置定时时间1ms → 自动生成代码
2️⃣ 如果你的LED不是接在P6口
请修改 GPIO_init() 中的端口配置:
- 改
P6M0/P6M1 为对应的 PxM0/PxM1
- 改
LED_PORT 宏定义中的端口
3️⃣ 如果不需要P4.0总电源控制
将 GPIO_init() 和 main() 中与 P4.0 相关的代码注释掉即可。
4️⃣ 流水灯方向
程序默认从左到右(P6.0 → P6.7),如需反转,将主循环里的 dir 变量改为 RIGHT_TO_LEFT。
5️⃣ 不依赖定时器的极简版(软件延时)
如果你不想用定时器,下面是一个最简单的软件延时流水灯版本:
#include "stc8h.h"
void delay_ms(u16 ms)
{
u16 i, j;
for(i = 0; i < ms; i++)
for(j = 0; j < 12000/12; j++);
}
void main(void)
{
u8 i;
P_SW2 |= 0x80;
// P6推挽输出,P4.0推挽输出
P6M0 = 0xFF; P6M1 = 0x00;
P4M0 = 0x01; P4M1 = 0x00;
P4 &= ~0x01; // P4.0=0,开启LED总电源
while(1)
{
for(i = 0; i < 8; i++)
{
P6 = ~(1 << i); // 逐位点亮
delay_ms(300); // 延时约300ms
}
}
}
📚 信息来源
| 内容 |
来源 |
| I/O口模式配置(P6M0/P6M1) |
STC8H数据手册第12章 配置I/O口 |
| 实验箱LED硬件原理(P6口接LED,P4.0总电源) |
STC8H实验指导书2.4~2.7 点灯实验 |
| 定时器0配置 |
STC8H数据手册第16章 定时器/计数器 —— 16.2.3/16.2.4 |
💬 如果在实际调试中遇到问题,欢迎继续提问!或者在 STC 官方论坛(www.stcaimcu.com)搜索更多示例。
🔍 搜索 "帮用 STC8H8K64U写个流水灯的演示程序"
📌 相关论坛讨论
- 8H8K64U 实验箱演示程序包中有 LCD12864, LCD1602的演示程序
- 请教关于 AiCube的I2C的两个问题 | 已解决,最新修改在5楼
- 从8051到32位8051,何宾教授带大家一起穿越