首页 > 其他分享 >stm32笔记[12]-LoRa通信

stm32笔记[12]-LoRa通信

时间:2024-01-18 18:57:30浏览次数:36  
标签:CODE HAL stm32 Init 12 USER GPIO LoRa RCC

摘要

在蓝桥杯物联网的CT127C开发板上测试LoRa通信;Node_A按下按钮触发按键中断,经过定时器消抖后触发LoRa发送函数并切换LED的状态,Node_B接收到数据后在屏幕显示累计次数.

开发环境

  • Keil 5.35.00
  • HAL库版本:STM32Cube FW_L0 V1.12.0
  • STM32CubeMX:6.2.1

原理简介

LoRa简介

[https://www.techphant.cn/blog/69480.html]
[https://zhuanlan.zhihu.com/p/339427181]

  1. LoRa技术是一种低功耗远距离无线通信技术,具有广泛的应用前景。
  2. LoRa采用扩频调制技术,利用长码调制和分散频谱技术,使得其在较低的信噪比下获得更远的传输距离。这一特点使得LoRa技术在城市覆盖和农村地区通信等场景中具有独特的优势。
  3. LoRaWAN协议是在LoRa技术基础上建立的一种开放式标准,能够支持大规模的低功耗无线传感器网络。LoRaWAN使用星型、树型、网状等多种拓扑结构,满足不同应用场景下的通信需求。
  4. LoRa技术特点
  • 长距离传输
      LoRa技术可以在城市环境下达到数公里的通信距离,而在郊区或农村地区,甚至能够实现数十公里的通信距离。这使得LoRa技术在远距离监测、物联网等领域具有广泛的应用前景。
  • 低功耗要求
      LoRa技术适用于电池供电设备,由于其低功耗的特点,可以延长设备的使用寿命,减少更换电池的频率,降低了设备运行和维护成本。
  • 总结
      LoRa技术以其长距离传输和低功耗要求成为物联网领域的热门选择。不仅如此,LoRa技术还具备良好的抗干扰能力、灵活的部署方式和广泛的应用场景。相信随着技术的不断发展,LoRa技术将在更多领域展现出其独特的价值。
  1. LoRa 是LPWAN通信技术中的一种,是美国Semtech公司采用和推广的一种基于扩频技术的超远距离无线传输方案。这一方案改变了以往关于传输距离与功耗的折衷考虑方式,为用户提供一种简单的能实现远距离、长电池寿命、大容量的系统,进而扩展传感网络。目前,LoRa 主要在全球免费频段运行,包括433、868、915MHz等。

ISM频段

[https://www.gov.cn/zhengce/2019-11/28/content_5456762.htm]
[https://www.gov.cn/xinwen/2019-10/13/content_5439016.htm]
中华人民共和国无线电频率划分规定
我国指定用于工业、科学及医疗(产生射频能量,以下简称ISM)应用的频段有哪些?与其他国家或者区域有何不同?
答:在我国,根据《中华人民共和国无线电频率划分规定》及其中脚注5.138和5.150,6765-6795kHz(中心频率6780kHz)、61-61.5GHz(中心频率61.25GHz)、122-123GHz(中心频率122.5GHz)、244-246GHz(中心频率245GHz)频段用于ISM应用,但其使用须经无线电主管部门给予特别批准;13553-13567kHz(中心频率13560kHz)、26957-27283kHz(中心频率27120kHz)、40.66-40.7MHz(中心频率40.68MHz)、2400-2500MHz(中心频率2450MHz)、5725-5875MHz(中心频率5800MHz)、24-24.25GHz(中心频率24.125GHz)频段也用于ISM应用,在这些频段内工作的无线电业务必须承受由于这些ISM应用产生的有害干扰。
国际上,433.05-434.79MHz(中心频率433.92MHz)频段是国际电联第一区部分欧洲国家指定用于ISM应用的频段,902-928MHz(中心频率915MHz)频段是美国等国际电联划分的第二区国家指定用于ISM应用的频段。与欧美相比,包括我国在内的大部分国际电联第三区国家在100MHz-1GHz频段中没有指定用于ISM应用的频段。
根据《中华人民共和国无线电频率划分规定》,上述指定用于ISM应用的频段也划分给了无线电业务使用,不论是ISM应用还是符合划分的无线电业务,都可以使用上述频段,但均要符合我国无线电管理有关规定。

stm32的HAL库的__weak弱函数

[https://juejin.cn/post/7124685305986154503]
其实函数名称前面加上__weak 修饰符,我们一般称这个函数为“弱函数”。
加上了__weak 修饰符的函数,我们可以在这个文件中重新定义一个同名函数,也就是自己也可以写一个void function(…),如果不加weak,那么肯定是报错的,但是加上weak以后,最终编译器编译的时候,会选择我们自己定义的函数,如果用户没有重新定义这个函数,那么编译器就会执行__weak 声明的函数,并且编译器不会报错。
所以我们可以在别的地方定义一个相同名字的函数,而不必也尽量不要修改之前的函数。
stm32的__weak弱函数定义:
stm32l0xx_hal_gpio.c

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);

  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Callback could be implemented in the user file
   */
}

stm32l0xx_hal_tim.c

__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(htim);

  /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_TIM_PeriodElapsedCallback could be implemented in the user file
   */
}

所以在main.c中可以直接重写函数,如上两个函数能被中断处理自动调用;

在开发板上进行LoRa通信的方式

开发板的LoRa通信系统框图

实现

引脚信息

单个LoRa节点:

  • OLED_SCL:PA8(I2C3_SCL)
  • OLED_SDA:PB4(I2C3_SDA)
  • OLED_PWR:PB5(低电平有效)
  • RELAY_K1:PA11(高电平有效)
  • RELAY_K2:PA12(高电平有效)
  • LORA_INT:PA10
  • LORA_RST:PA9(重要)
  • LORA_CS:PA4(重要)
  • LORA_CLK:PA5
  • LORA_MISO:PA6
  • LORA_MOSI:PA7
  • GENERAL1:PB0
  • GENERAL2:PB1
  • GENERAL3:PB4
  • GENERAL4:PA8
  • GENERAL5:PB6
  • GENERAL6:PB7
  • LED_LD5:PC15(低电平有效)
  • KEY_USER:PC14

NODE_A核心代码

  1. 设置定时器tim6
    tim.c
/**
  ******************************************************************************
  * @file    tim.c
  * @brief   This file provides code for the configuration
  *          of the TIM instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "tim.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

TIM_HandleTypeDef htim3;
TIM_HandleTypeDef htim6;

/* TIM3 init function */
void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 65535;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */

  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&htim3);

}
/* TIM6 init function */
void MX_TIM6_Init(void)
{

  /* USER CODE BEGIN TIM6_Init 0 */

  /* USER CODE END TIM6_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM6_Init 1 */

  /* USER CODE END TIM6_Init 1 */
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 3200-1;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 1000-1;
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM6_Init 2 */

  /* USER CODE END TIM6_Init 2 */

}

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle)
{

  if(tim_pwmHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspInit 0 */

  /* USER CODE END TIM3_MspInit 0 */
    /* TIM3 clock enable */
    __HAL_RCC_TIM3_CLK_ENABLE();
  /* USER CODE BEGIN TIM3_MspInit 1 */

  /* USER CODE END TIM3_MspInit 1 */
  }
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM6)
  {
  /* USER CODE BEGIN TIM6_MspInit 0 */

  /* USER CODE END TIM6_MspInit 0 */
    /* TIM6 clock enable */
    __HAL_RCC_TIM6_CLK_ENABLE();

    /* TIM6 interrupt Init */
    HAL_NVIC_SetPriority(TIM6_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM6_IRQn);
  /* USER CODE BEGIN TIM6_MspInit 1 */

  /* USER CODE END TIM6_MspInit 1 */
  }
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(timHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspPostInit 0 */

  /* USER CODE END TIM3_MspPostInit 0 */

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**TIM3 GPIO Configuration
    PB0     ------> TIM3_CH3
    PB1     ------> TIM3_CH4
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM3_MspPostInit 1 */

  /* USER CODE END TIM3_MspPostInit 1 */
  }

}

