2024年蓝桥杯物联网省赛

                                   #记录第四次蓝桥杯#

一、题目介绍

二、题目分析

2.1外设分析

        通过对题目解读,一共会用到如下外设和资源:GPIO、OLED、LED、Lora模块、矩阵按键、电位器、继电器等。

        软件层面需要使用到:定时器、中断、ADC

        通信协议:IIC(OLED控制)、SPI(Lora通信)

2.2思路

        我个人看到题目之后,是先从NODE.B开始编写的,除了Lora通信控制的部分,我是先写完NODE.B,再去写NODE.A的。先完成两个模块的一些基本功能(比如OLED显示、继电器控制、AD采集、按键等),最后再实现两边的通信。

三、CUBEMX配置

3.1控制器(NODE.A)

3.1.1引脚图

3.1.2时钟树

3.1.3定时器配置

3.1.4IIC配置

3.1.5 SPI配置

3.1.6 中断配置

定时器和外部中断设置好后,一定要记得使能(enable)

3.1.7GPIO配置

3.2采集器(NODE.B)

3.1.1引脚图

3.1.2ADC设置

ADC使用的是通道8和通道9

其余的配置同NODE.A一致,除了GPIO由于多了几个引脚可能配置不一样。

CUBEMX可能有些地方配置有些多余,这里仅供参考。

四、部分代码

这里只展示主函数部分,详细请看压缩包

4.1NODE.A

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "spi.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "lora.h"
#include "oled.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
void key_check(void);
void lora_proc(void);
void oled_proc(void);
uint16_t Scan_Col1(void);
uint16_t Scan_Col2(void);
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
struct key{
	uint8_t B1;
	uint8_t B2;
	uint8_t B4;
	uint8_t B5;
}key1;
struct show{
	float CV;
	float PV;
	uint8_t K1;
	uint8_t K2;
	uint8_t mode;
}show1;

uint8_t Lora_Txbuff[6];
uint8_t Lora_Rxbuff[7];
uint8_t Strbuff[17];
uint8_t key_value;
uint8_t Tx_flag;

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C3_Init();
  MX_SPI1_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
	//OLED_Init();
	HAL_NVIC_DisableIRQ(TIM2_IRQn);
	HAL_TIM_Base_Start_IT(&htim2);
	LORA_Init();
	
	
	Write(ROW1,RESET);
	Write(ROW2,RESET);
	key_value=0;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		lora_proc();
		key_check();
		oled_proc();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_3;
  RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_I2C3;
  PeriphClkInit.I2c3ClockSelection = RCC_I2C3CLKSOURCE_PCLK1;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	static uint16_t ms=0;
	static uint8_t s=0;
	if(++ms==999)
	{
		ms=0;
		if(++s==3)
		{
			s=0;
			Write(LD5,SET);
			HAL_NVIC_DisableIRQ(TIM2_IRQn);
		}
	}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	
	switch(GPIO_Pin)
	{
		case GPIO_PIN_1:
			key_value=Scan_Col1();
			while(Read(COL1)==0);
			break;
		case GPIO_PIN_0:
			key_value=Scan_Col2();
			while(Read(COL2)==0);
			break;
		default:
			break;
	}
}
	
void key_check(void)
{
	if(key_value != 0)
	{
		switch(key_value)
		{
			case 1:
				key1.B1=1;
				break;
			case 2:
				key1.B2=1;
				static uint8_t oled_flag=1;
				if(oled_flag==1)
				{
					OLED_Init();
					oled_flag=0;
				}
				Write(LD5,RESET);
				HAL_NVIC_EnableIRQ(TIM2_IRQn);
				break;
			case 4:
				key1.B4=1;
				break;
			case 5:
				key1.B5=1;
				break;
			default:
				break;
		}
		Tx_flag=1;
		key_value=0;
	}
}
uint16_t Scan_Col1(void)
{
	static	uint16_t ucKey_val=0;   //设立变量存键值
	HAL_GPIO_WritePin(ROW1,GPIO_PIN_SET);//拉高3列的电平
	HAL_GPIO_WritePin(ROW2,GPIO_PIN_SET);
	//遍历列
	for(uint8_t i=0;i<2;i++)
	{
		HAL_NVIC_DisableIRQ(EXTI0_1_IRQn);//关闭ROW1的中断
		switch(i){
			case 0:
				HAL_GPIO_WritePin(ROW1,GPIO_PIN_RESET);//拉低列1
				if(HAL_GPIO_ReadPin(COL1) == 0)//读取键值
					ucKey_val = 1;
				HAL_GPIO_WritePin(ROW1,GPIO_PIN_SET);//拉高列1
				break;
			case 1:
				HAL_GPIO_WritePin(ROW2,GPIO_PIN_RESET);//拉低列2
				if(HAL_GPIO_ReadPin(COL1) == 0)//读取键值
					ucKey_val = 4;
				HAL_GPIO_WritePin(ROW2,GPIO_PIN_SET);//拉高列2
				break;
			default:
				break;
			}
	}
        //拉低三列的电平
		HAL_GPIO_WritePin(ROW1,GPIO_PIN_RESET);
		HAL_GPIO_WritePin(ROW2,GPIO_PIN_RESET);
        //打开ROW1中断
		HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
 
	return ucKey_val;
}
uint16_t Scan_Col2(void)
{
	static	uint16_t ucKey_val=0;   //设立变量存键值
	HAL_GPIO_WritePin(ROW1,GPIO_PIN_SET);//拉高3列的电平
	HAL_GPIO_WritePin(ROW2,GPIO_PIN_SET);
	//遍历列
	for(uint8_t i=0;i<2;i++)
	{
		HAL_NVIC_DisableIRQ(EXTI0_1_IRQn);//关闭ROW1的中断
		switch(i){
			case 0:
				HAL_GPIO_WritePin(ROW1,GPIO_PIN_RESET);//拉低列1
				if(HAL_GPIO_ReadPin(COL2) == 0)//读取键值
					ucKey_val = 2;
				HAL_GPIO_WritePin(ROW1,GPIO_PIN_SET);//拉高列1
				break;
			case 1:
				HAL_GPIO_WritePin(ROW2,GPIO_PIN_RESET);//拉低列2
				if(HAL_GPIO_ReadPin(COL2) == 0)//读取键值
					ucKey_val = 5;
				HAL_GPIO_WritePin(ROW2,GPIO_PIN_SET);//拉高列2
				break;
			default:
				break;
			}
	}
        //拉低三列的电平
		HAL_GPIO_WritePin(ROW1,GPIO_PIN_RESET);
		HAL_GPIO_WritePin(ROW2,GPIO_PIN_RESET);
        //打开ROW1中断
		HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
 
	return ucKey_val;
}

