基于STM32的NRF24L01 2.4G通讯模块的驱动实验(HAL库)

news2024/10/5 14:27:50

前言:本文为手把手教学NRF24L01 2.4G通讯模块的驱动实验,本教程的 MCU 采用STM32F103ZET6STM32F103C8T6,彼此进行互相通讯。通过 CubeMX 软件配置 SPI 协议驱动NRF24L01 2.4G通讯模块(HAL库)。NRF24L01 2.4G是嵌入式较为常见的模块,希望这篇博文能给读者朋友的工程项目给予些许帮助。(文末代码开源!

硬件设备:STM32F103ZET6;STM32F103C8T6;NRF24L01 2.4G(2个);DHT11;OLED

硬件实物图:

效果图:

引脚连接:

NRF24L01 2.4G引脚(ZET6):

CSN --> PB3

CE --> PB4

IRQ --> PB5

SCK --> PA5

MISO --> PA6

MOSI --> PA7

Vcc --> 3.3v

GND --> GND

 DHT11引脚(ZET6):

PA1 --> DATA

Vcc --> 3.3v

GND --> GND

0.96寸OLED引脚(C8T6):

SDA --> PB7

SCL --> PB6

Vcc --> 3.3v

GND --> GND

一、NRF24L01 2.4G模块简介

NRF24L01 是北欧芯片巨头 Nordic 公司生产的一款无线通信芯片,可以工作在免费开放的 2.4GHz 频段,通信速率可以达到最高 2Mbps。采用 FSK 调制,内部集成 Nordic 自己的 Enhanced Short Burst 协议,可以实现 点对点 或者 1对6 的无线通信。

NRF24L01 2.4G 通讯模块采用 SPI 通信,引脚如下:

1、CSN:芯片的片选线,低电平芯片工作;

2、SCK:芯片控制的时钟线(SPI的时钟);

3、MISO:芯片控制数据线(SPI的MISO);

4、MOSI:芯片控制数据线(SPI的MOSI);

5、IRQ:中断信号,NRF24L01芯片收到数据、或者发送完数据等等一些情况会产生下降沿中断;

6、CE:芯片的模式控制线,决定了芯片的工作状态。

NRF24L01 的引脚情况如下图所示,上图仅供参考,实际情况以手中模块为准。 

NRF24L01 的涉及领域:

无线鼠标、键盘、游戏机操纵杆;无线门禁;无线数据通讯;无线数据通讯;遥控装置;遥感勘测;智能运动设备;工业传感器;玩具。

二、模块详解

2.1 工作模式

NRF24L01 共有 6 种工作模式工作模式由 PWR_UP 寄存器、PRIM_RX 寄存器 和 CE 决定,详见下表:

收发模式:

其中,收发模式又有: Enhanced ShockBurstTM 收发模式和 ShockBurstTM 收发模式,只有 Enhanced ShockBurstTM 收发模式支持自动 ACK 和自动重发。开启自动 ACK,则默认选择 Enhanced ShockBurstTM 模式

待机模式:

待机模式 I 在保证快速启动的同时减少系统平均消耗电流。在待机模式 I 下,晶振正常工作。在待机模式 II 下部分时钟缓冲器处在工作模式。当发送端 TX FIFO 寄存器为空并且 CE 为高电平时进入待机模式 II。在待机模式期间,寄存器配置字内容保持不变。

掉电模式:
在掉电模式下,nRF20L01 各功能关闭,保持电流消耗最小。进入掉电模式后,nRF24L01 停止工作,但寄存器内容保持不变。掉电模式由寄存器 PWR_UP 位来控制。

★在 Enhanced ShockBurstTM 收发模式下:

1、NRF24L01 自动处理字头和 CRC 校验码。在接收数据时,自动把字头和 CRC 校验码移去。在发送数据时,自动加上字头和 CRC 校验码,在发送模式下,置 CE 为高,至少 10us,将使能发送过程。

2、在接收模式下:最多可以接收 6 路不通的数据。每一个数据通道使用不同的地址,但是共用相同的频道。也就是说 6 个不同的 NRF24L01 置为发送模式后可以与同一个设置为接收模式的 NRF24L01 进行通讯,而设置为接收模式的 NRF24L01 可以对这 6 个发射端进行识别。

2.2 NRF24L01固件编程

NRF24L01 2.4G 的固件编程的基本思路如下:
  1. 置 CSN 为低,使能芯片,配置芯片各个参数(关键RX和TX配置),配置参数在PowerDown状态中完成。
  2. 如果是Tx模式,装载接收端地址,填充TxFIFO。
  3. 配置完成以后,通过CONFIG中的PWR_UP、PRIM_RX与CE参数确定24L01要切换到的状态。
  4. Tx Mode:PWR_UP=1;PRIM_RX=0;CE=1 (保持超过10us就可以);
  5. Rx Mode:PWR_UP=1;PRIM_RX=1;CE=1;
  6. 将IRQ 接到外部中断输入引脚,通过中断程序进行处理。IRQ引脚会在以下三种情况变低:
  7. Tx FIFO发完并且收到ACK(使能 ACK 情况下)
  8. Rx FIFO收到数据
  9. 达到最大重发次数

★Tx 与Rx 的配置过程:

本节只是叙述了采用 Enhanced ShockBurstTM 通信方式的Tx 与Rx 的配置及通信过程,熟悉了NRF24L01 以后可以采用别的通信方式。

2.2.1 Tx 模式初始化过程

(1)写Tx 节点的地址 TX_ADDR
(2)写Rx 节点的地址(主要是为了使能Auto Ack) RX_ADDR_P0
(3)使能AUTO ACK EN_AA
(4)使能PIPE 0 EN_RXADDR
(5)配置自动重发次数 SETUP_RETR
(6)选择通信频率 RF_CH
(7)配置发射参数(低噪放大器增益、发射功率、无线速率) RF_SETUP
(8 ) 选择通道0 有效数据宽度 Rx_Pw_P0
(9)配置24L01 的基本参数以及切换工作模式 CONFIG。

2.2.2 Rx 模式初始化过程

(1)写Rx 节点的地址 RX_ADDR_P0
(2)使能AUTO ACK EN_AA
(3)使能PIPE 0 EN_RXADDR
(4)选择通信频率 RF_CH
(5) 选择通道0 有效数据宽度 Rx_Pw_P0
(6)配置发射参数(低噪放大器增益、发射功率、无线速率) RF_SETUP
(7)配置24L01 的基本参数以及切换工作模式 CONFIG。

三、项目详解

3.1 项目概述

实验目标:实时进行 STM32F103ZET6 驱动 DHT11 进行环境测温,然后借助 NRF24L01 2.4G 模块将温度信息传输给 STM32F103C8T6,并在0.96寸OLED上进行显示。具体工程图如下:

3.2 项目模块

本项目除了 NRF24L01 2.4G 模块外,其余模块均为过往博客项目使用的模块,这里仅给读者朋友提供参考博客。

博客地址:http://t.csdn.cn/suwlV

四、CubeMX配置

★CubeMX 项目工程给出 NRF24L01 2.4G 的配置过程,2个板套件的 NRF24L01 2.4G 驱动方式一致(以STM32F103ZET6的CubeMX配置为例)。

1、RCC配置外部高速晶振(精度更高)——HSE;

2、SYS配置:Debug设置成Serial Wire否则可能导致芯片自锁);