void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* tim_pwmHandle)
{

  if(tim_pwmHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspDeInit 0 */

  /* USER CODE END TIM3_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM3_CLK_DISABLE();
  /* USER CODE BEGIN TIM3_MspDeInit 1 */

  /* USER CODE END TIM3_MspDeInit 1 */
  }
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM6)
  {
  /* USER CODE BEGIN TIM6_MspDeInit 0 */

  /* USER CODE END TIM6_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM6_CLK_DISABLE();

    /* TIM6 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM6_IRQn);
  /* USER CODE BEGIN TIM6_MspDeInit 1 */

  /* USER CODE END TIM6_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
  1. 设置GPIO中断
    gpio.c
/**
  ******************************************************************************
  * @file    gpio.c
  * @brief   This file provides code for the configuration
  *          of all used GPIO pins.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "gpio.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/*----------------------------------------------------------------------------*/
/* Configure GPIO                                                             */
/*----------------------------------------------------------------------------*/
/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/** Configure pins as
        * Analog
        * Input
        * Output
        * EVENT_OUT
        * EXTI
*/
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_9
                          |GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);

  /*Configure GPIO pin : PC14 */
  GPIO_InitStruct.Pin = GPIO_PIN_14;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : PC15 */
  GPIO_InitStruct.Pin = GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pins : PA0 PA1 PA4 PA9
                           PA11 PA12 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_9
                          |GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PA10 */
  GPIO_InitStruct.Pin = GPIO_PIN_10;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PB5 */
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);

}

