(二)项目主要使用模块讲解(小白向)


前言

之前说完了登录阿里云平台,也就是说在MQTT的客户端-服务器-客户端的模式中我们已经完成了客户端方的基本设置。接下来我们就将介绍一下单片机客户端方的一些设置。本次使用的为野火的指南者开发板,其使用芯片为STM32-F103VE。
虽然使用的32芯片,但是只使用过51芯片的uu不用太担心,有了51的基础之后32芯片是相对很容易上手的,在我上实验课刚刚接触32的实验时也被每个工程下一堆的文件吓到了。但是当你真正了解了其项目的基本结构后你就会发现其实这些项目文件大部分都只是项目中必要的文件,而真正需要你去写或者去修改的可能也就是那么几个文件,因而写在文章的开头首先需要说的是51与32工程文件之间的简单区别。

另:看到代码一定不要太害怕,不练永远学不会,在每一个传感器模块后面我附了一些相应的学习链接,可以配合代码进行学习。


一、51工程与32工程文件的区别

(1)51工程
51工程文件较为简单,因为其本身资源不多,引脚定义也相对较少,因而一般为单文件工程,相对较为简单。如下图为AT89C51单片机片内的基本结构。
在这里插入图片描述

(2)32工程
32的工程文件则相对比较复杂,因为使用的Cortex-M3内核相对51的复杂许多,同时其总线宽度也上升到32bit,速度和性能也得以提升,相对的,其工程文件也比51的工程文件复杂许多。下图为32单片机的基本结构。
在这里插入图片描述
接下来,我将会简单讲解一下32的工程结构及其各个文件基本的含义。
1. 启动文件
在这里插入图片描述
也就是上图中的startup_stm32f10x_hd.s文件,在不同型号的单片机中其使用的启动文件也不一样。其具体说明如下图所示。1
在这里插入图片描述

2. 内核相关文件
包含core_cm3.c 和 core_cm3.h 两个文件。Core_cm3.h 头文件里面实现了内核的寄存器映射,对应外设头文件 stm32f10x.h,区别就是一个针对内核的外设,一个针对片上(内核之外)的外设。core_cm3.c 文件实现了一下操作内核外设寄存器的函数,用的比较少。
我们还需要了解的是 core_cm3.h 头文件中包含了“stdint.h”这个头文件,这是一个 ANSI C 文件,是独立于处理器之外的,就像我们熟知的 C 语言头文件“stdio.h”文件一样。位于 RVMDK 这个软件的安装目录下,主要作用是提供一些类型定义。

3. 实现上外设所有寄存器映射的头文件——Stm32f10x.h
这个头文件实现了片上外设的所有寄存器的映射,是一个非常重要的头文件,在内核中与之相对应的头文件是 core_cm3.h。

4. 实现STM32的时钟配置的文件——system_stm32f10x.c
system_stm32f10x.c 文件实现了 STM32 的时钟配置,操作的是片上的 RCC 这个外设。系统在上电之后,首选会执行由汇编编写的启动文件,启动文件中的复位函数中调用的 SystemInit 函数就在这个文件里面定义。调用完之后,系统的时钟就被初始化成 72M。如果后面我们需要重新配置系统时钟,我们就可以参考这个函数重写。但是为了维持库的完整性,我们不会直接在这个文件里面修改时钟配置函数。

其中2,3,4,5中提到的文件在工程中具体位置如下图所示。
在这里插入图片描述
5. 针对外设文件编写的库函数文件
在这里插入图片描述
如上图所示,在32工程文件中一般有这些基本库函数文件。如misc.c 文件,这个文件提供了外设对内核中的 NVIC(中断向量控制器) 的访问函数,在配置中断时,我们必须把这个文件添加到工程中。
其在工程中的具体位置如下图所示。
在这里插入图片描述
6. 用户自定义文件
以上是基于STM32库的一个32工程需要的基本文件。而在用户自定义文件中,才是我们需要写的真正重要的地方。其在代码中的位置如下。其中DOC主要包含一些文档,用于告知用户使用的方法,功能等,可提高代码可读性。
在这里插入图片描述

7. 各库文件之间的关系
各库文件之间关系如下图所示。
在这里插入图片描述

最后,记得在keil中是需要打开.uvprojx文件来打开项目的哦,其通常会放在project文件夹下或者单独放在项目文件夹中。
在这里插入图片描述
还有keilkill.bat文件夹则是用删除一些编译连接生成过程中生成的一些中间文件。其删除文件后缀名如下图所示。
在这里插入图片描述

