数码之家

 找回密码
 立即注册
搜索
查看: 1116|回复: 14

用STC8G1K08实现LED多档控制

[复制链接]
发表于 2025-2-15 14:36:45 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册

x
使用STC8G1K08A单片机实现通过按键控制LED开关和亮度的代码练习,结合了deepseek和kimi提供的代码范例,但都无法在STC8G1K08A直接运行,要么提示变量不存在,要么就是编译下载后没达到预期效果,最终还是通过厂家的STC8G规格说明,才试验成功


代码基于STC单片机的C语言开发环境,使用PWM信号控制LED亮度,并通过按键切换高亮、中亮、低亮和熄灭状态,上电默认高亮,熄灭后自动进入掉电省电模式,减少电量损耗。




硬件连接说明
  • P32:按键输入,连接到单片机的P32引脚。
  • P54:PWM输出,连接到单片机的P54引脚,用于控制LED亮度,默认输出高电平(熄灭)。
  • LED:通过电阻连接到P54引脚,另一端接电源正极,当IO口低电平时点亮。
  • 按键:一端连接到P32引脚,另一端接地。
软件设计思路
  • PWM控制:使用STC单片机的定时器功能生成PWM信号,通过占空比控制LED亮度。
  • 按键检测:检测P32引脚的状态,判断按键是否按下。
  • 状态切换:通过按键切换LED的亮度状态(高亮、中亮、低亮、熄灭)。
  • 上电默认高亮:程序启动时,设置为高亮状态。




  1. #include "STC8G.H"
  2. #define MAIN_Fosc       24000000L   // 定义主时钟
  3. #define MCU_IDLE()          PCON |= 1   /* MCU 进入 IDLE 模式 */
  4. #define MCU_POWER_DOWN()    PCON |= 2   /* MCU 进入 睡眠 模式 */

  5. #define u1 bit
  6. #define u8 unsigned char
  7. #define u16 unsigned int
  8. #define u32 unsigned long
  9. #define IDLE_TIME 3000000L      // 空闲计数器阈值

  10. // 定义按键引脚
  11. #define KEY_PIN P32  // 按键连接P32

  12. // 定义亮度档位
  13. // 定义PWM相关参数
  14. #define PWM_HIGH_DUTY 0xFF   // 高亮占空比(高电平时间长) = 常亮
  15. #define PWM_MEDIUM_DUTY 0x80 // 中亮占空比
  16. #define PWM_LOW_DUTY 0x40    // 低亮占空比
  17. #define PWM_OFF_DUTY 0x00    // 熄灭占空比(低电平)

  18. extern void          _nop_     (void);

  19. // 定义状态变量
  20. u8 led_state = 0;             // LED状态:0-高亮,1-中亮,2-低亮,3-熄灭
  21. u1 wakeup_status = 1;        // 运行标志(0:休眠,1:活跃)
  22. u32 idle_time = 0;            // 空闲计数器

  23. // 延时函数, ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
  24. void delay_ms(unsigned int ms)
  25. {
  26.         unsigned int i;
  27.         do{
  28.                 i = MAIN_Fosc / 10000;
  29.                 while(--i);
  30.         }while(--ms);
  31. }

  32. // 初始化PWM
  33. void PWM_Init() {
  34.     // 配置 PCA
  35.         CCON= 0x00;
  36.         CL = 0x00;
  37.         CH = 0x00;

  38.         CCAPM2 = 0x42;           // PCA 模块2为PWM工作模式
  39.         CR = 1;                  // 启动PCA 计数器
  40.        
  41. }

  42. // 设置PWM占空比,输出8位的PWM
  43. void Set_PWM_Duty(u8 duty) {
  44.     if (duty == 0xFF){ // 固定输出低电平,常亮
  45.                 PCA_PWM2 &= 0x3F;
  46.                 CCAP2H    = 0xFF;
  47.         }else if (duty == 0x00){ // 固定输出高电平,熄灭
  48.                 PCA_PWM2 &= 0xC0;
  49.                 CCAP2H    = 0x00;
  50.         }else{ // 输出8位的PWM
  51.                 PCA_PWM2 &=0x00;
  52.                 CCAP2L = duty;   // 设置占空比(低字节)
  53.                 CCAP2H = duty;   // 设置占空比(高字节)
  54.         }
  55. }

  56. // 按键检测
  57. u8 Key_Scan() {
  58.     if (KEY_PIN == 0) {  // 检测按键是否按下
  59.         delay_ms(20);  // 消抖
  60.         if (KEY_PIN == 0) {
  61.             while (KEY_PIN == 0);  // 等待按键释放
  62.             return 1;  // 返回按键按下标志
  63.         }
  64.     }
  65.     return 0;  // 无按键按下
  66. }

  67. // 初始化I/O端口
  68. void InitPorts()
  69. {
  70.         // 初始化为准双向
  71.     P3M0 = 0x00; P3M1 = 0x00;
  72.     P5M0 = 0x00; P5M1 = 0x00;
  73. }

  74. // 外部中断0初始化
  75. void Int0_Init(void) {
  76.     IT0 = 1;         // 使能INT0下降沿中断
  77.     EX0 = 1;         // 使能INT0中断0
  78.     EA = 1;          // 使能中断总开关
  79. }

  80. // 掉电模式
  81. void PowerDownMode(void) {
  82.     wakeup_status = 0;
  83.     _nop_();
  84.     _nop_();
  85.     MCU_POWER_DOWN();  // MCU进入掉电模式(STC8G系列)
  86.     _nop_();
  87.     _nop_();
  88.     _nop_();
  89.     _nop_();
  90. }

  91. // 从掉电模式唤醒
  92. void WakeUpFromPowerDown(void) {
  93.     PCON &= 0xFD; // 清除掉电标志
  94. }

  95. // 外部中断0服务程序(按键唤醒)
  96. void INT0_ISR(void) interrupt 0 {
  97.     if (!wakeup_status){       // 如果在休眠状态,就执行唤醒操作
  98.         wakeup_status = 1;
  99.         WakeUpFromPowerDown(); // 从掉电模式唤醒
  100.     }
  101. }

  102. // 主函数
  103. void main() {
  104.         InitPorts(); // 初始化端口
  105.         Int0_Init(); // 初始化外部中断0
  106.     PWM_Init();  // 初始化PWM
  107.     // 上电默认高亮
  108.     Set_PWM_Duty(PWM_HIGH_DUTY);
  109.         led_state = 0;
  110.     while (1) {
  111.                 idle_time++;
  112.         if (Key_Scan()) {  // 检测按键
  113.             led_state++;  // 切换LED状态
  114.                         idle_time = 0; //重置空闲计数器
  115.             if (led_state > 3) {
  116.                 led_state = 0;  // 循环回到高亮状态
  117.             }
  118.             // 根据状态设置PWM占空比或普通输出高电平
  119.             switch (led_state) {
  120.                 case 0:  // 高亮
  121.                     Set_PWM_Duty(PWM_HIGH_DUTY);
  122.                     break;
  123.                 case 1:  // 中亮
  124.                     Set_PWM_Duty(PWM_MEDIUM_DUTY);
  125.                     break;
  126.                 case 2:  // 低亮
  127.                     Set_PWM_Duty(PWM_LOW_DUTY);
  128.                     break;
  129.                 case 3:  // 熄灭
  130.                     Set_PWM_Duty(PWM_OFF_DUTY);
  131.                     break;
  132.             }
  133.         }else{
  134.                         if (led_state == 3 && idle_time >= IDLE_TIME){ // 熄灭时,进入掉电省电模式
  135.                                 PowerDownMode();
  136.                         }
  137.                 }
  138.     }
  139. }