3、TIM2配置:由上面可知DHT11的使用需要us级的延迟函数,HAL库自带只有ms的,所以需要自己设计一个定时器;

4、SPI1配置:NRF24L01 2.4G模块采用SPI通讯;Mode设置:Full Duplex Master;Baud Rate:不可超10MBits/s速度;

5、UART1配置:通过串口1将DHT11测得温度实时打印,与NRF24L01通讯后的数据进行验证;

6、GPIO配置:PB3和PB4设置为output与PB5设置为input;PA1设置为output,即DHT11数据输出引脚;

7、时钟树配置

8、工程配置

五、代码与解析

5.1  STM32F103ZET6程序

STM32F103ZET6 通过 DHT11 模块测量温湿度,之后将测得的温度通过 NRF24L01 2.4G 发送给同 “地址” 并处于 “接受” 状态的 NRF24L01 2.4G 模块,之后再将接收到的温湿度数据显示在 OLED 上。

特别强调:

根据无线通讯原理,NRF24L01 发送数据给对端模块的时候要发射电磁波,这本质上是一个像四周空间 广播 的过程。只要是有效距离范围内的任意一个处于接收状态的 NRF24L01 模块,都能收到这个信号。辨别数据的前提就是 “地址”

总结:一定要保证接收端与发送端的地址一致并处于各自应该处于的模式下。

5.1.1 NRF24L01代码

根据上述解析可以得知,需要将程序中的 TX_ADDRESS[TX_ADR_WIDTH]  RX_ADDRESS[RX_ADR_WIDTH] 变量保持一致。同时根据 NRF24L01 2.4G 模块的 TxRx 的配置要求,编写寄存器的配置代码。代码框架为HAL库的API接口函数编写,具体参考如下:

nrf24l01.h:

#ifndef __nrf24L01_H
#define __nrf24L01_H
#include "stdint.h"
 
/* 宏定义 --------------------------------------------------------------------*/
 
#define NRF24L01_SPI_CS_ENABLE()    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_RESET)	//PB3
#define NRF24L01_SPI_CS_DISABLE()   HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_SET)
 
#define NRF24L01_CE_LOW()   HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET)					//PB4
#define NRF24L01_CE_HIGH() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET)
 
#define NRF24L01_IRQ_PIN_READ()  HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_5)									//PB5
 
 
// NRF24L01发送接收数据宽度定义
#define TX_ADR_WIDTH                                  5   	//5字节的地址宽度
#define RX_ADR_WIDTH                                  5   	//5字节的地址宽度
#define TX_PLOAD_WIDTH                                32  	//32字节的用户数据宽度
#define RX_PLOAD_WIDTH                                32  	//32字节的用户数据宽度
 
//NRF24L01寄存器操作命令
#define NRF_READ_REG                                  0x00  //读配置寄存器,低5位为寄存器地址
#define NRF_WRITE_REG                                 0x20  //写配置寄存器,低5位为寄存器地址
#define RD_RX_PLOAD                                   0x61  //读RX有效数据,1~32字节
#define WR_TX_PLOAD                                   0xA0  //写TX有效数据,1~32字节
#define FLUSH_TX                                      0xE1  //清除TX FIFO寄存器.发射模式下用
#define FLUSH_RX                                      0xE2  //清除RX FIFO寄存器.接收模式下用
#define REUSE_TX_PL                                   0xE3  //重新使用上一包数据,CE为高,数据包被不断发送.
#define NOP                                           0xFF  //空操作,可以用来读状态寄存器	 
//SPI(NRF24L01)寄存器地址
#define CONFIG                                        0x00  //配置寄存器地址;bit0:1接收模式,0发射模式;bit1:电选择;bit2:CRC模式;bit3:CRC使能;
                                                            //bit4:中断MAX_RT(达到最大重发次数中断)使能;bit5:中断TX_DS使能;bit6:中断RX_DR使能
#define EN_AA                                         0x01  //使能自动应答功能  bit0~5,对应通道0~5
#define EN_RXADDR                                     0x02  //接收地址允许,bit0~5,对应通道0~5
#define SETUP_AW                                      0x03  //设置地址宽度(所有数据通道):bit1,0:00,3字节;01,4字节;02,5字节;
#define SETUP_RETR                                    0x04  //建立自动重发;bit3:0,自动重发计数器;bit7:4,自动重发延时 250*x+86us
#define RF_CH                                         0x05  //RF通道,bit6:0,工作通道频率;
#define RF_SETUP                                      0x06  //RF寄存器;bit3:传输速率(0:1Mbps,1:2Mbps);bit2:1,发射功率;bit0:低噪声放大器增益
#define STATUS                                        0x07  //状态寄存器;bit0:TX FIFO满标志;bit3:1,接收数据通道号(最大:6);bit4,达到最多次重发
                                                            //bit5:数据发送完成中断;bit6:接收数据中断;
