基于stm32的温湿度检测案例(一)

系列文章目录

一、基于stm32的温度检测案例(一)

文章目录

目录

系列文章目录

一、基于stm32的温度检测案例(一)

文章目录

前言

一、实验器材简介

1.1、基于STM32F042F6P6的最小单片机系统

1.2、串口通信工具CH340G(USB转TTL)​编辑

1.3、仿真器(ST-LINK V2)

二、检测STM32F042F6P6功能是否正常

2.1、程序验证

 2.2、上电验证

三、代码演示

3.1、时钟树

3.2、Systick配置(Cortex--M0)

3.3、GPIO配置

3.2.1、方法功能测试

3.3、串口调试

3.3.1、串口配置

四、DHT11温湿度检测模块

4.1、引脚与接口

4.2、内部结构

4.3、根据时序写代码

4.2.1、时钟、端口、引脚、高低电平的配置

4.2.2、通讯过程

前言

使用基于stm32f042F6P6的最小单片机系统通过单总线与DHT11温湿度检测传感器通信,实现对当前环境下的温湿度检测。使用串口通信将DHT11模块检测到的数据在PC上显示。

一、实验器材简介

1.1、基于STM32F042F6P6的最小单片机系统

1.2、串口通信工具CH340G(USB转TTL)

1.3、仿真器(ST-LINK V2)

二、检测STM32F042F6P6功能是否正常

2.1、程序验证

通过观看原理图发现板子上有两个灯,一个电源指示灯与一个接在PB1引脚上的led。编写代码驱动接在PB1上的 LED,检查LED是否正常工作从而推论硬件是否有问题(量产的板子一般"冒得问题”)。

1、二极管工作原理:从标有三角那一端(P),流向标一横那一端(N)。实物:从标有“+”号那一端流向标有“-”号那一端。正向导通(P->N),反向截止(N->p)。

2、拉电流”,是指驱动LED负载的电流方向为  从电路输出端流向LED负载.  单片机给管脚高电平(推),LED熄灭
3、灌电流”是指驱动LED负载的电流方向为    从LED负载流向电路输出端。   单片机给管脚低电平 (挽),LED点亮

4、推挽输出(英语:Push–pull output)是一种使用一对选择性地从相连负载灌电流或者拉电流的器件的电路。它常常使用一对参数相同的功率三极管或MOSFET管,以推挽方式存在于电路中。

5、补充:推挽电路使用两个参数相同的三极管或MOSFET,以推挽方式存在于电路中。电路工作时,两只对称的开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负载灌电流,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。

6、I/o口默认输出为高电平状态。

 2.2、上电验证

用ST_LINK V2连接板子与电脑,通过电脑的USB口给板子供电,查看板子上的电源指示灯是否正常点亮。(电脑的usb口输出5v左右的电压,不可作为驱动高于5v的板子的电源,会烧电脑usb口甚至电脑主板)。

三、代码演示

3.1、时钟树

3.2、Systick配置(Cortex--M0)

#include "public.h"
	//    us延时倍乘数			
static st_u8  fac_us=0;	

	//    ms延时倍乘数
static st_u16 fac_ms=0;						
/*********************************************************************************
                                 初始化延迟函数
SYSCLK:系统时钟频率
*********************************************************************************/
void SysTick_Init(st_u8 SYSCLK)
{
	//   SYSTICK的时钟固定为AHB时钟的1/8     6M
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
	fac_us=SYSCLK/8;					
	fac_ms=(st_u16)fac_us*1000;		// 6000us  		   
}								    


		
/*********************************************************************************
                              延时nus
                              nus为要延时的us数.
*********************************************************************************/
void delay_us(st_u32 nus)
{		
	st_u32 temp;	    	 
	SysTick->LOAD=nus*fac_us; 					      //    时间加载	  		 
	SysTick->VAL=0x00;        					      //    清空计数器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//    开始倒数	  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		  //  等待时间到达   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//  关闭计数器
	SysTick->VAL =0X00;      					        //  清空计数器	 
}


/*********************************************************************************
                   延时nms
                 鈔ms的范围SysTick->LOAD为24位寄存器,所以,最大延时为:nms<=0xffffff*8*1000/SYSCLK
                 SYSCLK单位为Hz,nms单位为ms
                     对72M条件下,nms<=1864 
                      对24M条件下,nms<=5592
*********************************************************************************/
void delay_ms(st_u16 nms)
{	 		  	  
	st_u32 temp;		   
	SysTick->LOAD=(st_u32)nms*fac_ms;				   //  时间加载(SysTick->LOAD为24bit)
	SysTick->VAL =0x00;							           //  清空计数器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	 //  开始倒数  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		  //  等待时间到达   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//  关闭计数器
	SysTick->VAL =0X00;       				      	//  清空计数器	  	    
} 


3.3、GPIO配置

/*********************************************GPIO配置部分*********************************************/
/*********************************************
                  GPIO输出封装
1、时钟 RCC_AHBPeriph_x
2、端口 GPIOx
3、引脚 GPIO_PIN
4、输出模式  GPIOMode
5、输出类型  GPIOOType
5、指定所选引脚的操作上拉/下拉  GPIOPuPd
*********************************************/
void GPIOInit_Dout(st_u32 RCC_AHBPeriph_x,GPIO_TypeDef* GPIOx,st_u32 GPIO_PIN,GPIOMode_TypeDef GPIOMode,
	GPIOOType_TypeDef GPIOOType,GPIOPuPd_TypeDef GPIOPuPd)
{
	 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_x, ENABLE);      //  使能端口时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;
 
  /* Configure PC10 and PC11 in output pushpull mode */
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN;              //  引脚
  GPIO_InitStructure.GPIO_Mode = GPIOMode;             //  输入/输出模式
  GPIO_InitStructure.GPIO_OType = GPIOOType;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIOPuPd;            	//  上拉 or 下拉
  GPIO_Init(GPIOx, &GPIO_InitStructure);
}

