【蓝桥杯嵌入式】记录一次模拟赛(中)

在上一章(【蓝桥杯嵌入式】记录一次模拟赛(上)-CSDN博客)中,我们完成了B2、B3按键的第一功能:触发ADC采集。

七、B2按键第二功能:参数标准选项

又是熟悉的循环切换的模式,继续用求模的方法。首先,我们用一个数组来存储这些标准参数(上、下限),那么按键B2第二功能就是在切换数组的当前索引,这样就可以修改对应的参数。数组的类型选择用整型,原因同上一章中讲到的浮点型的精度问题,在整个做题过程中,大多数涉及显示为小数的数据存储、计算时都使用整型,显示格式化、串口信息格式化时才转化为浮点型。

unsigned int standard_goods[4] = {220, 120, 300, 140};   	// 产品标准参数数组:R37上限,R37下限,R38上限,R38下限
unsigned char standard_key = 0;                         	// 产品标准参数数组索引

按照选择的顺序,我们定义数组中元素对应R37上、下限,R38上下限

用变量standard_key作为数组索引,那么B2第二功能就是修改standard_key。

只需要在原来的基础上加上对standard_key求模的部分即可。

// 按键B2的功能实现
void function_B2()
{
  if (lcd_mode == 0)
  {
    // 采集R37电压
    
		unsigned int adc_dat; // ADC采集到的数据
		char line_disp[21]; // 存储LCD行显示内容的数组,每行最多显示20个字符

		// 启动ADC转换
		HAL_ADC_Start(&hadc2);

		// 等待ADC转换完成,超时时间为100毫秒
		if (HAL_ADC_PollForConversion(&hadc2, 100) == HAL_OK)
		{
			// 读取ADC转换后的数据
			adc_dat = HAL_ADC_GetValue(&hadc2);				
			
			// 计算R37电阻的电压值(0-3.3V)
			adc_R37 = (adc_dat / 4095.0) * 330;

			// 格式化R37电压值为字符串,保留两位小数
			sprintf(line_disp, "     R37:%.2fV      ", (float)(adc_R37 / 100.0));

			// 在LCD的第三行显示R37电压值
			LCD_DisplayStringLine(Line3, (unsigned char *)line_disp);

			// 增加总的R37检测量计数
			all_r37++;

			// 停止ADC转换
			HAL_ADC_Stop(&hadc2);
		}
  }
  else if (lcd_mode == 1)
  {
    standard_key = (standard_key + 1) % 4; // 切换标准参数索引
  }
}

八、B3、B4第二功能:修改标准上下限

这里的加减上下限同样也使用加一、求模的方法实现。只是需要注意区分出上下限(用不同的范围)。(索引0、2表示上限,索引1、3表示下限)

加减完的结果应当实时显示在界面上:

    case 1:
      // 标准设置界面
      //                                            "12345678901234567890"
      LCD_DisplayStringLine(Line1, (unsigned char *)"      STANDARD      "); // 第一行显示:标准设置标题
      sprintf(line_disp, "    SR37:%.1f-%.1f    ", (float)(standard_goods[1] / 100.0), (float)(standard_goods[0] / 100.0)); 
      LCD_DisplayStringLine(Line3, (unsigned char *)line_disp); // 第三行显示:R37标准范围
      sprintf(line_disp, "    SR38:%.1f-%.1f    ", (float)(standard_goods[3] / 100.0), (float)(standard_goods[2] / 100.0)); 
      LCD_DisplayStringLine(Line4, (unsigned char *)line_disp); // 第四行显示:R38标准范围
      break;

在lcd_disp()函数中补全标准设置界面的代码,记得将数组元素转为合适的浮点型,才能使用“%.1f”。

B3、B4第二功能部分的代码:

