找回密码
 立即注册
查看: 362|回复: 3

求助 关于stc8g1k08a 代码

[复制链接]
已绑定手机

1

主题

0

回帖

5

积分

新手上路

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

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

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

回复

使用道具 举报 送花

14

主题

1431

回帖

7982

积分

论坛元老

积分
7982
发表于 2026-3-26 21:04:06 | 显示全部楼层
下面提供一个严格符合 **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` 调整。  

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

回复

使用道具 举报 送花

已绑定手机

51

主题

2750

回帖

9613

积分

论坛元老

积分
9613
发表于 2026-3-27 09:03:41 | 显示全部楼层
这个帖子里面有按键检测的例子,包括长按与短按检测

[分享]简单的按键扫描程序
https://www.stcaimcu.com/thread-6445-1-1.html
(出处: 国芯人工智能技术交流网站)
回复

使用道具 举报 送花

已绑定手机

1

主题

3

回帖

13

积分

新手上路

积分
13
发表于 2026-5-11 23:10:23 | 显示全部楼层
angm*** 发表于 2026-3-26 21:04
下面提供一个严格符合 **C89** 标准的实现,使用 **静态内存分配**、**无递归**、**非阻塞** 状态机,通过  ...

等等,为什么我的sdcc没有stc8g.h这个头文件
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-11-7 14:34 , Processed in 0.067452 second(s), 57 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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