利用两个按键分别控制流水灯流动的方向,一个按键按下去之后,流水灯从左往右流动,另一个按键按下后,流水灯从右往左。
该回答引用chatgpt:
这里提供一种基于8051单片机的C语言程序,实现利用两个按键分别控制流水灯流动的方向,一个按键按下去之后,流水灯从左往右流动,另一个按键按下后,流水灯从右往左。
#include <reg51.h>
#define LED_PORT P1
sbit KEY1 = P2^0; //定义按键1对应的引脚为P2.0
sbit KEY2 = P2^1; //定义按键2对应的引脚为P2.1
void delay(unsigned int n)
{
while(n--);
}
void main()
{
unsigned char i = 0;
unsigned char flag = 0; //定义标志位,用来记录流水灯流动方向,0表示从左往右,1表示从右往左
while(1)
{
if(KEY1 == 0) //判断按键1是否被按下
{
delay(1000); //延时去抖动
if(KEY1 == 0)
{
flag = 0; //设置标志位为0,表示流水灯从左往右
}
while(KEY1 == 0); //等待按键1释放
}
if(KEY2 == 0) //判断按键2是否被按下
{
delay(1000); //延时去抖动
if(KEY2 == 0)
{
flag = 1; //设置标志位为1,表示流水灯从右往左
}
while(KEY2 == 0); //等待按键2释放
}
if(flag == 0) //从左往右
{
for(i=0; i<8; i++)
{
LED_PORT = ~(1<<i); //点亮LED
delay(50000); //延时一段时间,控制流水灯的流动速度
}
}
else //从右往左
{
for(i=7; i>=0; i--)
{
LED_PORT = ~(1<<i); //点亮LED
delay(50000); //延时一段时间,控制流水灯的流动速度
}
}
}
}
该程序中,定义了按键1和按键2对应的引脚,以及一个标志位flag用于记录流水灯的流动方向,0表示从左往右,1表示从右往左。在主程序中,通过检测按键1和按键2的状态来改变流水灯的流动方向,然后根据标志位flag的值来控制流水灯的流动方向,从而实现流水灯从左往右和从右往左的切换。延时函数delay用于控制流水灯的流动速度。
这与流水设计、微体系结构背景有关:
因特尔手册:32-bit operands generate a 32-bit result. zero-extended to a 64-bit result in the destination general-purpose register.
为什么?因为部分原因来自于微体系结构(即处理器)内部实现的效率方面的考虑,的是为了消除“部分数据依赖”。
解释如下:
现在的处理器,是基于流水操作的。流水线,让吞吐率变高,虽然总时间会升高(多了交接时间)。
如果流水线很深,有两条指令:读和写,前面的“读”指令不执行结束,后面的“写”指令就无法开始,二者有数据依赖。
这使指令的效率降低。
如果在64位模式做32位操作,对于64位的rax,修改了其低32位eax,而为了不使高32位产生数据依赖(被其他指令依赖),则强制把高32位置为0。
例子如下:
addw %bx, %ax
movl %eax, %ecx
可见,对%ax产生依赖(第一天指令执行完%ax,第二条才能去读%eax)。这种指令有优化的可能性,比如在两条指令间增加有用的其他指令,这样在addw执行同时,先去执行其他指令,而不会触发stop,使movl的流水线等待addw的流水线。
即尽量不用两个数据相关的指令挨在一起。