以上,我们简单梳理了一下32工程文件中各文件的基本作用,当然可能还是有一点容易迷糊,具体可以参照野火讲解视频对库文件进行学习。
相信在弄懂之后再次遇到32的工程文件后就能做到气定神闲,胸有成竹了。

二、本次实验基本功能实现讲解

(1)总体架构与连接

本系统主要运用了学习的传感器知识对环境的数据进行采集,并通过单片机对采集的数据进行处理和转发,服务器接收来自单片机的数据,用户则通过手机APP对服务器接收数据进行访问,并通过这些数据了解环境的实时状况,并且可通过程序控制灯的开关等。硬件部分总体架构图如下图所示。
在这里插入图片描述
硬件部分以STM32F103VET6作为核心进行控制,ESP8266WiFi模块作为接入点与网络进行连接。STM32单片机通过ADC转换模块对ADC采样模拟信号传感器进行转化,并将采集数据进行整合滤波得到可靠数据,并通过公式代换得到最终数据,并通过ESP8266模块发送到云端服务器进行数据流转。
在野火指南者上开发板连线如下图所示。ESP8266为板上自带的,因而只需要编写相关的软件程序即可使用。
请添加图片描述
(1)DHT11温湿度传感器,根据传感器使用手册配置好供电引脚后,将DATA引脚与开发板PC7引脚相连接。
(2)光敏传感器,根据传感器使用说明配置好供电引脚后,将AO引脚与开发板PC4相连接。
(3)土壤湿度传感器,根据传感器使用手册配置好供电引脚后,将AO端与PC1引脚相连接。

(2)DHT11传感器数据采集程序

首先使用DHT11_GPIO_Config ()函数配置DHT11使用的I/O口,而后将主机的PC7端口设置为输入并判断从机是否有低电平响应,若响应则继续轮询直到响应信号和标置信号结束,接着便使用传入的定义好的DHT11_Data_TypeDef类型的DHT11_Data对收到的温湿度数据和校验位进行收集,直到读取结束对读取数据校验位进行检查,若错误则返回ERROR。其设计流程图如图1.6.1所示。
在这里插入图片描述

// bsp_dht11.c
#include "bsp_dht11.h"
#include "bsp_SysTick.h"



static void                           DHT11_GPIO_Config                       ( void );
static void                           DHT11_Mode_IPU                          ( void );
static void                           DHT11_Mode_Out_PP                       ( void );
static uint8_t                        DHT11_ReadByte                          ( void );



 /**
  * @brief  DHT11 初始化函数
  * @param  无
  * @retval 无
  */
void DHT11_Init ( void )
{
    
    
	DHT11_GPIO_Config ();
	
	macDHT11_Dout_1;               // 拉高GPIOB10
}


/*
 * 函数名:DHT11_GPIO_Config
 * 描述  :配置DHT11用到的I/O口
 * 输入  :无
 * 输出  :无
 */
static void DHT11_GPIO_Config ( void )
{
    
    		
	/*定义一个GPIO_InitTypeDef类型的结构体*/
	GPIO_InitTypeDef GPIO_InitStructure;

	
	/*开启macDHT11_Dout_GPIO_PORT的外设时钟*/
  macDHT11_Dout_SCK_APBxClock_FUN ( macDHT11_Dout_GPIO_CLK, ENABLE );	

	/*选择要控制的macDHT11_Dout_GPIO_PORT引脚*/															   
  	GPIO_InitStructure.GPIO_Pin = macDHT11_Dout_GPIO_PIN;	

	/*设置引脚模式为通用推挽输出*/
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   

	/*设置引脚速率为50MHz */   
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 

	/*调用库函数,初始化macDHT11_Dout_GPIO_PORT*/
  	GPIO_Init ( macDHT11_Dout_GPIO_PORT, &GPIO_InitStructure );		  
	
}


/*
 * 函数名:DHT11_Mode_IPU
 * 描述  :使DHT11-DATA引脚变为上拉输入模式
 * 输入  :无
 * 输出  :无
 */
static void DHT11_Mode_IPU(void)
{
    
    
 	  GPIO_InitTypeDef GPIO_InitStructure;

	  	/*选择要控制的macDHT11_Dout_GPIO_PORT引脚*/	
	  GPIO_InitStructure.GPIO_Pin = macDHT11_Dout_GPIO_PIN;

	   /*设置引脚模式为浮空输入模式*/ 
	  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; 

	  /*调用库函数,初始化macDHT11_Dout_GPIO_PORT*/
	  GPIO_Init(macDHT11_Dout_GPIO_PORT, &GPIO_InitStructure);	 
	
}