#define MAX_TX  		                                  0x10  //达到最大发送次数中断
#define TX_OK   		                                  0x20  //TX发送完成中断
#define RX_OK   		                                  0x40  //接收到数据中断
 
#define OBSERVE_TX                                    0x08  //发送检测寄存器,bit7:4,数据包丢失计数器;bit3:0,重发计数器
#define CD                                            0x09  //载波检测寄存器,bit0,载波检测;
#define RX_ADDR_P0                                    0x0A  //数据通道0接收地址,最大长度5个字节,低字节在前
#define RX_ADDR_P1                                    0x0B  //数据通道1接收地址,最大长度5个字节,低字节在前
#define RX_ADDR_P2                                    0x0C  //数据通道2接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
#define RX_ADDR_P3                                    0x0D  //数据通道3接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
#define RX_ADDR_P4                                    0x0E  //数据通道4接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
#define RX_ADDR_P5                                    0x0F  //数据通道5接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
#define TX_ADDR                                       0x10  //发送地址(低字节在前),ShockBurstTM模式下,RX_ADDR_P0与此地址相等
#define RX_PW_P0                                      0x11  //接收数据通道0有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P1                                      0x12  //接收数据通道1有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P2                                      0x13  //接收数据通道2有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P3                                      0x14  //接收数据通道3有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P4                                      0x15  //接收数据通道4有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P5                                      0x16  //接收数据通道5有效数据宽度(1~32字节),设置为0则非法
#define NRF_FIFO_STATUS                               0x17  //FIFO状态寄存器;bit0,RX FIFO寄存器空标志;bit1,RX FIFO满标志;bit2,3,保留
                                                            //bit4,TX FIFO空标志;bit5,TX FIFO满标志;bit6,1,循环发送上一数据包.0,不循环;
                              
 
/* 函数声明 ------------------------------------------------------------------*/
void NRF24L01_RX_Mode(void);					//配置为接收模式
void NRF24L01_TX_Mode(void);					//配置为发送模式
uint8_t NRF24L01_Write_Buf(uint8_t reg, uint8_t *pBuf, uint8_t uint8_ts);//写数据区
uint8_t NRF24L01_Read_Buf(uint8_t reg, uint8_t *pBuf, uint8_t uint8_ts);	//读数据区		  
uint8_t NRF24L01_Read_Reg(uint8_t reg);					//读寄存器
uint8_t NRF24L01_Write_Reg(uint8_t reg, uint8_t value);		//写寄存器
uint8_t NRF24L01_Check(void);						//检查24L01是否存在
uint8_t NRF24L01_TxPacket(uint8_t *txbuf);				//发送一个包的数据
uint8_t NRF24L01_RxPacket(uint8_t *rxbuf);				//接收一个包的数据
void NRF_LowPower_Mode(void);	
 
 
#endif
 

nrf24l01.c:

#include "nrf24L01.h"
#include "spi.h"
 
const uint8_t TX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //发送地址
const uint8_t RX_ADDRESS[RX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //接收地址
  
/**
  * 函数功能: 往串行Flash读取写入一个字节数据并接收一个字节数据
  * 输入参数: byte:待发送数据
  * 返 回 值: uint8_t:接收到的数据
  * 说    明:无
  */
uint8_t SPIx_ReadWriteByte(SPI_HandleTypeDef* hspi,uint8_t byte)
{
  uint8_t d_read,d_send=byte;
  if(HAL_SPI_TransmitReceive(hspi,&d_send,&d_read,1,0xFF)!=HAL_OK)
  {
    d_read=0xFF;
  }
  return d_read; 
}
 
/**
  * 函数功能: 检测24L01是否存在
  * 输入参数: 无
  * 返 回 值: 0,成功;1,失败
  * 说    明:无          
  */ 
uint8_t NRF24L01_Check(void)
{
	uint8_t buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
	uint8_t i;
   
	NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,buf,5);//写入5个字节的地址.	
	NRF24L01_Read_Buf(TX_ADDR,buf,5); //读出写入的地址  
	for(i=0;i<5;i++)if(buf[i]!=0XA5)break;	 							   
	if(i!=5)return 1;   //检测24L01错误	
	return 0;		 	//检测到24L01
}	
 
/**
  * 函数功能: SPI写寄存器
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:reg:指定寄存器地址
  *           
  */ 
uint8_t NRF24L01_Write_Reg(uint8_t reg,uint8_t value)
{
    uint8_t status;	
  NRF24L01_SPI_CS_ENABLE();                 //使能SPI传输
  status =SPIx_ReadWriteByte(&hspi1,reg);   //发送寄存器号 
  SPIx_ReadWriteByte(&hspi1,value);         //写入寄存器的值
  NRF24L01_SPI_CS_DISABLE();                //禁止SPI传输	   
  return(status);       			//返回状态值
}
 
/**
  * 函数功能: 读取SPI寄存器值
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:reg:要读的寄存器
  *           
  */ 
uint8_t NRF24L01_Read_Reg(uint8_t reg)
{
	uint8_t reg_val;	    
 	NRF24L01_SPI_CS_ENABLE();          //使能SPI传输		
  SPIx_ReadWriteByte(&hspi1,reg);   //发送寄存器号
  reg_val=SPIx_ReadWriteByte(&hspi1,0XFF);//读取寄存器内容
  NRF24L01_SPI_CS_DISABLE();          //禁止SPI传输		    
  return(reg_val);           //返回状态值
}		
 