/*********************************************
                  GPIO输入封装
1、时钟  RCC_AHBPeriph_x
2、端口  GPIOx
3、引脚  GPIO_PIN
4、输入模式  GPIOMode
5、指定所选引脚的操作上拉/下拉  GPIOPuPd
*********************************************/
void GPIOInit_Din(st_u32 RCC_AHBPeriph_x,GPIO_TypeDef* GPIOx,st_u32 GPIO_PIN,GPIOMode_TypeDef GPIOMode,GPIOPuPd_TypeDef GPIOPuPd)
{
	GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_x, ENABLE);     //  使能时钟
  /* Configure PC10 and PC11 in output pushpull mode */
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN;              //  引脚
  GPIO_InitStructure.GPIO_Mode = GPIOMode;             //  输入/输出模式
  //GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIOPuPd;            	//  上拉 or 下拉
  GPIO_Init(GPIOx, &GPIO_InitStructure);
}

3.2.1、方法功能测试

通过一个LED的来验证,函数功能是否正常

//  LED初始化
void LED_Init(void)
{
	// 时钟  端口  引脚  输出模式   推挽输出类型  上拉/下拉
  GPIOInit_Dout(LED_RCC,LED_PORT,LED_PIN,GPIO_Mode_OUT,GPIO_OType_PP,GPIO_PuPd_NOPULL);
	GPIO_SetBits(LED_PORT,LED_PIN);    //  初始化后默认PB1输出高电平
}
//  测试LED  高低电频每隔500ms交替一次  低电平期间LED点亮  高电平期间LED熄灭
void LED_Test(void)
{
       delay_ms(500);
		LED_L;
		delay_ms(500);
		LED_H;
}

.h文件中定义

#ifndef _LED_H
#define _LED_H
/*********************************************
     时钟  端口  引脚宏定义
*********************************************/
#define LED_RCC   RCC_AHBPeriph_GPIOB
#define LED_PORT  GPIOB 
#define LED_PIN   GPIO_Pin_1

#define LED_H    GPIO_SetBits(LED_PORT,LED_PIN)    //  高电平
#define LED_L    GPIO_ResetBits(LED_PORT,LED_PIN)  //  低电平

extern void LED_Init(void);
extern void  LED_Test(void);
#endif 
 

主函数

#define ROOT
#include "public.h"

int main(void)
{
//  初始化systick
	SysTick_Init(48);
	LED_Init();
	//Uart2_Init1();
	while(1)
	{
    LED_Test();
		//Uart2_Test();
	}
}