void lora_proc(void)
{
	if(Tx_flag==1)
	{
		Tx_flag=0;
		Lora_Txbuff[0]='Z';			//数据校验
		Lora_Txbuff[1]=key1.B1;
		Lora_Txbuff[2]=key1.B2;
		Lora_Txbuff[3]=key1.B4;
		Lora_Txbuff[4]=key1.B5;
		Lora_Txbuff[5]='F';
		LORA_Tx(Lora_Txbuff,sizeof(Lora_Txbuff));
		//清空
		key1.B1=0; 
		key1.B2=0;
		key1.B4=0;
		key1.B5=0;
	}
	if(LORA_Rx(Lora_Rxbuff)==6&&Lora_Rxbuff[0]=='Y')
	{
		show1.CV=(float)Lora_Rxbuff[1]/10;
		show1.PV=(float)Lora_Rxbuff[2]/10;
		show1.K1=Lora_Rxbuff[3];
		show1.K2=Lora_Rxbuff[4];
		show1.mode=Lora_Rxbuff[5];
	}
}

void oled_proc(void)
{

	sprintf((char*)Strbuff,"   %.1fV - %.1fV    ",show1.CV,show1.PV);
	OLED_ShowString(0,Strbuff);
	sprintf((char*)Strbuff,"       %d%d%d   ",show1.K1,show1.K2,show1.mode);
	OLED_ShowString(2,Strbuff);
}

4.2NODE.B

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "i2c.h"
#include "spi.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "stdlib.h"
#include "oled.h"
#include "lora.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
void get_adc(void);		//ADC采样控制
void adc_Prog(void);
void para_Prog(void);
void relay_Prog(void);
void show_Prog(void);
void led_prog(void);
void lora_Prog(void);	//Lora通信设置
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint16_t Adc_val[2];
struct Adc{
	
	uint16_t  RP1;    //RP1电压
	uint16_t  RP2;    //RP2电压
	uint16_t  CV;    	//电压差
	uint16_t  PV;     //电压参数
}val;

struct time{
	
	uint16_t  us;    //定时微秒
	uint16_t  ms;    //定时毫秒
	uint16_t  s;     //定时器秒
}time;

uint8_t Lora_Txbuff[6];
uint8_t Lora_Rxbuff[7];
uint8_t Strbuff[17];			//OLED显示字符串
uint8_t dis_Mode;				//模式切换标志位
uint8_t work_Mode;				//模式选择
uint8_t adc_flag;				//ADC采样控制
uint8_t tx_flag;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
	
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC_Init();
  MX_I2C3_Init();
  MX_TIM2_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */
	OLED_Init();
	LORA_Init();                   //lora初始化
	HAL_TIM_Base_Start_IT(&htim2);	//打开定时器2
	dis_Mode=0;
	work_Mode=0;
	val.PV=10;
	adc_flag=1;
	tx_flag=0;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		led_prog();
		show_Prog();
		relay_Prog();
		lora_Prog();
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_3;
  RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_I2C3;
  PeriphClkInit.I2c3ClockSelection = RCC_I2C3CLKSOURCE_PCLK1;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