/*
 * 函数名:DHT11_Mode_Out_PP
 * 描述  :使DHT11-DATA引脚变为推挽输出模式
 * 输入  :无
 * 输出  :无
 */
static void DHT11_Mode_Out_PP(void)
{
    
    
 	GPIO_InitTypeDef GPIO_InitStructure;

	 	/*选择要控制的macDHT11_Dout_GPIO_PORT引脚*/															   
  	GPIO_InitStructure.GPIO_Pin = macDHT11_Dout_GPIO_PIN;	

	/*设置引脚模式为通用推挽输出*/
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   

	/*设置引脚速率为50MHz */   
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	/*调用库函数,初始化macDHT11_Dout_GPIO_PORT*/
  	GPIO_Init(macDHT11_Dout_GPIO_PORT, &GPIO_InitStructure);	 	 
	
}


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

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

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

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

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


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

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

	Delay_us(30);   //延时30us

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

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

		/*轮询直到从机发出的 80us 高电平 标置信号结束*/
		while(macDHT11_Dout_IN()==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_Mode_Out_PP();
		/*主机拉高*/
		macDHT11_Dout_1;

		/*检查读取的数据是否正确*/
		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;
	
}

	  


/*************************************END OF FILE******************************/

其中DHT11数据类型定义为:

// bsp_dht11.h
typedef struct
{
    
    
	uint8_t  humi_int;		//湿度的整数部分
	uint8_t  humi_deci;	 	//湿度的小数部分
	uint8_t  temp_int;	 	//温度的整数部分
	uint8_t  temp_deci;	 	//温度的小数部分
	uint8_t  check_sum;	 	//校验和
		                 
} DHT11_Data_TypeDef;

头文件定义如下:

#ifndef __DHT11_H
#define	__DHT11_H



#include "stm32f10x.h"



/************************** DHT11 数据类型定义********************************/
typedef struct
{
    
    
	uint8_t  humi_int;		//湿度的整数部分
	uint8_t  humi_deci;	 	//湿度的小数部分
	uint8_t  temp_int;	 	//温度的整数部分
	uint8_t  temp_deci;	 	//温度的小数部分
	uint8_t  check_sum;	 	//校验和
		                 
} DHT11_Data_TypeDef;


#define      macDHT11_Dout_SCK_APBxClock_FUN              RCC_APB2PeriphClockCmd
#define      macDHT11_Dout_GPIO_CLK                       RCC_APB2Periph_GPIOC

#define      macDHT11_Dout_GPIO_PORT                      GPIOC
#define      macDHT11_Dout_GPIO_PIN                       GPIO_Pin_7



/************************** DHT11 函数宏定义********************************/
#define      macDHT11_Dout_0	                            GPIO_ResetBits ( macDHT11_Dout_GPIO_PORT, macDHT11_Dout_GPIO_PIN ) 
#define      macDHT11_Dout_1	                            GPIO_SetBits ( macDHT11_Dout_GPIO_PORT, macDHT11_Dout_GPIO_PIN ) 

#define      macDHT11_Dout_IN()	                          GPIO_ReadInputDataBit ( macDHT11_Dout_GPIO_PORT, macDHT11_Dout_GPIO_PIN ) 



/************************** DHT11 函数声明 ********************************/
void                     DHT11_Init                      ( void );
uint8_t                  DHT11_Read_TempAndHumidity      ( DHT11_Data_TypeDef * DHT11_Data );

;

#endif /* __DHT11_H */

DHT11的原理可以参照这一篇博客STM32-DHT11.

还可以参照野火的官方文档中的例程进行小小的尝试。
其前置知识可参照野火教学视频串口部分.
在完成例程和基本原理的学习后相信这个部分可以很轻松地完成!

(3)光敏传感器和土壤湿度传感器程序设计数据采集程序

光敏和土壤湿度传感器较为类似,均为模拟信号输入而后进行ADC数据转换得到电压再进行函数关系变换得到数据。程序设计上我们先使用ADCx_Init()函数将两路输入的ADC1和ADC2进行初始化,而后将读出的电压数据进行函数变换从而得到相对亮度和土壤湿度。其设计流程图如下图所示。
在这里插入图片描述

