找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4891|回復(fù): 4
打印 上一主題 下一主題
收起左側(cè)

STM32F103C8T6實現(xiàn)用2.4G模塊NRF2401傳輸室內(nèi)溫濕度并顯示OLED 源程序

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:836950 發(fā)表于 2021-8-8 22:23 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
基于STM32F103C8T6實現(xiàn)用2.4G模塊(NRF2401)傳輸室內(nèi)溫濕度并顯示OLED

對于2.4G模塊上的應(yīng)用,很多是將這個這個模塊上的應(yīng)用實現(xiàn)在51單片機(jī)上,我問了很多相關(guān)文章的博主,他們從最開始的程序幾乎都是從51單片機(jī)上,進(jìn)行開發(fā),感謝這些趕路人,我們這些從事快速開發(fā)的愛好者做好的道路。
感謝[999994博主](http://www.torrancerestoration.com/bbs/space-uid-683358.html),[綻放中的青春博主](http://www.torrancerestoration.com/bbs/space-uid-290170.html)

好了,現(xiàn)在就進(jìn)入主食階段

## 一:對2.4G模塊(NRF2401)的介紹
作為我們在開發(fā)應(yīng)用的短距離傳輸信息的選擇模塊之一,作為在項目上實現(xiàn)互傳的模塊,可實現(xiàn)半雙工和全雙工,可以實現(xiàn)點對點或是 1 對 6 的無線通信。對于 NRF24L01 的固件編程工作主要是參照NRF24L01 的狀態(tài)機(jī)。主要有以下幾個狀態(tài):
Power Down Mode:掉電模式
Tx Mode:發(fā)射模式
Rx Mode:接收模式
Standby-1Mode:待機(jī) 1 模式
Standby-2 Mode:待機(jī) 2 模式

這里配上接線管腳
|PA1   |NRF- CSN  |
|--|--|
| PA5-SPI1-SCK | NRF -SCK
| PA6-SPI1-MISO |NRF -MISO  |
|PA7-SPI1-MOSI|NRF -MOSI|
| PA3         |  NRF-IRQ
| PA2         |NRF-CE  |

但是在我應(yīng)用的項目上我沒有使用全雙工,項目設(shè)計是一個板子(STM32最小系統(tǒng),以下皆是)上的一個作為主機(jī),一個作為從機(jī),其中主機(jī)是負(fù)責(zé)采集室內(nèi)的溫度,從機(jī)是為了負(fù)責(zé)接收主機(jī)主機(jī)上的數(shù)據(jù),顯示在OLED上面,同時為了讓自己的項目更好的檢測,我在從機(jī)上也實現(xiàn)了對主機(jī)數(shù)據(jù)的發(fā)送,主句實現(xiàn)接收。
主機(jī)上發(fā)送:

```cpp
printf("\r\n 主機(jī)端 進(jìn)入自應(yīng)答發(fā)送模式\r\n");
        NRF_TX_Mode();

        txbuf[0]=temp;                        
        txbuf[1]=humi;//將檢測到的溫度和濕度賦值給這個非空數(shù)組中,實現(xiàn)數(shù)據(jù)包的發(fā)送
        status = NRF_Tx_Dat(txbuf);//

                  switch(status)
                          {
                            case MAX_RT:
                                          printf("\r\n 主機(jī)端 沒接收到應(yīng)答信號,發(fā)送次數(shù)超過限定值,發(fā)送失敗。 \r\n");
                                 break;
        
                          case ERROR:
                                           printf("\r\n 未知原因?qū)е掳l(fā)送失敗。 \r\n");
                                 break;
        
                          case TX_DS:
                                          printf("\r\n 主機(jī)端 接收到 從機(jī)端 的應(yīng)答信號,發(fā)送成功! \r\n");                        
                                 break;                                                                  
                          }                                   
        
```
從機(jī)上接收:

```cpp
printf("\r\n 從機(jī)端 進(jìn)入接收模式\r\n");
        NRF_RX_Mode();     //這邊的是在收
         
        /*等待接收數(shù)據(jù)*/
        status = NRF_Rx_Dat(rxbuf);

           /*判斷接收狀態(tài)*/
                 if(status == RX_DR)
        {
                printf("\r\n 從機(jī)端 接收到 主機(jī)端 發(fā)送的數(shù)據(jù) \r\n");
          for(i=0;i<2;i++)
                                {        
                                        if(i%2==0)
                                        {
                                                printf("\r\n 溫度的數(shù)據(jù)為:%d \r\n",rxbuf[ i]);
                                                OLED_ShowNum(45,2,rxbuf[ i],3,16);//顯示溫度的碼值
                                                txbuf[ i] =1;
                                }
                                else
                               {
                                                printf("\r\n 濕度的數(shù)據(jù)為:%d \r\n",rxbuf[ i]);
                                            OLED_ShowNum(45,4,rxbuf[ i],3,16);//顯示濕度的碼值
                                                txbuf[ i] =1;
                               }                                                                        
                                }               
        }   
```
主機(jī)上接收從機(jī)數(shù)據(jù):

```cpp
printf("\r\n 主機(jī)端 進(jìn)入接收模式。 \r\n");        
                NRF_RX_Mode();
                status = NRF_Rx_Dat(rxbuf);        
                        
                switch(status)
                        {
                         case RX_DR:
                                 for(i=0;i<4;i++)
                                {                                       
                                        printf("\r\n 主機(jī)端 接收到 從機(jī)端 發(fā)送的數(shù)據(jù)為:%d \r\n",rxbuf[ i]);
                                        txbuf[ i] =rxbuf[ i];
                                                                                                               
                                }
                                  break;
                        
                         case ERROR:
                                          printf("\r\n 主機(jī)端 接收出錯。   \r\n");
                                  break;                  
                        }
               
```




從機(jī)上發(fā)送給主機(jī)數(shù)據(jù):

```cpp
printf("\r\n 溫度的數(shù)據(jù)為:%d \r\n",rxbuf[ i]);
                                                OLED_ShowNum(45,2,rxbuf[ i],3,16);//顯示溫度的碼值
                                                txbuf[ i] =1;//返回發(fā)送給主機(jī)上的值為1
```
txbuf[ i]就是發(fā)送個主機(jī)上面的數(shù)據(jù)

```cpp
printf("\r\n 濕度的數(shù)據(jù)為:%d \r\n",rxbuf[ i]);
                                            OLED_ShowNum(45,4,rxbuf[ i],3,16);//顯示濕度的碼值
                                                txbuf[ i] =1;//返回發(fā)送給主機(jī)上的值為1
```

## 二.溫濕度傳感器簡介
DHT11是一款價格便宜,易于使用的溫度濕度測量二合一傳感器。它使用單根總線與單片機(jī)進(jìn)行雙向的串行數(shù)據(jù)傳輸,信號傳輸距離可達(dá)20米以上。非常適用于對精度和實時性要求不高的溫濕度測量場合。![DHT117溫濕度傳感器](https://img-blog.csdnimg.cn/ddc7 ... ess=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3J5MTMyMzc2OTkyODE=,size_16,color_FFFFFF,t_70#pic_center)
接口設(shè)置:
|DATA  | PB11 |
|--|--|

這個模塊也是有相應(yīng)的代碼格式,我這里就提幾個注意事項:
1.DHT11使用單一總線通信,即DATA引腳和單片機(jī)連接的線。總線總是處于空閑狀態(tài)和通信狀態(tài)這個2個狀態(tài)之間。
2.DHT11上電后,要等待 約 1秒 以越過不穩(wěn)定狀態(tài),在此期間不能發(fā)送任何指令。
3.DHT11屬于低速傳感器,兩次通信請求之間的間隔時間不能太短,一般來說要不能低于1秒。
4.當(dāng)前DHT11通信幀的小數(shù)部分默認(rèn)都是0,廠商預(yù)留給以后實現(xiàn)。所以一般只讀取整數(shù)值部分即可。校驗和定義為:前4個Byte的總和的低8位。


## 三.OLED顯示屏
我所用的OLED屏有白色,屏的大小為0.96寸,像素點為128*64,也稱之為0.96OLED屏或者12864屏。通時我選擇的是4腳,運(yùn)用的協(xié)議是IIC協(xié)議,

```cpp
void IIC_Start(void)
{

        OLED_SCLK_Set() ;
        OLED_SDIN_Set();
        OLED_SDIN_Clr();
        OLED_SCLK_Clr();
}


理解了OLED的顯示方式,漢字取模也是很有必要的,我選擇列行式的取模方式,設(shè)置為C51原則:
[PLC取模軟件]


想要更加詳細(xì)的理解OLED上面的知識我推薦這位博主的博文[OLED詳細(xì)解剖](https://blog.csdn.net/u010858987 ... 1018.2226.3001.4187)

下面是主機(jī)項目工程中的main.c文件:

```cpp
#include "stm32f10x.h"
#include "usart.h"
#include "delay.h"
#include "DTH117.h"
#include "sys.h"
#include "SPI_NRF.h"
#include <stdarg.h>
#include <string.h>
#include <stdio.h>

u8 status;        //用于判斷接收/發(fā)送狀態(tài)
u8 txbuf[2];         //發(fā)送緩沖
u8 rxbuf[4];//接收緩沖
int i=0;
/*
*讀取溫濕度傳感器DHT11的值,并用串口打印出來
*/

void clock_init(void);

u8 temp = 0,humi = 0;


/**************************************************************************
函數(shù)名:int main(void)
參數(shù)說明:無
返回值:無
函數(shù)作用:主函數(shù)
***************************************************************************/
int main(void)
{        
         
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        SPI_NRF_Init();
        delay_init();
    DHT11_Init();         
    clock_init();        
    usart_init(115200);                //初始化串口
        printf("\r\n 這是一個 NRF24L01 無線傳輸實驗 \r\n");
        printf("\r\n 這是無線傳輸 主機(jī)端 的反饋信息\r\n");
        printf("\r\n   正在檢測NRF與MCU是否正常連接。。。\r\n");
        
         /*檢測NRF模塊與MCU的連接*/
           status = NRF_Check();

        /*判斷連接狀態(tài)*/  
   if(status == SUCCESS)           
                    printf("\r\n      NRF與MCU連接成功!\r\n");  
   else         
                printf("\r\n  NRF與MCU連接失敗,請重新檢查接線。\r\n");
         
         
         while(1)
         {        
        DHT11_Read_Data(&temp,&humi);
        printf("\r\n 主機(jī)端 進(jìn)入自應(yīng)答發(fā)送模式\r\n");
        NRF_TX_Mode();

        txbuf[0]=temp;                        
        txbuf[1]=humi;//將檢測到的溫度和濕度賦值給這個非空數(shù)組中,實現(xiàn)數(shù)據(jù)包的發(fā)送
        status = NRF_Tx_Dat(txbuf);//這里是發(fā)送
                  switch(status)                          {
                            case MAX_RT:
                                          printf("\r\n 主機(jī)端 沒接收到應(yīng)答信號,發(fā)送次數(shù)超過限定值,發(fā)送失敗。 \r\n");
                                 break;
        
                          case ERROR:
                                           printf("\r\n 未知原因?qū)е掳l(fā)送失敗。 \r\n");
                                 break;
        
                          case TX_DS:
                                          printf("\r\n 主機(jī)端 接收到 從機(jī)端 的應(yīng)答信號,發(fā)送成功! \r\n");                        
                                 break;                                                                  
                          }                                   
        
                 printf("\r\n 主機(jī)端 進(jìn)入接收模式。 \r\n");        
                NRF_RX_Mode();
                status = NRF_Rx_Dat(rxbuf);        
                        
                switch(status)
                        {
                         case RX_DR:
                                 for(i=0;i<4;i++)
                                {                                       
                                        printf("\r\n 主機(jī)端 接收到 從機(jī)端 發(fā)送的數(shù)據(jù)為:%d \r\n",rxbuf[ i]);
                                        txbuf[ i] =rxbuf[ i];
                                                                                                               
                                }
                                  break;
                        
                         case ERROR:
                                          printf("\r\n 主機(jī)端 接收出錯。   \r\n");
                                  break;                  
                        }
               
         }           
        
}
/**************************************************************************
函數(shù)名:void clock_init(void)
參數(shù)說明:無
返回值:無
函數(shù)作用:開啟高速外部時鐘,
ADCCLK設(shè)置為12MHZ,        SYSCLK設(shè)置為72Mhz,PCLK1設(shè)置為36MHZ,PKLC2設(shè)置為72mhz
***************************************************************************/
void clock_init(void)
{
        RCC->CR = 0x1010000;
        RCC->CFGR = 0x1DC402;
}

```

這里從機(jī)項目的main.c文件:

```cpp
#include "stm32f10x.h"
#include "usart.h"
#include "delay.h"
#include "oled.h"
#include "sys.h"
#include "SPI_NRF.h"
#include <stdarg.h>
#include <string.h>
#include <stdio.h>

u8 status;        //用于判斷接收/發(fā)送狀態(tài)
u8 txbuf[4];         //發(fā)送緩沖
u8 rxbuf[4];//接收緩沖
u8 i;
/*
*讀取溫濕度傳感器DHT11的值,并用串口打印出來
*/

void clock_init(void);
/**************************************************************************
函數(shù)名:int main(void)
參數(shù)說明:無
返回值:無
函數(shù)作用:主函數(shù)
***************************************************************************/
int main(void)
{        
         
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        SPI_NRF_Init();
        delay_init();
    OLED_Init();         
    clock_init();        
    usart_init(115200);                //初始化串口
         OLED_Clear();
        OLED_Display_On();
        OLED_ShowCHinese(40,0,0);
        OLED_ShowCHinese(60,0,1);
        OLED_ShowCHinese(80,0,2);
        OLED_ShowCHinese(100,0,3);
                 //
                 //顯示各個參數(shù)的中文
    OLED_ShowCHinese(0,2,4);
        OLED_ShowCHinese(18,2,5);         
        OLED_ShowString(35,2, ":",16);//顯示溫度中文
        
        OLED_ShowCHinese(0,4,6);
        OLED_ShowCHinese(18,4,7);         
        OLED_ShowString(35,4, ":",16);//顯示溫度中文        
        printf("\r\n 這是一個 NRF24L01 無線傳輸實驗 \r\n");
        printf("\r\n 這是無線傳輸 主機(jī)端 的反饋信息\r\n");
        printf("\r\n   正在檢測NRF與MCU是否正常連接。。。\r\n");
        
         /*檢測NRF模塊與MCU的連接*/
           status = NRF_Check();

        /*判斷連接狀態(tài)*/  
   if(status == SUCCESS)           
                    printf("\r\n      NRF與MCU連接成功!\r\n");  
   else         
                printf("\r\n  正在檢測NRF與MCU是否正常連接。。。\r\n");
         
         
         while(1)
         {        
                 
        printf("\r\n 從機(jī)端 進(jìn)入接收模式\r\n");
        NRF_RX_Mode();     //這邊的是在收
         
        /*等待接收數(shù)據(jù)*/
        status = NRF_Rx_Dat(rxbuf);

           /*判斷接收狀態(tài)*/
                 if(status == RX_DR)
        {
                printf("\r\n 從機(jī)端 接收到 主機(jī)端 發(fā)送的數(shù)據(jù) \r\n");
          for(i=0;i<2;i++)
                                {        
                                        if(i%2==0)
                                        {
                                                printf("\r\n 溫度的數(shù)據(jù)為:%d \r\n",rxbuf[ i]);
                                                OLED_ShowNum(45,2,rxbuf[ i],3,16);//顯示溫度的碼值
                                                txbuf[ i] =1;//返回發(fā)送給主機(jī)上的值為1
                                }
                                else
                               {
                                                printf("\r\n 濕度的數(shù)據(jù)為:%d \r\n",rxbuf[ i]);
                                            OLED_ShowNum(45,4,rxbuf[ i],3,16);//顯示濕度的碼值
                                                txbuf[ i] =1;//返回發(fā)送給主機(jī)上的值為1
                               }                                       
                                       
                                }        
        }   
         
                printf("\r\n 從機(jī)端 進(jìn)入自應(yīng)答發(fā)送模式");
                  NRF_TX_Mode();
               
                /*不斷重發(fā),直至發(fā)送成功*/         
         do
           {           
                status = NRF_Tx_Dat(txbuf);
                  
                }while(status == MAX_RT);
        }

}
/**************************************************************************
函數(shù)名:void clock_init(void)
參數(shù)說明:無
返回值:無
函數(shù)作用:開啟高速外部時鐘,
ADCCLK設(shè)置為12MHZ,        SYSCLK設(shè)置為72Mhz,PCLK1設(shè)置為36MHZ,PKLC2設(shè)置為72mhz
***************************************************************************/
void clock_init(void)
{
        RCC->CR = 0x1010000;
        RCC->CFGR = 0x1DC402;
}

```
成果展示:
[雙板接線圖]
串口打印]

[室內(nèi)檢測]

項目總結(jié):
總項目實現(xiàn)最大的難點是網(wǎng)上找到了相應(yīng)的NRF2401的傳輸格式,只是這個格式并不能實現(xiàn)對你想要的數(shù)據(jù)的傳輸,所以這個實現(xiàn)的核心代碼還是自己一遍又一遍根據(jù)模塊實現(xiàn)的邏輯不斷完善的,同時在數(shù)據(jù)傳輸?shù)倪^程,OLED的格式我也是將實現(xiàn)數(shù)據(jù)的傳輸,讓其在室溫顯示下更加的穩(wěn)定,同時這個傳輸有個小小的瑕疵就是,設(shè)置了一個閾值,傳輸?shù)拈撝狄坏骄蜁袚Q到主機(jī)變從機(jī),從機(jī)變主機(jī)的狀態(tài),鉆了全雙工的空子(假的(????))

代碼:
基于STM32F103C8T6實現(xiàn)用2.4G模塊(NRF2401)傳輸室內(nèi)溫濕度.7z (157.63 KB, 下載次數(shù): 227)

評分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏12 分享淘帖 頂1 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:584195 發(fā)表于 2021-8-19 16:02 | 只看該作者
我好多年以后做過STM8的傳輸,感覺還是沒有驅(qū)動好。
回復(fù)

使用道具 舉報

板凳
ID:836950 發(fā)表于 2021-8-31 16:48 | 只看該作者
zyluglugl 發(fā)表于 2021-8-19 16:02
我好多年以后做過STM8的傳輸,感覺還是沒有驅(qū)動好。

驅(qū)動在設(shè)置上使能沒有注意的話,然后自己也不知道錯在哪里,那就有的忙的!自己真心體會到這種不快樂的快樂
回復(fù)

使用道具 舉報

地板
ID:412508 發(fā)表于 2022-5-2 11:18 | 只看該作者
謝謝樓主,寫的很詳細(xì),自已慢慢消化一下。
回復(fù)

使用道具 舉報

5#
ID:1094757 發(fā)表于 2023-9-30 23:19 | 只看該作者

謝謝樓主,寫的很詳細(xì),自已慢慢消化一下。
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表