/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
  1. 设置LoRa
    注意,需要修改资料包的原始LORA_Init函数,
    对LoRa模块的操作通过SPI接口实现。
    lora.c文件中提供SPI_WriteRead接口函数。
    选手需要通过STM32 Cube MX配置硬件SPI接口工作模式,或使用GPIO模拟实现SPI总线时序,完成SPI_WriteRead接口函数功能。
    lora.c
+#include "spi.h"
+uint8_t SPI_WriteRead(uint8_t Addr,uint8_t Data){
+	uint8_t pTx[2]={Addr,Data};
+	uint8_t pRx[2];
+	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
+	HAL_SPI_TransmitReceive(&hspi1,pTx,pRx,2,10);
+	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
+	return pRx[1];
+}
/* 设置射频频率(137~525MHz) */
void LORA_SetRFFrequency(unsigned long freq)
{
  freq = (freq / 32) << 19;
  SPI_WriteRead(0x86, freq >> 16);
  SPI_WriteRead(0x87, (freq >> 8) & 0xFF);
  SPI_WriteRead(0x88, freq  & 0xFF);
}
/* 设置射频功率(2~20dBm) */
void LORA_SetRFPower(unsigned char power)
{
  power -= 2;
  if(power > 15)
  {
    power -= 3;
    SPI_WriteRead(0xCD, 0x87);
  }
  SPI_WriteRead(0x89, power|0x80);
}
/* 设置信号带宽(0~9) */
void LORA_SetBW(unsigned char bw)
{
  uint8_t ucRet;

  ucRet = SPI_WriteRead(0x1D, 0);
  ucRet &= 0x0F;
  ucRet |= bw<<4;
  SPI_WriteRead(0x9D, ucRet);
}
/* 设置纠错编码率(1~4) */
void LORA_SetCR(unsigned char cr)
{
  uint8_t ucRet;

  ucRet = SPI_WriteRead(0x1D, 0);
  ucRet &= 0xF1;
  ucRet |= cr<<1;
  SPI_WriteRead(0x9D, ucRet);
}
/* LoRa初始化 */
void LORA_Init(void)
{
	// 使能射频芯片
+	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
+	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_SET);
	
	// init
  SPI_WriteRead(0x81, 0);							/* 设置睡眠模式 */
  SPI_WriteRead(0x81, 0x80);					/* 设置LoRa模式 */
  SPI_WriteRead(0x81, 1);							/* 设置待机模式 */
  LORA_SetRFFrequency(434);						/* 设置射频频率(137~525MHz) */
  LORA_SetRFPower(10);								/* 设置射频功率(2~20dBm) */
  SPI_WriteRead(0x9E, 7<<4);					/* 设置扩频因子(7~12) */
  LORA_SetBW(7);											/* 设置信号带宽(0~9) */
  LORA_SetCR(1);											/* 设置纠错编码率(1~4) */
  SPI_WriteRead(0x81, 5);							/* 设置连续接收模式 */
	
}
/* LoRa发送: pucBuf-发送数据,ucSize-数据个数 */
void LORA_Tx(unsigned char *pucBuf, unsigned char ucSize)
{
  unsigned int i;
  unsigned char ret;

  SPI_WriteRead(0x81, 1);							/* 设置待机模式 */
  ret = SPI_WriteRead(0x0E, 0);				/* 读取FifoTxBaseAddr */
  SPI_WriteRead(0x8D, ret);						/* 设置FifoAddrPtr */
  SPI_WriteRead(0xA2, ucSize);				/* 设置PayloadLength */
  for(i=0; i<ucSize; i++)							/* 写数据到FIFO */
    SPI_WriteRead(0x80, pucBuf[i]);
  SPI_WriteRead(0x81, 3);							/* 设置发送模式 */
  i = 65535;
  do {
    ret = SPI_WriteRead(0x12, 0);			/* 读标志 */
		i--;
  }while(((ret & 8) == 0) && (i != 0));	/* 等待发送完成 */
  SPI_WriteRead(0x92, 8);							/* 清除发送完成 */
  SPI_WriteRead(0x81, 5);							/* 设置连续接收模式 */
}
/* Lora接收: pucBuf-接收数据,返回值-数据个数 */
unsigned char LORA_Rx(unsigned char *pucBuf)
{
  unsigned char i, ret;

  ret = SPI_WriteRead(0x12, 0);				/* 读标志 */
  if(ret & 0x40)											/* 接收完成 */
  {
    SPI_WriteRead(0x81, 1);						/* 设置待机模式 */
    SPI_WriteRead(0x92, 0x40);				/* 清除接收完成 */
    ret = SPI_WriteRead(0x10, 0);			/* 读取FifoRxCurrentAddr */
    SPI_WriteRead(0x8D, ret);					/* 设置FifoAddrPtr */
    ret = SPI_WriteRead(0x13, 0);			/* 读取RxNbBytes */
    for(i=0; i<ret; i++)
      pucBuf[i] = SPI_WriteRead(0, 0);/* 从FIFO读数据 */
    SPI_WriteRead(0x81, 5);						/* 设置连续接收模式 */
  }
  else
    ret = 0;
  return ret;
}

