找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 463|回复: 0
打印 上一主题 下一主题
收起左侧

atmega8多个按键控制多个LED

[复制链接]
跳转到指定楼层
楼主
ID:1073237 发表于 2025-10-31 23:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
atmega8多个按键控制多个LED
#include <iom8v.h>
#include <macros.h>

#define uchar unsigned char
#define uint unsigned int

// 按键和LED定义
#define KEY_PORT    PIND
#define LED_PORT    PORTC
#define DEBOUNCE_DELAY 10  // 消抖时间10ms
#define SLEEP_DELAY 5000   // 5秒无操作进入睡眠

// 延时函数
void delay_ms(uint ms) {
    uint i, j;
    for(i = 0; i < ms; i++)
        for(j = 0; j < 114; j++);  // 约1ms@8MHz
}

// 初始化外部中断(用于唤醒睡眠)
void wakeup_init(void) {
    // 配置INT0~INT2(PD0~PD2)为下降沿触发
    MCUCR |= (1 << 1) | (1 << 3);  // ISC01=1(INT0下降沿), ISC11=1(INT1下降沿)
    MCUCSR &= ~(1 << 6);           // ISC21=0(INT2下降沿)
    GICR |= (1 << 6) | (1 << 7) | (1 << 5);  // 使能INT0、INT1、INT2中断
}

// 进入睡眠模式(空闲模式):通过机器码直接执行sleep指令
void enter_sleep(void) {
    // 配置为空闲模式(SM1=0, SM0=0)并允许睡眠(SE=1)
    MCUCR &= ~((1 << 1) | (1 << 0));  // 空闲模式
    MCUCR |= (1 << 7);                // 允许睡眠

    // 写入sleep指令的机器码(0x94, 0x8F是AVR sleep指令的16位机器码)
    *(volatile unsigned short *)0x0000 = 0x948F;
}

// 外部中断服务程序(仅用于唤醒)
#pragma interrupt_handler ext_int0_isr:2
void ext_int0_isr(void) {}

#pragma interrupt_handler ext_int1_isr:3
void ext_int1_isr(void) {}

#pragma interrupt_handler ext_int2_isr:4
void ext_int2_isr(void) {}

void main(void) {
    uchar i;
    uchar key_flag[5] = {0};
    uchar key_last[5];
    uchar led_state = 0xFF;
    uint idle_cnt = 0;  // 空闲计数器

    // 配置IO口
    DDRD &= ~0x1F;       // PD0~PD4输入
    PORTD |= 0x1F;       // 使能上拉
    DDRC |= 0x1F;        // PC0~PC4输出
    LED_PORT = led_state;

    // 初始化按键状态
    for(i = 0; i < 5; i++) {
        key_last[i] = (KEY_PORT & BIT(i)) ? 1 : 0;
    }

    // 初始化唤醒中断和全局中断
    wakeup_init();
    SREG |= (1 << 7);  // 使能全局中断

    while(1) {
        uchar key_activity = 0;  // 按键活动标记

        // 按键检测逻辑
        for(i = 0; i < 5; i++) {
            uchar key_current = (KEY_PORT & BIT(i)) ? 1 : 0;

            if(key_current == 0 && key_last[i] == 1) {  // 按下边缘
                delay_ms(DEBOUNCE_DELAY);
                if((KEY_PORT & BIT(i)) == 0 && key_flag[i] == 0) {
                    led_state ^= BIT(i);
                    LED_PORT = led_state;
                    key_flag[i] = 1;
                    key_activity = 1;
                }
            } else if(key_current == 1 && key_last[i] == 0) {  // 释放边缘
                delay_ms(DEBOUNCE_DELAY);
                if((KEY_PORT & BIT(i)) != 0) {
                    key_flag[i] = 0;
                    key_activity = 1;
                }
            }
            key_last[i] = key_current;
        }

        // 无活动时进入睡眠
        if(key_activity) {
            idle_cnt = 0;
        } else {
            idle_cnt++;
            if(idle_cnt >= SLEEP_DELAY) {
                enter_sleep();  // 进入睡眠,等待按键唤醒
                idle_cnt = 0;
            }
        }

        delay_ms(1);  // 计数基准
    }
}


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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