基于STM32F103C8T6實現(xiàn)用2.4G模塊(NRF2401)傳輸室內(nèi)溫濕度并顯示OLED
對于2.4G模塊上的應用,很多是將這個這個模塊上的應用實現(xiàn)在51單片機上,我問了很多相關文章的博主,他們從最開始的程序幾乎都是從51單片機上,進行開發(fā),感謝這些趕路人,我們這些從事快速開發(fā)的愛好者做好的道路。
感謝[999994博主](http://www.zg4o1577.cn/bbs/space-uid-683358.html),[綻放中的青春博主](http://www.zg4o1577.cn/bbs/space-uid-290170.html)
好了,現(xiàn)在就進入主食階段
## 一:對2.4G模塊(NRF2401)的介紹
作為我們在開發(fā)應用的短距離傳輸信息的選擇模塊之一,作為在項目上實現(xiàn)互傳的模塊,可實現(xiàn)半雙工和全雙工,可以實現(xiàn)點對點或是 1 對 6 的無線通信。對于 NRF24L01 的固件編程工作主要是參照NRF24L01 的狀態(tài)機。主要有以下幾個狀態(tài):
Power Down Mode:掉電模式
Tx Mode:發(fā)射模式
Rx Mode:接收模式
Standby-1Mode:待機 1 模式
Standby-2 Mode:待機 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 |
但是在我應用的項目上我沒有使用全雙工,項目設計是一個板子(STM32最小系統(tǒng),以下皆是)上的一個作為主機,一個作為從機,其中主機是負責采集室內(nèi)的溫度,從機是為了負責接收主機主機上的數(shù)據(jù),顯示在OLED上面,同時為了讓自己的項目更好的檢測,我在從機上也實現(xiàn)了對主機數(shù)據(jù)的發(fā)送,主句實現(xiàn)接收。
主機上發(fā)送:
```cpp
printf("\r\n 主機端 進入自應答發(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 主機端 沒接收到應答信號,發(fā)送次數(shù)超過限定值,發(fā)送失敗。 \r\n");
break;
case ERROR:
printf("\r\n 未知原因?qū)е掳l(fā)送失敗。 \r\n");
break;
case TX_DS:
printf("\r\n 主機端 接收到 從機端 的應答信號,發(fā)送成功! \r\n");
break;
}
```
從機上接收:
```cpp
printf("\r\n 從機端 進入接收模式\r\n");
NRF_RX_Mode(); //這邊的是在收
/*等待接收數(shù)據(jù)*/
status = NRF_Rx_Dat(rxbuf);
/*判斷接收狀態(tài)*/
if(status == RX_DR)
{
printf("\r\n 從機端 接收到 主機端 發(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;
}
}
}
```
主機上接收從機數(shù)據(jù):
```cpp
printf("\r\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 主機端 接收到 從機端 發(fā)送的數(shù)據(jù)為:%d \r\n",rxbuf[ i]);
txbuf[ i] =rxbuf[ i];
}
break;
case ERROR:
printf("\r\n 主機端 接收出錯。 \r\n");
break;
}
```
從機上發(fā)送給主機數(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ā)送給主機上的值為1
```
txbuf[ i]就是發(fā)送個主機上面的數(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ā)送給主機上的值為1
```
## 二.溫濕度傳感器簡介
DHT11是一款價格便宜,易于使用的溫度濕度測量二合一傳感器。它使用單根總線與單片機進行雙向的串行數(shù)據(jù)傳輸,信號傳輸距離可達20米以上。非常適用于對精度和實時性要求不高的溫濕度測量場合。
接口設置:
|DATA | PB11 |
|--|--|
這個模塊也是有相應的代碼格式,我這里就提幾個注意事項:
1.DHT11使用單一總線通信,即DATA引腳和單片機連接的線。總線總是處于空閑狀態(tài)和通信狀態(tài)這個2個狀態(tài)之間。
2.DHT11上電后,要等待 約 1秒 以越過不穩(wěn)定狀態(tài),在此期間不能發(fā)送任何指令。
3.DHT11屬于低速傳感器,兩次通信請求之間的間隔時間不能太短,一般來說要不能低于1秒。
4.當前DHT11通信幀的小數(shù)部分默認都是0,廠商預留給以后實現(xiàn)。所以一般只讀取整數(shù)值部分即可。校驗和定義為:前4個Byte的總和的低8位。
## 三.OLED顯示屏
我所用的OLED屏有白色,屏的大小為0.96寸,像素點為128*64,也稱之為0.96OLED屏或者12864屏。通時我選擇的是4腳,運用的協(xié)議是IIC協(xié)議,
```cpp
void IIC_Start(void)
{
OLED_SCLK_Set() ;
OLED_SDIN_Set();
OLED_SDIN_Clr();
OLED_SCLK_Clr();
}
理解了OLED的顯示方式,漢字取模也是很有必要的,我選擇列行式的取模方式,設置為C51原則:
[PLC取模軟件]
1.png (46.27 KB, 下載次數(shù): 105)
下載附件
2021-8-9 04:43 上傳
想要更加詳細的理解OLED上面的知識我推薦這位博主的博文[OLED詳細解剖](https://blog.csdn.net/u010858987 ... 1018.2226.3001.4187)
下面是主機項目工程中的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 這是無線傳輸 主機端 的反饋信息\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 主機端 進入自應答發(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 主機端 沒接收到應答信號,發(fā)送次數(shù)超過限定值,發(fā)送失敗。 \r\n");
break;
case ERROR:
printf("\r\n 未知原因?qū)е掳l(fā)送失敗。 \r\n");
break;
case TX_DS:
printf("\r\n 主機端 接收到 從機端 的應答信號,發(fā)送成功! \r\n");
break;
}
printf("\r\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 主機端 接收到 從機端 發(fā)送的數(shù)據(jù)為:%d \r\n",rxbuf[ i]);
txbuf[ i] =rxbuf[ i];
}
break;
case ERROR:
printf("\r\n 主機端 接收出錯。 \r\n");
break;
}
}
}
/**************************************************************************
函數(shù)名:void clock_init(void)
參數(shù)說明:無
返回值:無
函數(shù)作用:開啟高速外部時鐘,
ADCCLK設置為12MHZ, SYSCLK設置為72Mhz,PCLK1設置為36MHZ,PKLC2設置為72mhz
***************************************************************************/
void clock_init(void)
{
RCC->CR = 0x1010000;
RCC->CFGR = 0x1DC402;
}
```
這里從機項目的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 這是無線傳輸 主機端 的反饋信息\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 從機端 進入接收模式\r\n");
NRF_RX_Mode(); //這邊的是在收
/*等待接收數(shù)據(jù)*/
status = NRF_Rx_Dat(rxbuf);
/*判斷接收狀態(tài)*/
if(status == RX_DR)
{
printf("\r\n 從機端 接收到 主機端 發(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ā)送給主機上的值為1
}
else
{
printf("\r\n 濕度的數(shù)據(jù)為:%d \r\n",rxbuf[ i]);
OLED_ShowNum(45,4,rxbuf[ i],3,16);//顯示濕度的碼值
txbuf[ i] =1;//返回發(fā)送給主機上的值為1
}
}
}
printf("\r\n 從機端 進入自應答發(fā)送模式");
NRF_TX_Mode();
/*不斷重發(fā),直至發(fā)送成功*/
do
{
status = NRF_Tx_Dat(txbuf);
}while(status == MAX_RT);
}
}
/**************************************************************************
函數(shù)名:void clock_init(void)
參數(shù)說明:無
返回值:無
函數(shù)作用:開啟高速外部時鐘,
ADCCLK設置為12MHZ, SYSCLK設置為72Mhz,PCLK1設置為36MHZ,PKLC2設置為72mhz
***************************************************************************/
void clock_init(void)
{
RCC->CR = 0x1010000;
RCC->CFGR = 0x1DC402;
}
```
成果展示:
[雙板接線圖]
2.jpg (1005.32 KB, 下載次數(shù): 83)
下載附件
2021-8-9 04:43 上傳
串口打印]
4.png (51.45 KB, 下載次數(shù): 107)
下載附件
2021-8-9 04:44 上傳
[室內(nèi)檢測]
3.jpg (950.66 KB, 下載次數(shù): 122)
下載附件
2021-8-9 04:43 上傳
項目總結:
總項目實現(xiàn)最大的難點是網(wǎng)上找到了相應的NRF2401的傳輸格式,只是這個格式并不能實現(xiàn)對你想要的數(shù)據(jù)的傳輸,所以這個實現(xiàn)的核心代碼還是自己一遍又一遍根據(jù)模塊實現(xiàn)的邏輯不斷完善的,同時在數(shù)據(jù)傳輸?shù)倪^程,OLED的格式我也是將實現(xiàn)數(shù)據(jù)的傳輸,讓其在室溫顯示下更加的穩(wěn)定,同時這個傳輸有個小小的瑕疵就是,設置了一個閾值,傳輸?shù)拈撝狄坏骄蜁袚Q到主機變從機,從機變主機的狀態(tài),鉆了全雙工的空子(假的(????))
代碼:
基于STM32F103C8T6實現(xiàn)用2.4G模塊(NRF2401)傳輸室內(nèi)溫濕度.7z
(157.63 KB, 下載次數(shù): 227)
2021-8-9 04:46 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|