void SystemInit(void)
{

}

3.3、串口调试

外接5电源到板子,串口调试工具与板子供地共GND,串口调试工具的RX、TX与板子的RX、TX交叉相接能正常收发数据。 

3.3.1、串口配置

库函数配置串口


/*********************************************  
中断优先级配置
cortex-m0 智能配置 0~3
********************************************/
void NVIC_Config(st_u8 IRQn,st_u8 IRQChannelPriority)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_InitStructure.NVIC_IRQChannel = IRQn;
	
	NVIC_InitStructure.NVIC_IRQChannelPriority = IRQChannelPriority;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

/*********************************************串口配置*********************************************/
/**********
STM32共有两种串口通信接口,分别是:UART通用异步收发器,USART:通用同步异步收发器
单工:数据传输只支持数据在一个方向上传输   一个通道
半双工:允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;  两个通道
全双工:允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。  两个通道

同步通信与异步通信
同步通信指的是带有时钟同步信号,比如:SPI通信、IIC通信;
异步通信指的是不带时钟同步信号比如:UART(通用异步收发器),单总线
**********/
void USART_Config(USART_TypeDef* USARTx,st_u32 Baudrate)
{
	if(USARTx==USART1)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	else
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	
	USART_InitTypeDef USART_InitStructure;
  USART_InitStructure.USART_BaudRate = 9600;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USARTx, &USART_InitStructure);
	
  USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);
  USART_Cmd(USARTx, ENABLE);
  }

/*********************************************
	          串口2通信初始化1
	*********************************************/
void Uart2_Init1(void)
{
  NVIC_Config(USART2_IRQn,0x00);
	//  TX        时钟                端口   引脚      复用模式     推挽输出       上拉/下拉
	//  推(拉电流) 驱动负载的电流方向为  从电路输出端流向负载
	//  挽(灌电流) 驱动负载的电流方向为  从负载流向电路输出端 
	GPIOInit_Dout(RCC_AHBPeriph_GPIOA,GPIOA,GPIO_Pin_2|GPIO_Pin_3,GPIO_Mode_AF,GPIO_OType_PP ,GPIO_PuPd_NOPULL);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_1);     // USART2_Tx
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_1);     // USART2_Rx
	USART_Config(USART2,9600);
}

中断服务函数

#include "public.h"

//  加入以下代码,支持printf函数,而不需要选择use MicroLIB	
#if 1
//#pragma import(__use_no_semihosting) 
#pragma import(__use_no_semihosting_swi)

struct  __FILE {st_32 handle;};   //  标准库需要的支持函数

FILE  _stdout;

void sys_exit(st_32 x){             // 定义_sys_exit()以避免使用半主机模式 
   x=x;
}
//  发送数据
//  重定向 c 库函数 printf 到串口,重定向后可使用 printf 函数
int fputc(int ch,FILE*p)
{
	//#if 1
  USART_SendData(USART2,(st_u8)ch);
	// USART_FLAG_TXE  数据寄存器为空的标记
	while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
	return ch;
	//#else
	//while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
 // USART1->TDR = (st_u8) ch;      
	//return ch;
	//#endif

}

//  接收数据
//  重定向 c 库函数 scanf 到串口,重写向后可使用 scanf、getchar 等函数
 int fgetc(FILE *f)
 {
 // 等待串口输入数据 
 while (USART_GetFlagStatus(USART2, USART_IT_RXNE) == RESET);
 return (st_32)USART_ReceiveData(USART2);
 }
 
 //  发送字符
void Usart_SendByte( USART_TypeDef * pUSARTx,st_u8 ch)
{
 
USART_SendData(pUSARTx,ch);
 while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}

//  发送字符串
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
  st_u32 k=0;
  do {
   Usart_SendByte( pUSARTx, *(str + k));
   k++;
} while (*(str + k)!='\0');
 while (USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) { /* 等待发送完成 */
   }
 }
