- 本文会介绍如何使用Lora开发板实现通讯(基于STM32F151C8T6芯片)
一.看题
- 仔细审题很重要,找出题目要我们最后实现的效果
二.理清思路
-
根据题目要求可知,我们最终要实现的效果分为一下几点:
-
根据题目要求,我们要使用两块Lora板子,一个当作主控端,另一个当作节点端;
-
按照顺序,我们先讲主控端:
-
主控端简单来讲要实现四个界面,菜单界面Menu,自动指示灯Auto Lamp,手动指示灯Mula Lamp,查看频率View Freq;
-
菜单界面Menu:屏幕按照要求显示Menu,1.Auto Lamp,2.Mula Lamp,3.View Freq,并且能够通过按键KEY2和KEY3进行上下移动,通过按下KEY4进行相应模式,第二次按下能够返回菜单界面Menu且能够正常进行按键上下移动,同时节点端显示Select Menu界面;
-
自动指示灯Auto Lamp:能够读取温湿度光照的值,并且能够根据光照的值改变节点端LED(这里由于作者的开发板外接不了,就没做这个)
-
手动指示灯Mula Lamp:按下按键KEY2、KEY3可以控制两块板子的LED1、LED2亮灭;
-
再就是节点端:
-
节点端除了第一个界面和主控端不一样,其他都一样,节点端主要做的就是接收主控端发过来的信号并能根据信号显示相对应的界面与功能;
-
查看频率View Freq:两块板子同时显示频率。
三.解题步骤
- 首先拿到物联网竞赛工程,对工程进行编译,养成良好的习惯!!!
- 显示0错误0警告,说明工程没问题。
- 首先先引入头文件,根据题目要求,我们要实现通讯、ADC取值和温湿度取值,引入一下头文件:
#include "NS_Radio.h"
#include <string.h>
#include "board.h"
#include "radio.h"
#include "adc_reader.h"
#include "stm32l1xx_hal.h"
#include "sht1x.h"
- 放在main函数头文件的位置就行,方便查找。
- 接下来就是一些按键和LED 的宏定义,这样方便编程,加快编程速度。
#define LED1_ON() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET)
#define LED1_OFF() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET)
#define LED2_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET)
#define LED2_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET)
#define KEY2 HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)
#define KEY3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define KEY4 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_5)
- 按键和LED灯所对应的引脚为:
- KEY2——>PC13
- KEY3——>PB1
- KEY4——>PB5
- LED1——>PA3
- LED2——>PB8
- 做完这些就可以开始写函数啦,在此之前,先介绍一下通讯用到函数:
- 在这个工程里,他有写好的封装好的通讯函数,我们只需要调用即可,但可能大家头疼的就是用哪个,这里就着重讲用到的这几个函数;
/**********************************************************************************************
*函数:void NS_RadioInit( uint32_t freq, int8_t power, uint32_t txTimeout, uint32_t rxTimeout)
*功能:对射频模块发送、接收参数进行初始化
*输入:
* freq载波频率,建议433MHz附近频率最佳
* power发射功率,最大20
* txTimeout发送超时时间
* uint32_t rxTimeout 接收超时时间
*输出:无
*特殊说明:无
**********************************************************************************************/
void NS_RadioInit( uint32_t freq, int8_t power, uint32_t txTimeout, uint32_t rxTimeout)
{
NS_RadioEventsInit();//无线射频模块注册事件回调函数
NS_RadioSetTxRxConfig( freq, power, txTimeout );
Radio.Rx( rxTimeout );//设置Lora模块为接收模式,同时设置超时时间,必许步骤
}
- 根据函数介绍可知,这个函数就是个初始化函数,调用的时候需要填载波频率、发射功率、发送超时时间和接收超时时间;
/*!
* \brief Sends the buffer of size. Prepares the packet to be sent and sets
* the radio in transmission
*
* \param [IN]: buffer Buffer pointer
* \param [IN]: size Buffer size
*/
void ( *Send )( uint8_t *buffer, uint8_t size );
- 根据介绍可知,这个函数就是发送函数,需要填的参数第一个是一个uint8类型的数组,第二个就是这个数组的大小;
void OnTxDone( void )
{
Radio.Sleep( );
Radio.Rx( RX_TIMEOUT_VALUE );
}
-
根据函数名可知,这个函数的功能为发送结束函数。(什么意思呢,相当于就是我前面发送了一个值给节点端,如果没有这个函数,那么程序就会一直发送)
-
以上就是本文会用到的通讯函数
-
接下来开始写函数:
-
首先先初始化通讯模块:
-
在这个初始化函数中,我没有直接填值,因为在NS.Radio.h已经有宏定义了,所有这边我就直接调用了
NS_RadioInit((uint32_t)RF_PING_PONG_FREQUENCY,(int8_t)TX_OUTPUT_POWER,(uint32_t)TX_TIMEOUT_VALUE,(uint32_t)RX_TIMEOUT_VALUE);
- 定义一个uint8类型的数组,此数组用来存储发送的值;
uint8_t str1[1];//发送的值
- 写菜单界面函数,我这里自定义名为 OLED_Display_dat_0();
void OLED_Display_dat_0()
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Menu");
OLED_ShowString(0,2,(uint8_t *)"1.Auto Lamp");
OLED_ShowString(0,4,(uint8_t *)"2.Mula Lamp");
OLED_ShowString(0,6,(uint8_t *)"3.View Freq");
OLED_ShowString(96,2,(uint8_t *)"<");
str1[0]=5;//定义数组str1[0]为5
Radio.Send(str1,1);//发送str1,字节大小为1
OnTxDone();//发送结束
}
- 另外写了两个函数,OLED_Display_dat_1();和OLED_Display_dat_2();函数,这两个函数显示的文字基本一样,唯一的区别就是箭头位置不同,为什么写这两个函数呢,当时想到的逻辑就是比如我选择2.Mula Lamp,进入到相应的界面后然后再按下KEY4返回菜单界面,此时箭头应该还是停留在2这里而不是1那里。
void OLED_Display_dat_1()
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Menu");
OLED_ShowString(0,2,(uint8_t *)"1.Auto Lamp");
OLED_ShowString(0,4,(uint8_t *)"2.Mula Lamp");
OLED_ShowString(0,6,(uint8_t *)"3.View Freq");
OLED_ShowString(96,4,(uint8_t *)"<");
}
void OLED_Display_dat_2()
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Menu");
OLED_ShowString(0,2,(uint8_t *)"1.Auto Lamp");
OLED_ShowString(0,4,(uint8_t *)"2.Mula Lamp");
OLED_ShowString(0,6,(uint8_t *)"3.View Freq");
OLED_ShowString(96,6,(uint8_t *)"<");
}
-
接下来就是按键控制函数,这里定义为KEY_Control();
-
按键的逻辑会比较复杂,这里会慢慢讲让大家好懂
-
这里首先先定义四个变量:
int a = 0;//上下移动的标志
int b = 0;//判断a所在的位置,做出相应的判断
int c = 0;//控制箭头,切换页面后不让箭头出现,显示温湿度光照值
int d = 0;//KEY4切换回主界面的标志,这里是第二次按下切换回主界面
- 这里先附上代码再讲解,不然讲的云里雾里了会;
void KEY_Control()
{
if(c==0)
{
if(KEY2==0)
{
HAL_Delay(50);
if(KEY2==0)
{
a--;
if(a==0)
{
OLED_ShowString(96,4,(uint8_t *)" ");
OLED_ShowString(96,2,(uint8_t *)"<");
}
if(a==1)
{
OLED_ShowString(96,6,(uint8_t *)" ");
OLED_ShowString(96,4,(uint8_t *)"<");
}
if(a<0)
{
a=0;
}
while(KEY2==0);
}
}
if(KEY3==0)
{
HAL_Delay(50);
if(KEY3==0)
{
a++;
if(a==1)
{
OLED_ShowString(96,2,(uint8_t *)" ");
OLED_ShowString(96,4,(uint8_t *)"<");
}
if(a==2)
{
OLED_ShowString(96,4,(uint8_t *)" ");
OLED_ShowString(96,6,(uint8_t *)"<");
}
if(a>2)
{
a=2;
}
while(KEY3==0);
}
}
}
if(KEY4==0)
{
HAL_Delay(50);
if(KEY4==0)
{
b=a;
if(b==0)
{
HAL_GPIO_EXTI_Callback(GPIO_PIN_13 );
c=1;
str1[0]=1;
Radio.Send(str1,1);
OnTxDone();
d++;
if(d==2)
{
OLED_Display_dat_0();
d=0;
c=0;
}
}
if(b==1)
{
HAL_GPIO_EXTI_Callback(GPIO_PIN_1 );
c=2;
str1[0]=2;
Radio.Send(str1,1);
OnTxDone();
d++;
if(d==2)
{
OLED_Display_dat_1();
d=0;
c=0;
str1[0]=5;
Radio.Send(str1,1);
OnTxDone();
}
}
if(b==2)
{
HAL_GPIO_EXTI_Callback(GPIO_PIN_5 );
c=4;
str1[0]=3;
Radio.Send(str1,1);
OnTxDone();
d++;
if(d==2)
{
OLED_Display_dat_2();
d=0;
c=0;
str1[0]=5;
Radio.Send(str1,1);
OnTxDone();
}
}
while(KEY4==0);
}
}
if(c==2)
{
if(KEY2==0)
{
HAL_Delay(50);
if(KEY2==0)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Mula Lamp");
OLED_ShowString(0,2,(uint8_t *)"Lamp:Open");
str1[0]=4;
Radio.Send(str1,1);
OnTxDone();
}while(KEY2==0);
}
if(KEY3==0)
{
HAL_Delay(50);
if(KEY3==0)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Mula Lamp");
OLED_ShowString(0,2,(uint8_t *)"Lamp:Close");
str1[0]=6;
Radio.Send(str1,1);
OnTxDone();
}while(KEY3==0);
}
}
}
void HAL_GPIO_EXTI_Callback( uint16_t GPIO_PIN )
{
if(GPIO_PIN==GPIO_PIN_13)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Auto Lamp");
OLED_ShowString(0,2,(uint8_t *)"Light:");
OLED_ShowString(0,4,(uint8_t *)"Temp:");
OLED_ShowString(0,6,(uint8_t *)"Humi:");
}
if(GPIO_PIN==GPIO_PIN_1)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Mula Lamp");
OLED_ShowString(0,2,(uint8_t *)"Lamp:Close");
}
if(GPIO_PIN==GPIO_PIN_5)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"View Freq");
OLED_ShowString(0,2,(uint8_t *)"Freq:");
OLED_ShowString(56,2,(uint8_t *)"433300000");
OLED_ShowCHinese(48,4,44);
}
}
- 先来看按键上下移动,a的变化其实就三张情况,0,1,2,根据这三个值,1.Auto Lamp所对应的就是0,2.Mula Lamp所对应的就是1,3.View Freq所对应的就是2,明白这一点,接下来的逻辑就很容易明白了,KEY2控制向上移动,定义为a - -,往上走的情况有三种,第一种就是从1走到0,第二种就是从2走到1,第三种就是停留在0位置;
if(KEY2==0)
{
HAL_Delay(50);
if(KEY2==0)
{
a--;
if(a==0)
{
OLED_ShowString(96,4,(uint8_t *)" ");
OLED_ShowString(96,2,(uint8_t *)"<");
}
if(a==1)
{
OLED_ShowString(96,6,(uint8_t *)" ");
OLED_ShowString(96,4,(uint8_t *)"<");
}
if(a<0)
{
a=0;
}
while(KEY2==0);
}
}
- 反之KEY3就是a + +,向下走的情况也是三种,第一种就是从0走到1,第二种就是从1走到2,第三种就是停留在2位置;
if(KEY3==0)
{
HAL_Delay(50);
if(KEY3==0)
{
a++;
if(a==1)
{
OLED_ShowString(96,2,(uint8_t *)" ");
OLED_ShowString(96,4,(uint8_t *)"<");
}
if(a==2)
{
OLED_ShowString(96,4,(uint8_t *)" ");
OLED_ShowString(96,6,(uint8_t *)"<");
}
if(a>2)
{
a=2;
}
while(KEY3==0);
}
}
- 到这步,你的按键就能实现控制箭头的上下移动啦!接下来就是至关重要的KEY4,因为KEY4要做的事不会像KEY2、KEY3简单;
- 在介绍KEY4前,先介绍一下中断回调函数HAL_GPIO_EXTI_Callback( uint16_t GPIO_PIN );这里我是重写了这个函数,它原函数是:
void HAL_GPIO_EXTI_Callback( uint16_t gpioPin )
{
uint8_t callbackIndex = 0;
if( gpioPin > 0 )
{
while( gpioPin != 0x01 )
{
gpioPin = gpioPin >> 1;
callbackIndex++;
}
}
if( GpioIrq[callbackIndex] != NULL )
{
GpioIrq[callbackIndex]( );
}
}
- 这里就是说明一下,防止大家疑惑,大家在用的时候一定要注释掉,严谨点!
-
KEY4里简单来说做的事情就是3个判断,判断b的值等于0、1或者2;
-
当b的值为0时,触发GPIO_PIN_13中断,显示Auto Lamp界面;
-
这时在KEY2、KEY3按键外套了个if语句,判断c==0执行按键控制箭头的上下移动,按下KEY4后,c=1,此时按键KEY2、KEY3就不能控制箭头上下移动;
-
将温湿度光照值显示在屏幕上,节点端同步主控端,定义三个变量:
char shuzu[32];//发送温度的值
char shuzu1[32];//发送湿度的值
int p = 0;//规定发送温度、湿度的先后顺序
- 接下来先把温湿度、光照的值拿到,拿到之后再去发送,当时在做的时候发现温湿度的值拿到之后不能一起发送,后面解决的办法就是顺序发送,先发送温度,再发送湿度,并且加了个变量p,防止程序运行速度太快数据错位
if(c==1)
{
if(i==2)
{
float temp, humidity;
char status;
HAL_Delay(10);
SHT1x_start_measure_temperature();
while(!is_SHT1x_measurement_end());
SHT1x_get_temperature_result(&temp);
sprintf(shuzu,"%.2f",temp);
OLED_ShowString(56,4,(uint8_t *)shuzu);
Radio.Send((uint8_t *)shuzu,8);
HAL_Delay(10);
p++;
}
if(p==1)
{
p=0;
float temp, humidity;
char status;
HAL_Delay(10);
SHT1x_start_measure_relative_humidity();
while(!is_SHT1x_measurement_end());
SHT1x_get_relative_humidity_result(&humidity);
SHT1x_get_status(&status);
sprintf(shuzu1,"%.2f",humidity);
OLED_ShowString(56,6,(uint8_t *)shuzu1);
shuzu1[9]=0x09;
Radio.Send((uint8_t *)shuzu1,10);
OnTxDone();
}
}
-
接下来就是发送光照值,光照值读的是AD值,然后通过公式再转换成光照值,然后就是要明白当我们切换到Auto Lamp界面,温湿度光照的值都要实时的显示到屏幕上,如果只用一个线程实现温湿度光照值的传递,程序肯定会卡,卡什么意思呢,就是当你再按一次KEY4切换回菜单界面时,可能会没反应,为了解决这个,我们把光照值放在定时器里,就能有效的解决这个问题;
-
首先在定时器tim_board.c引入头文件
#include "adc_reader.h"
#include "NS_Radio.h"
#include <string.h>
#include "radio.h"
- 由于我们要用到变量c,得声明c变量,并且定义i,用来判断光照值小于10时让LED1、与LED2同时两起,反之灭,再定义uint8类型的数组,用来当作发送的数组,最后定义一个char类型的数组,用来将光照值显示在主控端屏幕上相应位置;
extern int c;
int i = 0;//判断光照值小于10时,LED1、LED2同时亮起,反之灭
uint8_t str2[1];//用来当作
char st[4];//用来显示光照值在主控端屏幕上
-
通过定时器来控制每次读取AD值的速度,这里用的是定时器2,每250ms读取一次AD的值:
-
同样,读取和显示光照值都是与温湿度一起执行的,也就是都是在c=1的情况下,我们只需要在定时器的回调函数里做判断即可,这里我们定义了一个i变量,当c= =1时,定时器开始每250ms读取一次AD的值,我们在程序的最后加入了一个i + +,当i==3时做一次判断,判断光照值<10时LED1、LED2同时亮起发送值7到节点端,反之发送值8到节点端;
-
定时器的回调函数:
- 写在定时器回调函数里的代码:
if(c==1)
{
AdcScanChannel();
AdcReadCh0();
if(i==1)
{
sprintf(st,"%.2f",5/2*AdcReadCh0()/10);
OLED_ShowString(64,2,(uint8_t *)st);
Radio.Send((uint8_t *)st,6);
OnTxDone();
}
if(i==3)
{
i=0;
if(5/2*AdcReadCh0()/10<10)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
str2[0]=7;
Radio.Send(str2,1);
OnTxDone();
}
else
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
str2[0]=8;
Radio.Send(str2,1);
OnTxDone();
}
}
i++;
}
-
接下来就是发送值1到节点端,发的值为1;
-
d + +,第一次按下KEY4 d的值为1,第二次按下为2,也就是我们要切换回菜单界面,只需再加一个判断,判断d的值为2,就回到菜单界面,此时箭头应在2那行,就调用OLED_Display_dat_0();函数,同时将d、c赋回0,即可循环此操作。
if(b==0)
{
HAL_GPIO_EXTI_Callback(GPIO_PIN_13 );
c=1;
str1[0]=1;
Radio.Send(str1,1);
OnTxDone();
d++;
if(d==2)
{
OLED_Display_dat_0();
d=0;
c=0;
}
}
-
接下来就是判断b==1的情况:
-
当b等于1时,触发GPIO_PIN_1中断,显示Mula Lamp界面;
-
将c赋为2,当按下KEY2时,LED1和LED2同时两起,屏幕显示Lamp Open,同时发送值4到节点端;按下KEY3LED1和LED2同时灭,屏幕显示Lamp Close,同时发送值6到节点端;
if(c==2)
{
if(KEY2==0)
{
HAL_Delay(50);
if(KEY2==0)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Mula Lamp");
OLED_ShowString(0,2,(uint8_t *)"Lamp:Open");
str1[0]=4;
Radio.Send(str1,1);
OnTxDone();
}while(KEY2==0);
}
if(KEY3==0)
{
HAL_Delay(50);
if(KEY3==0)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Mula Lamp");
OLED_ShowString(0,2,(uint8_t *)"Lamp:Close");
str1[0]=6;
Radio.Send(str1,1);
OnTxDone();
}while(KEY3==0);
}
}
- 这里同样需要判断d的值为2时,切换回到菜单界面,同时箭头停留在2那行,发送值5到节点端;
if(b==1)
{
HAL_GPIO_EXTI_Callback(GPIO_PIN_1 );
c=2;
str1[0]=2;
Radio.Send(str1,1);
OnTxDone();
d++;
if(d==2)
{
OLED_Display_dat_1();
d=0;
c=0;
str1[0]=5;
Radio.Send(str1,1);
OnTxDone();
}
}
-
最后就是判断b==2的情况:
-
当b==2时,触发GPIO_PIN_5中断,注意一定要给c赋值,这里就随便给c赋一个4,只要不是0,1,2即可;
-
发送值3到节点端
-
同样也是d++,当d的值为2时,也就是第二次按下KEY4,返回菜单界面,发送值5到节点端;
if(b==2)
{
HAL_GPIO_EXTI_Callback(GPIO_PIN_5 );
c=4;
str1[0]=3;
Radio.Send(str1,1);
OnTxDone();
d++;
if(d==2)
{
OLED_Display_dat_2();
d=0;
c=0;
str1[0]=5;
Radio.Send(str1,1);
OnTxDone();
}
}
- main函数里主要调用即可:
int main( void )
{
Init();
OLED_Init();
ADCS_Init();
SHT1x_init();
NS_RadioInit((uint32_t)RF_PING_PONG_FREQUENCY,(int8_t)TX_OUTPUT_POWER,(uint32_t)TX_TIMEOUT_VALUE,(uint32_t)RX_TIMEOUT_VALUE);
OLED_Display_dat_0();
while( 1 )
{
KEY_Control();
if(c==1)
{
if(i==2)
{
float temp, humidity;
char status;
HAL_Delay(10);
SHT1x_start_measure_temperature();
while(!is_SHT1x_measurement_end());
SHT1x_get_temperature_result(&temp);
sprintf(shuzu,"%.2f",temp);
OLED_ShowString(56,4,(uint8_t *)shuzu);
Radio.Send((uint8_t *)shuzu,8);
HAL_Delay(10);
p++;
}
if(p==1)
{
p=0;
float temp, humidity;
char status;
HAL_Delay(10);
SHT1x_start_measure_relative_humidity();
while(!is_SHT1x_measurement_end());
SHT1x_get_relative_humidity_result(&humidity);
SHT1x_get_status(&status);
sprintf(shuzu1,"%.2f",humidity);
OLED_ShowString(56,6,(uint8_t *)shuzu1);
shuzu1[9]=0x09;
Radio.Send((uint8_t *)shuzu1,10);
OnTxDone();
}
}
}
}
- 到这里,主控端的所有工作就完成啦,接下来就是节点端;
- 在节点端里,同样需要初始化通讯模块,填的参数和主控端基本一致:
NS_RadioInit((uint32_t)RF_PING_PONG_FREQUENCY,(int8_t)TX_OUTPUT_POWER,(uint32_t)TX_TIMEOUT_VALUE,(uint32_t)RX_TIMEOUT_VALUE);
- 引入头文件:
#include "NS_Radio.h"
#include <string.h>
#include "board.h"
#include "radio.h"
- 定义一个uint8类型的数组,这个数组后面用来解析温湿度传过来的值:
uint8_t buf[32];
- 写接收函数,这里我命名为Receive();
void Receive()
{
uint16_t a = 0;//判断是否接收到数据,接收到数据,a>0,反之为0
uint8_t b[BUFFER_SIZE];//用来接收发送过来的数据
a = ReadRadioRxBuffer(b);//接收数据,接收到数据会返回一个字节大小值,将这个值赋给a
if(a>0)
{
if(b[0]==5)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Select Menu");
OLED_ShowCHinese(48,4,44);
}
else if(b[0]==1)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Auto Lamp");
OLED_ShowString(0,2,(uint8_t *)"Light:");
OLED_ShowString(0,4,(uint8_t *)"Temp:");
OLED_ShowString(0,6,(uint8_t *)"Humi:");
}
else if(b[0]==2)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Mula Lamp");
OLED_ShowString(0,2,(uint8_t *)"Lamp:Close");
}
else if(b[0]==3)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"View Freq");
OLED_ShowString(0,2,(uint8_t *)"Freq:");
OLED_ShowString(56,2,(uint8_t *)"433300000");
}
else if(b[0]==4)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Mula Lamp");
OLED_ShowString(0,2,(uint8_t *)"Lamp:Open");
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
}
else if(b[0]==6)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Mula Lamp");
OLED_ShowString(0,2,(uint8_t *)"Lamp:Close");
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}
else if(b[0]==7)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
}
else if(b[0]==8)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}
else if(a==6)
{
OLED_ShowString(64,2,(uint8_t *)b);
}
else if(a==8)
{
buf[0]=b[0];
buf[1]=b[1];
buf[2]=b[2];
buf[3]=b[3];
buf[4]=b[4];
OLED_ShowString(56,4,(uint8_t *)buf);
}
else if(b[9]==0x09)
{
buf[0]=b[0];
buf[1]=b[1];
buf[2]=b[2];
buf[3]=b[3];
buf[4]=b[4];
OLED_ShowString(56,6,(uint8_t *)buf);
}
}
}
-
在函数里,我又定义了uint16类型的变量,用来判断节点端是否接收到数据,如果接收到数据,a的值肯定是大于0的;
-
再定义uint8类型的数组b,用来接收发送过来的值;
- 接下来就是判断接收到的值,这里接收到的值放在了uint8_t b[BUFFER_SIZE]数组里;
- 接收到的值一共有11种,分别是5,1,2,3,4,6,7,8,温度,湿度,光照;
其实现在做的就是根据主控端发过来的值显示相应内容即可;
- 当b[0]==5时,节点端显示Select Menu界面,同时显示WiFi图标,表示节点端与主控端连接上;
if(b[0]==5)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Select Menu");
OLED_ShowCHinese(48,4,44);
}
- 当b[0]==1时,节点端显示Auto Lamp界面;
else if(b[0]==1)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Auto Lamp");
OLED_ShowString(0,2,(uint8_t *)"Light:");
OLED_ShowString(0,4,(uint8_t *)"Temp:");
OLED_ShowString(0,6,(uint8_t *)"Humi:");
}
- 当b[0]==2时,节点端显示Mula Lamp界面;
else if(b[0]==2)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Mula Lamp");
OLED_ShowString(0,2,(uint8_t *)"Lamp:Close");
}
- 当b[0]==3时,,节点端屏幕显示载波率;
else if(b[0]==3)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"View Freq");
OLED_ShowString(0,2,(uint8_t *)"Freq:");
OLED_ShowString(56,2,(uint8_t *)"433300000");
}
- 当b[0]==4时,节点端还是在Mula Lamp界面,此时Lamp:Open,同时板上的LED亮起;
else if(b[0]==4)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Mula Lamp");
OLED_ShowString(0,2,(uint8_t *)"Lamp:Open");
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
}
- 当b[0]==6时,节点端还是在Mula Lamp界面,此时Lamp:Close,同时板上的LED灭;
else if(b[0]==6)
{
OLED_Clear();
OLED_ShowString(16,0,(uint8_t *)"Mula Lamp");
OLED_ShowString(0,2,(uint8_t *)"Lamp:Close");
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}
- 当b[0]==7时,节点端的界面在Auto Lamp界面,此时板上的LED亮起;
else if(b[0]==7)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
}
- 当b[0]==8时,节点端的界面在Auto Lamp界面,此时板上的LED灭;
else if(b[0]==8)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}
- 当a==6时,节点端界面在Auto Lamp界面,实时接收光照的值;
else if(a==6)
{
OLED_ShowString(64,2,(uint8_t *)b);
}
- 当a==8时,此时就用到前面定义的buf数组,将接收到的数组b按照顺序放在buf数组里并显示在屏幕上;
else if(a==8)
{
buf[0]=b[0];
buf[1]=b[1];
buf[2]=b[2];
buf[3]=b[3];
buf[4]=b[4];
OLED_ShowString(56,4,(uint8_t *)buf);
}
- 当b[9]==0x09时,将接收到的数组b按照顺序放在buf数组里并显示在屏幕上;
else if(b[9]==0x09)
{
buf[0]=b[0];
buf[1]=b[1];
buf[2]=b[2];
buf[3]=b[3];
buf[4]=b[4];
OLED_ShowString(56,6,(uint8_t *)buf);
}
- 最后在main函数里调用即可:
int main( void )
{
Init();
OLED_Init();
NS_RadioInit((uint32_t)RF_PING_PONG_FREQUENCY,(int8_t)TX_OUTPUT_POWER,(uint32_t)TX_TIMEOUT_VALUE,(uint32_t)RX_TIMEOUT_VALUE);
while( 1 )
{
Receive();
}
}
四.功能展示
- 在视频中,由于作者没有温湿度光照二合一模块,就只好拿一个温湿度模块和光照模块代替,出现的问题就是当用光照模块读取光照值时,切不回来菜单界面,原因大概率是读取温湿度函数上,如果你们手头上有这种二合一的模块,那就不会出现这种问题。
物联网竞赛--Lora开发板通讯