/**
  * 函数功能: 在指定位置读出指定长度的数据
  * 输入参数: 无
  * 返 回 值: 此次读到的状态寄存器值 
  * 说    明:无
  *           
  */ 
uint8_t NRF24L01_Read_Buf(uint8_t reg,uint8_t *pBuf,uint8_t len)
{
	uint8_t status,uint8_t_ctr;	   
  
  NRF24L01_SPI_CS_ENABLE();           //使能SPI传输
  status=SPIx_ReadWriteByte(&hspi1,reg);//发送寄存器值(位置),并读取状态值   	   
 	for(uint8_t_ctr=0;uint8_t_ctr<len;uint8_t_ctr++)
  {
    pBuf[uint8_t_ctr]=SPIx_ReadWriteByte(&hspi1,0XFF);//读出数据
  }
  NRF24L01_SPI_CS_DISABLE();       //关闭SPI传输
  return status;        //返回读到的状态值
}
 
/**
  * 函数功能: 在指定位置写指定长度的数据
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:reg:寄存器(位置)  *pBuf:数据指针  len:数据长度
  *           
  */ 
uint8_t NRF24L01_Write_Buf(uint8_t reg, uint8_t *pBuf, uint8_t len)
{
	uint8_t status,uint8_t_ctr;	    
 	NRF24L01_SPI_CS_ENABLE();          //使能SPI传输
  status = SPIx_ReadWriteByte(&hspi1,reg);//发送寄存器值(位置),并读取状态值
  for(uint8_t_ctr=0; uint8_t_ctr<len; uint8_t_ctr++)
  {
    SPIx_ReadWriteByte(&hspi1,*pBuf++); //写入数据	 
  }
  NRF24L01_SPI_CS_DISABLE();       //关闭SPI传输
  return status;          //返回读到的状态值
}		
 
/**
  * 函数功能: 启动NRF24L01发送一次数据
  * 输入参数: 无
  * 返 回 值: 发送完成状况
  * 说    明:txbuf:待发送数据首地址
  *           
  */ 
uint8_t NRF24L01_TxPacket(uint8_t *txbuf)
{
	uint8_t sta; 
	NRF24L01_CE_LOW();
    NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF  32个字节
 	NRF24L01_CE_HIGH();//启动发送	 
  
	while(NRF24L01_IRQ_PIN_READ()!=0);//等待发送完成
  
	sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值	   
	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
	if(sta&MAX_TX)//达到最大重发次数
	{
		NRF24L01_Write_Reg(FLUSH_TX,0xff);//清除TX FIFO寄存器 
		return MAX_TX; 
	}
	if(sta&TX_OK)//发送完成
	{
		return TX_OK;
	}
	return 0xff;//其他原因发送失败
}
 
/**
  * 函数功能:启动NRF24L01接收一次数据
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  *           
  */ 
uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)
{
	uint8_t sta;		 
	sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值    	 
	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
	if(sta&RX_OK)//接收到数据
	{
		NRF24L01_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
		NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器 
		return 0; 
	}	   
	return 1;//没收到任何数据
}			
 
/**
  * 函数功能: 该函数初始化NRF24L01到RX模式
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  *           
  */ 
void NRF24L01_RX_Mode(void)
{
  NRF24L01_CE_LOW();	  
  NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0F);//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC 
  NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);    //使能通道0的自动应答    
  NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);//使能通道0的接收地址  	 
  NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);	     //设置RF通信频率		  
  NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);//设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度 	       
  NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址
  NRF24L01_CE_HIGH(); //CE为高,进入接收模式 
  HAL_Delay(1);
}	
 
/**
  * 函数功能: 该函数初始化NRF24L01到TX模式
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  *           
  */ 
void NRF24L01_TX_Mode(void)
{														 
  NRF24L01_CE_LOW();	    
  NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址 
  NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK	  
  NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);     //使能通道0的自动应答    
  NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址  
  NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0xff);//设置自动重发间隔时间:4000us + 86us;最大自动重发次数:15次
  NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);       //设置RF通道为40
  NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
  NRF24L01_CE_HIGH();//CE为高,10us后启动发送
  HAL_Delay(1);
}
 
/**
  * 函数功能: 该函数NRF24L01进入低功耗模式
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  *           
  */
void NRF_LowPower_Mode(void)
{
	NRF24L01_CE_LOW();	 
	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x00);		//配置工作模式:掉电模式
}
 

5.1.2 DHT11代码 

dht11.h:

#ifndef __DHT11_H__
#define __DHT11_H__
 
/* Private includes ----------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "stdio.h"
#include "tim.h"
#include "stm32f1xx.h"
 
/* Private define ------------------------------------------------------------*/
#define DHT11_PIN_SET   HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET)                                            //  拉高GPIO
#define DHT11_PIN_RESET HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET)                                          //  拉低GPIO
#define DHT11_READ_IO   HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)                                                          //  DHT11 GPIO数据引脚
 
#define DLY_TIM_Handle (&htim2)                                                                                     // 定时器
 
 
/* Private variables ---------------------------------------------------------*/
 
/* Private typedef -----------------------------------------------------------*/
 
/* Private function prototypes -----------------------------------------------*/
void DHT11(void);
void DHT11_START(void);
unsigned char DHT11_READ_BIT(void);
unsigned char DHT11_READ_BYTE(void);
unsigned char DHT11_READ_DATA(void);
unsigned char DHT11_Check(void);
static void DHT11_GPIO_MODE_SET(uint8_t mode);
void Tims_delay_us(uint16_t nus);
void delay_us(uint16_t nus);
    
#endif

dht11.c:

#include "dht11.h"
#include "stdio.h"
#include "nrf24l01.h"

/**
  * @brief  温湿度传感器主函数
  * @param  void
  * @retval None
  */
void DHT11(void)
{
    DHT11_READ_DATA();
    HAL_Delay(50);  		             // 预设一定缓冲
}
 
/**
  * @brief  温湿度传感器启动信号发送
  * @param  void
  * @retval None
  */
