第十届蓝桥杯嵌入式(省赛)程序题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解读:参照第七届蓝桥杯省赛设计

第七届蓝桥杯嵌入式省赛link
多读任务要求,多读任务要求,多读任务要求,需要用到哪些外设?功能如何设计?

这两届的省赛差别不大(客观上来说这届的更简单)
第七届是采集R37模拟电压,设置阈值(按键可调),液位等级实时显示,i2c总线上的AT24C02保存
第十届是采集R37模拟电压,设置阈值(按键可调),电压状态实时显示,这里没有说用AT24C02保存但是我把这个功能加上了,多了一个LED的选择(LED可调)

程序设计用到的资源:
1,LCD
2,ADC
3,按键
4,LED

思路陈述:(一步一步来,做大做强,再创辉煌)

1.先做LCD两面屏幕,屏幕做出来之后可以做按键一和按键二(可以实现功能:LCD两屏切换,第二屏的各选项轮循)
2.再添加ADC采集(可以实现功能:采集模拟电压在LCD显示)
3.做按键三四的功能,电压阈值的调整以及LED的选择调整(这里要求是不能同时将两个状态设置为同一个LED(这个程序设计最关键的地方))
(可以实现功能:第二屏的按键全部可调,但是还没有关联实际功能)
4,关联功能,这里就需要做LED,阈值,以及状态显示的关联(实现所有功能)
5,这里程序设计差不多就完成了,最后添加保存的功能(这里是我自己添加的,设计无要求)

各模块程序设计:

LCD

这里的状态显示添加标志,有三个状态不确定,留标志以便后面关联。
清屏/(更新,占用)(如果不清除第二屏的line3,line9,则切屏两行会显示在第一屏)
这里电压阈值设置为小数,我直接用的float,程序设计中最好不要有浮点运算,耗资源,这里我用的浮点运算(懒,哈哈、、、)

void LCD_Proc(void)
{
  if(ucState==0)											
  {
    LCD_DisplayStringLine(Line1, (u8*)"        Main        ");
		
    
    temp = (float)uiAdc_Val*3.30/4095;//采集值转化
    sprintf((char*)pucStr, "    Volt:  %4.2fV    ", temp);
    LCD_DisplayStringLine(Line5, pucStr);
		
   if(V_Status==1)
	 {sprintf((char*)pucStr, "    Status: Upper        ");//高于阈值
    LCD_DisplayStringLine(Line7, pucStr);}
	 
	  if(V_Status==2)
	 {sprintf((char*)pucStr, "    Status: Lower        ");//低于阈值
    LCD_DisplayStringLine(Line7, pucStr);}
	 
	  if(V_Status==3)
	 {sprintf((char*)pucStr, "    Status: Normal        ");//正常
    LCD_DisplayStringLine(Line7, pucStr);}
	 
    LCD_DisplayStringLine(Line3, (u8*)"                      ");//清屏
	  LCD_DisplayStringLine(Line9, (u8*)"                      ");
	}
  else													
  {
    LCD_DisplayStringLine(Line1, (u8*)"       Setting       ");
 
    sprintf((char*)pucStr, "  Max Volt:%4.2fV         ", max);//最高电压阈值
    if(ucState == 1) LCD_SetBackColor(Red);
    LCD_DisplayStringLine(Line3, pucStr);
    LCD_SetBackColor(Blue);
 
    sprintf((char*)pucStr, "  Min Volt:%4.2fV          ", min);//最低电压阈值
    if(ucState == 2) LCD_SetBackColor(Red);
    LCD_DisplayStringLine(Line5, pucStr);
    LCD_SetBackColor(Blue);

    sprintf((char*)pucStr, "  Upper:LD%d            ",Upper_led);//超过上限
    if(ucState == 3) LCD_SetBackColor(Red);
    LCD_DisplayStringLine(Line7, pucStr);
    LCD_SetBackColor(Blue);
		
		sprintf((char*)pucStr, "  Lower:LD%d             ", Lower_led);//超过下限
    if(ucState == 4) LCD_SetBackColor(Red);
    LCD_DisplayStringLine(Line9, pucStr);
    LCD_SetBackColor(Blue);
  }
}