复制代码


发表于 2025-2-15 15:15:54 | 显示全部楼层
家电中单片机控制越来越多了,也带来了单片机成本的降低
回复 支持 反对

使用道具 举报

发表于 2025-2-15 15:33:07 | 显示全部楼层
LED电流多大?直接灌进单片机,不好吧?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-2-15 18:09:42 | 显示全部楼层
zhonsir 发表于 2025-2-15 15:33
LED电流多大?直接灌进单片机,不好吧?

这片单片机输出电流很小的,供电电压一般用USB 充电器或锂电电池,所以电压就是3.7~5.2V,建议串接一个1K电阻,LED限流3~5mA。要驱动更大的电流电器,建议增加外接电路,例如驱动MOS管AO3400,这是电压型MOS驱动管,电流只有几毫安。
回复 支持 反对

使用道具 举报

发表于 2025-2-15 23:55:11 来自手机浏览器 | 显示全部楼层
试试一个亮度开灯渐亮关灯渐灭然后低功耗等待唤醒…看看这个AI能不能弄出来
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-2-16 18:22:22 来自手机浏览器 | 显示全部楼层
触景情伤 发表于 2025-2-15 23:55
试试一个亮度开灯渐亮关灯渐灭然后低功耗等待唤醒…看看这个AI能不能弄出来 ...

