从机采集温湿度及超标报警并显示在oled屏幕上,按下按键通过lora模块传输给主机,主机再也显示在其搭载的屏幕上

1、项目简介

在这里插入图片描述

2、实现逻辑

在这里插入图片描述
#从机实现对温湿度数据的检测
#从机将数据显示到oled上
#从机检测到数据超标后进行蜂鸣器报警
#从机将检测到的数据进行编码并无线传输
#从机按键能控制数据发送和停止(按一下一直发,按一下停,发送快一些)
#从机上两个指示灯,绿色代表正在发送数据,红色代表停止发送
#主机通过规定好的协议进行数据解析及在oled上显示数据

3、应用场景

#远程(中距离)检测温湿度
#粮库使用

4、核心代码梳理

//从机程序
void RF_Initial(uint8_t mode)  //0 rx  1 tx
{
    SX1276_Init(MODE_LORA);
    SX1276_LoRa_SetDataRate(2);
    SX1276_SetFreq(23);             //23,433Hz
    SX1276_SetPower(15, 1);         //20dBm
    SX1276_SetRxMode();          //
}

uint8_t RF_SendPacket(uint8_t *Sendbuffer, uint8_t length)
{
    uint8_t error = 0, i=0, ack_len=0, ack_buffer[65]= { 0 }, TxBuffer[100];

    SX1276_SendPacket(Sendbuffer, length);

    return (0);
}

void RF_RecvHandler(void)
{
    uint8_t error=0, i=0, length=0, recv_buffer[20]= { 0 };

    uint8_t temp;
    uint8_t TL,TH;
    uint16_t tem;
    length = SX1276_ReceivePacket(recv_buffer);     //

    if(length==9)
    {
        if ((recv_buffer[0]==0x55) && (recv_buffer[1]==0xAA))
        {
            uint16_t sum = recv_buffer[3]+recv_buffer[4]+recv_buffer[5]+recv_buffer[6]+recv_buffer[7];
            sum = sum & 0x00ff;
            if(sum != recv_buffer[8])
                return;

            //HAL_GPIO_TogglePin(GPIOC, BOARD_LED_Pin);
            TH = recv_buffer[4];
            TL = recv_buffer[5];
            if(TH>7)
            {
                TH=~TH;
                TL=~TL;
                temp=0;//温度为负
            } else temp=1;//温度为正
            tem=TH; //获得高八位
            tem<<=8;
            tem+=TL;//获得底八位
            check_temp = (float)tem*0.625;//转换
            if(!temp)
                check_temp = -check_temp;
            check_temp = check_temp/10;
            printf("The temp is: %.2fC\r\n", check_temp);

            check_hump = (float)recv_buffer[7];
            check_hump = recv_buffer[6] + check_hump/100;
            printf("The hump is: %.2f%c\r\n", check_hump, '%');
        }

        SX1276_SetRxMode();
    }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
    uint32_t  clk;
  /* 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_ADC1_Init();
  MX_I2C1_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  MX_USART3_UART_Init();
  /* USER CODE BEGIN 2 */
    OLED_Init();
    OLED_ColorTurn(0);//0正常显示,1 反色显示
    OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
    OLED_Refresh();
    DS18B20_Init();
    RF_Initial(0);
    OLED_Clear();
    OLED_ShowString(0,0,"TEMP:    .    C",16);
    OLED_ShowString(0,14,"HUMP:    .    %",16);
    OLED_ShowString(0,28,"ALARM:",24);
		OLED_ShowNum(53,0,12,2,16);
		OLED_ShowNum(77,0,34,2,16);
		OLED_ShowString(43,0,"-",16);
		OLED_ShowString(80,28,"T",24);
		OLED_ShowString(100,28,"H",24);
		OLED_ShowString(100,28," ",24);
    OLED_Refresh();
  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
#ifdef TX

        //check temp
        check_temp = DS18B20_Get_Temp()/10;
        intT = (int)check_temp;          /*合成实际温度整数部分****精度相对上面的更高*/
			  float tem_tmp = check_temp-intT;         /*合成实际温度小数部分*/
        decT = tem_tmp*100;

        //check hump
        check_hump = 4092-ADC_num;
        check_hump = (float)(check_hump/3292*100);//ad->hump%
        if((check_hump >= 0) && (check_hump <= 100))
        {
            intH = (int)check_hump;
					  float hum_tmp = check_hump - intH;
					  hum_tmp *= 100;
            decH = hum_tmp;
            lora_order[6] = intH;
            lora_order[7] = decH;
        }

        HAL_ADC_Start_IT(&hadc1);

        //check alarm
        if((check_temp > TEMP_ALARM_UP) || (check_hump > HUMP_ALARM_UP) || (check_temp < TEMP_ALARM_DOWN)
					  || (check_hump < HUMP_ALARM_DOWN)) //超标报警
        {
            HAL_GPIO_WritePin(GPIOC, BEEP_Pin, GPIO_PIN_SET);
            if((check_temp > TEMP_ALARM_UP) || (check_temp < TEMP_ALARM_DOWN))
                OLED_ShowString(80,28,"T",24);
						else OLED_ShowString(80,28," ",24);
            if((check_hump > HUMP_ALARM_UP) || ((check_hump < HUMP_ALARM_DOWN)))
                OLED_ShowString(100,28,"H",24);
						else OLED_ShowString(100,28," ",24);
            OLED_Refresh();
        }
        else
        {
            HAL_GPIO_WritePin(GPIOC, BEEP_Pin, GPIO_PIN_RESET);
            OLED_ShowString(80,28," ",24);
            OLED_ShowString(100,28," ",24);
            OLED_Refresh();
        }


        //send by lora / led display
        if(clk % 10 == 0)
        {
            if(send_flag%2)//send
            {
                uint16_t sum = lora_order[3]+lora_order[4]+lora_order[5]+lora_order[6]+lora_order[7];
                sum = sum & 0x00ff;
                lora_order[8] = sum;
                RF_SendPacket(lora_order, 9);

                HAL_GPIO_WritePin(GPIOB, SEND_LED_Pin, GPIO_PIN_RESET);
                HAL_GPIO_WritePin(GPIOB, STOP_LED_Pin, GPIO_PIN_SET);
            }
            else//stop
            {
                HAL_GPIO_WritePin(GPIOB, SEND_LED_Pin, GPIO_PIN_SET);
                HAL_GPIO_WritePin(GPIOB, STOP_LED_Pin, GPIO_PIN_RESET);
            }

            if(check_temp < 0)
                OLED_ShowString(43,0,"-",16);
            else
                OLED_ShowString(43,0," ",16);
            OLED_ShowNum(53,0,intT,2,16);
            OLED_ShowNum(77,0,decT,2,16);
            OLED_ShowNum(53,14,intH,2,16);
            OLED_ShowNum(77,14,decH,2,16);
            OLED_Refresh();
					}


        HAL_Delay(100);
        //HAL_GPIO_TogglePin(GPIOC, BOARD_LED_Pin);

        clk++;
#endif

#ifdef RX
        RF_RecvHandler();
#endif
    }
  /* USER CODE END 3 */
}