spi.c

/**
  ******************************************************************************
  * @file    spi.c
  * @brief   This file provides code for the configuration
  *          of the SPI instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "spi.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

SPI_HandleTypeDef hspi1;

/* SPI1 init function */
void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspInit 0 */

  /* USER CODE END SPI1_MspInit 0 */
    /* SPI1 clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* SPI1 interrupt Init */
    HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(SPI1_IRQn);
  /* USER CODE BEGIN SPI1_MspInit 1 */

  /* USER CODE END SPI1_MspInit 1 */
  }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{

  if(spiHandle->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspDeInit 0 */

  /* USER CODE END SPI1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI1_CLK_DISABLE();

    /**SPI1 GPIO Configuration
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);

    /* SPI1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(SPI1_IRQn);
  /* USER CODE BEGIN SPI1_MspDeInit 1 */

  /* USER CODE END SPI1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
  1. 主函数
    注意:定时器tim6需要使用HAL_TIM_Base_Start_IT(&htim6);使能;
    main.c
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#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 */

/* 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 */
void fn_lora_rx_handler(void);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t g_uart2_rx_buffer[256]; // 串口接收缓存区
int g_uart2_rx_buffer_pos; // 串口接收缓存区索引
struct Time{
	uint8_t Hours;
	uint8_t Mins;
	uint8_t secs;
	uint8_t Subsecs;
}g_time={23,59,55}; // 时间
uint8_t g_oled_buf[17]; // 显示屏缓存区
uint8_t g_lora_rx_buf[23]; // lora接收缓存
uint8_t g_lora_tx_buf[23]; // lora发送缓存
uint8_t g_key_user_status = 0; // key_user status
uint8_t g_tim_count = 0; // tim6 count(ms)
uint8_t g_tim_status = 0; // tim6 status
/* 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_USART2_UART_Init();
  MX_TIM3_Init();
  MX_TIM6_Init();
  /* USER CODE BEGIN 2 */
    HAL_TIM_Base_Start_IT(&htim6); // 使能TIM6
    HAL_UART_Transmit(&huart2, (uint8_t *)"hihi", strlen("hihi"), strlen("hihi") * 10);
  fn_uart2_printf("hello");

  // OLED初始化
  OLED_Init();
  sprintf((char*)g_oled_buf,"%02d:%02d:%02d",g_time.Hours,g_time.Mins,g_time.secs);
  OLED_ShowString(24,0,g_oled_buf,16);
	
	// 继电器初始化
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_SET);

  // LORA初始化
  LORA_Init();
	
	// blink
	HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_15);
	HAL_Delay(1000);
	HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_15);
  
  // OLED_ShowString(28,2,(uint8_t *)"hihi",16);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		if(g_key_user_status == 1){
			g_lora_tx_buf[0]='A';
			g_lora_tx_buf[1]=g_time.Hours;
			g_lora_tx_buf[2]=g_time.Mins;
			g_lora_tx_buf[3]=g_time.secs;
			g_lora_tx_buf[4]='c';
			g_lora_tx_buf[5]='d';
			LORA_Tx(g_lora_tx_buf,6);
			// reset
			g_key_user_status = 0;
			// blink
			HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_15);
		}
		
		char b3[32];
    sprintf(b3,"Rec:%s\n",g_uart2_rx_buffer);
		if(g_uart2_rx_buffer[0] != '\0'){	
			fn_uart2_printf(b3);
		}
	  g_uart2_rx_buffer[0] = '\0'; // 清空接收
    g_uart2_rx_buffer_pos = 0;
		
    // fn_lora_rx_handler();

    /* 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_4;
  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_USART2|RCC_PERIPHCLK_I2C3;
  PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
  PeriphClkInit.I2c3ClockSelection = RCC_I2C3CLKSOURCE_PCLK1;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/*
LORA接收处理
*/
void fn_lora_rx_handler(void){
	unsigned char s_length = LORA_Rx((unsigned char*)g_lora_rx_buf);
	if(g_lora_rx_buf[0] != '\0'){
		HAL_UART_Transmit(&huart2,g_lora_rx_buf,16,160);
	}
  if(g_lora_rx_buf[0]=='A'){
    OLED_ShowString(28,2,(uint8_t *)"hihi",16);
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_RESET);
		HAL_Delay(1000);
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_SET);
  }
}