请参考呼吸灯代码,中间就是常亮,熄灭后无操作等待后进入省电模式。
回复 支持 反对

使用道具 举报

发表于 2025-2-20 14:41:38 | 显示全部楼层
程序为什么在stc12c5a上灯不亮?-不懂就问。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-2-20 18:02:22 | 显示全部楼层
ctlu 发表于 2025-2-20 14:41
程序为什么在stc12c5a上灯不亮?-不懂就问。

两个芯片的中断0和PWM2绑定的引脚不一样,需要适配吧。 这代码中KEY_PIN绑定P32 GPIO口,对于STC8G1K08A就是中断0,所以中断代码有效。而PWM2占空比代码,对于STC8G1K08A就是P54引脚,为了避免宏定义简单替换引脚而忽略下面的代码,我把P54直接在代码函数中使用。 所以,如果芯片不同,未必能正确运行并点亮的,用deeepseek提供的代码,也是因为这样的适配原因,拿到也无法直接运行,要调试很久。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-2-20 18:08:02 | 显示全部楼层
ctlu 发表于 2025-2-20 14:41
程序为什么在stc12c5a上灯不亮?-不懂就问。

DeepSeek的迁移建议:
要将代码从 STC8G1K08A 移植到 STC12C5A,需要注意以下几点:
  • 寄存器差异

    • STC8G 和 STC12C5A 的寄存器名称和功能可能不同,尤其是 PWM 和中断相关的寄存器。
    • STC12C5A 的 PWM 功能通常通过定时器实现,而不是 PCA 模块。

  • 时钟配置
    • STC12C5A 的时钟配置可能与 STC8G 不同,需要根据具体需求调整。

  • 中断配置
    • 外部中断的配置方式可能略有不同。

  • 电源管理模式
    • STC12C5A 的电源管理模式可能与 STC8G 不同,需要调整相关代码。