//复位DS18B20
void DS18B20_Rst(void)
{
    HAL_GPIO_WritePin(DS18B20_GPIO_Port,DS18B20_Pin,GPIO_PIN_RESET); //拉低DQ
    delay_us(750);    //拉低750us
    HAL_GPIO_WritePin(DS18B20_GPIO_Port,DS18B20_Pin,GPIO_PIN_SET); //DQ=1
    delay_us(15);     //15US
}
//等待DS18B20的回应
//返回1:未检测到DS18B20的存在
//返回0:存在
uint8_t DS18B20_Check(void)
{
    uint8_t retry=0;
    //SET PB1 INPUT
    while (HAL_GPIO_ReadPin(DS18B20_GPIO_Port,DS18B20_Pin) && retry<200)
    {
        retry++;
        delay_us(1);
    };
    if(retry>=200)return 1;
    else retry=0;
    while (!HAL_GPIO_ReadPin(DS18B20_GPIO_Port,DS18B20_Pin)&&retry<240)
    {
        retry++;
        delay_us(1);
    };
    if(retry>=240)return 1;
    return 0;
}
//从DS18B20读取一个位
//返回值:1/0
uint8_t DS18B20_Read_Bit(void) 			 // read one bit
{
    uint8_t data;
    HAL_GPIO_WritePin(DS18B20_GPIO_Port,DS18B20_Pin,GPIO_PIN_RESET);
    delay_us(2);
    HAL_GPIO_WritePin(DS18B20_GPIO_Port,DS18B20_Pin,GPIO_PIN_SET);
    delay_us(12);
    if(HAL_GPIO_ReadPin(DS18B20_GPIO_Port,DS18B20_Pin))data=1;
    else data=0;
    delay_us(50);
    return data;
}
//从DS18B20读取一个字节
//返回值:读到的数据
uint8_t DS18B20_Read_Byte(void)    // read one byte
{
    uint8_t i,j,dat;
    dat=0;
    for (i=1; i<=8; i++)
    {
        j=DS18B20_Read_Bit();
        dat=(j<<7)|(dat>>1);
    }
    return dat;
}
//写一个字节到DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(uint8_t dat)
{
    uint8_t j;
    uint8_t testb;
    for (j=1; j<=8; j++)
    {
        testb=dat&0x01;
        dat=dat>>1;
        if (testb)
        {
            HAL_GPIO_WritePin(DS18B20_GPIO_Port,DS18B20_Pin,GPIO_PIN_RESET);// Write 1
            delay_us(2);
            HAL_GPIO_WritePin(DS18B20_GPIO_Port,DS18B20_Pin,GPIO_PIN_SET);
            delay_us(60);
        }
        else
        {
            HAL_GPIO_WritePin(DS18B20_GPIO_Port,DS18B20_Pin,GPIO_PIN_RESET);// Write 0
            delay_us(60);
            HAL_GPIO_WritePin(DS18B20_GPIO_Port,DS18B20_Pin,GPIO_PIN_SET);
            delay_us(2);
        }
    }
}
//开始温度转换
void DS18B20_Start(void)// ds1820 start convert
{
    DS18B20_Rst();
    DS18B20_Check();
    DS18B20_Write_Byte(0xcc);// skip rom
    DS18B20_Write_Byte(0x44);// convert
}
//初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在
uint8_t DS18B20_Init(void)
{
    DS18B20_Rst();
    return DS18B20_Check();
}
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250)
float DS18B20_Get_Temp(void)
{
    uint8_t temp;
    uint8_t TL,TH;
    short tem;
    float return_tem;
    DS18B20_Start();                    // ds1820 start convert
    DS18B20_Rst();
    DS18B20_Check();
    DS18B20_Write_Byte(0xcc);// skip rom
    DS18B20_Write_Byte(0xbe);// convert
    TL=DS18B20_Read_Byte(); // LSB
    TH=DS18B20_Read_Byte(); // MSB
    lora_order[4] = TH;
    lora_order[5] = TL;

    if(TH>7)
    {
        TH=~TH;
        TL=~TL;
        temp=0;//温度为负
    } else temp=1;//温度为正
    tem=TH; //获得高八位
    tem<<=8;
    tem+=TL;//获得底八位
    return_tem = (float)tem*0.625;//转换
    if(temp)return return_tem; //返回温度值
    else return -return_tem;
}

