目录
功能:
通过LoRa模块与主机进行通信,监测环境中的温度、湿度、土壤湿度和光照强度等参数,并根据预设的自动控制逻辑或者手动指令控制继电器开关,从而调节风扇、加热器、水泵、喷雾器和灯光等设备,为植物提供适宜的生长环境。
1.制作LORA双机通信的硬件名单:
STM32C8T6核心板 | 2个 |
OLED屏幕 | 2 |
lora模块 | 2 |
有源蜂鸣器 | 1 |
按键 | 6 |
DHT11温湿度传感器 | 1 |
土壤湿度传感器 | 1 |
四路继电器 | 1 |
1路继电器 | 1 |
2.引脚图
1.主机
2.从机
3.先让两个单片机实现通信并OLED显示出来
使用的Lora是大夏龙雀的感觉这个是我使用过的Lora里面最好用的,因为不用设置频道就可以直接透明传输,使用起来得心应手。
就像两个单片机直接串口通信一样,缺点是异步串行,不能同时进行接收和发送。
官方的LR01视频教程:https://www.bilibili.com/video/BV1XC4y1K7Mc/?spm_id_from=333.999.0.0
1.主机代码
usart1.c
/***************************************
* 文件名 :usart1.c
* 描述 :配置USART1
* 实验平台:MINI STM32开发板 基于STM32F103C8T6
* 硬件连接:------------------------
* | PA9 - USART1(Tx) |
* | PA10 - USART1(Rx) |
* ------------------------
* 库版本 :ST3.0.0
**********************************************************************************/
#include "usart1.h"
#include <stdarg.h>
#include "delay.h"
#include <string.h>
void USART1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* 使能 USART1 时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
/* USART1 使用IO端口配置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA
/* USART1 工作模式配置 */
USART_InitStructure.USART_BaudRate = 9600; //波特率设置:115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位数设置:8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位设置:1位
USART_InitStructure.USART_Parity = USART_Parity_No ; //是否奇偶校验:无
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制模式设置:没有使能
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//接收与发送都使能
USART_Init(USART1, &USART_InitStructure); //初始化USART1
USART_Cmd(USART1, ENABLE);// USART1使能
}
/*发送一个字节数据*/
void UART1SendByte(unsigned char SendData)
{
USART_SendData(USART1,SendData);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
/*接收一个字节数据*/
unsigned char UART1GetByte(unsigned char* GetData)
{
if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)
{ return 0;//没有收到数据
}
*GetData = USART_ReceiveData(USART1);
return 1;//收到数据
}
/*接收一个数据,马上返回接收到的这个数据*/
void UART1Test(int *a)
{
int state = 0;
unsigned char i = 0;
while(1)
{
while(UART1GetByte(&i))
{
UART1SendByte(i);
}
if(i == 'O')
state = 1;
if(i == 'K' && state == 1)
{
*a = 1;
break;
}
}
}
void UART1TX(char a[100])
{
int i = 0;
while(a[i] != '\0')
{
UART1SendByte(a[i]);
i++;
}
UART1SendByte('\r');
UART1SendByte('\n');
}
usart1.h
#include "stm32f10x.h"
#include <stdio.h>
void USART1_Config(void);
void UART1Test(int *a);
void UART1TX(char a[100]);
unsigned char UART1GetByte(unsigned char* GetData);
int UART1RX_OK(char tx[10]);
void UART1SendByte(unsigned char SendData);
usart3.c
/***************************************
* 文件名 :usart3.c
* 描述 :配置USART3
* 实验平台:MINI STM32开发板 基于STM32F103C8T6
* 硬件连接:------------------------
* | PB10 - USART3(Tx) |
* | PB11 - USART3(Rx) |
* ------------------------
* 库版本 :ST3.0.0
**********************************************************************************/
#include "delay.h"
#include "usart3.h"
#include <stdarg.h>
#include <string.h>
#include "usart1.h"
u8 USART3_TX_BUF[600];
u16 USART3_RX_STA=0;
u8 USART3_RX_BUF[1024]; //接收缓冲,最大USART3_MAX_RECV_LEN个字节.
void USART3_Config(int BaudRate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* 使能 USART1 时钟*/
//RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3 , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
/* USART1 使用IO端口配置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOA
/* USART1 工作模式配置 */
USART_InitStructure.USART_BaudRate = BaudRate; //波特率设置:115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位数设置:8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位设置:1位
USART_InitStructure.USART_Parity = USART_Parity_No ; //是否奇偶校验:无
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制模式设置:没有使能
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//接收与发送都使能
USART_Init(USART3, &USART_InitStructure); //初始化USART1
USART_Cmd(USART3, ENABLE);// USART1使能
}
/*发送一个字节数据*/
void UART3SendByte(unsigned char SendData)
{
USART_SendData(USART3,SendData);
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
}
/*接收一个字节数据*/
unsigned char UART3GetByte(unsigned char* GetData)
{
if(USART_GetFlagStatus(USART3, USART_FLAG_RXNE) == RESET)
{ return 0;//没有收到数据
}
*GetData = USART_ReceiveData(USART3);
return 1;//收到数据
}
/*判断是不是OK*/
void UART3Test(int *a)
{
int state = 0;
unsigned char i = 0;
while(1)
{
UART3GetByte(&i);
//UART1SendByte(i);
if(i == 'O')
state = 1;
if(i == 'K' && state == 1)
{
*a = 1;
break;
}
}
}
/*发送字符串*/
void UART3TX(char a[100])
{
int i = 0;
while(a[i] != '\0')
{
UART3SendByte(a[i]);
i++;
}
UART3SendByte('\r');
UART3SendByte('\n');
}
usart3.h
#include "stm32f10x.h"
#include <stdio.h>
void USART3_Config(int BaudRate);
void UART3Test(int *a);
void UART3TX(char a[100]);
unsigned char UART3GetByte(unsigned char* GetData);
void UART3SendByte(unsigned char SendData);
lora.c
#include "lora.h"
#include "usart1.h"
#include "usart3.h"
#include "delay.h"
#include "OLED.h"
extern char sj;
void lora_transmit(char* a)//定向传输,给主机发送数据
{
int i = 0;
UART3SendByte('#');//起始符
while(a[i] != '\0')
{
UART3SendByte(a[i]);
i++;
}
UART3SendByte('$');//结束符
}
void lora_receive(void)
{
unsigned char i = 0;
extern char lora_rx_data[100];
int t1 = 0,t2 = 0;
while(1)
{
UART3GetByte(&i);
if(i=='#')
{
while(1)
{
if(UART3GetByte(&i) == 1 && i!='$')
{
lora_rx_data[t1++]=i;
}
else if(i=='$')
break;
}
while(1)
{
UART1SendByte(lora_rx_data[t2++]);
if(t1 == t2)
{
UART1SendByte('\r');
UART1SendByte('\n');
break;
}
}
break;
}
if(i=='a')
{
OLED_ShowString(1, 1,"l");
while(1)
{
if(UART3GetByte(&i) == 1 && i!='$')
{
sj=i;
}
else if(i=='$')
break;
}
break;
}
}
}
Lora.h
#include "stm32f10x.h"
void lora_receive(void);
void lora_transmit(char* a);
main
#include "stm32f10x.h"
#include "Serial.h"
#include "usart1.h"
#include "usart3.h"
#include "lora.h"
#include "delay.h"
#include "OLED.h"
#include "string.h"
#include <stdio.h>
#include "LED.h"
#include "key.h"
#include "timer.h"
char lora_tx_data[100];
char lora_rx_data[100];
int main(void)
{
SystemInit(); //配置系统时钟为 72M
Serial_Init();
USART3_Config(9600); //USART3 配置
OLED_Init();
Device_Init();
Key_Init();
TIM3_Int_Init(99, 7199);//初始化定时器设置10ms定时
LED1_ON();
while(1)
{
sprintf((char*)lora_tx_data,"#s$");
OLED_ShowString(1, 1, lora_tx_data);
lora_transmit(lora_tx_data);
lora_receive();
OLED_ShowString(3, 1, lora_rx_data);
OLED_ShowString(2, 1, "KW KS TS GQ");
sscanf(lora_rx_data, "%d %d %d %d", &temperature, &humidity,&Soil,&photosensitive);//字符串转化成整数
OLED_ShowNum(4,1,temperature,3); OLED_ShowNum(4,5,humidity,3);OLED_ShowNum(4,9,Soil,3);OLED_ShowNum(4,13,photosensitive,3);
}
}
2.从机代码
lora和usrat和主机的是一样的
main
#include "stm32f10x.h"
#include "Serial.h"
#include "usart1.h"
#include "usart3.h"
#include "lora.h"
#include "delay.h"
#include "DHT11.h"
#include "OLED.h"
#include "string.h"
#include "GM.h"
#include "Relay.h"
int main(void)
{
SystemInit(); //配置系统时钟为 72M
Serial_Init();
USART3_Config(9600); //USART3 配置
OLED_Init();
DHT11_Init ();
adc_Init();
Relay_Init();
while(1)
{
//temp humi数据处理
DHT11_Read_Data(&temperature,&humidity);//温湿度
Soil=Get_ADC_Val();//土壤速度
photosensitive=Get_Adc_Average();
sprintf((char*)lora_tx_data,"%d %d %d %d",temperature,humidity,Soil,photosensitive);//"1.Temp:%d^ Humi:%d"区分节点
OLED_ShowString(1, 1, "LoRa Node");
OLED_ShowString(2, 1, lora_tx_data);
//等待接收主机的start命令
lora_receive();
lora_transmit(lora_tx_data);
OLED_ShowString(4, 1, lora_rx_data);
memset(lora_rx_data, 0, sizeof(lora_rx_data));
}
}
4.实现农业系统基本功能
1.使用温度传感器测当前环境的温湿度
2.使用土壤湿度传感器检测土壤湿度
3.使用光敏电阻检测光照情况
4.继电器灯亮模拟打开对应的风扇、水泵、灯、喷雾、加热
主机主要实现了以下功能:
- 通过串口与LoRa模块进行通信,发送和接收数据。
- 通过串口与另一个设备进行通信,发送控制指令。
- 通过OLED显示屏显示从机采集的温度、湿度、土壤湿度和光照强度等传感器数据。
- 通过按键控制从机继电器的开关状态。
- 通过定时器定时扫描按键和执行一些周期性任务。
具体功能描述如下:
- 串口通信:通过USART1和USART3配置,分别与LoRa模块和另一个设备进行通信。
- LoRa通信:发送和接收数据,发送的数据格式为"#s$",接收到的数据解析后包括温度、湿度、土壤湿度和光照强度等信息。
- OLED显示:使用OLED显示屏显示节点状态信息以及传感器采集的温度、湿度、土壤湿度和光照强度。
- 按键控制:通过按键控制继电器的开关状态,按键扫描函数Key_Scan()用于检测按键状态。
- 定时器:使用定时器TIM3实现10ms的定时中断服务程序,用于定时扫描按键和执行一些周期性任务。
从机实现的功能
-
温湿度、土壤湿度和光敏传感器数据处理:
- 使用 DHT11 传感器读取温度和湿度。
- 使用 ADC 获取土壤湿度和光敏传感器的数据。
- 将获取到的数据格式化为字符串,并显示在 OLED 上。
-
LoRa 通信:
- 调用
lora_receive()
函数等待接收来自主机的命令。 - 根据接收到的命令,设置控制变量
automatic
和各个继电器的状态。 - 将传感器数据转换成字符串并通过 LoRa 传输。
- 显示接收到的 LoRa 数据在 OLED 上。
- 调用
-
继电器控制:
- 根据控制变量
automatic
的值进行自动控制或手动控制。 - 在自动模式下,根据预设的阈值控制各个继电器的状态。
- 在手动模式下,根据接收到的命令控制各个继电器的状态。
- 根据控制变量
主机main
#include "stm32f10x.h"
#include "Serial.h"
#include "usart1.h"
#include "usart3.h"
#include "lora.h"
#include "delay.h"
#include "OLED.h"
#include "string.h"
#include <stdio.h>
#include "LED.h"
#include "key.h"
#include "timer.h"
char lora_tx_data[100];
char lora_rx_data[100];
u8 temperature,humidity;//温湿度
u8 en_send_data_to_master = 0;//@使能给主机发送数据
char DataBuf[20];
u8 Soil,photosensitive;
char sj;
int a;
int kz=0,kz1=0;
void pd(void )
{
if (temperature > 35 || temperature < 15 || humidity < 45 || Soil < 35 || photosensitive > 60) {
LED1_OFF();
Buzzer_OFF();
} else {
LED1_ON();
Buzzer_ON();
}
}
void kry_bross(void)
{
if(KeyFlag==1)//自动与手动切换
{
a++;
if(a==1)//自动
{
UART3SendByte('#');//起始符
UART3SendByte('1');
UART3SendByte('$');//结束符
kz1=1;
}
if(a==2)//手动
{
UART3SendByte('#');//起始符
UART3SendByte('0');
UART3SendByte('$');//结束符
a=0;
kz1=0;
}
KeyFlag=0;
}
if(KeyFlag==2)//继电器1
{
UART3SendByte('#');//起始符
UART3SendByte('2');
UART3SendByte('$');//结束符
kz=1;
KeyFlag=0;
}
if(KeyFlag==3)//继电器2
{
UART3SendByte('#');//起始符
UART3SendByte('3');
UART3SendByte('$');//结束符
kz=1;
KeyFlag=0;
}
if(KeyFlag==4)//继电器3
{
UART3SendByte('#');//起始符
UART3SendByte('4');
UART3SendByte('$');//结束符
kz=1;
KeyFlag=0;
}
if(KeyFlag==5)//继电器4
{
UART3SendByte('#');//起始符
UART3SendByte('5');
UART3SendByte('$');//结束符
kz=1;
KeyFlag=0;
}
if(KeyFlag==6)//继电器5
{
UART3SendByte('#');//起始符
UART3SendByte('6');
UART3SendByte('$');//结束符
kz=1;
KeyFlag=0;
}
}
int main(void)
{
SystemInit(); //配置系统时钟为 72M
Serial_Init();
USART3_Config(9600); //USART3 配置
OLED_Init();
Device_Init();
Key_Init();
TIM3_Int_Init(99, 7199);//初始化定时器设置10ms定时
LED1_ON();
while(1)
{
sprintf((char*)lora_tx_data,"#s$");//"1.Temp:%d^ Humi:%d"区分节点
OLED_ShowString(1, 1, lora_tx_data);
lora_transmit(lora_tx_data);
//等待接收主机的start命令
lora_receive();
OLED_ShowString(3, 1, lora_rx_data);
OLED_ShowString(2, 1, "KW KS TS GQ");
sscanf(lora_rx_data, "%d %d %d %d", &temperature, &humidity,&Soil,&photosensitive);//字符串转化成整数
OLED_ShowNum(4,1,temperature,3); OLED_ShowNum(4,5,humidity,3);OLED_ShowNum(4,9,Soil,3);OLED_ShowNum(4,13,photosensitive,3);
kry_bross();
if(kz==0||kz1==0){pd();}
if(kz==1){ LED1_ON(); Buzzer_ON();}
if(kz1==1){kz=0;delay_ms(1000);LED1_ON(); Buzzer_ON();}
}
}
int ms_10,ys;
//定时器3中断服务程序10ms
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)//是更新中断
{
Key_Scan();//按键扫描
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIM3更新中断标志
ms_10++;
if(ms_10>100){ms_10=0;ys++;}//10分钟重置
if(ys>180){ys=0;kz=0;kz1=0;}
}
}
从机main
#include "stm32f10x.h"
#include "Serial.h"
#include "usart1.h"
#include "usart3.h"
#include "lora.h"
#include "delay.h"
#include "DHT11.h"
#include "OLED.h"
#include "string.h"
#include "GM.h"
#include "Relay.h"
char lora_tx_data[100];
char lora_rx_data[100];
u8 temperature,humidity;//温湿度
u8 en_send_data_to_master = 0;//@使能给主机发送数据
char DataBuf[20];
u8 Soil,photosensitive;
char automatic;
char Relay1,Relay2,Relay3,Relay4,Relay5;
extern char sj;
void Relay_prcoos(void)
{
if(automatic==0)
{
if(Relay1==1)Relay1_OFF();//风扇
if(Relay2==1)Relay2_OFF();//加热
if(Relay3==1)Relay3_OFF();//水泵
if(Relay4==1)Relay4_OFF();//喷雾
if(Relay5==1)Relay5_OFF();//灯光
if(Relay1==0)Relay1_ON();//风扇
if(Relay2==0)Relay2_ON();//加热
if(Relay3==0)Relay3_ON();//水泵
if(Relay4==0)Relay4_ON();//喷雾
if(Relay5==0)Relay5_ON();//灯光
}
}
void automatic_prcoos(void)
{
if(automatic==1)
{
Relay1=0;
Relay2=0;
Relay3=0;
Relay4=0;
Relay5=0;
if(temperature>35)
{
Relay1_OFF();
Relay2_ON();
}
if(temperature<15)
{
Relay1_ON();
Relay2_OFF();
}
if(temperature<35&&temperature>15)
{
Relay1_ON();
Relay2_ON();
}
if(humidity<45)
{
Relay4_OFF();
}
if(humidity>45)
{
Relay4_ON();
}
if(Soil<35)
{
Relay3_OFF();
}
if(Soil>35)
{
Relay3_ON();
}
if(photosensitive>60)
{
Relay5_OFF();
}
if(photosensitive<60)
{
Relay5_ON();
}
}
}
int main(void)
{
SystemInit(); //配置系统时钟为 72M
Serial_Init();
USART3_Config(9600); //USART3 配置
OLED_Init();
DHT11_Init ();
adc_Init();
Relay_Init();
while(1)
{
//temp humi数据处理
DHT11_Read_Data(&temperature,&humidity);//温湿度
Soil=Get_ADC_Val();//土壤速度
photosensitive=Get_Adc_Average();
sprintf((char*)lora_tx_data,"%d %d %d %d",temperature,humidity,Soil,photosensitive);//"1.Temp:%d^ Humi:%d"区分节点
OLED_ShowString(1, 1, "LoRa Node");
OLED_ShowString(2, 1, lora_tx_data);
//等待接收主机的start命令
lora_receive();
if(sj=='0')
{
automatic=0;
}
if(sj=='1')
{
automatic=1;
}
if(sj=='2')
{
Relay1=1;
automatic=0;
}
if(sj=='3')
{
Relay2=1;
automatic=0;
}
if(sj=='4')
{
Relay3=1;
automatic=0;
}
if(sj=='5')
{
Relay4=1;
automatic=0;
}
if(sj=='6')
{
Relay5=1;
automatic=0;
}
lora_transmit(lora_tx_data);
OLED_ShowString(4, 1, lora_rx_data);
memset(lora_rx_data, 0, sizeof(lora_rx_data));
Relay_prcoos();
automatic_prcoos();
}
}
-----------------------欢迎大家指正交流,有空可以一起讨论代码啊。--------------------------------
链接:https://pan.baidu.com/s/10nDkz743tXq9MGB6wKCbkA
提取码:5bq3
有偿回答可以加QQ:1521354774