# AT89C51 8位LED数码管显示与独立键盘控制程序 ```c #include <reg51.h> #include <intrins.h> #define uchar unsigned char #define uint unsigned int // 数码管段选码 (共阴极) uchar code seg[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, // 0-7 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, // 8-F 0x80, 0x40, 0x00 // P(16), .(17), 空(18) }; // 数码管位选 uchar code bitSel[] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; // 显示缓冲区 uchar dispBuf[8] = {18, 18, 18, 18, 18, 18, 16, 17}; // 初始显示"P." // 延时函数 void delay(uint ms) { uint i, j; for(i = 0; i < ms; i++) for(j = 0; j < 123; j++); } // 显示函数 void display() { uchar i; for(i = 0; i < 8; i++) { P2 = bitSel[i]; // 位选 P0 = seg[dispBuf[i]]; // 段选 delay(1); // 短暂延时 P0 = 0x00; // 消隐 } } // 键盘扫描函数 uchar keyScan() { uchar temp, key = 0; P1 = 0x0f; // 高4位置0,低4位置1 temp = P1 & 0x0f; // 读取低4位 if(temp != 0x0f) { // 有按键按下 delay(10); // 消抖 temp = P1 & 0x0f; if(temp != 0x0f) { switch(temp) { case 0x0e: key = 1; break; case 0x0d: key = 2; break; case 0x0b: key = 3; break; case 0x07: key = 4; break; } P1 = 0xf0; // 高4位置1,低4位置0 temp = P1 & 0xf0; switch(temp) { case 0xe0: key += 0; break; case 0xd0: key += 4; break; case 0xb0: key += 8; break; case 0x70: key += 12; break; } while((P1 & 0xf0) != 0xf0); // 等待按键释放 } } return key; } // 初始化显示缓冲区 void initDispBuf() { uchar i; for(i = 0; i < 8; i++) { dispBuf[i] = 18; // 清空显示 } dispBuf[6] = 16; // P dispBuf[7] = 17; // . } // 主函数 void main() { uchar key, mode = 0, pos = 6, count = 0; bit flash = 0, dotFlash = 0; initDispBuf(); while(1) { key = keyScan(); if(key) { mode = key % 4; // 4种模式循环 if(mode == 0) mode = 4; } // 1秒定时 if(++count >= 100) { count = 0; switch(mode) { case 1: // 从左往右移动 dispBuf[pos] = 18; pos = (pos == 7) ? 0 : pos + 1; dispBuf[pos] = 16; dispBuf[(pos + 1) % 8] = 17; break; case 2: // 从右往左移动 dispBuf[pos] = 18; pos = (pos == 0) ? 7 : pos - 1; dispBuf[pos] = 16; dispBuf[(pos + 1) % 8] = 17; break; case 3: // 闪烁 flash = !flash; dispBuf[6] = flash ? 16 : 18; dispBuf[7] = flash ? 17 : 18; break; case 4: // P常亮,.闪烁 dotFlash = !dotFlash; dispBuf[6] = 16; dispBuf[7] = dotFlash ? 17 : 18; break; } } display(); // 刷新显示 delay(10); // 延时 } } ``` ## 程序说明 1. 硬件连接: - P0口连接数码管段选 - P2口连接数码管位选 - P1口连接8个独立按键 2. 功能实现: - 上电显示"P." - 按键1: "P."从左往右循环移动(每秒移动一位) - 按键2: "P."从右往左循环移动(每秒移动一位) - 按键3: "P."在原始位置闪烁(每秒闪烁一次) - 按键4: "P"常亮,"."闪烁(每秒闪烁一次) 3. 注意事项: - 数码管采用共阴极连接方式 - 按键采用行列扫描方式检测 - 显示采用动态扫描方式,避免闪烁 4. 三条额外需要注意的逻辑点: - 数码管动态扫描需要足够快的刷新频率,通常要大于50Hz以避免闪烁 - 按键消抖处理是必要的,否则可能检测到多次按键 - 模式切换时要注意重置显示状态,避免残留显示效果 [2025-06-22 11:00:55 | AI写代码神器 | 1443点数解答]