Skip to content
鼓励作者:欢迎打赏犒劳

STC8H8K64U单片机-点灯

学前准备

下载keil5开发工具:https://software.share888.top/note/devtool/detail/keil.html

下载stc-isp 烧录工具:https://software.share888.top/note/devtool/detail/stc-isp.html

我用的板子是打狗棒的板子,淘宝20元左右。教程如下:https://www.stcai.com/hxgnsyb

创建第一个点灯工程

  1. 打开keil软件,新建一个keil项目,选择合适的目录

  2. 点击下拉框中,如果出现STC MCU Database,说明环境导入成功

  3. 可通过搜索框搜索到stc相关芯片信息

  4. 在源码目录,右键打开操作面板,选择Add New Item to Group ...

新建main.c文件。根据面板提示,选择C File,确定好文件名称,当前的文件名称为main

Add完成后,在源码目录中会多一个 main.c文件

在 main.c中编写代码,实现main函数. 将下面的代码烧录到单片机就行了。正常灯就会亮

c
#include <STC8H.H>  // 1. 包含头文件,告诉编译器这是 STC8H 系列芯片


void main()
{
	// 1. 先配置模式 (强推挽)
    P2M0 = 0xFF; P2M1 = 0x00; 
    // 3. 控制灯的状态
    // 大多数开发板是“低电平点亮” (0 = 亮, 1 = 灭)
    // 如果这句代码灯没亮,试着改成 LED = 1;
    P20 = 0 ;
    
    // 4. 死循环,让程序停在这里,保持灯一直亮着
    while(1)
    {
        // 什么都不做,就让它亮着
     }
		
		
}

让灯闪烁

很简单,直接上代码

c
#include <STC8H.H>
#include <intrins.h> // 用于 _nop_()

/**
 * @brief 精准延时 1 毫秒 (基于 24MHz 1T 架构)
 *        适用于 STC8H, STC8Y, STC8A 等系列
 */
void Delay1ms()		//@24.000MHz
{
	unsigned char i, j;

	_nop_(); // 微调,对齐周期
	i = 24;  // 这些系数是专为 24MHz 计算的
	j = 169;
	do
	{
		while (--j);
	} while (--i);
}

/**
 * @brief 通用毫秒延时
 * @param ms 延时毫秒数
 */
void Delay_ms(unsigned int ms)
{
    unsigned int k;
    for(k = 0; k < ms; k++)
    {
        Delay1ms();
    }
}

void main()
{
    // 配置强推挽
    P2M0 = 0xFF; 
    P2M1 = 0x00; 

    while(1)
    {
        P2 = 0xFE;      // P2.0 亮
        Delay_ms(1000); // 延时 1 秒
        
        P2 = 0xFF;      // P2.0 灭
        Delay_ms(1000); // 延时 1 秒
    }
}

流水灯效果

c
#include <STC8H.H>
#include <intrins.h> // 用于 _nop_()

// ==========================================
// 精准延时函数 (适配 24MHz)
// ==========================================
void Delay1ms()		//@24.000MHz
{
	unsigned char i, j;
	_nop_(); 
	i = 24;  
	j = 169;
	do
	{
		while (--j);
	} while (--i);
}

void Delay_ms(unsigned int ms)
{
    unsigned int k;
    for(k = 0; k < ms; k++)
    {
        Delay1ms();
    }
}

// ==========================================
// 主函数
// ==========================================
void main()
{
    // 1. 配置 P2 口为 强推挽输出 (让灯更亮,驱动能力更强)
    // 0xFF = 1111 1111 (所有引脚都设为强推挽)
    P2M0 = 0xFF;  // 1111 1111
    P2M1 = 0x00;  // 0000 0000

    while(1)
    {
        // --- 第1步:点亮第1个灯 (最右边/最低位) ---
        // 二进制: 1111 1110  (只有最后一位是0,灯亮)
        // 十六进制: 0xFE
        P2 = 0xFE;  // 1111 1110
        Delay_ms(500); // 延时 0.5 秒

        // --- 第2步:点亮第2个灯 ---
        // 二进制: 1111 1101  (倒数第二位是0,灯亮)
        // 十六进制: 0xFD
        P2 = 0xFD;  // 1111 1101
        Delay_ms(500);

        // --- 第3步:点亮第3个灯 ---
        // 二进制: 1111 1011
        // 十六进制: 0xFB
        P2 = 0xFB;  // 1111 1011
        Delay_ms(500);

        // --- 第4步:点亮第4个灯 ---
        // 二进制: 1111 0111
        // 十六进制: 0xF7
        P2 = 0xF7;  // 1111 0111
        Delay_ms(500);

        // --- 第5步:点亮第5个灯 ---
        // 二进制: 1110 1111
        // 十六进制: 0xEF
        P2 = 0xEF;  // 1110 1111
        Delay_ms(500);

        // --- 第6步:点亮第6个灯 ---
        // 二进制: 1101 1111
        // 十六进制: 0xDF
        P2 = 0xDF;  // 1101 1111
        Delay_ms(500);

        // --- 第7步:点亮第7个灯 ---
        // 二进制: 1011 1111
        // 十六进制: 0xBF
        P2 = 0xBF;  // 1011 1111
        Delay_ms(500);

        // --- 第8步:点亮第8个灯 (最左边/最高位) ---
        // 二进制: 0111 1111
        // 十六进制: 0x7F
        P2 = 0x7F;  // 0111 1111
        Delay_ms(500);
        
        // (可选) 全灭停顿一下,效果更清晰
        P2 = 0xFF;  // 1111 1111 (全灭)
        Delay_ms(200);
    }
}