// bsp_adc.c
#include "bsp_adc.h"
#include "stm32f10x_dma.h"
#include "stm32f10x_adc.h"

__IO uint32_t ADC_ConvertedValue[NOFCHANEL] = {
    
    0};

/**
  * @brief  ADC GPIO 初始化
  * @param  无
  * @retval 无
  */
static void ADCx_GPIO_Config(void)
{
    
    
	GPIO_InitTypeDef GPIO_InitStructure;
	
	// ADCx_1 GPIO 初始化
	ADCx_1_GPIO_APBxClock_FUN ( ADCx_1_GPIO_CLK, ENABLE );
	GPIO_InitStructure.GPIO_Pin = ADCx_1_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(ADCx_1_PORT, &GPIO_InitStructure);

	// ADCx_2 GPIO 初始化
	ADCx_1_GPIO_APBxClock_FUN ( ADCx_2_GPIO_CLK, ENABLE );
	GPIO_InitStructure.GPIO_Pin = ADCx_2_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(ADCx_2_PORT, &GPIO_InitStructure);	
}

/**
  * @brief  配置ADC工作模式
  * @param  无
  * @retval 无
  */
static void ADCx_Mode_Config(void)
{
    
    
	DMA_InitTypeDef DMA_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	
	// 打开DMA时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	// 打开ADC时钟
	ADCx_1_APBxClock_FUN ( ADCx_1_CLK, ENABLE );
	ADCx_2_APBxClock_FUN ( ADCx_2_CLK, ENABLE );
	
  /* ------------------DMA模式配置---------------- */	
	// 复位DMA控制器
	DMA_DeInit(ADC_DMA_CHANNEL);	
	// 配置 DMA 初始化结构体
	// 外设基址为:ADC 数据寄存器地址
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&( ADCx_1->DR ));	
	// 存储器地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue;	
	// 数据源来自外设
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;	
	// 缓冲区大小,应该等于数据目的地的大小
	DMA_InitStructure.DMA_BufferSize = NOFCHANEL;	
	// 外设寄存器只有一个,地址不用递增
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	// 存储器地址递增
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 	
	// 外设数据大小
	DMA_InitStructure.DMA_PeripheralDataSize = 
	                                  DMA_PeripheralDataSize_Word;	
	// 内存数据大小,跟外设数据大小相同
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;	
	// 循环传输模式
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;	
	// DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;	
	// 禁止存储器到存储器模式,因为是从外设到存储器
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;	
	// 初始化DMA
	DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);	
	// 使能 DMA 通道
	DMA_Cmd(ADC_DMA_CHANNEL , ENABLE);
	
	/* ----------------ADCx_1 模式配置--------------------- */
	// 双ADC的规则同步
	ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;	
	// 扫描模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE ; 
	// 连续转换模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
	// 不用外部触发转换,软件开启即可
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	// 转换结果右对齐
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	
	// 转换通道个数
	ADC_InitStructure.ADC_NbrOfChannel = NOFCHANEL;			
	// 初始化ADC
	ADC_Init(ADCx_1, &ADC_InitStructure);	
	// 配置ADC时钟N狿CLK2的8分频,即9MHz
	RCC_ADCCLKConfig(RCC_PCLK2_Div8); 	
	// 配置ADC 通道的转换顺序和采样时间
	ADC_RegularChannelConfig(ADCx_1, ADCx_1_CHANNEL, 1, 
	                         ADC_SampleTime_239Cycles5);	
	// 使能ADC DMA 请求
	ADC_DMACmd(ADCx_1, ENABLE);
	
	
		/* ----------------ADCx_2 模式配置--------------------- */
	// 双ADC的规则同步
	ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;	
	// 扫描模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE ; 
	// 连续转换模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
	// 不用外部触发转换,软件开启即可
	ADC_InitStructure.ADC_ExternalTrigConv = 
	                           ADC_ExternalTrigConv_None;
	// 转换结果右对齐
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	
	// 转换通道个数
	ADC_InitStructure.ADC_NbrOfChannel = NOFCHANEL;			
	// 初始化ADC
	ADC_Init(ADCx_2, &ADC_InitStructure);	
	// 配置ADC时钟为PCLK2的8分频,即9MHz
	RCC_ADCCLKConfig(RCC_PCLK2_Div8); 	
	// 配置ADC 通道的转换顺序和采样时间
	ADC_RegularChannelConfig(ADCx_2, ADCx_2_CHANNEL, 1, 
	                         ADC_SampleTime_239Cycles5);
	/* 使能ADCx_2的外部触发转换 */
  ADC_ExternalTrigConvCmd(ADC2, ENABLE);
	
	/* ----------------ADCx_1 校准--------------------- */
	// 开启ADC ,并开始转换
	ADC_Cmd(ADCx_1, ENABLE);	
	// 初始化ADC 校准寄存器  
	ADC_ResetCalibration(ADCx_1);
	// 等待校准寄存器初始化完成
	while(ADC_GetResetCalibrationStatus(ADCx_1));	
	// ADC开始校准
	ADC_StartCalibration(ADCx_1);
	// 等待校准完成
	while(ADC_GetCalibrationStatus(ADCx_1));
	
  /* ----------------ADCx_2 校准--------------------- */
		// 开启ADC ,并开始转换
	ADC_Cmd(ADCx_2, ENABLE);	
	// 初始化ADC 校准寄存器  
	ADC_ResetCalibration(ADCx_2);
	// 等待校准寄存器初始化完成
	while(ADC_GetResetCalibrationStatus(ADCx_2));	
	// ADC开始校准
	ADC_StartCalibration(ADCx_2);
	// 等待校准完成
	while(ADC_GetCalibrationStatus(ADCx_2));

	// 由于没有采用外部触发,所以使用软件触发ADC转换 
	ADC_SoftwareStartConvCmd(ADCx_1, ENABLE);
}

