找回密码
 立即注册
查看: 17|回复: 1

求助 关于stc8g1k08a 代码

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2026-03-26 19:06:37
已绑定手机

1

主题

0

回帖

5

积分

新手上路

积分
5
发表于 昨天 19:06 | 显示全部楼层 |阅读模式
stc8g1k08a   我让AI给我写了好多代码都不好使  不知道为什么?、
我就是想 让5.5 按一个开关 短按一下控制 3.2 开关

5.5 长按 按住3秒 控制3.3 开关

我让ai 给我写了一下午 也没有一个能好使的。 不知道为什么  求大神帮帮我

回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:841
  • 最近打卡:2026-03-26 07:36:26

12

主题

1331

回帖

7160

积分

论坛元老

积分
7160
发表于 昨天 21:04 | 显示全部楼层
下面提供一个严格符合 **C89** 标准的实现,使用 **静态内存分配**、**无递归**、**非阻塞** 状态机,通过 **定时器中断** 扫描按键。代码已针对 **STC8G1K08A** 的引脚和寄存器进行配置,可直接在 Keil C51 或 SDCC 环境下编译使用。

```c
/*----------------------------------------------------------------------------
*  长按/短按按键检测 (STC8G1K08A)
*  P5.5 按键: 短按 (<3s) 翻转 P3.2, 长按 (≥3s) 翻转 P3.3
*  定时器1中断 (10ms), 状态机消抖, 非阻塞
*----------------------------------------------------------------------------*/

#include <STC8G.h>                       /* STC8G 系列寄存器头文件 */

/*-------------------------- 端口定义 --------------------------------------*/
sbit KEY = P5^5;                         /* 按键输入 (低电平有效) */
sbit OUT_SHORT = P3^2;                   /* 短按输出 */
sbit OUT_LONG  = P3^3;                   /* 长按输出 */

/*-------------------------- 时间常数 --------------------------------------*/
#define TICK_MS           10             /* 定时器中断周期 (ms) */
#define DEBOUNCE_TICKS     3             /* 消抖时间 = 3 × 10ms = 30ms */
#define LONG_PRESS_TICKS 300             /* 长按时间 = 300 × 10ms = 3.0s */

/*-------------------------- 按键状态机枚举 --------------------------------*/
enum KEY_STATE {
    KEY_STATE_IDLE,                      /* 空闲状态 */
    KEY_STATE_DEBOUNCE,                  /* 消抖状态 */
    KEY_STATE_PRESSED,                   /* 按下计数状态 */
    KEY_STATE_LONG_PRESSED               /* 长按已触发状态 */
};

/*-------------------------- 静态全局变量 ----------------------------------*/
static enum KEY_STATE key_state = KEY_STATE_IDLE;  /* 当前状态 */
static unsigned char  debounce_cnt;                /* 消抖计数器 */
static unsigned int   press_duration;              /* 按下持续时间 (10ms 单位) */

/*-------------------------- 定时器1初始化 ---------------------------------*/
/* 系统时钟假设为 24MHz, Timer1 12T模式, 16位自动重载
* 计数频率 = 24MHz / 12 = 2MHz
* 10ms 需要计数 20000 次
* 重载值 = 65536 - 20000 = 45536 (0xB1E0)
*/
static void Timer1_Init(void)
{
    AUXR &= ~(1 << 6);                  /* Timer1 12T模式 (清除 T1x12 位) */
    TMOD &= 0x0F;                       /* 清除 Timer1 模式位 */
    TMOD |= 0x00;                       /* Timer1 模式0 (16位自动重载) */
    TH1 = 0xB1;                         /* 重载值高字节 */
    TL1 = 0xE0;                         /* 重载值低字节 */
    ET1 = 1;                            /* 使能 Timer1 中断 */
    TR1 = 1;                            /* 启动 Timer1 */
    EA  = 1;                            /* 开启总中断 */
}

/*-------------------------- 端口初始化 ------------------------------------*/
static void Port_Init(void)
{
    /* P3.2, P3.3 配置为推挽输出 */
    P3M1 &= ~0x0C;                      /* 清除对应位: 输入模式清除 */
    P3M0 |=  0x0C;                      /* 设置推挽输出 */
    OUT_SHORT = 0;                      /* 初始低电平 */
    OUT_LONG  = 0;

    /* P5.5 配置为准双向口 (带弱上拉) */
    P5M1 &= ~0x20;                      /* 清除 P5.5 对应位 */
    P5M0 &= ~0x20;                      /* 准双向模式 */
}

/*-------------------------- 按键扫描 (在中断中调用) -----------------------*/
static void Key_Scan(void)
{
    unsigned char key_down = (KEY == 0);   /* 读取按键: 0=按下, 1=释放 */

    switch (key_state)
    {
        case KEY_STATE_IDLE:
            if (key_down)
            {
                key_state = KEY_STATE_DEBOUNCE;
                debounce_cnt = 0;
            }
            break;

        case KEY_STATE_DEBOUNCE:
            if (key_down)
            {
                debounce_cnt++;
                if (debounce_cnt >= DEBOUNCE_TICKS)
                {
                    /* 按键稳定按下 */
                    key_state = KEY_STATE_PRESSED;
                    press_duration = 0;
                }
            }
            else
            {
                /* 抖动干扰, 返回空闲 */
                key_state = KEY_STATE_IDLE;
            }
            break;

        case KEY_STATE_PRESSED:
            if (key_down)
            {
                press_duration++;
                if (press_duration >= LONG_PRESS_TICKS)
                {
                    /* 长按阈值到达, 翻转长按输出 */
                    OUT_LONG = !OUT_LONG;
                    key_state = KEY_STATE_LONG_PRESSED;
                }
            }
            else
            {
                /* 按键释放, 判断是否为短按 */
                if (press_duration < LONG_PRESS_TICKS)
                {
                    OUT_SHORT = !OUT_SHORT;   /* 翻转短按输出 */
                }
                key_state = KEY_STATE_IDLE;
            }
            break;

        case KEY_STATE_LONG_PRESSED:
            if (!key_down)                   /* 等待按键释放 */
            {
                key_state = KEY_STATE_IDLE;
            }
            break;

        default:
            key_state = KEY_STATE_IDLE;
            break;
    }
}

/*-------------------------- Timer1 中断服务函数 ---------------------------*/
void Timer1_ISR(void) interrupt 3        /* Timer1 中断向量号为 3 */
{
    TF1 = 0;                             /* 清除中断标志 (自动重载模式下仍需手动清除) */
    Key_Scan();                          /* 每10ms扫描一次按键 */
}

/*-------------------------- 主函数 ---------------------------------------*/
void main(void)
{
    Port_Init();                         /* 配置 I/O 口 */
    Timer1_Init();                       /* 启动定时器中断 */

    while (1)
    {
        /* 主循环可添加其他任务, 按键处理完全由中断完成, 非阻塞 */
    }
}
```

