STC15开发板以其高性价比、增强型8051内核、丰富片上资源(ADC、PWM、定时器、串口等)和强大的抗干扰能力,在嵌入式开发爱好者、学生和工程师中广受欢迎,掌握其程序开发是解锁其潜力的关键,以下是一份详尽的开发教程,助你快速上手并进阶:

开发环境搭建 (基石准备)
-
Keil C51 IDE:
- 下载并安装最新版Keil uVision (C51版本)。
- 安装STC官方提供的器件数据库,运行STC-ISP下载工具,在
Keil仿真设置选项卡中点击添加MCU型号到Keil中,按提示完成。 - 在Keil中新建工程,选择
STC MCU Database,找到你的具体型号(如STC15F2K60S2)。
-
头文件与寄存器定义:
- 强烈建议使用STC官方提供的
stc15.h或针对具体型号的精简头文件(如stc15f2k60s2.h),这些文件包含了所有特殊功能寄存器(SFR)的地址和位定义。 - 将头文件复制到你的工程目录,并在主程序
main.c开头包含它 (#include "stc15f2k60s2.h")。
- 强烈建议使用STC官方提供的
-
程序下载 (STC-ISP):
- 准备USB转TTL串口模块(如CH340, CP2102)。
- 连接开发板:
TXD-> 模块RXD,RXD-> 模块TXD,GND->GND。注意: STC15通常需要冷启动下载,即点击下载按钮后再给开发板上电。 - 打开STC-ISP软件,选择正确的单片机型号、串口号。
- 设置合适的波特率(首次可尝试较低值如
115200或57600),选择编译Keil生成的Hex文件。 - 点击
下载/编程,然后给开发板上电复位,等待下载完成提示。
基础I/O控制:点亮LED (入门实践)
-
硬件连接:
- 假设LED阳极通过限流电阻接VCC,阴极接单片机IO口(如P1.0),控制逻辑:IO输出低电平(
0)点亮LED,高电平(1)熄灭。
- 假设LED阳极通过限流电阻接VCC,阴极接单片机IO口(如P1.0),控制逻辑:IO输出低电平(
-
GPIO模式配置 (关键步骤):
- STC15的IO口有4种模式:准双向口/弱上拉、推挽输出/强上拉、高阻输入、开漏输出,模式由端口配置寄存器
PxM0和PxM1控制(x=0,1,2,3…)。 - 对于驱动LED,设置为推挽输出模式驱动能力最强:
// 配置P1.0为推挽输出模式 (M1=0, M0=1) P1M0 |= 0x01; // 设置P1.0的M0位为1 P1M1 &= ~0x01; // 设置P1.0的M1位为0
- STC15的IO口有4种模式:准双向口/弱上拉、推挽输出/强上拉、高阻输入、开漏输出,模式由端口配置寄存器
-
闪烁LED程序:
#include "stc15f2k60s2.h" // 根据实际型号修改 #include <intrins.h> // 包含_nop_()延时函数 void DelayMS(unsigned int ms) { // 粗略毫秒延时函数 unsigned int i, j; for(i = ms; i > 0; i--) for(j = 1140; j > 0; j--); // 此值需根据主频校准 } void main() { // 配置P1.0为推挽输出 P1M0 = 0x01; P1M1 = 0x00; while(1) { P10 = 0; // P1.0输出低电平,LED亮 DelayMS(500); // 延时500ms P10 = 1; // P1.0输出高电平,LED灭 DelayMS(500); // 延时500ms } }
按键检测与消抖 (输入处理)
-
硬件连接:
按键一端接地(GND),另一端接IO口(如P3.2)和上拉电阻(STC15准双向口模式内置上拉,通常可省略外接)。

-
配置IO为输入:
- 将按键对应的IO口(如P3.2)配置为准双向口或高阻输入模式,准双向口模式更常用:
// 配置P3.2为准双向口 (默认状态,通常无需额外配置,M1=0, M0=0) P3M0 &= ~(1 << 2); // 清除M0位 P3M1 &= ~(1 << 2); // 清除M1位
- 将按键对应的IO口(如P3.2)配置为准双向口或高阻输入模式,准双向口模式更常用:
-
按键检测与软件消抖:
#define KEY P32 // 定义按键引脚为P3.2 bit KeyScan() { if (KEY == 0) { // 检测按键是否按下 (低电平有效) DelayMS(10); // 延时10ms消抖 if (KEY == 0) { // 再次确认按键按下 while(!KEY); // 等待按键释放 (松手检测) DelayMS(10); // 松手消抖 return 1; // 返回有效按键 } } return 0; // 无按键 } void main() { // ... (LED和按键IO配置) while(1) { if (KeyScan()) { P10 = ~P10; // 按键按下,LED状态翻转 } // 其他任务... } }
定时器中断应用 (精准计时)
STC15通常有多个定时器(T0, T1, T2等),以16位自动重载模式(模式0)的Timer0为例,实现1ms定时中断。
-
定时器初始化:
void Timer0_Init(void) { // 1ms @11.0592MHz AUXR |= 0x80; // 定时器0为1T模式 (12T模式时AUXR &= 0x7F) TMOD &= 0xF0; // 清除T0控制位 TMOD |= 0x00; // T0模式0: 16位自动重载 (STC15特有) TL0 = 0x66; // 设置定时初值低8位 TH0 = 0xFC; // 设置定时初值高8位 TF0 = 0; // 清除T0溢出标志 TR0 = 1; // 启动T0 ET0 = 1; // 允许T0中断 EA = 1; // 开启总中断 }- 初值计算:
- 1T模式:
TimerCount = 65536 - (FOSC / 1000)(FOSC=11059200Hz) TimerCount = 65536 - 11059200/1000 = 65536 - 11059.2 ≈ 54477 (0xD4ED)->TH0=0xD4, TL0=0xED(需根据实际主频精确计算)。
- 1T模式:
- 初值计算:
-
中断服务程序:
volatile unsigned int msCount = 0; // 毫秒计数器,volatile防止优化 void timer0_isr() interrupt 1 { // Timer0中断号是1 msCount++; // 毫秒计数器递增 // 可以在此添加其他需要定时执行的任务... } -
应用示例 (精准1秒LED闪烁):
void main() { Timer0_Init(); // ... (LED配置) while(1) { if (msCount >= 1000) { // 达到1000ms (1秒) msCount = 0; // 复位计数器 P10 = ~P10; // LED翻转 } // 主循环处理其他非实时性任务 } }
PWM输出控制 (呼吸灯)
STC15内置硬件PWM发生器(通常与定时器复用,如PWM可用Timer0/1/2或专用PWM定时器),以使用P1.3作为PWM输出(对应PWM2或特定通道)为例。
-
PWM初始化 (以PWM2为例):
void PWM2_Init(void) { P1M0 |= 0x08; P1M1 &= ~0x08; // P1.3设置为推挽输出 (用于PWM输出) CCON = 0x00; // 清零CF, CR, 初始化PCA计数器控制寄存器 CL = 0; CH = 0; // PCA计数器清零 CMOD = 0x04; // PCA时钟源 = SYSclk / 1 (1T模式), 禁止PCA中断 CCAPM2 = 0x42; // 设置PCA模块2为8位PWM模式 (ECOM2=1, PWM2=1) PCA_PWM2 = 0x00; // PWM2占空比控制寄存器清零 (初始化) CR = 1; // 启动PCA计数器 } void PWM2_SetDuty(unsigned char duty) { // 设置PWM2占空比 (0-255) CCAP2H = duty; // 写入捕获比较寄存器高8位 (决定占空比) PCA_PWM2 &= 0xC0; // 清除占空比低2位 (PCA_PWM2[1:0]) PCA_PWM2 |= (duty & 0x03); // 设置占空比低2位 (8位PWM时,duty是8位,低2位写入PCA_PWM2[1:0]) }- 注意: 具体PWM通道、寄存器名称(
CCAPMx,CCAPxH,PCA_PWMx)需严格参照对应型号的数据手册。
- 注意: 具体PWM通道、寄存器名称(
-
实现呼吸灯:

void main() { unsigned char duty = 0; bit dir = 0; // 方向: 0=渐亮, 1=渐暗 PWM2_Init(); while(1) { PWM2_SetDuty(duty); DelayMS(10); // 用延时或定时器控制变化速度 if (!dir) { if (++duty == 0xFF) dir = 1; // 加到最大转渐暗 } else { if (--duty == 0x00) dir = 0; // 减到最小转渐亮 } } }
串口通信 (UART) 与PC交互
STC15通常有多个串口(UART1, UART2等),以UART1为例,实现与PC串口助手的收发。
-
串口初始化 (模式1, 8位数据, 无校验, 1停止位):
void UART1_Init(void) { // 9600bps @11.0592MHz P_SW1 |= 0x40; // UART1切换使用P3.0(Rx) P3.1(Tx) (具体切换位看手册) SCON = 0x50; // 8位数据位, 可变波特率, 允许接收 (SM0=0, SM1=1, REN=1) AUXR |= 0x01; // 串口1选择定时器1为波特率发生器 (S1ST2=0) AUXR |= 0x40; // 定时器1为1T模式 (T1x12=1) TMOD &= 0x0F; // 清除定时器1控制位 TMOD |= 0x20; // 定时器1工作于模式2 (8位自动重载) TL1 = 0xE0; // 设置定时初值 TH1 = 0xFE; // 设置重载值 ET1 = 0; // 禁止定时器1中断 TR1 = 1; // 启动定时器1 ES = 1; // 允许串口1中断 EA = 1; // 开总中断 }- 波特率计算:
- 1T模式:
BaudRate = (2^SMOD / 32) (FOSC / (256 - TH1)) - 9600bps @11.0592MHz, 1T模式:
TH1 = TL1 = 256 - FOSC / (32 BaudRate) = 256 - 11059200 / (32 9600) ≈ 256 - 36 = 220 (0xDC)->TH1=0xFE, TL1=0xE0(需根据实际主频精确计算)。
- 1T模式:
- 波特率计算:
-
中断服务程序 (接收与回显):
void uart1_isr() interrupt 4 { // UART1中断号是4 if (RI) { // 接收中断标志 RI = 0; // 软件清零接收标志 SBUF = SBUF; // 将接收到的数据原样发回 (回显) // 也可将接收数据存入缓冲区处理: RxData = SBUF; } if (TI) { // 发送中断标志 TI = 0; // 软件清零发送标志 // 发送完成处理 (如设置标志位通知主程序可发送下一字节) } } -
发送数据函数:
void UART1_SendByte(unsigned char dat) { SBUF = dat; // 将数据写入发送缓冲器 while (!TI); // 等待发送完成 (TI置位) TI = 0; // 软件清零发送中断标志 } void UART1_SendString(char s) { // 发送字符串 while (s) { UART1_SendByte(s++); } }
进阶建议与总结
- 深入理解数据手册: STC15的丰富功能(ADC、SPI、I2C、看门狗、低功耗)都需仔细研读官方数据手册,了解寄存器配置细节和时序要求。
- 模块化编程: 将GPIO、定时器、PWM、UART等驱动封装成独立的
.c/.h文件,提高代码复用性和可维护性。 - 使用库函数: 考虑使用成熟的第三方库(如STC官方库或社区库)简化开发,但理解底层原理仍至关重要。
- 仿真与调试: 利用Keil的软件仿真功能调试逻辑,配合串口打印调试信息 (
printf重定向到UART)。 - 抗干扰设计: STC15以抗干扰著称,但在复杂环境中仍需注意电源滤波、IO保护、PCB布局布线。
- RTOS探索: 对于复杂任务,可研究小型RTOS(如FreeRTOS、RT-Thread Nano)在STC15上的移植与应用。
STC15开发板是学习8051内核和嵌入式开发的优秀平台,通过掌握核心外设的驱动开发(GPIO、定时器、中断、PWM、UART),并遵循模块化、规范化的编程原则,你能够高效地构建稳定可靠的嵌入式应用,从简单的LED控制到物联网节点、小型控制器等。
现在轮到你动手了!你正计划用STC15开发板实现什么有趣或实用的项目?是环境监测、智能小车控制、还是自定义的通讯协议?欢迎在评论区分享你的想法或开发中遇到的难题,我们一起交流探讨,攻克技术瓶颈!
原创文章,作者:世雄 - 原生数据库架构专家,如若转载,请注明出处:https://idctop.com/article/10124.html