以下是修改后的代码,适用于 STC12C5A

  1. #include "STC12C5A.H"

  2. #define MAIN_Fosc       24000000L   // 定义主时钟
  3. #define MCU_IDLE()          PCON |= 0x01   /* MCU 进入 IDLE 模式 */
  4. #define MCU_POWER_DOWN()    PCON |= 0x02   /* MCU 进入 睡眠 模式 */

  5. #define u1 bit
  6. #define u8 unsigned char
  7. #define u16 unsigned int
  8. #define u32 unsigned long
  9. #define IDLE_TIME 3000000L      // 空闲计数器阈值

  10. // 定义按键引脚
  11. #define KEY_PIN P3_2  // 按键连接P3.2

  12. // 定义亮度档位
  13. #define PWM_HIGH_DUTY 0xFF   // 高亮占空比(高电平时间长) = 常亮
  14. #define PWM_MEDIUM_DUTY 0x80 // 中亮占空比
  15. #define PWM_LOW_DUTY 0x40    // 低亮占空比
  16. #define PWM_OFF_DUTY 0x00    // 熄灭占空比(低电平)

  17. extern void          _nop_     (void);

  18. // 定义状态变量
  19. u8 led_state = 0;             // LED状态:0-高亮,1-中亮,2-低亮,3-熄灭
  20. u1 wakeup_status = 1;        // 运行标志(0:休眠,1:活跃)
  21. u32 idle_time = 0;            // 空闲计数器

  22. // 延时函数, ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
  23. void delay_ms(unsigned int ms)
  24. {
  25.     unsigned int i;
  26.     do {
  27.         i = MAIN_Fosc / 10000;
  28.         while (--i);
  29.     } while (--ms);
  30. }

  31. // 初始化PWM(使用定时器2)
  32. void PWM_Init() {
  33.     // 配置定时器2为PWM模式
  34.     AUXR |= 0x04;       // 定时器2为1T模式
  35.     T2L = 0x00;         // 定时器2低字节
  36.     T2H = 0x00;         // 定时器2高字节
  37.     AUXR |= 0x10;       // 启动定时器2

  38.     // 配置PWM输出引脚(P1.0)
  39.     P1M0 |= 0x01;       // 设置P1.0为推挽输出
  40.     P1M1 &= ~0x01;
  41. }

  42. // 设置PWM占空比,输出8位的PWM
  43. void Set_PWM_Duty(u8 duty) {
  44.     if (duty == 0xFF) { // 固定输出低电平,常亮
  45.         P1_0 = 0;       // 直接控制P1.0输出低电平
  46.     } else if (duty == 0x00) { // 固定输出高电平,熄灭
  47.         P1_0 = 1;       // 直接控制P1.0输出高电平
  48.     } else { // 输出PWM
  49.         CCAP2H = duty;   // 设置占空比
  50.         CCAP2L = duty;
  51.     }
  52. }

  53. // 按键检测
  54. u8 Key_Scan() {
  55.     if (KEY_PIN == 0) {  // 检测按键是否按下
  56.         delay_ms(20);  // 消抖
  57.         if (KEY_PIN == 0) {
  58.             while (KEY_PIN == 0);  // 等待按键释放
  59.             return 1;  // 返回按键按下标志
  60.         }
  61.     }
  62.     return 0;  // 无按键按下
  63. }

  64. // 初始化I/O端口
  65. void InitPorts() {
  66.     // 初始化为准双向
  67.     P3M0 = 0x00; P3M1 = 0x00;
  68.     P1M0 = 0x00; P1M1 = 0x00;
  69. }

  70. // 外部中断0初始化
  71. void Int0_Init(void) {
  72.     IT0 = 1;         // 使能INT0下降沿中断
  73.     EX0 = 1;         // 使能INT0中断
  74.     EA = 1;          // 使能中断总开关
  75. }

  76. // 掉电模式
  77. void PowerDownMode(void) {
  78.     wakeup_status = 0;
  79.     _nop_();
  80.     _nop_();
  81.     MCU_POWER_DOWN();  // MCU进入掉电模式
  82.     _nop_();
  83.     _nop_();
  84.     _nop_();
  85.     _nop_();
  86. }

  87. // 从掉电模式唤醒
  88. void WakeUpFromPowerDown(void) {
  89.     PCON &= 0xFD; // 清除掉电标志
  90. }

  91. // 外部中断0服务程序(按键唤醒)
  92. void INT0_ISR(void) interrupt 0 {
  93.     if (!wakeup_status) {       // 如果在休眠状态,就执行唤醒操作
  94.         wakeup_status = 1;
  95.         WakeUpFromPowerDown(); // 从掉电模式唤醒
  96.     }
  97. }

  98. // 主函数
  99. void main() {
  100.     InitPorts(); // 初始化端口
  101.     Int0_Init(); // 初始化外部中断0
  102.     PWM_Init();  // 初始化PWM
  103.     // 上电默认高亮
  104.     Set_PWM_Duty(PWM_HIGH_DUTY);
  105.     led_state = 0;
  106.     while (1) {
  107.         idle_time++;
  108.         if (Key_Scan()) {  // 检测按键
  109.             led_state++;  // 切换LED状态
  110.             idle_time = 0; //重置空闲计数器
  111.             if (led_state > 3) {
  112.                 led_state = 0;  // 循环回到高亮状态
  113.             }
  114.             // 根据状态设置PWM占空比或普通输出高电平
  115.             switch (led_state) {
  116.                 case 0:  // 高亮
  117.                     Set_PWM_Duty(PWM_HIGH_DUTY);
  118.                     break;
  119.                 case 1:  // 中亮
  120.                     Set_PWM_Duty(PWM_MEDIUM_DUTY);
  121.                     break;
  122.                 case 2:  // 低亮
  123.                     Set_PWM_Duty(PWM_LOW_DUTY);
  124.                     break;
  125.                 case 3:  // 熄灭
  126.                     Set_PWM_Duty(PWM_OFF_DUTY);
  127.                     break;
  128.             }
  129.         } else {
  130.             if (led_state == 3 && idle_time >= IDLE_TIME) { // 熄灭时,进入掉电省电模式
  131.                 PowerDownMode();
  132.             }
  133.         }
  134.     }
  135. }