void DHT11_START(void)
{
    DHT11_GPIO_MODE_SET(0);                         //  主机设置为输出模式
    
    DHT11_PIN_RESET;                                //  主机拉低电平
    
    HAL_Delay(20);                                  //  主机等待 18 < ms > 30
    
    DHT11_GPIO_MODE_SET(1);                         //  主机设置为输入模式,等待DHT11答应
}                                                   //  因为设置了上拉输入,GPIO -> 1
 
/**
  * @brief  读取一位数据 1bit
  * @param  void
  * @retval 0/1
  */
unsigned char DHT11_READ_BIT(void)
{
    while(!DHT11_READ_IO);                          //  过度数据的低电平 
    
    Tims_delay_us(40);                              //  过度数据的高电平
    
    if(DHT11_READ_IO)                               //  此时如果还为高电平则数据为 1
    {
        while(DHT11_READ_IO);                       //  过度数据的高电平
        return 1;
    }   
    else                                            //  若此时为低则为 0
    {
        return 0;
    }
}
 
/**
  * @brief  读取一个字节数据 1byte / 8bit
  * @param  void
  * @retval temp
  */
unsigned char DHT11_READ_BYTE(void)
{
    uint8_t i,temp = 0;                             //  暂时存储数据
    
    for(i=0; i<8 ;i++)
    {
        temp <<= 1;                                 
        if(DHT11_READ_BIT())                        //  1byte -> 8bit
        {
            temp |= 1;                              //  0000 0001
        }
    }
    return temp;
}
 
/**
  * @brief  读取温湿度传感器数据 5byte / 40bit
  * @param  void
  * @retval 0/1/2
  */
unsigned char DHT11_READ_DATA(void)
{
    uint8_t i;
    uint8_t data[5] = {0};
    
    DHT11_START();                                  //  主机发送启动信号
    
    if(DHT11_Check())                               //  如果DHT11应答     
    {  
        while(!DHT11_READ_IO);                      //  过度DHT11答复信号的低电平
        while(DHT11_READ_IO);                       //  过度DHT11答复信号的高电平
        
        for(i=0; i<5; i++)
        {                        
            data[i] = DHT11_READ_BYTE();            //  读取 5byte
        }
        
        if(data[0] + data[1] + data[2] + data[3] == data[4])
        {
           //显示温度
		   printf("TEMP:%d\r\n",data[2]);
					
		   //显示湿度
		   printf("HUM:%d\r\n",data[0]);
		   NRF24L01_TxPacket(data);
           return 1;                               //  数据校验通过
        }
        else
        {
            return 0;                               //  数据校验失败
        }
    }
    else                                            //  如果DHT11不应答
    {
        return 2;
    }
}
 
/**
  * @brief  检测温湿度传感器是否存在(检测DHT11的应答信号)
  * @param  void
  * @retval 0/1
  */
unsigned char DHT11_Check(void)
{
    Tims_delay_us(40);
    if(DHT11_READ_IO == 0)                          //  检测到DHT11应答
    {
        return 1;
    }
    else                                            //  检测到DHT11不应答
    {
        return 0;
    }
}
 
/**
  * @brief  设置引脚模式
  * @param  mode: 0->out, 1->in
  * @retval None
  */
static void DHT11_GPIO_MODE_SET(uint8_t mode)
{
    if(mode)
    {
        /*  输入  */
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.Pin = GPIO_PIN_1;                   //  9号引脚
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;             //  输入模式
        GPIO_InitStruct.Pull = GPIO_PULLUP;                 //  上拉输入
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    }
    else 
    {
        /*  输出  */
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.Pin = GPIO_PIN_1;                //  9号引脚
        GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;      //  Push Pull 推挽输出模式
        GPIO_InitStructure.Pull = GPIO_PULLUP;              //  上拉输出
        GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;    //  高速
        HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
    }
}
 
/**
  * @brief  定时器延时us,Prescaler -> 32-1
  * @param  us: <= 65535
  * @retval None
  */
void Tims_delay_us(uint16_t nus)
{
	__HAL_TIM_SET_COUNTER(DLY_TIM_Handle, 0);
	__HAL_TIM_ENABLE(DLY_TIM_Handle);
	while (__HAL_TIM_GET_COUNTER(DLY_TIM_Handle) < nus)
	{
	}
	__HAL_TIM_DISABLE(DLY_TIM_Handle);
}

上述代码核心如下代码:

 if(data[0] + data[1] + data[2] + data[3] == data[4])
{
    //显示温度
	printf("TEMP:%d\r\n",data[2]);
	//显示湿度
	printf("HUM:%d\r\n",data[0]);
	NRF24L01_TxPacket(data);
    return 1;                               //  数据校验通过
}

 当 DHT11 测得数据满足 DHT11 的数据验证格式,则串口打印出温湿度信息,并用 NRF24L01_TxPacket(data) 函数将温湿度信息进行发送广播。

5.2  STM32F103C8T6程序

STM32F103C8T6 通过设置 NRF24L01 2.4G 模块为接收模式(并且保证收发地址一致),来接收发送过来的温湿度数据。将接收到的温湿度数据,通过 OLED 屏幕进行显示。

5.2.1 NRF24L01代码

nrf24l01.h:

#ifndef __nrf24L01_H
#define __nrf24L01_H
#include "stdint.h"
 
/* 宏定义 --------------------------------------------------------------------*/
 
#define NRF24L01_SPI_CS_ENABLE()    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET)	//PB0
#define NRF24L01_SPI_CS_DISABLE()   HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET)
 
#define NRF24L01_CE_LOW()   HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET)					//PB1
#define NRF24L01_CE_HIGH() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET)
 
#define NRF24L01_IRQ_PIN_READ()  HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_10)									//PB10
 
 
// NRF24L01发送接收数据宽度定义
#define TX_ADR_WIDTH                                  5   	//5字节的地址宽度
#define RX_ADR_WIDTH                                  5   	//5字节的地址宽度
#define TX_PLOAD_WIDTH                                32  	//32字节的用户数据宽度
#define RX_PLOAD_WIDTH                                32  	//32字节的用户数据宽度
 
