stm32笔记[12]-LoRa通信
摘要
在蓝桥杯物联网的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]
- LoRa技术是一种低功耗远距离无线通信技术,具有广泛的应用前景。
- LoRa采用扩频调制技术,利用长码调制和分散频谱技术,使得其在较低的信噪比下获得更远的传输距离。这一特点使得LoRa技术在城市覆盖和农村地区通信等场景中具有独特的优势。
- LoRaWAN协议是在LoRa技术基础上建立的一种开放式标准,能够支持大规模的低功耗无线传感器网络。LoRaWAN使用星型、树型、网状等多种拓扑结构,满足不同应用场景下的通信需求。
- LoRa技术特点
- 长距离传输
LoRa技术可以在城市环境下达到数公里的通信距离,而在郊区或农村地区,甚至能够实现数十公里的通信距离。这使得LoRa技术在远距离监测、物联网等领域具有广泛的应用前景。 - 低功耗要求
LoRa技术适用于电池供电设备,由于其低功耗的特点,可以延长设备的使用寿命,减少更换电池的频率,降低了设备运行和维护成本。 - 总结
LoRa技术以其长距离传输和低功耗要求成为物联网领域的热门选择。不仅如此,LoRa技术还具备良好的抗干扰能力、灵活的部署方式和广泛的应用场景。相信随着技术的不断发展,LoRa技术将在更多领域展现出其独特的价值。
- 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核心代码
- 设置定时器tim6
tim.c
/**
******************************************************************************
* @file tim.c
* @brief This file provides code for the configuration
* of the TIM instances.
******************************************************************************
* @attention
*
* <h2><center>© 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 = 32-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****/
- 设置GPIO中断
gpio.c
/**
******************************************************************************
* @file gpio.c
* @brief This file provides code for the configuration
* of all used GPIO pins.
******************************************************************************
* @attention
*
* <h2><center>© 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****/
- 设置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>© 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****/
- 主函数
注意:定时器tim6需要使用HAL_TIM_Base_Start_IT(&htim6);
使能;
main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© 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>© 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双节点通信 |
---|