Key

按键一:加了i2c
按键二:轮循
按键三四(重点)
这里的按键三四注意设置LED选项,要求不能重复,这里是做了1-8-1这种,当两个相等要如何处理?
拿一个举例:

 case 3:(这里是case 3(按键三)里面的case 31		if(++Upper_led>=9)Upper_led=1; 
2       if(Upper_led==Lower_led)//相等处理
3	    if(++Upper_led >= 9) Upper_led = 1;
		break;

第一行:实现功能,按一次加一,范围1-8
第二行第三行:加入限制条件,当Upper_led==Lower_led(两个要显示相同时候)
Upper_led再加一(这里是按键三,做加,所以要+1跳过相同的)

如果是要减,如下:

  case 3:(这里是case 4(按键四)里面的case 31		 if(--Upper_led==0)Upper_led=8;
2		 if(Upper_led==Lower_led)//相等处理
3		 {if(--Upper_led==0)Upper_led=8;}
		 break; 

第一行:实现功能,按一次减一,范围1-8
第二行第三行:加入限制条件,当Upper_led==Lower_led(两个要显示相同时候)
Upper_led再减一(这里是按键四,做减,所以要-1跳过)

void KEY_Proc(void)
{
  unsigned char ucKey_Val;

  ucKey_Val = KEY_Scan();
  if(ucKey_Val != ucKey_Long)
    ucKey_Long = ucKey_Val;
  else
    ucKey_Val = 0;

  switch(ucKey_Val)
  {
case 1:	
        if(ucState==0)	ucState=1;
	      else 
			{
		    pucTh[0]=max*10;  //保存整数,读取时需要转化
		    pucTh[1]=min*10;
            pucTh[2]=Upper_led;
            pucTh[3]=Lower_led;					
            i2c_write(pucTh,0,4);
				ucState=0;
			}
	      break;
case 2:
		    if(++ucState==5)
			  ucState=1;
			  break;
case 3:
     switch(ucState)
		 {
			case 1:
				 max+=0.30;if(max>=3.30) max=3.30; 
				 break;
			case 2:
				 min+=0.30;if(min>=3.30) min=3.30; 
				 break;
      case 3:
				if(++Upper_led>=9)Upper_led=1; 
        if(Upper_led==Lower_led)//相等处理
				if(++Upper_led >= 9) Upper_led = 1;
				break;
      case 4:
				if(++Lower_led>=9)Lower_led=1;
			  if(Upper_led==Lower_led)//相等处理
				 if(++Lower_led>=9)Lower_led=1;
        break;
			}break;
		
case 4:
	   switch(ucState)
		 {
			case 1:
				max-=0.30;if(max<=0.00) max=0.00;
			  break; 
      case 2:
				min-=0.30;if(min<=0.00) min=0.00;
		  	break; 
      case 3:
				if(--Upper_led==0)Upper_led=8;
				if(Upper_led==Lower_led)//相等处理
				{if(--Upper_led==0)Upper_led=8;}
				break; 
      case 4:
				if(--Lower_led==0)Lower_led=8;
			  if(Upper_led==Lower_led)//相等处理
		    {if(--Lower_led==0)Lower_led=8;}
				break; 
     }  break; 
    }
	 }

SysTick_Handler

ADC的采集周期为1s,处于第一屏时LED才会运行,在第二屏设置的时候LED不会运行。

unsigned char led[9]={0,1,2,4,8,16,32,64,128};
void SysTick_Handler(void)
{
  ulTick_ms++;

  if(ulTick_ms%1000 == 0)
	{ 
		ucSec++;
		uiAdc_Val = ADC1_Conv();//获取转化值(采集周期1S)
	}
  
	if(ucState==0)
	{
	 //高于阈值 Normal
	 if(temp>max){V_Status=1;  if(ulTick_ms%200 == 0) ucLed ^= led[Upper_led]; }

	 //低于阈值 Lower
	 if(temp<min){V_Status=2;  if(ulTick_ms%200 == 0) ucLed ^= led[Lower_led]; }
	
	 //正常范围 Upper
	 if((temp<=max)&&(temp>=min)){V_Status=3;ucLed=0X00;}
	}
	else ucLed=0;//切屏关闭LED
	LED_Disp(ucLed);
		
  }

参数保存

在做按键的时候加入了参数的写入,在程序重新运行时候要读出来
所以在主函数中加入参数的读取,如下:

 i2c_read(pucTh,0,4);//i2c读取
	
	max=pucTh[0]/10.0;
	min=pucTh[1]/10.0;
	Upper_led=pucTh[2];
    Lower_led=pucTh[3];
	
	if(max>3.3)max=2.4;  //上电默认2.4V
	if(min>3.3)min=1.2;  //上电默认1.2V
	if(Upper_led>8)Upper_led=1;//上电默认设置为LED1
	if(Lower_led>8)Lower_led=2;//上电默认设置为LED2

整体程序设计如下:

#include "key.h"
#include "led.h"
#include "lcd.h"
#include "usart.h"
#include "adc.h"
#include "at24c02.h"

unsigned int uiAdc_Val;
unsigned char ucState, pucStr[21], pucTh[4];
unsigned char ucLed;
unsigned char ucSec, ucSec1, ucKey_Long;
unsigned long ulTick_ms;
unsigned char V_Status;
unsigned char Upper_led,Lower_led;
float max,min;

void KEY_Proc(void);
void LCD_Proc(void);
void Delay_ms(unsigned char ms);


int main(void)
{
	SysTick_Config(72000);
    KEY_Init();
    LED_Init();
	LCD_Init();
    ADC1_Init();
	i2c_init();
    i2c_read(pucTh,0,4);//i2c读取
	
	max=pucTh[0]/10.0;
	min=pucTh[1]/10.0;
	Upper_led=pucTh[2];
    Lower_led=pucTh[3];
	
	if(max>3.3)max=2.4;  //上电默认2.4V
	if(min>3.3)min=1.2;  //上电默认1.2V
	if(Upper_led>8)Upper_led=1;//上电默认设置为LED1
	if(Lower_led>8)Lower_led=2;//上电默认设置为LED2
	
	while(1)
  {
    KEY_Proc();
    LCD_Proc();
	}
}

void KEY_Proc(void)
{
  unsigned char ucKey_Val;

  ucKey_Val = KEY_Scan();
  if(ucKey_Val != ucKey_Long)
    ucKey_Long = ucKey_Val;
  else
    ucKey_Val = 0;

  switch(ucKey_Val)
  {
case 1:	
        if(ucState==0)	ucState=1;
	      else 
			{
		    pucTh[0]=max*10;  //保存整数,读取时需要转化
				pucTh[1]=min*10;
        pucTh[2]=Upper_led;
        pucTh[3]=Lower_led;					
        i2c_write(pucTh,0,4);
				ucState=0;
			}
	      break;
case 2:
		    if(++ucState==5)
			  ucState=1;
			  break;
case 3:
     switch(ucState)
		 {
			case 1:
				 max+=0.30;if(max>=3.30) max=3.30; 
				 break;
			case 2:
				 min+=0.30;if(min>=3.30) min=3.30; 
				 break;
            case 3:
				if(++Upper_led>=9)Upper_led=1; 
                if(Upper_led==Lower_led)//相等处理
				if(++Upper_led >= 9) Upper_led = 1;
				break;
             case 4:
				if(++Lower_led>=9)Lower_led=1;
			    if(Upper_led==Lower_led)//相等处理
			    if(++Lower_led>=9)Lower_led=1;
        break;
			}break;
		
case 4:
	   switch(ucState)
		 {
			case 1:
				max-=0.30;if(max<=0.00) max=0.00;
			    break; 
            case 2:
				min-=0.30;if(min<=0.00) min=0.00;
		  	    break; 
            case 3:
				if(--Upper_led==0)Upper_led=8;
				if(Upper_led==Lower_led)//相等处理
				{if(--Upper_led==0)Upper_led=8;}
				break; 
            case 4:
				if(--Lower_led==0)Lower_led=8;
			    if(Upper_led==Lower_led)//相等处理
		        {if(--Lower_led==0)Lower_led=8;}
				break; 
         }  break; 
       }
	 }

float temp;
void LCD_Proc(void)
{
  if(ucState==0)											
  {
    LCD_DisplayStringLine(Line1, (u8*)"        Main        ");
		
    
    temp = (float)uiAdc_Val*3.30/4095;
    sprintf((char*)pucStr, "    Volt:  %4.2fV    ", temp);
    LCD_DisplayStringLine(Line5, pucStr);
		
   if(V_Status==1)
	 {sprintf((char*)pucStr, "    Status: Upper        ");//高于阈值
    LCD_DisplayStringLine(Line7, pucStr);}
	 
	  if(V_Status==2)
	 {sprintf((char*)pucStr, "    Status: Lower        ");//低于阈值
    LCD_DisplayStringLine(Line7, pucStr);}
	 
	  if(V_Status==3)
	 {sprintf((char*)pucStr, "    Status: Normal        ");//正常
    LCD_DisplayStringLine(Line7, pucStr);}
	 
    LCD_DisplayStringLine(Line3, (u8*)"                      ");//清屏
	  LCD_DisplayStringLine(Line9, (u8*)"                      ");
	}
  else													
  {
    LCD_DisplayStringLine(Line1, (u8*)"       Setting       ");
 
    sprintf((char*)pucStr, "  Max Volt:%4.2fV         ", max);//最高电压阈值
    if(ucState == 1) LCD_SetBackColor(Red);
    LCD_DisplayStringLine(Line3, pucStr);
    LCD_SetBackColor(Blue);
 
    sprintf((char*)pucStr, "  Min Volt:%4.2fV          ", min);//最低电压阈值
    if(ucState == 2) LCD_SetBackColor(Red);
    LCD_DisplayStringLine(Line5, pucStr);
    LCD_SetBackColor(Blue);

    sprintf((char*)pucStr, "  Upper:LD%d            ",Upper_led);//超过上限
    if(ucState == 3) LCD_SetBackColor(Red);
    LCD_DisplayStringLine(Line7, pucStr);
    LCD_SetBackColor(Blue);
		
		sprintf((char*)pucStr, "  Lower:LD%d             ", Lower_led);//超过下限
    if(ucState == 4) LCD_SetBackColor(Red);
    LCD_DisplayStringLine(Line9, pucStr);
    LCD_SetBackColor(Blue);
  }
}


unsigned char led[9]={0,1,2,4,8,16,32,64,128};
// SysTick中断处理程序
void SysTick_Handler(void)
{
  ulTick_ms++;

  if(ulTick_ms%1000 == 0)
	{ 
		ucSec++;
		uiAdc_Val = ADC1_Conv();//获取转化值(采集周期1S)
	}
  
	if(ucState==0)
	{
	 //高于阈值 Normal
	 if(temp>max){V_Status=1;  if(ulTick_ms%200 == 0) ucLed ^= led[Upper_led]; }

	 //低于阈值 Lower
	 if(temp<min){V_Status=2;  if(ulTick_ms%200 == 0) ucLed ^= led[Lower_led]; }
	
	 //正常范围 Upper
	 if((temp<=max)&&(temp>=min)){V_Status=3;ucLed=0X00;}
	}
	else ucLed=0;//切屏关闭LED
	LED_Disp(ucLed);
		
  }


作者:江多多(在校学生)
版权所有,欢迎保留原文链接进行转载:)

不忘初心,牢记使命,励志成为一名优秀的嵌入式工程师! (我的第十八篇博客)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值