## 关键设计说明

1. **定时器中断周期**  
   使用 Timer1 的 16 位自动重载模式,每 10ms 产生一次中断。系统时钟为 24MHz 时,重载值计算正确;若实际时钟频率不同,需调整 `TH1`、`TL1` 的初值。

2. **按键消抖**  
   消抖时间设为 30ms(3 个中断周期)。只有当按键电平连续稳定 30ms 后,才确认为有效按下,避免机械抖动误判。

3. **长/短按判别**  
   - 在 `KEY_STATE_PRESSED` 状态中,每 10ms 累加 `press_duration`。  
   - 若累加值达到 `LONG_PRESS_TICKS` (300 次 = 3 秒),立即触发长按动作(翻转 P3.3),并转入 `KEY_STATE_LONG_PRESSED` 状态,等待按键释放。  
   - 若按键在达到 3 秒前释放,则视为短按,翻转 P3.2。

4. **非阻塞设计**  
   所有按键处理均在定时器中断服务程序中完成,主循环完全空闲,可任意添加其他实时任务而不会阻塞按键响应。

5. **符合 C89 规范**  
   - 使用 `/* ... */` 注释,避免 `//` 注释。  
   - 变量声明均位于函数开头(代码块起始处)。  
   - 静态内存分配(`static` 变量),无动态内存申请。  
   - 无递归调用。

## 引脚配置说明

| 引脚 | 功能               | 配置                   |
|------|--------------------|------------------------|
| P5.5 | 按键输入 (低有效)  | 准双向口 (弱上拉)      |
| P3.2 | 短按输出           | 推挽输出 (初始低电平)  |
| P3.3 | 长按输出           | 推挽输出 (初始低电平)  |

## 编译与烧录注意事项

- 若使用 **Keil C51**,请将项目芯片型号设置为 `STC8G1K08A` 或 `STC8G` 系列,并确保包含 `STC8G.h` 头文件。  
- 若使用 **SDCC**,需将 `sbit` 语法替换为 `__sbit`,并包含相应的头文件。  
- 定时器重载值基于 **24MHz** 系统时钟计算,若实际时钟频率不同,需根据公式 `重载值 = 65536 - (系统时钟频率 / 12) × TICK_MS / 1000` 调整。  

该设计简洁、可靠,可直接应用于实际产品中。

回复

使用道具 举报 送花

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-3-27 05:52 , Processed in 0.099486 second(s), 46 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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