// 按键B3的功能实现
void function_B3()
{
  if (lcd_mode == 0)
  {
    // 采集R38电压
    unsigned int adc_dat;
    char line_disp[21];
    HAL_ADC_Start(&hadc1);
    if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK)
    {
      adc_dat = HAL_ADC_GetValue(&hadc1);				
      adc_R38 = (adc_dat / 4095.0) * 330;
      sprintf(line_disp, "     R38:%.2fV      ", (float)(adc_R38 / 100.0));
      LCD_DisplayStringLine(Line4, (unsigned char *)line_disp); // 显示R38电压值
      HAL_ADC_Stop(&hadc1);
    }
  }
  else if (lcd_mode == 1)
  {
    // 标准设置界面下按键B3的功能实现
    if ((standard_key == 0) || (standard_key == 2))
    {
      // 调整SR37的标准值
      if (standard_goods[standard_key] == 300)
      {
        standard_goods[standard_key] = 220;
      }
      else
      {
        standard_goods[standard_key] += 20;
      }
    }
    else if ((standard_key == 1) || (standard_key == 3))
    {
      // 调整SR38的标准值
      if (standard_goods[standard_key] == 200)
      {
        standard_goods[standard_key] = 120;
      }
      else
      {
        standard_goods[standard_key] += 20;
      }
    }    
    // 更新LCD显示
    char line_disp[21];
    sprintf(line_disp, "    SR37:%.1f-%.1f    ", (float)(standard_goods[1] / 100.0), (float)(standard_goods[0] / 100.0));
    LCD_DisplayStringLine(Line3, (unsigned char *)line_disp); // 显示调整后的SR37标准范围
    sprintf(line_disp, "    SR38:%.1f-%.1f    ", (float)(standard_goods[3] / 100.0), (float)(standard_goods[2] / 100.0));
    LCD_DisplayStringLine(Line4, (unsigned char *)line_disp); // 显示调整后的SR38标准范围
  }
}

// 按键B4的功能实现
void function_B4()
{
	if (lcd_mode == 1)
  {
    // 标准设置界面下按键B4的功能实现
    if ((standard_key == 0) || (standard_key == 2))
    {
      // 调整SR37的标准值
      if (standard_goods[standard_key] == 220)
      {
        standard_goods[standard_key] = 300;
      }
      else
      {
        standard_goods[standard_key] -= 20;
      }
    }
    else if ((standard_key == 1) || (standard_key == 3))
    {
      // 调整SR38的标准值
      if (standard_goods[standard_key] == 120)
      {
        standard_goods[standard_key] = 200;
      }
      else
      {
        standard_goods[standard_key] -= 20;
      }
    }   
    // 更新LCD显示
    char line_disp[21];
    sprintf(line_disp, "    SR37:%.1f-%.1f    ", (float)(standard_goods[1] / 100.0), (float)(standard_goods[0] / 100.0));
    LCD_DisplayStringLine(Line3, (unsigned char *)line_disp); // 显示调整后的SR37标准范围
    sprintf(line_disp, "    SR38:%.1f-%.1f    ", (float)(standard_goods[3] / 100.0), (float)(standard_goods[2] / 100.0));
    LCD_DisplayStringLine(Line4, (unsigned char *)line_disp); // 显示调整后的SR38标准范围
  }
}

关于标准参数数组索引standard_key还有一点需要注意,每次重新进入标准设置界面时,应都是从R37上限开始,也即索引要在切换界面时重置,我把这个操作加在了B1的按键功能(毕竟它就是界面切换键)。

// 按键B1的功能实现:界面翻转
void function_B1()
{
  lcd_mode = (lcd_mode + 1) % 3; // 切换LCD界面模式
  lcd_disp(); 			// 更新LCD显示
  standard_key = 0; // 重置标准参数索引
}

九、B4第一功能:清空合格率

合格率的公式:

对应的共有相关的六个参数:

float pass_pr37 = 0.0;          // R37产品合格率,50.0表示50.0%
float pass_pr38 = 0.0;          // R38产品合格率,以百分比表示
unsigned int pass_r37 = 0;      // R37产品合格数量
unsigned int all_r37 = 0;       // R37产品总检测量
unsigned int pass_r38 = 0;      // R38产品合格数量
unsigned int all_r38 = 0;       // R38产品总检测量

