用独立按键控制LED灯显示二进制(普中51开发板)

这是独立按键控制章节的第三个小实验了,其中也应用到了很多前面两节的知识了,延时函数和应用十六进制和加加运算控制二进制显示。

图1

图1还是老样子,延时函数,用函数和while语句去控制循环次数 。

图2

控制二进制时需要知道,二进制是什么,在这里不做过多解释。用标识符char来定义变量,因为控制显示二进制需要循环128次,而char定义的字符正好可以循环128次。第一步if语句判读按键是否按下,while语句则对按键再次进行判断(严谨点),lednum++则是控制二进制+1的,将二进制的值赋给P0(LED灯),进行显示,因为char的容量是128位,所以只能实现128次。 

新手小白学习嵌入式,不喜请勿喷,欢迎各位大佬在评论区指点一二,也欢迎跟我一样的同学互相交流,谢谢了。

 

 

<think>我们基于普中A2开发板(通常使用51单片机,如STC89C52)来实现四个按键控制四种LED功能。根据引用内容,我们了解到: 1. 按键检测:按键连接到P3口,按下时对应引脚为低电平(0),松开为高电平(1)。 2. LED控制:通常使用P2口(或P0口,但P0需要上拉电阻,普中开发板一般已处理好)控制LED,低电平点亮(共阳)或高电平点亮(共阴)。根据引用[1][2][3][4][5],我们这里假设LED是共阴连接(即低电平点亮),因为引用[1]中按键按下为0,LED控制也是低电平点亮(P2_0=0点亮)。但注意,引用[3]中流水程序使用P2口,且赋值0xfe(11111110)点亮第一个,说明是低电平点亮(共阳则是高电平点亮)。为了统一,我们按照低电平点亮(共阴)来设计。 根据普中A2开发板的原理图(由于未提供,我们按照常规设计): - 假设4个独立按键分别连接在P3^0, P3^1, P3^2, P3^3(对应K1, K2, K3, K4) - LED使用P2口,共8个LED(低电平点亮) 功能分配: 按键1(P3^0):控制LED亮灭(即按下点亮,松开熄灭,但这里我们设计为按下一次切换状态,即按一次亮,再按一次灭) 按键2(P3^1):LED每2秒闪烁一次(按下后进入该模式,LED以2秒周期闪烁,即亮1秒灭1秒) 按键3(P3^2):流水程序(按下后开始流水,每个LED依次点亮) 按键4(P3^3):LED显示二进制(按下后,LED显示0~255的二进制计数,每次加1,间隔一定时间) 注意:由于四个按键分别控制不同的模式,我们需要在程序中通过变量记录当前模式,并且每次只能有一个模式运行(或切换模式时停止上一个模式)。但也可以设计为按键按下时执行一次,然后回到初始状态(无模式),但这样无法持续。这里我们设计为:按下某个按键,进入相应模式,并持续执行该模式,直到按下其他按键。 因此,我们定义: unsigned char mode = 0; // 0:初始状态(所有LED灭) 1:按键1模式(单个LED亮灭切换) 2:2秒闪烁 3:流水 4:二进制显示 对于模式1(按键1控制亮灭切换),我们设计为:按下按键1,LED状态切换(如果当前是亮则灭,灭则亮)。注意:这里我们只用一个LED(比如P2^0)来演示。 由于按键需要消抖,我们采用简单的延时消抖。 程序框架: main函数中循环检测按键,根据当前模式执行相应的LED效果。 注意:在模式执行过程中,需要不断检测按键,以便随时切换模式。 我们将使用定时器来产生精确延时(避免使用Delay函数导致按键检测不灵敏),但为了简单,我们先使用Delay函数(实际中不推荐,因为会阻塞)。这里为了演示,我们采用非阻塞方式,使用定时器中断来计时。 但考虑到复杂度,我们先使用带延时的消抖,并且每个模式中可能使用延时,这样会导致按键响应不够及时。因此,我们采用状态机的方式,每个模式中不写长延时,而是用定时器中断来计时。 然而,根据要求,我们尽量简单实现。这里我们使用一个定时器中断来提供时间基准,用于按键扫描和模式中的计时。 步骤: 1. 初始化定时器,设置定时器中断(比如1ms中断一次) 2. 定义全局变量用于计时(按键消抖计时、闪烁计时、流水移位计时、二进制计数计时) 3. 在中断服务函数中更新计时变量 4. 主循环中根据当前模式执行相应操作,并检测按键 由于代码较长,我们分步骤实现。 我们选择定时器0,模式1(16位定时),系统晶振11.0592MHz,定时1ms。 定时器初值计算: 定时1ms = 1000us 机器周期 = 12 / 11.0592MHz ≈ 1.085us 计数次数 = 1000 / 1.085 ≈ 921 则初值 = 65536 - 921 = 64615 = 0xFC17 初始化定时器0: TMOD = 0x01; // 定时器0,工作方式1 TH0 = 0xFC; TL0 = 0x17; ET0 = 1; // 允许定时器0中断 EA = 1; // 开总中断 TR0 = 1; // 启动定时器0 定义全局变量: unsigned int time_count = 0; // 用于1ms计数 unsigned char key_scan_count = 0; // 按键扫描计数 bit key_scan_flag = 0; // 按键扫描标志,每10ms扫描一次 // 按键相关 unsigned char key_value = 0; // 当前按键值 unsigned char key_last = 0; // 上一次按键值(用于消抖) unsigned char key_down = 0; // 按键按下事件(下降沿) // 模式相关 unsigned char mode = 0; // 当前模式 unsigned int flash_count = 0; // 闪烁计时 bit flash_state = 0; // 闪烁状态(0灭1亮) unsigned int flow_count = 0; // 流水计时 unsigned char flow_index = 0; // 流水索引 unsigned int bin_count = 0; // 二进制计数计时 unsigned char bin_value = 0; // 二进制计数值 中断服务函数: void timer0() interrupt 1 { TH0 = 0xFC; TL0 = 0x17; // 重装初值 time_count++; if (time_count % 10 == 0) // 10ms { key_scan_flag = 1; // 设置按键扫描标志 } } 主函数: main() { // 初始化 TMOD = 0x01; TH0 = 0xFC; TL0 = 0x17; ET0 = 1; EA = 1; TR0 = 1; P2 = 0xFF; // 初始LED全灭 while(1) { if (key_scan_flag) // 每10ms扫描一次按键 { key_scan_flag = 0; key_scan(); // 按键扫描函数 } switch (mode) { case 0: // 初始状态,所有LED灭 P2 = 0xFF; break; case 1: // 按键1控制亮灭切换(这里我们假设用P2^0) // 这个模式在按键按下切换时已经改变了状态,所以不需要在这里做持续操作 // 但注意:模式1是切换一次后保持状态,所以这里不需要操作,保持当前P2的状态即可 // 但是,我们可以在模式1时,只控制P2^0,其他LED灭?根据要求,我们只用一个LED // 我们可以在切换模式时,初始化状态 break; case 2: // 2秒闪烁(周期2秒,亮1秒灭1秒) if (flash_count < 1000) // 1000ms=1秒 { // 等待 } else { flash_count = 0; flash_state = !flash_state; if (flash_state) P2 = 0x00; // 全部亮(但要求是单个LED?这里我们指定P2^0) else P2 = 0xFF; // 全部灭?但要求是单个LED,所以我们只控制P2^0 // 修改:我们只控制一个LED(P2^0),所以: // P2 = flash_state ? 0xFE : 0xFF; // 0xFE: 11111110(P2^0亮) 0xFF: 灭 // 但这样会改变其他LED,所以我们用位操作 P2_0 = !flash_state; // 因为低电平点亮,所以当flash_state为1(亮)时,P2_0=0;灭时P2_0=1(高电平) // 但是注意,其他LED要保持不变,所以不能直接赋值,应该只改变P2_0 // 我们可以:P2 = (P2 & 0xFE) | (flash_state?0x00:0x01); 这样不对 // 正确:当需要亮(flash_state=1)时,P2_0=0;灭时P2_0=1 // 所以:P2 = (P2 & 0xFE) | (flash_state?0:1); // 但这样写复杂,我们使用位操作:P2_0 = flash_state?0:1; 但是注意,flash_state取反,因为亮对应0 // 我们定义:flash_state=1表示亮,那么P2_0=0;flash_state=0表示灭,P2_0=1 // 所以:P2_0 = ~flash_state; // 这样不对,因为~flash_state是取反,比如flash_state=1,~1=0xFE(整个字节),赋值给P2_0会出错 // 正确做法:用位操作 if (flash_state) P2 &= 0xFE; // 将P2.0置0(亮) else P2 |= 0x01; // 将P2.0置1(灭) } break; case 3: // 流水 if (flow_count >= 500) // 500ms移动一次 { flow_count = 0; // 流水移动(8个LED) // 从P2^0到P2^7依次点亮 P2 = ~(0x01 << flow_index); // 因为低电平点亮,所以取反:初始flow_index=0,则0x01左移0位还是0x01,取反为0xFE(11111110)第一个亮 flow_index++; if (flow_index >= 8) flow_index = 0; } break; case 4: // LED显示二进制 if (bin_count >= 200) // 200ms加一次 { bin_count = 0; bin_value++; P2 = ~bin_value; // 因为低电平点亮,所以二进制数取反后输出(0亮,1灭,所以直接取反:比如0x00取反0xFF全灭,0x01取反0xFE,P2^0亮) // 注意:这样是低8位二进制,从0到255循环 } break; } } } 按键扫描函数: void key_scan() { unsigned char key_now = P3 & 0x0F; // 取P3的低4位(K1~K4) if (key_now != key_last) // 有变化 { key_last = key_now; return; // 跳过,等待下一次稳定 } // 如果稳定,检测按键按下(下降沿:之前为0xF,现在不为0xF) if (key_now != 0x0F) // 有按键按下 { if (key_down == 0) // 之前没有按下事件 { key_down = 1; // 标记按下事件 // 根据按键值切换模式 switch (key_now) { case 0x0E: // 1110,K1按下(P3^0) mode = 1; // 在模式1下,每次按下按键1,切换LED状态(这里我们只控制P2^0) // 注意:这里我们设计为按下按键1就切换状态 static bit led_state = 1; // 初始灭(高电平) led_state = !led_state; P2 = (P2 & 0xFE) | (led_state?0x01:0x00); // 如果led_state=0(亮),则P2.0=0;led_state=1(灭),P2.0=1 // 或者:P2_0 = led_state; // 因为led_state=1灭(高电平),0亮(低电平) break; case 0x0D: // 1101,K2按下(P3^1) mode = 2; // 进入闪烁模式,初始化状态 flash_count = 0; flash_state = 0; // 初始灭 // 先熄灭 P2 |= 0x01; // P2.0置1(灭) break; case 0x0B: // 1011,K3按下(P3^2) mode = 3; flow_count = 0; flow_index = 0; break; case 0x07: // 0111,K4按下(P3^3) mode = 4; bin_count = 0; bin_value = 0; break; } } } else { key_down = 0; // 按键释放 } } 注意:在模式1中,我们是在按键按下时立即切换LED状态,并且模式1不需要持续操作(保持状态)。而其他模式需要持续操作(在case中根据计时器改变状态)。 但是,上面的代码在模式2、3、4中,我们使用全局变量flash_count, flow_count, bin_count,这些变量需要在定时器中断中累加。 修改中断函数,增加这些计数(注意:这些计数是16位,在主循环中会清零,所以中断中只对未达到最大值的计数加1,避免在主循环中长时间不处理导致溢出) 我们不在中断中处理这些计数,因为中断只提供时间基准,我们在主循环中判断时间标志。但上面的框架中,计数变量在主循环中并没有累加。所以我们需要在中断中累加。 修改:在中断中,我们设置一个1ms的标志,然后在主循环中检查这个标志并累加计数。但这样会增加主循环的负担。我们在中断中直接累加计数(因为都是unsigned int,最大65535,且我们在主循环中会清零,所以不会溢出)。 修改中断函数: void timer0() interrupt 1 { TH0 = 0xFC; TL0 = 0x17; // 重装初值 time_count++; if (time_count % 10 == 0) // 10ms { key_scan_flag = 1; // 设置按键扫描标志 } // 模式2的计数 if (mode == 2) flash_count++; // 模式3的计数 if (mode == 3) flow_count++; // 模式4的计数 if (mode == 4) bin_count++; } 注意:这样会导致即使不在该模式,也会累加,但进入该模式时我们会清零,所以没关系。而且,只有当前模式对应的计数会被使用。 但是,这样中断服务函数会变长,如果模式很多,中断会占用较长时间。我们可以只在主循环中累加,但需要保证主循环执行速度很快。 我们修改:在主循环中,根据模式累加计数。这样,我们就不在中断中累加模式计数了。 因此,我们去掉中断中对模式计数的累加,改为在主循环中累加。但是,我们需要知道1ms的时间,所以我们在中断中设置一个标志,比如ms_flag,每1ms置1一次。 修改: 中断中: static unsigned int ms_count = 0; ms_count++; if (ms_count >= 1) // 1ms { ms_flag = 1; ms_count = 0; } 主循环中: if (ms_flag) { ms_flag = 0; if (mode == 2) flash_count++; if (mode == 3) flow_count++; if (mode == 4) bin_count++; } 但这样会使得主循环中每次只加1,而中断1ms一次,所以累加是1ms加一次。 然而,为了简化,我们直接使用中断中的time_count(每1ms加1),然后在主循环中判断: if (mode == 2) flash_count = time_count; // 这样不行,因为time_count一直在加 或者,我们在进入模式时记录一个开始时间,然后计算差值。这样更复杂。 我们回到最初:在中断中只更新一个全局的时间戳,然后在主循环中,我们记录进入模式时的时间戳,然后计算差值。这样需要额外的变量。 为了简单,我们采用第一种方法:在中断中根据模式累加计数(因为模式切换时我们会清零计数,所以不会溢出)。 因此,我们保留在中断中累加模式计数。 总结:由于时间关系,我们采用在中断中累加模式计数(仅当处于该模式时,我们才在中断中累加该模式的计数)。但注意,中断中不能有太多分支。我们可以在中断中只累加一个全局时间戳,然后在主循环中计算每个模式的时间差,但这样更复杂。 我们修改:在中断中,我们只更新时间戳(每1ms加1),然后在主循环中,如果处于某个模式,则用当前时间戳减去进入模式时的时间戳,得到计数。这样需要记录每个模式进入的时刻。 我们选择简单处理:在中断中累加模式计数(因为模式不多,中断中只增加几个变量,且都是无符号整数,操作很快)。 最终中断函数: void timer0() interrupt 1 { TH0 = 0xFC; TL0 = 0x17; time_count++; // 每10ms设置按键扫描标志 if (time_count % 10 == 0) key_scan_flag = 1; // 模式计数 switch (mode) { case 2: flash_count++; break; case 3: flow_count++; break; case 4: bin_count++; break; default: break; } } 注意:在模式0和1中,我们不累加这些计数。 现在,我们编写完整代码。由于代码较长,我们分模块。 注意:在模式1中,我们是在按键扫描函数中直接切换LED状态,所以主循环中模式1的case不需要做任何操作。 另外,在切换模式时,我们需要初始化一些变量,并且可能需要改变LED状态。 我们开始写代码: 注意:由于开发板上的LED连接方式,请根据实际修改。这里假设低电平点亮。 代码中使用的位操作:P2_0,这是C51的扩展语法,可以直接操作位。如果编译器不支持(如sbit),我们可以用位运算。 定义sbit: sbit K1 = P3^0; sbit K2 = P3^1; sbit K3 = P3^2; sbit K4 = P3^3; sbit LED0 = P2^0; 但是,在按键扫描函数中,我们使用整个P3口读取,所以用P3。 我们使用寄存器位操作和字节操作混合。 完整代码: #include <REGX52.H> // 包含STC89C52的头文件 // 定义按键对应的引脚(也可以不用,直接使用P3) sbit K1 = P3^0; sbit K2 = P3^1; sbit K3 = P3^2; sbit K4 = P3^3; // 定义LED(这里我们只用一个LED,但流水二进制显示需要8个) // 我们直接操作P2口 // 全局变量 unsigned int time_count = 0; // 1ms计数 bit key_scan_flag = 0; // 按键扫描标志(10ms) unsigned char key_value = 0; // 当前按键值 unsigned char key_last = 0; // 上一次按键值 bit key_down = 0; // 按键按下事件标志 unsigned char mode = 0; // 当前模式 // 模式2相关 unsigned int flash_count = 0; // 闪烁模式计时 bit flash_state = 0; // 闪烁状态(0灭,1亮) // 模式3相关 unsigned int flow_count = 0; // 流水计时 unsigned char flow_index = 0; // 流水索引 // 模式4相关 unsigned int bin_count = 0; // 二进制计数计时 unsigned char bin_value = 0; // 二进制计数值 // 模式1的状态(独立,因为模式1是切换后保持) bit led_state = 1; // 模式1的LED状态(1灭,0亮) // 函数声明 void key_scan(void); void timer0_init(void); void main() { timer0_init(); // 定时器初始化 P2 = 0xFF; // 初始化LED全灭 while(1) { if (key_scan_flag) { key_scan_flag = 0; key_scan(); } switch (mode) { case 0: // 所有LED灭(已经在初始化做了) break; case 1: // 模式1不需要持续操作,因为按键按下时已经改变了LED状态 break; case 2: // 闪烁模式 if (flash_count >= 1000) // 1000ms=1秒 { flash_count = 0; // 清零计数器 flash_state = !flash_state; // 状态翻转 if (flash_state) { // 亮:将P2.0置0(低电平点亮) P2 &= 0xFE; // 11111110,其他位不变 } else { // 灭:将P2.0置1 P2 |= 0x01; } } break; case 3: // 流水 if (flow_count >= 500) // 500ms { flow_count = 0; // 流水移动 P2 = ~(0x01 << flow_index); // 取反:低电平点亮,所以取反后,对应位为0则亮,其他为1灭 flow_index++; if (flow_index >= 8) flow_index = 0; } break; case 4: // 二进制显示 if (bin_count >= 200) // 200ms { bin_count = 0; bin_value++; P2 = ~bin_value; // 直接取反,因为低电平点亮 } break; } } } // 定时器0初始化 void timer0_init() { TMOD &= 0xF0; // 清除T0的控制位 TMOD |= 0x01; // T0工作方式1 TH0 = 0xFC; TL0 = 0x17; ET0 = 1; EA = 1; TR0 = 1; } // 定时器0中断服务函数 void timer0_isr() interrupt 1 { TH0 = 0xFC; TL0 = 0x17; time_count++; // 每10ms设置按键扫描标志 if (time_count % 10 == 0) { key_scan_flag = 1; } // 根据模式增加计数 switch (mode) { case 2: flash_count++; break; case 3: flow_count++; break; case 4: bin_count++; break; default: break; } } // 按键扫描函数 void key_scan() { key_value = P3 & 0x0F; // 读取P3口低4位 if (key_value != key_last) // 有变化 { key_last = key_value; return; } // 按键值稳定 if (key_value != 0x0F) // 有按键按下 { if (key_down == 0) // 检测到下降沿(之前没有按下) { key_down = 1; // 标记已按下 // 判断哪个按键 switch (key_value) { case 0x0E: // K1(P3^0)按下 mode = 1; led_state = !led_state; // 状态翻转 if (led_state) { // 灭:P2.1置1 P2 |= 0x01; } else { // 亮:P2.0置0 P2 &= 0xFE; } break; case 0x0D: // K2(P3^1)按下 mode = 2; flash_count = 0; flash_state = 0; // 初始为灭 // 先确保LED灭 P2 |= 0x01; break; case 0x0B: // K3(P3^2)按下 mode = 3; flow_count = 0; flow_index = 0; break; case 0x07: // K4(P3^3)按下 mode = 4; bin_count = 0; bin_value = 0; break; } } } else { key_down = 0; // 按键释放 } } 注意:在模式1中,我们每次按下K1,都会切换LED状态(led_state取反),并立即改变P2.0的状态。 在模式2中,我们初始化flash_state=0(灭),然后等待计时到1000ms(1秒)后切换状态。 在模式3中,流水从flow_index=0开始,每500ms移动一次。 在模式4中,bin_value从0开始,每200ms加1,然后取反输出到P2。 请根据实际开发板调整LED的连接(如果LED是共阳,则需要修改输出逻辑)。 由于代码较长,可能需要根据实际调试。 最后,生成相关问题。</think>以下是基于普中A2开发板单片机控制方案,通过四个独立按键分别控制四种LED功能。代码使用Keil C51语法,适用于STC89C52单片机(晶振频率11.0592MHz)。 ### 系统设计 1. **按键分配**(P3口低4位): - K1(P3^0):LED亮灭控制 - K2(P3^1):2秒周期闪烁 - K3(P3^2):流水效果 - K4(P3^3):二进制计数显示 2. **LED连接**:P2口控制8个LED(低电平点亮) ```c #include <REGX52.H> // 全局变量定义 unsigned char mode = 0; // 当前模式(0-4) unsigned int flash_count = 0; // 闪烁计时 bit flash_state = 0; // 闪烁状态 unsigned int flow_count = 0; // 流水计时 unsigned char flow_index = 0; // 流水索引 unsigned int bin_count = 0; // 二进制计时 unsigned char bin_value = 0; // 二进制计数值 bit led_toggle = 1; // LED开关状态(1灭0亮) // 函数声明 void Timer0_Init(void); void Key_Scan(void); void Delay(unsigned int ms); void main() { P2 = 0xFF; // 初始化LED全灭 Timer0_Init(); while(1) { Key_Scan(); // 持续检测按键 // 模式执行 switch(mode) { case 1: // LED亮灭控制(K1) // 模式切换时已执行操作,无需持续操作 break; case 2: // 2秒闪烁(K2) if(flash_count >= 1000) { // 1秒到达 flash_count = 0; flash_state = !flash_state; P2_0 = flash_state; // 控制P2^0引脚 } break; case 3: // 流水(K3) if(flow_count >= 500) { // 500ms到达 flow_count = 0; P2 = ~(0x01 << flow_index); // 移位点亮 flow_index = (flow_index + 1) % 8; } break; case 4: // 二进制显示(K4) if(bin_count >= 200) { // 200ms到达 bin_count = 0; bin_value++; P2 = ~bin_value; // 二进制取反输出 } break; } } } // 定时器0初始化(1ms中断) void Timer0_Init() { TMOD &= 0xF0; // 清除T0设置 TMOD |= 0x01; // 模式1(16位定时) TL0 = 0x18; // 初值设置(1ms@11.0592MHz) TH0 = 0xFC; ET0 = 1; // 启用T0中断 EA = 1; // 全局中断使能 TR0 = 1; // 启动定时器 } // 定时器0中断服务函数 void Timer0_ISR() interrupt 1 { TL0 = 0x18; // 重载初值 TH0 = 0xFC; // 模式计时更新 if(mode == 2) flash_count++; if(mode == 3) flow_count++; if(mode == 4) bin_count++; } // 按键扫描函数 void Key_Scan() { unsigned char key_press = P3 & 0x0F; // 读取P3低4位 if(key_press != 0x0F) { // 有按键按下 Delay(20); // 消抖延时 if(key_press != 0x0F) { switch(key_press) { case 0x0E: // K1(P3^0) mode = 1; led_toggle = !led_toggle; P2_0 = led_toggle; // 切换P2^0状态 break; case 0x0D: // K2(P3^1) mode = 2; flash_count = 0; flash_state = 0; P2 = 0xFF; // 关闭其他LED break; case 0x0B: // K3(P3^2) mode = 3; flow_count = 0; flow_index = 0; break; case 0x07: // K4(P3^3) mode = 4; bin_count = 0; bin_value = 0; break; } while((P3 & 0x0F) != 0x0F); // 等待按键释放 } } } // 延时函数(1ms基准) void Delay(unsigned int ms) { unsigned int i, j; for(i=0; i<ms; i++) for(j=0; j<114; j++); } ``` ### 功能说明 1. **K1控制亮灭** 按下K1切换P2^0的LED状态(亮/灭),其他LED不受影响。 2. **K2控制闪烁** 按下K2后,P2^0的LED以2秒周期闪烁(亮1秒灭1秒),其他LED关闭。 3. **K3控制流水** 按下K3启动流水,8个LED依次点亮(间隔500ms),形成循环流动效果。 4. **K4控制二进制显示** 按下K4后,LED二进制形式显示计数值(0~255),每200ms自动加1。 ### 硬件连接建议 1. 按键连接:K1~K4 → P3.0~P3.3(共阴极设计,按下=低电平)[^1] 2. LED连接:D1~D8 → P2.0~P2.7(低电平点亮) 3. 需在开发板正确配置上拉电阻(普中A2通常已内置) ### 注意事项 1. 定时器中断负责模式计时,确保时间精度 2. 按键扫描包含消抖处理和释放等待 3. 模式切换时自动重置相关变量 4. LED显示采用取反操作:`P2 = ~value`(因低电平点亮) [^1]: 按键按下时与GND接通,返回低电平(0),松开返回高电平(1) [^2]: LED闪烁本质是电平周期性切换,配合延时实现 [^3]: 流水通过位位移操作实现动态效果 [^4]: 二进制显示直接映射计数值到LED状态
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值