#endif
 
 /*********************************************第一种方式*********************************************/
 #if USART2_RX_EN
  //USART2_RX_BUF[USART2_REC_LEN];
 // USART2_RX_STA=0;

 
 void USART2_IRQHandler(void)
 {
	INTX_DISABLE();  //  中断屏蔽
  st_u8 r;
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断
	{
		r =USART_ReceiveData(USART2);//(USART1->DR);	//读取接收到的数据
		if((USART2_RX_STA&0x8000)==0)//接收未完成
		{
			if(USART2_RX_STA&0x4000)//接收到了0x0d
			{
				if(r!=0x0a)USART2_RX_STA=0;//接收错误,重新开始
				else USART2_RX_STA|=0x8000;	//接收完成了 
			}
			else //还没收到0X0D
			{	
				if(r==0x0d)USART2_RX_STA|=0x4000;
				else
				{
					USART2_RX_BUF[USART2_RX_STA&0X3FFF]=r;
					USART2_RX_STA++;
					if(USART2_RX_STA>(USART2_REC_LEN-1))USART2_RX_STA=0;//接收数据错误,重新开始接收	  
				}		 
			}
		}   		 
	} 
	INTX_ENABLE();  //  放开中断屏蔽
 }
 #endif

 

四、DHT11温湿度检测模块

4.1、引脚与接口

  • VCC:DTH11的供电电压为 3-5.5V。传感器上电后,要等待 1s 以越过不稳定状态在此期间无需发送任何指令。
  • DATA:mcu与DHT11单总线通信引脚。一次通讯时间4ms左右,数据分小数部分和整数部分.
  • GND:接地。

DTH11工作流程:

  • MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,
  • DHT11发送响应信号,送出40bit的数据,并触发一次信号采集, 用户可选择读取部分数据.
  • 从模式下,DHT11接收到开始信号触发一次温湿度采集, 如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集.采集数据后转换到低速模式。

4.2、内部结构

传感器包括一个电阻式感湿元件和一个NTC测 温元件,并与一个高性能8位单片机相连接。

4.3、根据时序写代码

4.2.1、时钟、端口、引脚、高低电平的配置

#ifndef  _DHT_11
#define  _DHT_11 
//  时钟  端口  引脚   
#define DHT11_RCC RCC_AHBPeriph_GPIOA
#define DHT11_PORT GPIOA
#define DHT11_PIN GPIO_Pin_7


#define DHT11_H    GPIO_SetBits(DHT11_PORT,DHT11_PIN)    //  高电平
#define DHT11_L    GPIO_ResetBits(DHT11_PORT,DHT11_PIN)  //  低电平



#endif
int8_t GPIOSet(GPIO_TypeDef* GPIOx, uint16_t GPIOPin, uint16_t GPIOMode)
{
	if(GPIOMode == 0)
	{
		GPIO_ResetBits(GPIOx,GPIOPin);
	}
	else
	{
		GPIO_SetBits(GPIOx,GPIOPin);
	}
	return GPIOMode;
}

//  uint8_t GPIOGet(GPIO_TypeDef* GPIOx, uint16_t GPIOPin)
uint8_t GPIOGet(GPIO_TypeDef* GPIOx, uint16_t GPIOPin)
{
	return (GPIO_ReadInputDataBit(GPIOx, GPIOPin));
}
//  输出配置
void DHT11_GPIO_Out(void)
{
	//  时钟   端口  引脚  输出模式  推挽输出   不上拉/不下拉
  GPIOInit_Dout(DHT11_RCC,DHT11_PORT,DHT11_PIN,GPIO_Mode_OUT,GPIO_OType_PP,GPIO_PuPd_NOPULL);
}

//  输入配置
void DHT11_GPIO_In(void)
{
	
	//   时钟  端口  引脚  输入模式   上拉输入
  GPIOInit_Din(DHT11_RCC,DHT11_PORT,DHT11_PIN,GPIO_Mode_IN,GPIO_PuPd_UP);
}

4.2.2、通讯过程

三种写时序的方式


//  输出配置
void DHT11_GPIO_Out(void)
{
	//  时钟   端口  引脚  输出模式  推挽输出   不上拉/不下拉
  GPIOInit_Dout(DHT11_RCC,DHT11_PORT,DHT11_PIN,GPIO_Mode_OUT,GPIO_OType_PP,GPIO_PuPd_NOPULL);
}