//NRF24L01寄存器操作命令
#define NRF_READ_REG                                  0x00  //读配置寄存器,低5位为寄存器地址
#define NRF_WRITE_REG                                 0x20  //写配置寄存器,低5位为寄存器地址
#define RD_RX_PLOAD                                   0x61  //读RX有效数据,1~32字节
#define WR_TX_PLOAD                                   0xA0  //写TX有效数据,1~32字节
#define FLUSH_TX                                      0xE1  //清除TX FIFO寄存器.发射模式下用
#define FLUSH_RX                                      0xE2  //清除RX FIFO寄存器.接收模式下用
#define REUSE_TX_PL                                   0xE3  //重新使用上一包数据,CE为高,数据包被不断发送.
#define NOP                                           0xFF  //空操作,可以用来读状态寄存器	 
//SPI(NRF24L01)寄存器地址
#define CONFIG                                        0x00  //配置寄存器地址;bit0:1接收模式,0发射模式;bit1:电选择;bit2:CRC模式;bit3:CRC使能;
                                                            //bit4:中断MAX_RT(达到最大重发次数中断)使能;bit5:中断TX_DS使能;bit6:中断RX_DR使能
#define EN_AA                                         0x01  //使能自动应答功能  bit0~5,对应通道0~5
#define EN_RXADDR                                     0x02  //接收地址允许,bit0~5,对应通道0~5
#define SETUP_AW                                      0x03  //设置地址宽度(所有数据通道):bit1,0:00,3字节;01,4字节;02,5字节;
#define SETUP_RETR                                    0x04  //建立自动重发;bit3:0,自动重发计数器;bit7:4,自动重发延时 250*x+86us
#define RF_CH                                         0x05  //RF通道,bit6:0,工作通道频率;
#define RF_SETUP                                      0x06  //RF寄存器;bit3:传输速率(0:1Mbps,1:2Mbps);bit2:1,发射功率;bit0:低噪声放大器增益
#define STATUS                                        0x07  //状态寄存器;bit0:TX FIFO满标志;bit3:1,接收数据通道号(最大:6);bit4,达到最多次重发
                                                            //bit5:数据发送完成中断;bit6:接收数据中断;
#define MAX_TX  		                                  0x10  //达到最大发送次数中断
#define TX_OK   		                                  0x20  //TX发送完成中断
#define RX_OK   		                                  0x40  //接收到数据中断
 
#define OBSERVE_TX                                    0x08  //发送检测寄存器,bit7:4,数据包丢失计数器;bit3:0,重发计数器
#define CD                                            0x09  //载波检测寄存器,bit0,载波检测;
#define RX_ADDR_P0                                    0x0A  //数据通道0接收地址,最大长度5个字节,低字节在前
#define RX_ADDR_P1                                    0x0B  //数据通道1接收地址,最大长度5个字节,低字节在前
#define RX_ADDR_P2                                    0x0C  //数据通道2接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
#define RX_ADDR_P3                                    0x0D  //数据通道3接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
#define RX_ADDR_P4                                    0x0E  //数据通道4接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
#define RX_ADDR_P5                                    0x0F  //数据通道5接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
#define TX_ADDR                                       0x10  //发送地址(低字节在前),ShockBurstTM模式下,RX_ADDR_P0与此地址相等
#define RX_PW_P0                                      0x11  //接收数据通道0有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P1                                      0x12  //接收数据通道1有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P2                                      0x13  //接收数据通道2有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P3                                      0x14  //接收数据通道3有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P4                                      0x15  //接收数据通道4有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P5                                      0x16  //接收数据通道5有效数据宽度(1~32字节),设置为0则非法
#define NRF_FIFO_STATUS                               0x17  //FIFO状态寄存器;bit0,RX FIFO寄存器空标志;bit1,RX FIFO满标志;bit2,3,保留
                                                            //bit4,TX FIFO空标志;bit5,TX FIFO满标志;bit6,1,循环发送上一数据包.0,不循环;
                              
 
/* 函数声明 ------------------------------------------------------------------*/
void NRF24L01_RX_Mode(void);					//配置为接收模式
void NRF24L01_TX_Mode(void);					//配置为发送模式
uint8_t NRF24L01_Write_Buf(uint8_t reg, uint8_t *pBuf, uint8_t uint8_ts);//写数据区
uint8_t NRF24L01_Read_Buf(uint8_t reg, uint8_t *pBuf, uint8_t uint8_ts);	//读数据区		  
uint8_t NRF24L01_Read_Reg(uint8_t reg);					//读寄存器
uint8_t NRF24L01_Write_Reg(uint8_t reg, uint8_t value);		//写寄存器
uint8_t NRF24L01_Check(void);						//检查24L01是否存在
uint8_t NRF24L01_TxPacket(uint8_t *txbuf);				//发送一个包的数据
uint8_t NRF24L01_RxPacket(uint8_t *rxbuf);				//接收一个包的数据
void NRF_LowPower_Mode(void);	
 
 
#endif
 

nrf24l01.c:同上STM32F103ZET6的nrf24l01.c

5.2.2 OLED代码

OLED参考博客:http://t.csdn.cn/heTcD

5.3 主程序

主函数中分别通过 NRF24L01_TX_Mode() NRF24L01_RX_Mode() 将各自设置成发送和接收模式,然后通过 NRF24L01_TxPacket(data) 和 NRF24L01_RxPacket(Receive) 函数分别发送和接收 data 数组(data数组和Receive数组一致)。

STM32F103ZET6的主程序:

int main(void)
{/* USER CODE BEGIN 1 */

  /* 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_SPI1_Init();
  MX_TIM2_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  while(NRF24L01_Check())
  {
	printf("检测不到NRF24L01无线模块,请检查硬件连接\r\n"); 
 	HAL_Delay(1000);
  }
	
  printf("NRF24L01无线模块硬件连接正常\r\n");
  NRF24L01_TX_Mode();//设置为发送模式
  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
	DHT11();	    /* DHT11()程序中包含了NRF24L01的数据发送代码 */	
  }
  /* USER CODE END 3 */
}

STM32F103C8T6的主程序:

int main(void)
{
  /* USER CODE BEGIN 1 */
  uint8_t Receive[6];
  /* 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_I2C1_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */
  OLED_Init();
  OLED_CLS();
	
  while(NRF24L01_Check())
  {
	printf("硬件查寻不到NRF24L01无线模块\n"); 
 	HAL_Delay(1000);
  }
	
  printf("NRF24L01无线模块硬件连接正常\n");	
  NRF24L01_RX_Mode();
  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
	if(NRF24L01_RxPacket(Receive)==0)
    {
        Receive[5]=0; 
	    OLED_ShowStr(0,0,"Temperature:",2);
		OLED_ShowStr(0,2,"Humidity:",2);
        OLED_ShowNum(100,0,Receive[2],2,16);
		OLED_ShowNum(75,2,Receive[0],2,16);		
    }
    HAL_Delay(500);
  }
  /* USER CODE END 3 */
}

5.4 补充程序

上述是通过NRF传输数据,其实也可以通过 NRF24L01 传输字符串等,提供如下代码示例:

5.4.1 发送端main.c部分代码

//---------------------------添加头文件------------------------------
#include "stdio.h"
#include "nrf24L01.h"
 