复制代码
主要修改点
  • PWM 初始化

    • STC12C5A 使用定时器2实现 PWM 功能,而不是 PCA 模块。
    • 配置定时器2为 PWM 模式,并通过 P1.0 输出 PWM 信号。

  • 引脚配置
    • STC12C5A 的 PWM 输出引脚为 P1.0,需要配置为推挽输出。

  • 电源管理模式
    • STC12C5A 的电源管理模式与 STC8G 类似,直接使用 PCON 寄存器控制。

  • 中断配置
    • 外部中断0的配置方式与 STC8G 相同。



注意事项
  • 确保硬件连接正确,特别是 PWM 输出引脚和按键引脚。
  • 根据实际需求调整时钟频率和 PWM 占空比。
  • 如果使用其他定时器或 PWM 模块,需根据 STC12C5A 的数据手册调整代码。


回复 支持 反对

使用道具 举报

发表于 2025-2-23 15:32:38 | 显示全部楼层
aming_ou 发表于 2025-2-20 18:08
DeepSeek的迁移建议:要将代码从 STC8G1K08A 移植到 STC12C5A,需要注意以下几点:
  • 寄存器差异:

  • 感谢耐心细致回复。似乎与数模转换相似,输出脚由其控制寄存器确定,看来换不同单片机,还是要认真了解相关两款MCU的资料。
    回复 支持 反对

    使用道具 举报

     楼主| 发表于 2025-3-3 20:12:37 来自手机浏览器 | 显示全部楼层
    在嘉立创打了一份板子,可以玩到天荒地老了

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x
    回复 支持 反对

    使用道具 举报

    发表于 2025-3-3 21:54:03 | 显示全部楼层
    前几天我也简单玩了一下这个单片机。

    测试了一下省电(掉电和空闲)模式,以及使用外部中断唤醒。
    实际就是实现了个单键开关机功能。

    1. ;STC8G1K08A省电测试
    2. ;STC8G1K08A实现单键开关机
    3. ;
    4. P3M0  DATA 0B2H
    5. P3M1  DATA 0B1H
    6. ;IDL  EQU 01H            ;PCON.0
    7. PD    EQU 02H            ;PCON.1
    8. ;KEY  EQU P3.2           ;按键接P3.2和GND之间,需并个1~100nF(102~104)电容防抖
    9. LED   EQU P3.3           ;开关输出,输出高为开。

    10. ORG 0000H
    11.         SJMP  MAIN
    12. ORG 0003H                ;INT0中断服务入口点
    13.         CPL   LED        ;反转开关状态
    14.         RETI
    15. MAIN:
    16.         CLR   LED        ;上电默认输出高(开),改为输出低(关)。
    17.         MOV   P3M0,#08H  ;设置P3为开漏模式,P3.3推挽输出
    18.         MOV   P3M1,#00H
    19.         
    20.         SETB  IT0        ;设置INT0下降沿中断
    21.         SETB  EX0        ;使能INT0中断
    22.         SETB  EA         ;开启中断
    23. AA:
    24.         ;MOV  PCON,#IDL  ;使MCU进入 空闲 模式
    25.         ORL   PCON,#PD   ;使MCU进入 掉电 模式
    26.         SJMP  AA
    27. END
    复制代码




    回复 支持 反对

    使用道具 举报

    发表于 2025-3-4 13:14:49 | 显示全部楼层
    我用STC8H单片机也碰到这个问题,貌似是寄存器设置的问题。
    回复 支持 反对

    使用道具 举报

    发表于 3 天前 | 显示全部楼层
    aming_ou 发表于 2025-2-20 18:08
    DeepSeek的迁移建议:要将代码从 STC8G1K08A 移植到 STC12C5A,需要注意以下几点:
  • 寄存器差异:

  • 说的挺细致的
    回复 支持 反对

    使用道具 举报

     楼主| 发表于 3 天前 来自手机浏览器 | 显示全部楼层
    xiaocake 发表于 2025-3-3 21:54
    前几天我也简单玩了一下这个单片机。

    测试了一下省电(掉电和空闲)模式,以及使用外部中断唤醒。

    汇编代码,↑强
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

    闽公网安备35020502000485号

    闽ICP备2021002735号-2

    GMT+8, 2025-3-15 22:57 , Processed in 0.140400 second(s), 11 queries , Redis On.

    Powered by Discuz!

    © 2006-2025 MyDigit.Net

    快速回复 返回顶部 返回列表