//  输入配置
void DHT11_GPIO_In(void)
{
	 //  
	 // GPIOInit_Din(DHT11_RCC,DHT11_PORT,DHT11_PIN,GPIO_Mode_IN,GPIO_PuPd_DOWN);
	
	  //GPIOInit_Din(DHT11_RCC,DHT11_PORT,DHT11_PIN,GPIO_Mode_IN,GPIO_PuPd_NOPULL);
	
	 //   时钟  端口  引脚  输入模式   上拉输入    经过测试此处必须设置为上拉才能上数据
    GPIOInit_Din(DHT11_RCC,DHT11_PORT,DHT11_PIN,GPIO_Mode_IN,GPIO_PuPd_UP);
	
}

void DHT11_Init(void)
{
  DHT11_GPIO_Out();
	DHT11_H;
	
}

#if 1
/* 
 * 从DHT11读取一个字节,MSB先行
 */
static st_u8 DHT11_ReadByte ( void )
{
	st_u8 i, temp=0;
	

	for(i=0;i<8;i++)    
	{	 
		/*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/  
		while(DHT11_Input==Bit_RESET);

		/*DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”,
		 *通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时 
		 */
		delay_us(40); //延时x us 这个延时需要大于数据0持续的时间即可	   	  

		if(DHT11_Input==Bit_SET)/* x us后仍为高电平表示数据“1” */
		{
			/* 等待数据1的高电平结束 */
			while(DHT11_Input==Bit_SET);

			temp|=(st_u8)(0x01<<(7-i));  //把第7-i位置1,MSB先行 
		}
		else	 // x us后为低电平表示数据“0”
		{			    
			temp&=(st_u8)~(0x01<<(7-i)); //把第7-i位置0,MSB先行  高位先出。  高位 1111 1111  地位  左边高位,右边地位  
		}
	}
	
	return temp;
	
}

/*
 * 一次完整的数据传输为40bit,高位先出
 * 8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和 
 */
st_u8 DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{  
	/*输出模式*/
	DHT11_GPIO_Out();
	/*主机拉低*/
	DHT11_L;
	/*延时18ms*/
	delay_us(18);

	/*总线拉高 主机延时30us*/
	DHT11_H; 

	delay_ms(30);   //延时30us

	/*主机设为输入 判断从机响应信号*/ 
	DHT11_GPIO_In();

	/*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/   
	if(DHT11_Input==Bit_RESET)     
	{
		/*轮询直到从机发出 的80us 低电平 响应信号结束*/  
		while(DHT11_Input==Bit_RESET);

		/*轮询直到从机发出的 80us 高电平 标置信号结束*/
		while(DHT11_Input==Bit_SET);

		/*开始接收数据*/   
		DHT11_Data->humi_int= DHT11_ReadByte();

		DHT11_Data->humi_deci= DHT11_ReadByte();

		DHT11_Data->temp_int= DHT11_ReadByte();

		DHT11_Data->temp_deci= DHT11_ReadByte();

		DHT11_Data->check_sum= DHT11_ReadByte();


		/*读取结束,引脚改为输出模式*/
		DHT11_GPIO_Out();
		/*主机拉高*/
		DHT11_H;

		/*检查读取的数据是否正确*/
		// 一次完整的数据传输为40bit,高位先出。数据格式:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和
		if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)
			return SUCCESS;
		else 
			return ERROR;
	}
	
	else
		return ERROR;
	
}
#elif select1
//从DHT11读取一个位
//返回值:1/0
st_u8 DHT11_Read_Bit(void) 			 
{
 	st_u8 retry=0;
	while(DHT11_Input==0 &&retry<100)//等待变为低电平 12-14us 开始
	{
		retry++;
		delay_us(1);
	}
	retry=0;
	while(!DHT11_Input&&retry<100)//等待变高电平	 26-28us表示0,116-118us表示1
	{
		retry++;
		delay_us(1);
	}
	delay_us(40);//等待40us
	if(DHT11_Input)return 1;
	else return 0;		   
}

//从DHT11读取一个字节
//返回值:读到的数据
st_u8 DHT11_Read_Byte(void)    
{        
    st_u8 i,dat;
    dat=0;
	for (i=0;i<8;i++) 
	{
   		dat<<=1; 
	    dat|=DHT11_Read_Bit();
    }						    
    return dat;
}

