第一讲 决赛试题与过渡模拟一
笔记根据b站教程:
题目1(决赛试题)
后续补充
注意点
1.彩灯设计
从左往右、从右往左—位移操作:
_crol_(位移变量,位移次数) --- a=_cror_(a,1)
_cror_()
2.不要对寄存器直接进行操作,须使用中间变量进行
P1 = ucLed;
3.避免模式4到模式1忽略L1
if(ucLed ==0x7e) //判断是否从模式4切换至模式1 若是,则复位ucLed数据
ucLed == 0xfe;
else
{
ucLed == _cror_(ucLed,1);//模式1 L1-L8
if(ucLed == 0x7f) Led_Mode = 1;//当L8点亮时,跳转到模式2
}
4.数码管闪烁
全部正常显示
case 1://流转时间设置界面
Seg_Buf[0] = 13;
Seg_Buf[1] = Led_Time_Set_Index++;
Seg_Buf[2] = Led_Time_Set[Led_Time_Set_Index] / 1000 %10;
Seg_Buf[3] = Led_Time_Set[Led_Time_Set_Index] / 100 % 10;
Seg_Buf[4] = Led_Time_Set[Led_Time_Set_Index] / 10 % 10;
Seg_Buf[5] = Led_Time_Set[Led_Time_Set_Index] % 10;
设置闪烁时间和取反变量
if(++Timer_400Ms == 400)//400毫秒触发一次
{
Timer_400Ms = 0;
Seg_Star_Flag ^= 1;
}
覆盖闪烁显示
if(Seg_Flag == 0)
{
Seg_Buf[0] = Seg_Star_Flag?13:10;
Seg_Buf[1] = Seg_Star_Flag?Led_Time_Set_Index+1:10;
}
else
{
Seg_Buf[2] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] / 1000 % 10:10;
Seg_Buf[3] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] / 100 % 10:10;
Seg_Buf[4] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] / 10 % 10:10;
Seg_Buf[5] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] % 10:10;
}
避免按下切换按键后再执行一次
case 6://设置切换按键
if(Seg_Disp_Mode == 0)//若在显示界面下使能此按键
{
for(i=0;i<4;i++)//读取当前设置数据
Led_Time_Set[i] = Led_Time_Data[i]
Seg_Disp_Mode = 1;//跳转到参数设置界面
}
else if(Seg_Disp_Mode == 1)//else-为了避免第一次按下后直接执行下列程序 所以需要另外加else使得在执行完if语句后跳转出判断主体
{
Seg_Flag ^= 1;//用于判断设置处于哪个状态的变量
if(Seg_Flag == 0)//第二次跳转到模式设置状态
{
for(i=0;i<4;i++)
Led_Time_Data[i] = Led_Time_Set[i];//保存当前设置数据
Seg_Disp_Mode = 0;
}
}
break;
注释—知识点回忆—异或
结合代码 Seg_Flag ^= 1;
,我们可以更具体地理解异或操作在C51中的应用场景。这行代码的作用是翻转 Seg_Flag
的最低位(即第0位),通常用于切换某个状态标志。
1.代码分析
Seg_Flag ^= 1; // 等价于 Seg_Flag = Seg_Flag ^ 1;
Seg_Flag
是一个变量,用于表示某个状态或标志。^= 1
表示将Seg_Flag
的最低位与1
进行异或操作。
2.异或操作的具体行为:
- 如果
Seg_Flag
的最低位是0
,则0 ^ 1 = 1
,最低位变为1
。 - 如果
Seg_Flag
的最低位是1
,则1 ^ 1 = 0
,最低位变为0
。
因此,这行代码的作用是切换 Seg_Flag
的最低位。
3.结合应用场景
Seg_Flag
是一个用于判断设置处于哪个状态的变量。假设 Seg_Flag
的最低位用于表示某个状态(例如 0
表示状态A,1
表示状态B),那么 Seg_Flag ^= 1;
的作用就是在状态A和状态B之间切换。
示例:
假设 Seg_Flag
的初始值为 0
(状态A):
- 第一次执行
Seg_Flag ^= 1;
:Seg_Flag = 0 ^ 1 = 1
,切换到状态B。
- 第二次执行
Seg_Flag ^= 1;
:Seg_Flag = 1 ^ 1 = 0
,切换回状态A。
通过这种方式,Seg_Flag ^= 1;
可以用于在两个状态之间循环切换。
4.更完整的代码示例
以下是一个更完整的代码示例,展示如何使用 Seg_Flag ^= 1;
来切换状态并执行不同的操作:
#include <reg51.h>
bit Seg_Flag = 0; // 定义一个位变量,用于表示状态
void main() {
while (1) {
if (Seg_Flag == 0) {
// 状态A的操作
P1 = 0x0F; // 例如,设置P1端口的低4位为高电平
} else {
// 状态B的操作
P1 = 0xF0; // 例如,设置P1端口的高4位为高电平
}
// 切换状态
Seg_Flag ^= 1;
// 延时
delay();
}
}
void delay() {
int i, j;
for (i = 0; i < 100; i++)
for (j = 0; j < 100; j++);
}
5.总结
结合 Seg_Flag ^= 1;
这行代码,异或操作在C51中的意义是:
- 切换状态:通过翻转
Seg_Flag
的最低位,可以在两个状态之间切换。 - 高效操作:异或操作是位运算,执行速度快,适合在嵌入式系统中使用。
- 简洁代码:使用
^= 1
可以避免复杂的条件判断,使代码更简洁。
Seg_Flag ^= 1;
用于切换设置状态,可能是为了在设置小时和分钟之间切换,或者在设置闹钟的不同参数之间切换。
按键长按
if(System_Flag == 0)//系统处于暂停状态
{
if(Key_Old == 4 && Seg_Disp_Mode == 0)//在显示界面下长按S4
Data_Disp_Flag = 1;//显示数据
else
Data_Disp_Flag = 0;//显示状态
}
else
Data_Disp_Flag = 0;
LED数据
i = 0;//每次循环判断前将i置0,便于读取Led状态
while(~ucLed & (0x01 << i) == 0)
i++;
题目2(过渡模拟一)—模拟电压采集记录器
后续补充
注意点
1.输入限制
if(Key_Down >= 1 && Key_Down <= 10)//键盘使能条件
{
if(Seg_Disp_Mode == 0 && Seg_Input_Index < 4)
{
Seg_Input[Seg_Input_Index] = Key_Down -1;
Seg_Input_Index++;
Key_Error_Count = 0;
}
else
Key_Error_Count++;
}
2.闪烁避免程序卡死
if(Seg_Buf[5] == 11)//只有当最后一位为-时,才实现数码管闪烁功能
Seg_Buf[2+Seg_Input_Index] = Seg_Flag?Seg_Input[Seg_Input_Index]:10;
3.进位的思路
四舍五入保留两位数字
Voltage = (Seg_Input[0] * 1000 + Seg_Input[1] * 100 + Seg_Input[2] * 10 +Seg_Input[3] +5)/1000.0;
4.Float显示数码管
思路:强制类型转换
Seg_Buf[3] = (unsigned char)Voltage_Parameter % 10;
Seg_Buf[4] = (unsigned int)(Voltage_Parameter * 100) / 10 % 10;
Seg_Buf[5] = (unsigned int)(Voltage_Parameter * 100) % 10;
5.9999mV进位之后为10.0V
Seg_Point[3+(int)Voltage/10] = 1;
6.数码管数据刷新
case 0://电压采集界面
Seg_Point[3+(int)Voltage/10] = 0;
Seg_Buf[0] = Seg_Buf[1] = 10;
for(i = 0;i<4;i++)
Seg_Buf[2+i] = Seg_Input[i];
if(Seg_Buf[5] == 11)//只有当最后一位为-时,才实现数码管闪烁功能
Seg_Buf[2+Seg_Input_Index] = Seg_Flag?Seg_Input[Seg_Input_Index]:10;
break;
case 1://数据显示界面
Seg_Point[3+(int)Voltage / 10] = 1;
Seg_Buf[0] = 12;
Seg_Buf[1] = Seg_Buf[2] = 10;
Seg_Buf[3] = (int)Voltage/10?1:(unsigned char)Voltage % 10;
Seg_Buf[4] = (unsigned int)(Voltage * 100) / 10 % 10;
Seg_Buf[5] = (unsigned int)(Voltage * 100) % 10;
break;
7.高位熄灭
while(Seg_Buf[j] == 0)
{
Seg_Buf[j] = 10;
if(++j == 5) break;
}
8.计数值增加
if(Voltage > Voltage_Parameter_Ctrol)//当实际电压大于参考电压时
Voltage_Flag = 1;//拉高标志位
else if(Voltage_Flag == 1)
{
Voltage_Flag = 0 ;//标志位复位
count++;//计数值+1
}
9.注意LED模块的显示
void Led_Disp(unsigned char addr,ebable)
{
static unsigned char temp = 0x00;
static unsigned char temp_old = 0xff;
if(enable)
temp |= 0x01 << addr;
else
temp &= ~(0x01 << addr);
if(temp != temp_old)
{
P1 =~temp;
temp_old = temp;
}
}
if(++Led_Pos == 8) Led_Pos = 0;
Led_Disp(Led_Pos,ucLed[Led_POS]);
ucLed[1] = Count % 2;
ucLed[2] = Key_Error_Count / 3;
后续或将补充完整代码及题目…