/**
  * @brief  ADC初始化
  * @param  无
  * @retval 无
  */
void ADCx_Init(void)
{
    
    
	ADCx_GPIO_Config();
	ADCx_Mode_Config();
}


/*********************************************END OF FILE**********************/

// bsp_adc.h:
#ifndef __ADC_H
#define	__ADC_H


#include "stm32f10x.h"

// 双模式时,ADC1和ADC2转换的数据都存放在ADC1的数据寄存器,
// ADC1的在低十六位,ADC2的在高十六位
// 双ADC模式的第一个ADC,必须是ADC1
#define    ADCx_1                           ADC1
#define    ADCx_1_APBxClock_FUN             RCC_APB2PeriphClockCmd
#define    ADCx_1_CLK                       RCC_APB2Periph_ADC1

#define    ADCx_1_GPIO_APBxClock_FUN        RCC_APB2PeriphClockCmd
#define    ADCx_1_GPIO_CLK                  RCC_APB2Periph_GPIOC  
#define    ADCx_1_PORT                      GPIOC
#define    ADCx_1_PIN                       GPIO_Pin_1
#define    ADCx_1_CHANNEL                   ADC_Channel_11

// 双ADC模式的第二个ADC,必须是ADC2
#define    ADCx_2                           ADC2
#define    ADCx_2_APBxClock_FUN             RCC_APB2PeriphClockCmd
#define    ADCx_2_CLK                       RCC_APB2Periph_ADC2

#define    ADCx_2_GPIO_APBxClock_FUN        RCC_APB2PeriphClockCmd
#define    ADCx_2_GPIO_CLK                  RCC_APB2Periph_GPIOC  
#define    ADCx_2_PORT                      GPIOC
#define    ADCx_2_PIN                       GPIO_Pin_4
#define    ADCx_2_CHANNEL                 ADC_Channel_14

#define    NOFCHANEL                        1

// ADC1 对应 DMA1通道1,ADC3对应DMA2通道5,ADC2没有DMA功能
#define    ADC_DMA_CHANNEL               DMA1_Channel1


void ADCx_Init(void);


#endif /* __ADC_H */


由于这两个都是使用的ADC转换,因此需要设置为双路ADC模式,
对应的教程讲解知识可参照野火双路ADC部分
小案例可以参照光敏传感器实验
STM32串口打印土壤温湿度数据
野火光敏传感器资料

(4)LED和蜂鸣器

这两个的控制实际上就是向GPIO口写入高低电平,相对来说是程序中较为容易的一部分,其对应参考资料可以见使用固件库点亮LED


三、总结

本次主要是针对32工程文件的主要结构进行简要讲解,而后对几种使用的硬件进行讲解,不知不觉一万多字了(虽然占了一些代码),ESP8266的通信模块就等到下一篇再肝。本来还要加一些电机模块的,但是之前疫情没买回来,就没有使用这个模块了。


  1. [野火]《STM32库开发实战指南》 ↩︎

猜你喜欢

转载自blog.csdn.net/qq_51658236/article/details/129282826