//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
st_u8 DHT11_Read_Data(st_u8 *temp,st_u8 *humi)    
{        
 	st_u8 buf[5];
	st_u8 i;
	DHT11_Rst();
	if(DHT11_Check()==0)
	{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=DHT11_Read_Byte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
		{
			*humi=buf[0];
			*temp=buf[2];
		}
		
	}else return 1;
	return 0;	    
}
#else
// 转译采集DHT11发送给IO口的电平信号(8位)
// 从DHT11读取一位(8字节)信号
st_u8 DHT11_Read_Byte(void)
{
   st_u8 ReadData = 0; // 存放8bit数据,即8个单次读取的1bit数据的组合
	 st_u8 temp;         // 临时存放信号电平(0或1)
	 st_u8 retry =0;     //  retry用于防止卡死
	 st_u8 i;
	for(i=0;i<8;i++)      // 一次温湿度信号读取八位
	{
	    while(DHT11_Input==0&&retry<100)
			{
			  // 等待直到DHT11输出高电平:
				// 当PA7=1,上升沿,表示开始接受数据,可以判断0 or 1,跳出循环,执行后续判断(若PA7=0,将一直循环等待)
			   delay_us(1);
				 retry++;
			};
			 retry=0;
			delay_us(40);
			//  根据时序图,DHT传回高电平信号维持26us~28us表示0,	维持70us表示1
		  //  延时30us后,如果IO读取到仍是高电平,说明采集到1;如果IO读取到低电平,说明采集到0
			//  读取电平信号暂存temp内,随后会压入ReadData中
     while(DHT11_Input==1&&retry<100)
		 {
			  delay_us(1);
				 retry++;
		 };
		 retry=0;
		 ReadData <<=1;  //  ReadData内信号先全部左移一位,空出末尾位置
		 ReadData|=temp;
	}
	return ReadData;
}