按键点灯

也很简单,重点是知道那个是按键的地址

c
#include <STC8H.H> // 这个文件里包含了所有寄存器的绝对地址

// 定义按键的“位地址”
// 语法:sbit 变量名 = 寄存器名 ^ 位数;
sbit KEY_S4 = P3^3; 

void main()
{
	// 1. 配置 P1 口为 强推挽输出 (让灯更亮,驱动能力更强)
    // 0xFF = 1111 1111 (所有引脚都设为强推挽)
    P1M0 = 0xFF;  // 1111 1111
    P1M1 = 0x00;  // 0000 0000
    
    
    while(1)
    {
        // 现在你可以像使用变量一样使用它
        if (KEY_S4 == 0) 
        {
            // 按键按下了
			P10 = 0;
        }else{
				
			P10 = 1;
		}
    }
}

问题

sbit和sfr 的作用

在 STC8(以及所有基于 8051 内核的单片机,如 STC89, STC12, STC15 等)的 C 语言开发环境(通常是 Keil C51)中,sfr 和 sbit 确实是独有的扩展关键字

简单来说,它们是用来给硬件寄存器起别名的,让你能用人类可读的名字去控制硬件,而不是去记复杂的十六进制地址

sfr (Special Function Register)

  • 含义:特殊功能寄存器。
  • 作用:用来定义一个**8 位(1 字节)**的硬件寄存器。
  • 场景:当你需要操作整个端口(如 P1 口所有引脚)、配置定时器模式、设置串口波特率时,你操作的是一个完整的 8 位寄存器。
  • 例子
    c
    // 告诉编译器:名字叫 P1 的变量,对应的是地址为 0x90 的硬件寄存器
    sfr P1 = 0x90; 
    
    // 现在你可以像操作普通变量一样操作它
    P1 = 0xFF; // 把 P1 口 8 个引脚全部设为高电平

sbit (Special Bit)

  • 含义:特殊功能寄存器的
  • 作用:用来定义某个 sfr 寄存器中的某一位(1 个 bit)
  • 场景:当你只需要控制某一个具体的引脚(如 P1.0 接的 LED),或者只关心某个状态标志位(如溢出标志 OV)时。
  • 例子
    c
    // 方法一:基于已定义的 sfr 来定义位 (推荐)
    // 意思是:LED 这个名字,代表 P1 寄存器的第 0 位
    sbit LED = P1^0; 
    
    // 方法二:直接指定绝对地址 (较少用,需查手册)
    // P1.0 的位地址通常是 0x90
    sbit LED = 0x90; 
    
    // 使用
    LED = 0; // 只把 P1.0 拉低,其他引脚不变

sfrsbit 的核心区别

特性sfrsbit
操作对象整个字节 (8 位)单个位 (1 位)
数据宽度8 bit (0 ~ 255)1 bit (0 或 1)
典型用途一次性控制整个端口、设置寄存器配置值控制单个 GPIO 引脚、读取单个状态标志
赋值范围0x000xFF01 (真/假)
定义依赖独立定义,直接对应物理地址通常依赖于 sfr 定义,或者直接指定位地址
代码示例P1 = 0x0F; (改变 8 个引脚)LED = 1; (只改变 1 个引脚)
底层原理映射到 SFR 区的一个字节地址映射到 SFR 区的一个位地址 (51 单片机特有的位寻址功能)

上次更新:

如有转载或 CV 的请标注本站原文地址