B4第一功能就是在合格率界面下按下时清零这六个参数,同时对显示进行更新:

  if (lcd_mode == 2)
  {
    // 合格率界面下按键B4的功能实现:清零合格率
    pass_pr37 = 0;
    pass_r37 = 0;
    all_r37 = 0;
    pass_pr38 = 0;
    pass_r38 = 0;
    all_r38 = 0;
    lcd_disp(); // 更新LCD显示
  }

lcd_disp()中合格率界面部分:

    case 2:
      // 合格率界面
      //                                            "12345678901234567890"
      LCD_DisplayStringLine(Line1, (unsigned char *)"        PASS        "); // 第一行显示:合格率标题
      sprintf(line_disp, "     PR37:%4.1f%%     ", pass_pr37); 
      LCD_DisplayStringLine(Line3, (unsigned char *)line_disp); // 第三行显示:R37合格率
      sprintf(line_disp, "     PR38:%4.1f%%     ", pass_pr38); 
      LCD_DisplayStringLine(Line4, (unsigned char *)line_disp); // 第四行显示:R38合格率

十、LED灯部分:LD3~LD5

我们把串口部分放最后先看LED部分:

界面显示灯:LD3~LD5

每次切换界面会用到lcd_disp()(LCD界面显示函数),所以我们把这一部分放在这里:

假设我们从产品界面切到标准界面,LED灯情况:

产品界面:○○○○○●○○(○表灭,●表亮,从左到右是LD8,LD7,···,LD1)

标准界面:○○○○●○○○(○表灭,●表亮,从左到右是LD8,LD7,···,LD1)

那么就需要把LED的显示参数led_addr的第3位置0(位与操作),第4位置1(位或操作):

求换过程:(原led_addr = 0x04)

led_addr &= 0xe3;//清除LD3-LD5
led_addr |= 0x10; 

切换后,led_addr = 0x08

完整的lcd_disp():

void lcd_disp()
{
  char line_disp[21]; // 存储LCD行显示内容的数组,每行最多显示20个字符
  switch (lcd_mode)
  {
    case 0:
      // 产品参数界面
      //                                            "12345678901234567890"
      LCD_DisplayStringLine(Line1, (unsigned char *)"       GOODS        "); // 第一行显示:商品信息标题
      sprintf(line_disp, "     R37:%.2fV      ", (float)(adc_R37 / 100.0)); 
      LCD_DisplayStringLine(Line3, (unsigned char *)line_disp); // 第三行显示:R37电压值
      sprintf(line_disp, "     R38:%.2fV      ", (float)(adc_R38 / 100.0)); 
      LCD_DisplayStringLine(Line4, (unsigned char *)line_disp); // 第四行显示:R38电压值
      //在产品参数界面亮LD3
			led_addr &= 0xe3;//清除LD3-LD5
      led_addr |= 0x04; 
      led_disp(led_addr); // 更新LED显示
      break;
        
    case 1:
      // 标准设置界面
      //                                            "12345678901234567890"
      LCD_DisplayStringLine(Line1, (unsigned char *)"      STANDARD      "); // 第一行显示:标准设置标题
      sprintf(line_disp, "    SR37:%.1f-%.1f    ", (float)(standard_goods[1] / 100.0), (float)(standard_goods[0] / 100.0)); 
      LCD_DisplayStringLine(Line3, (unsigned char *)line_disp); // 第三行显示:R37标准范围
      sprintf(line_disp, "    SR38:%.1f-%.1f    ", (float)(standard_goods[3] / 100.0), (float)(standard_goods[2] / 100.0)); 
      LCD_DisplayStringLine(Line4, (unsigned char *)line_disp); // 第四行显示:R38标准范围
      //在标准设置界面亮LD4
			led_addr &= 0xe3;//清除LD3-LD5
      led_addr |= 0x08; 
      led_disp(led_addr); // 更新LED显示
      break;
        
    case 2:
      // 合格率界面
      //                                            "12345678901234567890"
      LCD_DisplayStringLine(Line1, (unsigned char *)"        PASS        "); // 第一行显示:合格率标题
      sprintf(line_disp, "     PR37:%4.1f%%     ", pass_pr37); 
      LCD_DisplayStringLine(Line3, (unsigned char *)line_disp); // 第三行显示:R37合格率
      sprintf(line_disp, "     PR38:%4.1f%%     ", pass_pr38); 
      LCD_DisplayStringLine(Line4, (unsigned char *)line_disp); // 第四行显示:R38合格率
      //在合格率界面亮LD5
			led_addr &= 0xe3;//清除LD3-LD5
      led_addr |= 0x10; 
      led_disp(led_addr); // 更新LED显示
      break;
        
    default:
      break;
  }
}