/*外部中断*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(HAL_GPIO_ReadPin(USER)==0)
		if(++dis_Mode==2)
			dis_Mode=0;
}
/*定时器中断*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(++time.ms==99)
	{
			time.ms=0;
			adc_flag=1;
	}
		
}
void get_adc(void)
{
	HAL_ADC_Start(&hadc);
	if(HAL_ADC_PollForConversion(&hadc,10)==HAL_OK)
		Adc_val[0]=HAL_ADC_GetValue(&hadc);
	if(HAL_ADC_PollForConversion(&hadc,10)==HAL_OK)
		Adc_val[1]=HAL_ADC_GetValue(&hadc);
	val.RP1=(int)(Adc_val[1]*3.3/4095*10);
	val.RP2=(int)(Adc_val[0]*3.3/4095*10);
}
/*ADC显示程序*/
void adc_Prog(void)
{
	sprintf((char*)Strbuff,"    RP1:%.1fV  ",(float)val.RP1/10);
	OLED_ShowString(0,Strbuff);
	sprintf((char*)Strbuff,"    RP2:%.1fV  ",(float)val.RP2/10);
	OLED_ShowString(2,Strbuff);
}
void para_Prog(void)
{
	sprintf((char*)Strbuff,"    CV:%.1fV   ",(float)val.CV/10);
	OLED_ShowString(0,Strbuff);
	sprintf((char*)Strbuff,"    PV:%.1fV   ",(float)val.PV/10);
	OLED_ShowString(2,Strbuff);
}
void relay_Prog(void)
{
	if(work_Mode==0)
	{
		if(val.CV>val.PV)
		{
			HAL_GPIO_WritePin(Relay1,OFF);
			HAL_GPIO_WritePin(Relay2,ON);
		}
		else 
		{
			HAL_GPIO_WritePin(Relay1,ON);
			HAL_GPIO_WritePin(Relay2,OFF);
		}
	}
}

/*OLED显示*/
void show_Prog(void)
{
	if(adc_flag==1)
	{
		get_adc();
		adc_flag=0;
		val.CV=abs(val.RP1-val.RP2);
	}
	if(dis_Mode==0)
		adc_Prog();
	else
		para_Prog();
}
/*LED指示灯*/
void led_prog(void)
{
	if(work_Mode==0)
		HAL_GPIO_WritePin(LD5,OFF);
	else
		HAL_GPIO_WritePin(LD5,ON);
}
void lora_Prog(void)
{
	if(tx_flag==1)
	{
		tx_flag=0;
		Lora_Txbuff[0]='Y';			//数据校验
		Lora_Txbuff[1]=(int)(val.CV);
		Lora_Txbuff[2]=(int)(val.PV);
		Lora_Txbuff[3]=Read(Relay1);
		Lora_Txbuff[4]=Read(Relay2);
		Lora_Txbuff[5]=work_Mode;
		LORA_Tx(Lora_Txbuff,sizeof(Lora_Txbuff));
	}
	if(LORA_Rx(Lora_Rxbuff)==6&&Lora_Rxbuff[0]=='Z'&&Lora_Rxbuff[5]=='F')
	{
		if(Lora_Rxbuff[1]==1)
		{
			if(++work_Mode==2)
				work_Mode=0;
		}
		if(Lora_Rxbuff[2]==1)
		{
			tx_flag=1;
		}
		if(Lora_Rxbuff[3]==1)
		{
			switch(work_Mode)
			{
				case 0:
					val.PV+=1;
					break;
				case 1:
					HAL_GPIO_TogglePin(Relay1);
					break;
				default:
					break;
			}
		}
		if(Lora_Rxbuff[4]==1)
		{
			switch(work_Mode)
			{
				case 0:
					val.PV-=1;
					break;
				case 1:
					HAL_GPIO_TogglePin(Relay2);
					break;
				default:
					break;
			}
		}
	}
}
/* USER CODE END 4 */

五、效果

效果还没拍视频,后期再补上

六、总结与感悟

        这是本人第一次写这么多内容的blog,还有本人语文素养比较低。可能有些措辞不当或者语句不通顺的地方,希望能够指正。

        代码总体来说的话,大部分是自己编写的,有一部分是借鉴网上的大佬的代码。由于本人C语言功底比较薄弱,所以有些语法写的很笨。或许有更好更高效的方法,也希望能给我指出一些建议。

        第四次参加蓝桥杯了,之前参加的是单片机和嵌入式组。今年是第一次参加物联网,也是最后一次参加蓝桥杯了。赛前没有很好的准备,赛场上只完成了部分功能,赛后经过不断完善,基本上将所有功能都实现了。虽然没有在赛场上完成全部功能,但是赛后能把所有功能都实现,也算是不给自己留下太多遗憾了。

七、代码及题目链接

百度网盘:链接:https://pan.baidu.com/s/16Qw5IuQn-rivRKj6Fb_RAg?pwd=h8tu 提取码:h8tu

作者:Aladdin5298

物联沃分享整理
物联沃-IOTWORD物联网 » 2024年蓝桥杯物联网省赛

发表回复