/**
 * @brief	EXIT中断回调函数
 * @param GPIO_Pin —— 触发中断的引脚
 * @retval	none
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    /* 判断哪个引脚触发了中断 */
    switch(GPIO_Pin)
    {
    case GPIO_PIN_8:
        /* 处理GPIO8发生的中断 */
        delay_us(10000);//消抖
        if(HAL_GPIO_ReadPin(SEND_BUT_GPIO_Port, SEND_BUT_Pin))
        {
            send_flag++;
            HAL_GPIO_TogglePin(GPIOC, BOARD_LED_Pin);
        }
        break;
    default:
        break;
    }
}

//get hump by adc conv
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    HAL_ADC_Stop_IT(hadc);
    ADC_num = HAL_ADC_GetValue(hadc);
}


//主机程序
//和从机差不太多,见资料包


5、部分参考资料

ds18b20参考:
https://mculover666.blog.csdn.net/article/details/108302704?utm_medium=distribute.pc_relevant.
none-task-blog-BlogCommendFromMachineLearnPai2-1.control&dist_request_id=&depth_1-utm_source=distribute.
pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

https://blog.csdn.net/qq153471503/article/details/102858978

yl69参考:
https://blog.csdn.net/qq_41960161/article/details/106118778?utm_medium=distribute.
pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242

LCD12864参考:
https://blog.csdn.net/as480133937/article/details/97765912?utm_medium=distribute.pc_relevant_download.
none-task-blog-baidujs-2.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-baidujs-2.nonecase

通讯协议格式说明(注:为16进制):
帧头 数据帧长度 设备ID 温度(℃) 湿度(%) 和校验(低8位)
55 AA 1字节(0-255) 1字节(0-255) 2字节(TH TL) 2字节(HH HL) 1字节

温度转换:u8 temp;

      u8 TL,TH;
      short tem;

TL=DS18B20_Read_Byte(); // LSB
TH=DS18B20_Read_Byte(); // MSB
if(TH>7)
{

    TH=~TH;
    TL=~TL;
    temp=0;//温度为负

}else temp=1;//温度为正
tem=TH; //获得高八位
tem<<=8;
tem+=TL;//获得底八位
tem=(float)tem*0.625;//转换
if(temp) return tem; //返回温度值
else return -tem; //tem是实际温度的10倍

例:01 17 = (1*256+23)*0.625=174.375 则实际温度是17.4375℃(举例用) 温度范围 -55℃-+125℃
湿度转换:float hum = HH+HL%100 例:24 57 = 36+87%100 = 36.87 ->湿度36.87%
和校验 = (设备ID+TH+TL+HH+HL)低8位
例:55 AA 06 01(默认ID为01) 01 17 24 57 94

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
主从机硬件pcb、原理图见资料包

6、注意事项

#sx1276是spi通信,也有那种直接封装好使用串口的lora模块,比如E19
#本来要使用lcd做显示,后来种种原因使用的oled 9.6
#注意主从机之间的协议

完整可运行项目地址

或 点击下方”大饼匠人“卡片,关注并回复"15"免费下载开发资料

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