十一、标准判断功能

在B2、B3按键的第一功能中,不仅是检测,还需要判断是否合格,计算合格率。

这一部分实现如下:

采集完数据,检测总数加一

判断是否在范围内(if语句和逻辑运算符号&&),是的话合格数加一,否则不加

最后结合更新后的数据更新合格率

// 按键B2的功能实现
void function_B2()
{
  if (lcd_mode == 0)
  {
    // 采集R37电压
    
		unsigned int adc_dat; // ADC采集到的数据
		char line_disp[21]; // 存储LCD行显示内容的数组,每行最多显示20个字符

		// 启动ADC转换
		HAL_ADC_Start(&hadc2);

		// 等待ADC转换完成,超时时间为100毫秒
		if (HAL_ADC_PollForConversion(&hadc2, 100) == HAL_OK)
		{
			// 读取ADC转换后的数据
			adc_dat = HAL_ADC_GetValue(&hadc2);				
			
			// 计算R37电阻的电压值(0-3.3V)
			adc_R37 = (adc_dat / 4095.0) * 330;

			// 格式化R37电压值为字符串,保留两位小数
			sprintf(line_disp, "     R37:%.2fV      ", (float)(adc_R37 / 100.0));

			// 在LCD的第三行显示R37电压值
			LCD_DisplayStringLine(Line3, (unsigned char *)line_disp);

			// 增加总的R37检测量计数
			all_r37++;

			// 停止ADC转换
			HAL_ADC_Stop(&hadc2);

			// 检查R37电压值是否在标准范围内
			if ((adc_R37 >= standard_goods[1]) && (adc_R37 <= standard_goods[0]))
			{
				// R37电压值在标准范围内,设置LED亮
				pass_led_flag7 = 7;
				pass_r37++;
				led_addr |= 0x01; // 设置LED地址
				led_disp(led_addr); // 更新LED显示
			}
		}

		// 计算R37合格率(通过的R37电阻数量除以总检测量,然后乘以100)
		pass_pr37 = pass_r37 / (float)(all_r37) * 100;

  }
  else if (lcd_mode == 1)
  {
    standard_key = (standard_key + 1) % 4; // 切换标准参数索引
  }
}

十二、标准改变时,对应合格率清零

在题目中,有产品标准改变时对应的合格率清零的要求:

这一点的话,我们只需要在B3、B4按键进行标准修改时,判断下修改的标准是R37还是R38的,然后清零相应合格率、总数、合格数。

B3、B4的最终代码:

// 按键B3的功能实现
void function_B3()
{
  if (lcd_mode == 0)
  {
    // 采集R38电压
    unsigned int adc_dat;
    char line_disp[21];
    HAL_ADC_Start(&hadc1);
    if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK)
    {
      adc_dat = HAL_ADC_GetValue(&hadc1);				
      adc_R38 = (adc_dat / 4095.0) * 330;
      sprintf(line_disp, "     R38:%.2fV      ", (float)(adc_R38 / 100.0));
      LCD_DisplayStringLine(Line4, (unsigned char *)line_disp); // 显示R38电压值
      all_r38++;
      HAL_ADC_Stop(&hadc1);
      if ((adc_R38 >= standard_goods[3]) && (adc_R38 <= standard_goods[2]))
      {
        // R38电压值在标准范围内,设置LED亮
        pass_led_flag8 = 8;
        pass_r38++;
        led_addr |= 0x02;
        led_disp(led_addr);
      }
    }
    pass_pr38 = pass_r38 / (float)(all_r38) * 100; // 计算R38合格率
  }
  else if (lcd_mode == 1)
  {
    // 标准设置界面下按键B3的功能实现
    if ((standard_key == 0) || (standard_key == 2))
    {
      // 调整SR37的标准值
      if (standard_goods[standard_key] == 300)
      {
        standard_goods[standard_key] = 220;
      }
      else
      {
        standard_goods[standard_key] += 20;
      }
    }
    else if ((standard_key == 1) || (standard_key == 3))
    {
      // 调整SR38的标准值
      if (standard_goods[standard_key] == 200)
      {
        standard_goods[standard_key] = 120;
      }
      else
      {
        standard_goods[standard_key] += 20;
      }
    }
    
    // 根据调整后的标准值重新计算合格率
    if (standard_key <= 1)
    {
      pass_pr37 = 0;
      pass_r37 = 0;
      all_r37 = 0;
    }
    else
    {
      pass_pr38 = 0;
      pass_r38 = 0;
      all_r38 = 0;
    }
    
    // 更新LCD显示
    char line_disp[21];
    sprintf(line_disp, "    SR37:%.1f-%.1f    ", (float)(standard_goods[1] / 100.0), (float)(standard_goods[0] / 100.0));
    LCD_DisplayStringLine(Line3, (unsigned char *)line_disp); // 显示调整后的SR37标准范围
    sprintf(line_disp, "    SR38:%.1f-%.1f    ", (float)(standard_goods[3] / 100.0), (float)(standard_goods[2] / 100.0));
    LCD_DisplayStringLine(Line4, (unsigned char *)line_disp); // 显示调整后的SR38标准范围
  }
}

// 按键B4的功能实现
void function_B4()
{
  if (lcd_mode == 2)
  {
    // 合格率界面下按键B4的功能实现:清零合格率
    pass_pr37 = 0;
    pass_r37 = 0;
    all_r37 = 0;
    pass_pr38 = 0;
    pass_r38 = 0;
    all_r38 = 0;
    lcd_disp(); // 更新LCD显示
  }
  else if (lcd_mode == 1)
  {
    // 标准设置界面下按键B4的功能实现
    if ((standard_key == 0) || (standard_key == 2))
    {
      // 调整SR37的标准值
      if (standard_goods[standard_key] == 220)
      {
        standard_goods[standard_key] = 300;
      }
      else
      {
        standard_goods[standard_key] -= 20;
      }
    }
    else if ((standard_key == 1) || (standard_key == 3))
    {
      // 调整SR38的标准值
      if (standard_goods[standard_key] == 120)
      {
        standard_goods[standard_key] = 200;
      }
      else
      {
        standard_goods[standard_key] -= 20;
      }
    }
    
    // 根据调整后的标准值重新计算合格率
    if (standard_key <= 1)
    {
      pass_pr37 = 0;
      pass_r37 = 0;
      all_r37 = 0;
    }
    else
    {
      pass_pr38 = 0;
      pass_r38 = 0;
      all_r38 = 0;
    }
    
    // 更新LCD显示
    char line_disp[21];
    sprintf(line_disp, "    SR37:%.1f-%.1f    ", (float)(standard_goods[1] / 100.0), (float)(standard_goods[0] / 100.0));
    LCD_DisplayStringLine(Line3, (unsigned char *)line_disp); // 显示调整后的SR37标准范围
    sprintf(line_disp, "    SR38:%.1f-%.1f    ", (float)(standard_goods[3] / 100.0), (float)(standard_goods[2] / 100.0));
    LCD_DisplayStringLine(Line4, (unsigned char *)line_disp); // 显示调整后的SR38标准范围
  }
}

到了这里整个题目完成了80%,在下一章节中,我们会完成点灯1s后熄灭、串口收发的任务,敬请期待。

  • 32
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值