//---------------------------main函数部分----------------------------
int main(void)
{
  /* USER CODE BEGIN 1 */
uint8_t Send_Out[33]="本段数据来自NRF24L01发送端 ";   //要发送的内容(单次最多32个字节)
  /* 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_SPI1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
 
while(NRF24L01_Check())
	{
		printf("检测不到NRF24L01无线模块,请检查硬件连接\r\n"); 
 		HAL_Delay(1000);
	}
	
	printf("NRF24L01无线模块硬件连接正常\r\n");
	NRF24L01_TX_Mode();//设置为发送模式
    printf("进入数据发送模式,每1s发送一次数据\r\n");
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      HAL_Delay(1000);
      
      if(NRF24L01_TxPacket(Send_Out)==TX_OK)
    {
      printf("NRF24L01无线模块数据发送成功:%s\r\n",Send_Out);
    }
    else
    {
      printf("NRF24L01无线模块数据发送失败\r\n");
    } 
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

5.4.2 接受端main.c部分代码 

//---------------------------添加头文件-------------------------------
#include "stdio.h"
#include "nrf24L01.h"
 
//---------------------------main函数部分-------------------------------
int main(void)
{
  /* USER CODE BEGIN 1 */
   uint8_t Receive[33];
  /* 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_SPI1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
    while(NRF24L01_Check())
	{
		printf("硬件查寻不到NRF24L01无线模块\n"); 
 		HAL_Delay(1000);
	}
	
	printf("NRF24L01无线模块硬件连接正常\n");
	
	NRF24L01_RX_Mode();
    printf("进入数据接收模式\n");
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      if(NRF24L01_RxPacket(Receive)==0)
    {
      Receive[32]=0;//加入字符串结束符      
      printf("NRF24L01无线模块数据接收成功:%s\r\n",Receive);
    }
    HAL_Delay(500);
 
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

六、实验效果

NRF24L01

七、代码开源

代码地址:基于STM32的NRF24L012.4G通讯模块的驱动实验代码(HAL库)资源-CSDN文库

如果积分不够的朋友,点波关注评论区留下邮箱,作者无偿提供源码和后续问题解答。求求啦关注一波吧 !!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/537588.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

渗透测试--5.2.hash密码的破解

目录 1.hashcat简介 2.hashcat参数 常见参数 哈希类型&#xff08;-m&#xff09; 破解模式&#xff08;-a&#xff09; 3.实例 步骤一&#xff1a;使用hash-identifier工具判断哈希值类型 步骤二&#xff1a;使用字典攻击进行破解 1.hashcat简介 hashcat号称世界上最…

js实现点击改变文字大小

目录 一、前言二、代码实现 一、前言 在编写代码之前我们先来看看通过js获取元素有几种方式&#xff1a; 1.第一种 document.querySelector() 返回文档中匹配指定的选择器组的第一个元素document.querySelectorAll(); 返回文档中匹配指定的选择器组的所有元素 <!DOCTYPE ht…

vector容器 [上]

目录 一、 对于vector的介绍 二、vector的定义 0x01 无参构造 0x02 构造并初始化n个val 0x03 使用迭代器进行初始化构造 0x04 拷贝构造 0x05 比较 三、 vector的遍历 0x01 push_back() 0x02 operator[] 和at() 0x03 遍历 四、vector 容量空间 0x01 max_size : 返回v…

【设置教程】未使用系统分配DNS地址 如何设置?答:

未使用系统分配DNS地址&#xff0c;是你的域名解析DNS地址不是当前系统的DNS地址。 设置方法&#xff1a;先关闭更新。域名控制台--域名列表--安全设置&#xff1a; 通过短信验证。 2、修改DNS地址&#xff1a;域名控制台--域名列表&#xff1a;点击域名&#xff1a; 3、点击&…

C语言函数速查

scanf函数 函数概要&#xff1a; scanf 函数从标准输入流中读取格式化字符串。 与 printf 格式化输出函数相反&#xff0c;scanf 函数是格式化输入函数。 函数原型&#xff1a; #include <stdio.h> ... int scanf(const char *format, ...);参数解析&#xff1a; 1…

事务 ---MySQL的总结(六)

事务 多进程进行并改变同一个数据&#xff0c;如果没有进行版本控制&#xff0c;就会出现数据不确定的问题&#xff0c;为此引入了事务的概念。可以进行数据回滚&#xff0c;解决潜在的问题。 事务的概念 一组的DML组成&#xff0c;这一些的DML要么同时成功&#xff0c;要么同…

Linux上开启coredump

Linux上开启core dump Core dump&#xff08;核心转储&#xff09;是在程序崩溃时生成的一种文件&#xff0c;其中包含了程序在崩溃时的内存状态信息。它可以帮助程序员在调试程序时快速定位问题&#xff0c;并且是一种非常有用的调试工具。core dump的作用如下&#xff1a; 帮…

Java面向对象程序设计实验报告(实验二 面向对象基础练习)

✨作者&#xff1a;命运之光 ✨ 专栏&#xff1a;Java面向对象程序设计实验报告 目录 ✨一、需求设计 ✨二、概要设计 ✨三、详细设计 ✨四、调试结果 ✨五、测试结果 ✨附录&#xff1a;源程序代码&#xff08;带注释&#xff09; 测试类demo2 Address类 Employee类…

Docker之DockerFile相关基础知识

DockerFile相关基础知识 一、Docker镜像原理1、操作系统组成部分1.1 七大子系统1.2 Linux文件系统 2、Docker镜像原理介绍2.1 原理图2.2 Docker镜像本质2.3 统一文件系统2.4 复用性2.5 统一性 二、容器转为镜像1、Docker镜像的制作1.1 容器转换为镜像1.2 镜像转为压缩文件1.3 导…

【SpringBoot】三:访问数据库

文章目录 1.DataSource2.JdbcTemplate2.1 准备环境2.2 准备表和数据2.3 配置数据源2.4 JdbcTemplate访问mysql2.5 创建实体类 ArticlePO2.6 测试2.6.1 测试聚合函数 3.mybatis3.1 单表CRUMD3.1.1 创建模块3.1.2 查询3.1.3 插入3.1.4 更新3.1.5 删除 3.2 ResultMap3.3 SQL 提供者…

Elasticsearch 集群部署管理

Elasticsearch 集群配置版本均为8以上 安装前准备 CPU 2C 内存4G或更多 操作系统: Ubuntu20.04,Ubuntu18.04,Rocky8.X,Centos 7.X 操作系统盘50G 主机名设置规则为nodeX.qingtong.org 生产环境建议准备单独的数据磁盘主机名 #各自服务器配置自己的主机名 hostnamectl set-ho…

【2023/05/17】smalltalk

Hello&#xff01;大家好&#xff0c;我是霜淮子&#xff0c;2023倒计时第12天。 Share His own morning are new surprises to God. 译文&#xff1a; 神自己的清晨&#xff0c;在他自己看来也是新奇的。 Life finds its wealth by the claims of the world,and its worth…

基于UIAutomation+Python+Unittest+Beautifulreport的WindowsGUI自动化测试框架

1 main.py主入口 # -*- coding:utf-8 -*- # 作者&#xff1a;虫无涯 # 日期&#xff1a;2023/2/17 # 文件名称&#xff1a;main.py # 作用&#xff1a;框架的主入口函数# codingutf-8import time from common.reportOut import report_out from common.logOut import log_out …

Wandb.init和wandb.sweep的使用准则

目录 在使用 wandb.init() 初始化函数时&#xff0c;你可以包含以下信息&#xff1a; 如果在同一个代码中多次调用 wandb.init()&#xff0c;可能会导致以下问题&#xff1a; 如果你在一个大文件中使用了 wandb.init()&#xff0c;并且想在其他小文件中使用 wandb.log() 来记…

docker-compose部署sonarqube开源代码审计和分析平台

生成文件夹 mkdir -p /docker/sonar/postgres/postgresql mkdir -p /docker/sonar/postgres/datamkdir -p /docker/sonar/sonarqube chmod 777 -R /docker/sonar/sonarqube echo "vm.max_map_count262144" > /etc/sysctl.conf sysctl -p 创建docker-compose.yml文…

Kuberentes,k8s诞生简介

一、前言 什么是k8s&#xff1f; Kuberentes 是基于容器的集群管理平台&#xff0c;它的简称&#xff0c;是K8S。有人说之所以叫k8s&#xff0c;是因为k到s中间有8个字母&#xff0c;因此叫k8s&#xff0c;也有人说&#xff0c;在使用k8s的安装配置流程中&#xff0c;共分为8…

6年测开经验面试十家大厂,整理出来的笔记...

我第一次接触自动化是在2016年。那时刚毕业一年有余&#xff0c;组内一直做手工功能测试&#xff0c;大概在2018年9月&#xff0c;部门领导要求测试组引入自动化。组内之前从没有开展过任何自动化&#xff0c;测试主管安排了一个刚入职不久的研究生同事去研究。 当时自己内心还…

STM32独立按键扫描,支持同时按下、长按、快速键值

背景 有个项目在实际应用中&#xff0c;采用8个独立按键&#xff0c;每个按键都赋予不同功能&#xff0c;实际使用过程中很多时候都是需要比较特殊的按键操作&#xff0c;例如&#xff1a;长按10s按键、长按5s按键&#xff0c;或者长按需要有快速按键值的反馈&#xff0c;这个…

wordcloud背景图多图形演示

文章目录 前言一、问题二、多图层1.部分重叠1.1背景图1.2词云图 2.完全重叠2.1背景图2.2词云图 3.不重叠3.1背景图3.2词云图 三、不同形状1.背景图2.词云图 四、代码总结 前言 大家好&#xff0c;我是空空star&#xff0c;本篇给大家分享一下wordcloud背景图多图形演示。 一、问…

网络安全真的那么好吗?

近几年&#xff0c;随着网络安全被列为国家安全战略的一部分&#xff0c;这个曾经细分的领域发展提速了不少&#xff0c;除了一些传统安全厂商以外&#xff0c;一些互联网大厂也都纷纷加码了在这一块的投入&#xff0c;随之而来的吸引了越来越多的新鲜血液不断涌入。 网络安全…