/*
 pc14 callback
 override __weak function
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_PIN){
		 if(GPIO_PIN == GPIO_PIN_14){
				if(g_tim_status == 1){
					// key pressed
					g_key_user_status = 1;
					// reset tim
					g_tim_status = 0;
				}
		 }
}

/*
	tim6 interrupt callback
override __weak function
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
		if(htim->Instance == TIM6){
			g_tim_count ++;
			if(g_tim_count % 3 == 0){
				g_tim_status = 1;
				g_tim_count = 0;
			}
		}
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

NODE_B核心代码

main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* 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 "string.h"
#include "stdio.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 */

/* USER CODE END PM */

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

/* USER CODE BEGIN PV */
struct Time{
	uint8_t Hours;
	uint8_t Mins;
	uint8_t secs;}ucTime[15];
uint8_t Strbuff[17];
uint8_t Lora_Rxbuff[7];
uint8_t Lora_Rxcount;
float    height_f,height_sam,height_max=0,height_min=10.0;
float  height_data[20];
uint8_t ucDly,Page_flag=1;
uint8_t Key_num,x=1;
uint8_t Key_name[2][2]={{'1','4'},{'2','5'}};
uint16_t ROW[2]={ROW1_Pin,ROW2_Pin};
uint16_t COL[2]={COL1_Pin,COL2_Pin};
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
uint8_t Mix_Key(void);
void OLED_Proc(uint8_t page);
void Key_Proc(void);
void Lora_Proc(void);
/* 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_TIM6_Init();
  /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim6);
	OLED_Init();
	LORA_Init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		Key_Proc();
		Lora_Proc();
		OLED_Proc(Page_flag);
    /* 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_4;
  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)
{
		if(htim->Instance == TIM6)
		{
			if(++ucDly==30)
				ucDly=0;
		}
}
void Key_Proc(void)
{
	Key_num=Mix_Key();
	if(Key_num!=0&&Lora_Rxcount>0)
		{
			if(Key_num=='1')
			{
				Page_flag++;
				if(Page_flag==4)
					Page_flag=1;
				if(Page_flag==3)
					x=1;
			}
			if(Key_num=='2')
				x++;
			if(Key_num=='5')
				x--;
			Key_num=0;
		}
}
void Lora_Proc(void)
{
	uint8_t s_lora_rx = LORA_Rx(Lora_Rxbuff);
	if(s_lora_rx != 0){
		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_15);
	}
	if(s_lora_rx==6&&Lora_Rxbuff[0]=='A')
		{
			Lora_Rxcount++;
			height_f=((Lora_Rxbuff[4]<<8|Lora_Rxbuff[5])*3.3/4095)*5-5.0;
			height_data[Lora_Rxcount]=height_f;
			height_sam+=height_f;
			ucTime[Lora_Rxcount].Hours=Lora_Rxbuff[1];
			ucTime[Lora_Rxcount].Mins=Lora_Rxbuff[2];
			ucTime[Lora_Rxcount].secs=Lora_Rxbuff[3];
			if(height_max<height_f)
				height_max=height_f;
			if(height_min>height_f)
				height_min=height_f;
		}
}
void OLED_Proc(uint8_t page)
{
	switch(page)
	{
		case 1:sprintf((char*)Strbuff,"N:%d            ",Lora_Rxcount);
					 OLED_ShowString(0,0,Strbuff,16);
						memset(Strbuff,0,16);
					 sprintf((char*)Strbuff,"Total:%.1fkg     ",height_sam);
					 OLED_ShowString(0,2,Strbuff,16);break;
		case 2:sprintf((char*)Strbuff,"MAX:%.1fkg       ",height_max);
					 OLED_ShowString(0,0,Strbuff,16);
						memset(Strbuff,0,16);
					 sprintf((char*)Strbuff,"MIN:%.1fkg       ",height_min);
					 OLED_ShowString(0,2,Strbuff,16);break;
		case 3:
					 sprintf((char*)Strbuff,"     W:%.1fkg      ",height_data[x]);
					 OLED_ShowString(0,0,Strbuff,16);
						memset(Strbuff,0,16);
					 sprintf((char*)Strbuff,"    %02d:%02d:%02d ",ucTime[x].Hours,ucTime[x].Mins,ucTime[x].secs);
					 OLED_ShowString(0,2,Strbuff,16);break;
	}
}
uint8_t Mix_Key(void)
{
	uint8_t key_buff=0,i,j;
	if(ucDly==20)
		return 0;
	HAL_GPIO_WritePin(GPIOB,COL1_Pin,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOB,COL2_Pin,GPIO_PIN_SET);
	for(i=0;i<2;i++)
	{
		HAL_GPIO_WritePin(GPIOB,COL[i],GPIO_PIN_RESET);
		for(j=0;j<2;j++)
		{
			if(HAL_GPIO_ReadPin(GPIOB,ROW[j]) == GPIO_PIN_RESET)
			{
				HAL_Delay(10);
				if(HAL_GPIO_ReadPin(GPIOB,ROW[j]) == GPIO_PIN_RESET)
				{
					key_buff = Key_name[i][j];
					while(HAL_GPIO_ReadPin(GPIOB,ROW[j]) == GPIO_PIN_SET);
				}
			}
		}
		HAL_GPIO_WritePin(GPIOB,COL[i],GPIO_PIN_SET);
	}
	return key_buff;
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

效果

LoRa双节点通信

标签:CODE,HAL,stm32,Init,12,USER,GPIO,LoRa,RCC
From: https://www.cnblogs.com/qsbye/p/17973185

相关文章

  • 首次公开发声,OpenAI CEO 奥特曼回忆“宫斗门”丨 RTE 开发者日报 Vol.129
       开发者朋友们大家好: 这里是「RTE开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享RTE(RealTimeEngagement)领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编辑的个人观......
  • 世微AP2121太阳能草坪灯驱动芯片
    概述AP2121是一款专为太阳能LED草坪灯设计的专用集成电路。AP2121仅需一个外接电感即可组成太阳能照明装置。AP2121由开关型驱动电路、光控开关电路、过放保护电路、内部集成的肖特基二极管等电路组成。AP2121采用专利技术,使得欠压关断时LED灯无闪烁AP2121工......
  • LeetCode 第 121 场双周赛
    LeetCode第121场双周赛大于等于顺序前缀和的最小缺失整数代码:classSolution{public:intmissingInteger(vector<int>&nums){intn=nums.size();set<int>s;for(autox:nums){s.insert(x);}......
  • 如何在 Debian 12 上安装 MariaDB
    MariaDB是一个开源多线程的关系数据库管理系统,是MySQL的替代品。MariaDB是Debian中MySQL的默认替换方案。本教程介绍如何在Debian12上安装MariaDB。准备条件1、一台安装了Debian12的VPS虚拟机(推荐您购买一台阿里云VPS或者腾讯云VPS虚拟主机,如果你更喜欢国......
  • rke2 offline install kubernetes v1.26.12
    文章目录1.准备2.安装ansible3.基础配置3.1配置hosts3.2安装软件包3.3内核参数3.4连接数限制3.5关闭swap、selinux、防火墙3.6时间同步4.RKE2安装4.1下载安装4.2配置其他管理节点4.3新增worker节点1.准备7台主机主机名ipcpu内存diskos角色user密码kube-mast......
  • AWR1243案例——软件篇
    一、软件安装列表MMWAVE-STUDIO:mmwave_studio_02_01_01_00_win32.exeMCR_R2015aSP1_win32_installer.exeftd2xx.dll二、安装详情1.MMWAVE-STUDIOMMWAVE-STUDIO可从TI官网进行下载:https://www.ti.com.cn/tool/cn/MMWAVE-STUDIO#downloads选择AWR1243对应的软件版本,如图......
  • 2024省选联测12
    A.硬币给定\(n\),在满足\(x\timesy=n^2+1\)且\(x,y\ge2\)的前提下,最大化\(x+y\)。从后向前扫描序列,第\(i\)个数被扫到时为\(p\),\(p\)为质数或者为\(1\)。第\(i+kp,k\in\mathbb{Z}\)个数仍然是\(p\)的倍数。因为\[i^2+1\equiv0\modp\]所以\[(i+kp)^2+......
  • stm32硬件实现IIC
    #include"Driver_IIC.h"#include"Delay.h"/***IIC默认地工作于从模式。*生成起始条件后自动地从从模式切换到主模式,*当仲裁丢失或产生停止信号时,从主模式切换到从模式。***从模式用于接收数据;主模式用于发送数据。*//***初始化*/voidDriver_II......
  • 常见错误记录之连接MySQL8.0(Navicate Premium 12,出现BigInteger错误)
    一、NavicatePremium12连接MySQL8.0包如下错误: 出错原因:mysql8之前的版本中加密规则为mysql_native_passwordmysql8以后的加密规则为caching_sha2_password解决方法:(1)更新navicat驱动来解决此问题(2)将mysql用户登录的加密规则常用第二种方法:1.用管理员权限打开cmd,输入mysql......
  • STM32系统开发--位、字节操作
    针对MCU的嵌入是开发中经常涉及到寄存器的操作,例如GPIO配置低寄存器GPIOx_CRL(共32个bit),有时需要改变其中的一位或者几位bit值,同时不能影响其它bit位的值。 例如,需要设置第0位bit=1时,不能简单的设置为:GPIOx_CRL=0x01,这样的方法会使得低配置寄存器GPIOx_CRL的其它比特位都置......