st_u8 DHT_Read(void)
{
	 st_u8 retry=0;
	 st_u8 i;
		
	 DHT11_GPIO_Out();    //IO设置为输出模式。在传输的最开始,MCU要向DHT11发送信号
	 DHT11_L;   //IO->DHT11:先拉低电平18ms(应时序要求)
	 delay_us(18);
	DHT11_H;   //IO->DHT11:随后拉高电平20us
	 delay_us(20);
	
	//MCU通过IO向DHT11发送请求完毕。接下来DHT11向IO发送响应,IO转为输入模式。在这之后就开始信号的转译读取。
	DHT11_GPIO_In();
	delay_us(20);
	if(DHT11_Input==0) //DHT11发回低电平响应(读取到低电平,说明DHT11有响应)
	{
		//接下来,DHT11拉低电平一段时间后拉高电平一段时间
		while(DHT11_Input==0 && retry<100)  
		{
		   delay_us(1);
			 retry++;
		}
		 retry=0;
		while(DHT11_Input==1 && retry<100) 
		{
		   delay_us(1);
			 retry++;
		}
		retry=0;
		
		//一共传输40位,一次DHT_Read_Byte返回8位,共读取5次。存储在Data[]中。(Data[]定义为全局)
		for(i=0; i<5; i++)
		{
			 Data[i] = DHT11_Read_Byte();  //每次读取一字节(8位)
		}
		delay_us(50);
		//说明:Data[0]湿度, Data[2]温度。Data[1]和Data[3]分别为0和2的小数位。Data[4]用于校验。
	}
	 st_u32 sum=Data[0]+Data[1]+Data[2]+Data[3];  //校验
	 if((sum)==Data[4])    return 1;  
	   else   return 0;
}
#endif
<think>好的,我现在需要回答用户关于在CentOS虚拟机上配置DPDK的方法和步骤的问题。首先,我得仔细回顾用户提供的引用内容,确保回答准确。用户引用了三个资源,其中引用[2]详细介绍了使用dpdk-setup.sh安装DPDK的步骤,而引用[3]提到了安装CentOS虚拟机的步骤,引用[1]则涉及DPDK环境的目录结构。 首先,我需要确认用户的需求是在已经安装好的CentOS虚拟机上配置DPDK,所以可能需要先确认虚拟机的安装是否正确,不过引用[3]是关于安装虚拟机的基本步骤,但用户可能已经完成了这一步。因此,重点应放在DPDK的配置上,特别是使用dpdk-setup.sh脚本的方法,如引用[2]所述。 接下来,我需要整理DPDK配置的主要步骤。根据引用[2],步骤包括下载DPDK、安装依赖项、解压并进入目录、运行dpdk-setup.sh脚本、配置大页内存、绑定网卡驱动等。同时,引用[1]提到目标环境目录的结构,可能需要说明编译后的文件位置,如build/app目录下的测试程序。 需要注意用户可能的环境差异,比如CentOS版本是否为7,是否需要特定的内核模块或驱动。此外,用户可能对某些步骤不熟悉,比如绑定网卡到vfio-pci驱动,可能需要详细说明或注意事项,例如如何避免网络中断,或者如何恢复原有驱动。 另外,引用[3]中提到的虚拟机设置可能需要配置足够的内存和CPU资源,特别是大页内存的设置,这在虚拟机环境中可能需要额外的步骤,比如在VMware或VirtualBox中启用大页内存支持。不过用户提供的引用中没有详细说明这部分,可能需要根据通用知识补充。 需要检查步骤之间的逻辑顺序,确保先安装依赖,再编译DPDK,然后配置环境。同时,测试步骤如testpmd的使用,应指导用户如何验证DPDK是否正常工作。 可能遇到的问题包括依赖包安装失败、编译错误、网卡绑定失败等,应在回答中适当加入常见问题解决建议,比如确保所有依赖已安装,检查内核版本兼容性,或者使用合适的驱动绑定工具。 最后,生成的相关问题需要围绕DPDK配置的后续步骤、优化方法或应用场景,例如性能调优、多线程配置或具体应用案例。 总结回答的结构:先概述步骤,再分步详细说明,包含代码块和命令示例,注意使用正确的LaTeX格式,最后生成相关问题。需要确保所有技术术语准确,步骤清晰,并正确引用提供的资料。</think>### 在 CentOS 虚拟机中配置 DPDK 的方法和步骤 #### **1. 环境准备** - **操作系统**: CentOS 7(需已安装虚拟机,参考引用[3]中虚拟机创建步骤) - **硬件要求**: 至少 2 核 CPU、2GB 内存,建议开启虚拟化支持(如 Intel VT-x/AMD-V) - **网络配置**: 至少一个虚拟网卡(建议使用 Virtio 驱动) #### **2. 安装依赖项** ```bash sudo yum groupinstall "Development Tools" sudo yum install -y kernel-devel numactl-devel python3 pciutils ``` #### **3. 下载并解压 DPDK** 从 [DPDK官网](https://core.dpdk.org/download/) 下载最新稳定版(如 22.11.2): ```bash wget https://fast.dpdk.org/rel/dpdk-22.11.2.tar.xz tar xf dpdk-22.11.2.tar.xz && cd dpdk-22.11.2 ``` #### **4. 编译 DPDK** 使用 `dpdk-setup.sh` 脚本自动化配置(参考引用[2]): ```bash export RTE_SDK=$(pwd) export RTE_TARGET=x86_64-native-linuxapp-gcc make config T=$RTE_TARGET make -j$(nproc) ``` #### **5. 配置大页内存** - 修改内核参数: ```bash echo "vm.nr_hugepages=1024" | sudo tee -a /etc/sysctl.conf sudo sysctl -p ``` - 挂载大页内存: ```bash sudo mkdir -p /mnt/huge echo "nodev /mnt/huge hugetlbfs defaults 0 0" | sudo tee -a /etc/fstab sudo mount -a ``` #### **6. 绑定网卡到 DPDK 驱动** - 查看网卡 PCI 地址: ```bash lspci | grep Ethernet ``` - 解绑内核驱动并绑定 `vfio-pci`: ```bash sudo modprobe vfio-pci sudo ./usertools/dpdk-devbind.py --bind=vfio-pci <PCI_ADDRESS> ``` #### **7. 验证环境** 进入编译目录并运行测试程序: ```bash cd build/app sudo ./testpmd -l 0-1 -- -i ``` 若输出显示端口初始化成功,则配置完成[^1][^2]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旭日初扬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值