NB-IOT实验练习3——传感器采集及执行器控制

上一节介绍了无锡学蠡信息科技有限公司的无线传感器网络实验平台关于STM32F103单片机的基础实验,这一章,主要是使用STM32对单个传感器或执行器模块的单个实验进行介绍和演示。

1. 传感器模块类型的自动识别

无线传感器网络实验平台提供的实验代码在senior_main.c文件中为所有的传感器和执行器都编写了独立的.c文件以进行传感器初始化、模块类型识别、GPIO初始化操作等对每个传感器模块进行底层硬件操作,同时为了可以统一的管理所有的传感器模块,在main.h中建立了结构体,以实现一个工程代码可以实现所有传感器和执行器模块的功能演示,只要更换传感器模块直接复位即可切换不同传感器模块的对应程序切换,避免了不同模块需要烧录不同程序的不便。

1.1 传感器类型识别硬件相关

在无线传感器网络实验平台中,为了可以实现传感器模块插拔后能够自动识别传感器模块的类型,实验平台对每个类型的传感器模块都设计有不同的两路分压电路,使用STM32读取分压电路的两端电压值,因为每个分压电路所使用的电阻其电阻值是不同的,所以内部设定的分压电路的两端电压值也是不同的,所以在进行传感器模块的插拔更换后,MCU只要读取分压电路两端的电压值再与预先设定好的值进行比较,就可以实现传感器类型自动识别。
分压电路(之一)原理图:
NB-IOT实验练习3——传感器采集及执行器控制_第1张图片

1.2 传感器类型识别软件代码相关

1.2.1 传感器管理结构体

在main.h文件中,建立了一个结构体,用于存放传感器类型序列 id, 用于识别区分传感器模块的分压电路的PA4、PA5的电压值, 传感器类型名以及传感器对应的处理功能函数。
结构体如下:

typedef struct
{
	uint16_t id;
	//传感器类型序号
	uint16_t boardpa4voltage; //PA4 引脚电压值
	uint16_t boardpa6voltage; //PA6 引脚电压值
	char *boardtype;
	//传感器类型名
	void (*func) (void);
	//传感器处理函数
}Sensortype_t;

实际定义的结构体变量写在main.c文件中,具体代码如下:

Sensortype_t sensortype[SENSORTYPE_NUM] =
{
	{1, 0 , 290, " 8x8Led ", Led8x8_main},
	{2, 0 , 2200, " Infrared ", Infrared_main},
	{3, 0 , 540, " 4Led ", Led4_main},
	{4, 0 , 1620, " 2Realy ", Realy2_main},
	{5, 3300, 1620, " Hall ", Hall_main},
	{6, 3300, 1920, " LED-Light ", Ledlight_main},
	{7, 0 , 1035, "BEEP-POR-TEM", BeepPortemp_main},
	{8, 0 , 2440, " Shack ", Shack_main},
	{9, 3300, 2245, " Flame ", Flame_main},
	{10, 0 , 1310, " Pressure ", Pressure_main},
	{11, 0 , 800, " Humidity ", SHT10_main},
	{12, 3300, 290, " Gas ", Gas_main},
	{13, 0 , 2690, " Acc ", Acc_main},
	{14, 3300, 1035, " Ulrasonic ", Ultrasonic_main}
};

1.2.2 识别传感器类型代码

实验平台通过ADC采集函数——BoardPAXMeasureVolage,采集分压电路 PA4 PA6 引脚电压值,然后在循环中不断和传感器结构体变量sensortype预存的值进行对比,通过变量i来进行传感器类型序号的记录,对比成功则break跳出循环,跳出循环时的i值就是对应在使用的传感器类型序号。
实现代码如下:

while(adccnt++ < 10)
{
	adctotal1 += BoardPAXMeasureVolage(&hadc1, ADC_CHANNEL_4);
	adctotal2 += BoardPAXMeasureVolage(&hadc1, ADC_CHANNEL_6);
}
BoardPA4Voltage = adctotal1 / 10;
BoardPA6Voltage = adctotal2 / 10;
{
	uint8_t i = 0;
	for(i = 0; i < SENSORTYPE_NUM; i++)
	{
		if(sensortype[i].boardpa4voltage == 0)
		{
			if((BoardPA4Voltage < sensortype[i].boardpa4voltage + 200) &&
			(BoardPA6Voltage > sensortype[i].boardpa6voltage - 200) &&
			(BoardPA6Voltage < sensortype[i].boardpa6voltage + 200))
			{
				break;
			}
		}
		else if(sensortype[i].boardpa4voltage == 3300)
		{
			if((BoardPA4Voltage > sensortype[i].boardpa4voltage - 200) &&
			(BoardPA6Voltage > sensortype[i].boardpa6voltage - 200) &&
			(BoardPA6Voltage < sensortype[i].boardpa6voltage + 200))
			{
				break;
			}
		}
	}
}

通过以上的分压电路和对应的软件代码,就能实现传感器模块类型的上电自动识别功能,接下来就开始进行单个传感器模块的实验。

2. 传感器模块实验

2.1 8x8点阵屏模块实验

  • 实验目的:了解并掌握 LED 点阵的控制原理。
  • 实验现象:控制 LED 点阵显示数字“8”。
  • 硬件介绍
    一个 8x8 的点阵就是由 64 个 LED 小灯组成。下图就是一个点阵 LED 最小单元,即一个 8*8 的点阵 LED。
    NB-IOT实验练习3——传感器采集及执行器控制_第2张图片
    8x8点阵屏的内部结构原理图如下所示:
    NB-IOT实验练习3——传感器采集及执行器控制_第3张图片
    受限于单片机的IO口数量,为了用更少的IO口驱动设备,在本实验平台中使用74HC595芯片进行串并转换,原本需要16个IO口,现在只需要3个IO口就可以完成点阵屏内容显示的需求。
    74HC595与点阵屏电路原理图如下:
    NB-IOT实验练习3——传感器采集及执行器控制_第4张图片 NB-IOT实验练习3——传感器采集及执行器控制_第5张图片
  • 实现过程以及代码展示
    1. 完成数字取模
      使用取模软件,安装点阵屏大小以及你实际想要显示的字体大小进行数字取模,在本实验中使用的字模设置为阳码、逐行扫描、顺向。设置完成后就会自动生成对应的字模数组。
      NB-IOT实验练习3——传感器采集及执行器控制_第6张图片

    2. 初始化GPIO口

      void LED8X8Init(void)
      {
      	GPIO_InitTypeDef GPIO_InitStruct;
      	GPIO_InitStruct.Pin = HC595_SER_PIN;
      	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
      	GPIO_InitStruct.Pull = GPIO_PULLUP;
      	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
      	HAL_GPIO_Init(HC595_SER_PORT, &GPIO_InitStruct);
      	GPIO_InitStruct.Pin = HC595_RCLK_PIN;
      	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
      	GPIO_InitStruct.Pull = GPIO_PULLUP;
      	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
      	HAL_GPIO_Init(HC595_RCLK_PORT, &GPIO_InitStruct);
      	GPIO_InitStruct.Pin = HC595_SCK_PIN;
      	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
      	GPIO_InitStruct.Pull = GPIO_PULLUP;
      	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
      	HAL_GPIO_Init(HC595_SCK_PORT, &GPIO_InitStruct);
      	GpioWrite(HC595_SER_PORT,HC595_SER_PIN,GPIO_PIN_RESET);
      	GpioWrite(HC595_RCLK_PORT,HC595_RCLK_PIN,GPIO_PIN_RESET);
      	GpioWrite(HC595_SCK_PORT,HC595_SCK_PIN,GPIO_PIN_RESET);
      	Write595(0X00);
      	Write595(0xff);
      	GpioWrite(HC595_SER_PORT,HC595_SER_PIN,GPIO_PIN_SET);
      	GpioWrite(HC595_SER_PORT,HC595_SER_PIN,GPIO_PIN_RESET);//重启时无显示
      }
      
    3. 完成数据显示
      调用 SHT10_ LED8X8Init 初始化函数之后,进入 while(1)循环,不停的向 74HC595 发送字模
      数据,显示数字。

      void Led8x8_main(void)
      {
      	static unsigned char disnum=5;
      	LED8X8Init();
      	while(1)
      	{
      		static unsigned char i;
      		Write595(FontSystem8x8[disnum*8+i]);
      		Write595(~DispWm);
      		GpioWrite(HC595_RCLK_PORT,HC595_RCLK_PIN,GPIO_PIN_SET);
      		GpioWrite(HC595_RCLK_PORT,HC595_RCLK_PIN,GPIO_PIN_RESET);//重启时无显示
      		DispWm <<= 1;
      		if(++i == 8)
      		{
      			DispWm = 1;
      			i = 0;
      		}
      	}
      }
      
  • 实验现象
    NB-IOT实验练习3——传感器采集及执行器控制_第7张图片

2.2 高精温湿度传感器模块实验

  • 实验目的:了解并掌握温湿度传感器的采集原理。
  • 实验现象:通过 OLED 液晶屏显示当前温度和湿度。
  • 硬件介绍
    温湿度传感器硬件原理图:
    NB-IOT实验练习3——传感器采集及执行器控制_第8张图片
  • 实现过程以及代码
    1. 初始化GPIO引脚
      void SHT10_Config(void)
      {
      	GPIO_InitTypeDef GPIO_InitStruct;
      	GPIO_InitStruct.Pin = SHT10_SDA_PIN;
      	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
      	GPIO_InitStruct.Pull = GPIO_PULLUP;
      	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
      	HAL_GPIO_Init(SHT10_SDA_PORT, &GPIO_InitStruct);
      	GpioWrite(SHT10_SDA_PORT,SHT10_SDA_PIN,GPIO_PIN_SET);
      	GPIO_InitStruct.Pin = SHT10_SCK_PIN;
      	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
      	GPIO_InitStruct.Pull = GPIO_PULLUP;
      	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
      	HAL_GPIO_Init(SHT10_SCK_PORT, &GPIO_InitStruct);
      	GpioWrite(SHT10_SCK_PORT,SHT10_SCK_PIN,GPIO_PIN_SET);
      	SHT10_ConReset(); //复位通讯
      }
      
    2. 温湿度数据处理
      void SHT10_main(void)
      {
      	uint16_t humi_val, temp_val;
      	uint8_t err = 0, checksum = 0;
      	float temp_val_real=0.0;
      	float humi_val_real=0.0;
      	// float dew_point=0.0;
      	char tempBuf[12];
      	SHT10_Config();
      	while(1)
      	{
      		err += SHT10_Measure(&temp_val, &checksum, TEMP);
      		err += SHT10_Measure(&humi_val, &checksum, HUMI);
      		if(err != 0)
      		{
      			SHT10_ConReset();
      		}
      		else
      		{
      			SHT10_Calculate(temp_val, humi_val, &temp_val_real, &humi_val_real);
      			// dew_point = SHT10_CalcuDewPoint(temp_val_real, humi_val_real);
      			sprintf( (void *)tempBuf,"%2.1fC %2.1f%%",temp_val_real, humi_val_real);
      			LcdPutString16_8(0,0,(uint8_t*)tempBuf,12,1);
      		}
      		Delay(1);
      	}
      }
      
    3. 主函数
      int main(void)
      {
      	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      	HAL_Init();
      	/* Configure the system clock */
      	SystemClock_Config();
      	/* Initialize all configured peripherals */
      	MX_DMA_Init();
      	MX_ADC1_Init();
      	MX_USART1_UART_Init();
      	MX_USART2_UART_Init();
      	EnableUartIT();
      	printf("LPMD007-LPSENSOR-SDK-V1.00\r\n");
      	BoardInitPeriph();
      	/* Infinite loop */
      	while (1)
      	{
      	}
      }
      
  • 实验现象
    NB-IOT实验练习3——传感器采集及执行器控制_第9张图片

2.3 温度、光敏、蜂鸣器模块实验

  • 实验目的:了解并掌握温度传感器、光敏传感器的采集原理。
  • 实验现象:通过 OLED 液晶屏显示当前温度和光敏 ADC 采集值。
  • 硬件介绍
    • 温度传感器电路原理图
      NB-IOT实验练习3——传感器采集及执行器控制_第10张图片
    • 光敏电阻电路原理图
      NB-IOT实验练习3——传感器采集及执行器控制_第11张图片
    • 蜂鸣器电路原理图
      NB-IOT实验练习3——传感器采集及执行器控制_第12张图片
  • 实现代码
    1. 初始化GPIO引脚
      void BeepPortempInit(void)
      {
      	GPIO_InitTypeDef GPIO_InitStruct;
      	GPIO_InitStruct.Pin = BEEP1_PIN;
      	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
      	GPIO_InitStruct.Pull = GPIO_PULLUP;
      	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
      	HAL_GPIO_Init(BEEP1_PORT, &GPIO_InitStruct);
      	GpioWrite(BEEP1_PORT,BEEP1_PIN,GPIO_PIN_SET);
      	GPIO_InitStruct.Pin = TC77_DIO_PIN;
      	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
      	GPIO_InitStruct.Pull = GPIO_PULLUP;
      	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
      	HAL_GPIO_Init(TC77_DIO_PORT, &GPIO_InitStruct);
      	GPIO_InitStruct.Pin = TC77_CLK_PIN;
      	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
      	GPIO_InitStruct.Pull = GPIO_PULLUP;
      	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
      	HAL_GPIO_Init(TC77_CLK_PORT, &GPIO_InitStruct);
      	GpioWrite(TC77_CLK_PORT,TC77_CLK_PIN,GPIO_PIN_RESET);
      	GPIO_InitStruct.Pin = TC77_NSS_PIN;
      	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
      	GPIO_InitStruct.Pull = GPIO_PULLUP;
      	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
      	HAL_GPIO_Init(TC77_NSS_PORT, &GPIO_InitStruct);
      	GpioWrite(TC77_NSS_PORT,TC77_NSS_PIN,GPIO_PIN_RESET);
      }
      
    2. 传感器处理函数
      void BeepPortemp_main(void)
      {
      	int8 temperature;
      	int16 light;
      	char tempBuf[12];
      	uint8_t dispcount=0;
      	BeepPortempInit();
      	while(1)
      	{
      		KeyScan();
      		DelayMs(10);
      		if(KeyValue==HAL_KEY_CENTER)
      		{
      			GpioToggle( BEEP1_PORT,BEEP1_PIN);
      		}
      		NB-IOT 实验指导手册
      		119 / 214
      		//采集温度
      		temperature = ReadTc77Temp();
      		//采集光敏电阻
      		light = AdcMcuReadChannel( &hadc1,ADC_CHANNEL_0 );
      		if(dispcount++>100)
      		{
      			dispcount=0;
      			sprintf( (void *)tempBuf,"T:%2d L:%4d ",temperature,light);
      			LcdPutString16_8(0,0,(uint8_t*)tempBuf,12,1);//CENTER
      		}
      	}
      }
      
  • 实验效果:
    NB-IOT实验练习3——传感器采集及执行器控制_第13张图片

2.4 两路继电器模块实验

  • 实验目的:了解并掌握继电器的工作原理。
  • 实验现象:通过拨动方向按键,从而实现对继电器的控制,分别控制两路继电器模块的通
    断。
  • 硬件介绍
    继电器(英文名称:relay)是一种电控制器件,是当输入量(激励量)的变化达到规定要
    求时,在电气输出电路中使被控量发生预定的阶跃变化的一种电器。它具有控制系统(又
    称输入回路)和被控制系统(又称输出回路)之间的互动关系。通常应用于自动化的控制
    电路中,它实际上是用小电流去控制大电流运作的一种“自动开关”。故在电路中起着自动
    调节、安全保护、转换电路等作用。
    继电器模块的核心执行部件为 HK4100F 继电器,如下图所示。
    NB-IOT实验练习3——传感器采集及执行器控制_第14张图片
    继电器的引脚分布图如下所示,其中引脚 1、2 为线圈,引脚 3、6 为公共端,引脚 4 为
    常闭触点, 引脚 5 为常开触点。当线圈得电时,常开触点与公共端接通,常闭触点与公
    共端断开;当线圈失电时,常开触点与公共端断开,常闭触点与公共端接通。
    在这里插入图片描述
    电路原理图:
    NB-IOT实验练习3——传感器采集及执行器控制_第15张图片
  • 实现代码
    1. GPIO初始化
    void Realy2Init(void)
    {
    	GPIO_InitTypeDef GPIO_InitStruct;
    	GPIO_InitStruct.Pin = RELAY1_PIN;
    	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    	GPIO_InitStruct.Pull = GPIO_PULLUP;
    	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    	HAL_GPIO_Init(RELAY1_PORT, &GPIO_InitStruct);
    	GPIO_InitStruct.Pin = RELAY2_PIN;
    	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    	GPIO_InitStruct.Pull = GPIO_PULLUP;
    	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    	HAL_GPIO_Init(RELAY2_PORT, &GPIO_InitStruct);
    }
    
    1. 方向按键采集函数
    uint8_t KeyValue = HAL_KEY_NULL;
    void KeyScan(void)
    {
    	static uint8_t g_ucLastKeypad, KeyNum, ShortKey, LongKey;
    	uint8_t KeyStatus = 0;
    	KeyStatus = KeyRead();
    	ShortKey = ShortKey;
    	LongKey = LongKey;
    	if(g_ucLastKeypad == HAL_KEY_NULL && KeyStatus != g_ucLastKeypad){//按键刚被按下
    		KeyNum = 0;
    		ShortKey = 0;
    		LongKey = 0;
    		KeyValue = HAL_KEY_NULL;
    	}
    	else if(KeyStatus == g_ucLastKeypad && KeyStatus != HAL_KEY_NULL){//按键正被按着
    		KeyNum++;
    		if(KeyNum == KEY_LONG_TIMES){
    			ShortKey = 0;
    			LongKey = 1;
    			KeyValue = g_ucLastKeypad;
    		}
    	}
    	else if(KeyStatus == HAL_KEY_NULL && KeyStatus != g_ucLastKeypad){//按键被放开
    		if(KeyNum < KEY_LONG_TIMES && KeyNum > KEY_SHORT_TIMES){
    		KeyNum = 0;
    		ShortKey = 1;
    		LongKey = 0;
    		KeyValue= g_ucLastKeypad;
    		}
    	}
    	else{
    		KeyNum = 0;
    		ShortKey = 0;
    		LongKey = 0;
    		KeyValue = HAL_KEY_NULL;
    	}
    	g_ucLastKeypad = KeyStatus;
    }
    
    1. 继电器处理功能函数
    void Realy2_main(void)
    {
    	Realy2Init();
    	LcdPutString16_8(0,0," K1&K2-CLOSE",12,1);//CENTER
    	while(1)
    	{
    		KeyScan();
    		DelayMs(10);
    		switch (KeyValue)
    		{
    			case HAL_KEY_UP:
    			GpioWrite(RELAY1_PORT,RELAY1_PIN,GPIO_PIN_RESET);
    			LcdPutString16_8(0,0," K1-CLOSE ",12,1);//UP
    			break;
    			case HAL_KEY_DOWN:
    			GpioWrite(RELAY1_PORT,RELAY1_PIN,GPIO_PIN_SET);
    			LcdPutString16_8(0,0," K1-OPEN ",12,1);//DOWN
    			break;
    			case HAL_KEY_LEFT:
    			GpioWrite(RELAY2_PORT,RELAY2_PIN,GPIO_PIN_RESET);
    			LcdPutString16_8(0,0," K2-CLOSE ",12,1);//LEFT
    			break;
    			case HAL_KEY_RIGHT:
    			GpioWrite(RELAY2_PORT,RELAY2_PIN,GPIO_PIN_SET);
    			LcdPutString16_8(0,0," K2-OPEN ",12,1);//RIGHT
    			break;
    			case HAL_KEY_CENTER:
    			GpioWrite(RELAY1_PORT,RELAY1_PIN,GPIO_PIN_RESET);
    			GpioWrite(RELAY2_PORT,RELAY2_PIN,GPIO_PIN_RESET);
    			LcdPutString16_8(0,0," K1&K2-CLOSE",12,1);//CENTER
    			break;
    			default:
    			break;
    		}
    	}
    }
    
  • 实验效果:
    NB-IOT实验练习3——传感器采集及执行器控制_第16张图片

2.5 可燃气体传感器模块实验

  • 实验目的:了解并掌握可燃气体传感器的采集原理。

  • 实验效果:通过 OLED 液晶屏显示当前传感器的检测值。

  • 硬件介绍:
    这里选用 MQ-5 气体传感器。MQ-5 气体传感器所使用的气敏材料是在清洁空气中电导率
    较低的二氧化锡(SnO2)。当传感器所处环境中存在可燃气体时,传感器的电导率随空气中
    可燃气体浓度的增加而增大。使用简单的电路即可将电导率的变化转换为与该气体浓度相
    对应的输出信号。
    MQ-5 气体传感器对丁烷、丙烷、甲烷灵敏度高,对甲烷和丙烷可较好的兼顾,这种传感
    器可检测多种可燃性气体,特别是液化气(丙烷),是一款适合多种应用的低成本传感器。
    P14 为电子开关控制引脚,当 P14 输入高电平三极管 Q1 导通,气体传感器 5 脚与 GND 导
    通,传感器开始工作。P14 与 MCU 的 PB1 连通。
    根据可燃气体传感器的电路原理图可知,可燃气体传感器的探测引脚为 P00,当可燃气体
    传感器检测到可燃气时,P00 引脚电压会产生变化,探测引脚 P00 与 MCU 的 PA7 引脚
    相连,所以在此实验中,我们采集 PA4 引脚的电压就可判断出可燃气体浓度水平。
    电路原理图:
    NB-IOT实验练习3——传感器采集及执行器控制_第17张图片

  • 实现代码:

    1. GPIO初始化
    void GasInit(void)
    {
    	GPIO_InitTypeDef GPIO_InitStruct;
    	GPIO_InitStruct.Pin = GASPW_PIN;
    	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    	GPIO_InitStruct.Pull = GPIO_PULLUP;
    	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    	HAL_GPIO_Init(GASPW_PORT, &GPIO_InitStruct);
    	GpioWrite(GASPW_PORT,GASPW_PIN,GPIO_PIN_RESET);
    }
    
    1. 可燃气体传感器处理函数
    void Gas_main(void)
    {
    	int16 gas;
    	char tempBuf[12];
    	uint8_t dispcount=0;
    	GasInit();
    	GpioWrite(GASPW_PORT,GASPW_PIN,GPIO_PIN_SET);
    	while(1)
    	{
    		DelayMs(10);
    		//采集可燃气体传感器
    		gas = AdcMcuReadChannel( &hadc1,ADC_CHANNEL_7 );
    		if(dispcount++>100)
    		{
    			dispcount=0;
    			sprintf( (void *)tempBuf,"gas:%04d ",gas);
    			LcdPutString16_8(0,0,(uint8_t*)tempBuf,12,1);//CENTER
    		}
    	}
    }
    
  • 实验效果:
    NB-IOT实验练习3——传感器采集及执行器控制_第18张图片

2.6 可调亮度 LED 模块实验

  • 实验目的:了解并掌握高亮 LED 的调节亮度原理。

  • 实验效果:通过按键控制 MCU 输出不同占空比的 PWM 波形,并驱动点亮不同亮度 LED。

  • PWM脉冲宽度调制介绍:
    脉冲宽度调制是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。我们可以让定时器产生 PWM, 在计数器频率固定时,PWM 频率或者周期由自动重载寄存器(TIMx_ARR)的值决定,其占空比由捕获/比较寄存器(TIMx_CCRx)的值决定。

    • 定时器 PWM 输出模式配置步骤
      1. 开启 TIMx 和通道输出的 GPIO 时钟,配置该 IO 口的复用功能输出
      2. 初始化 TIMx,设置 TIMx 的 ARR 和 PSC 等参数
      3. 设置 TIMx_CHy 的 PWM 模式,输出比较极性,比较值等参数
      4. 使能 TIMx,使能 TIMx 的 CHy 输出
      5. 修改 输出比较结构体 TIM_OC_InitTypeDef 来控制占空比
  • 电路原理图:
    NB-IOT实验练习3——传感器采集及执行器控制_第19张图片

  • 实现代码:

    1. 初始化定时器TIM4并配置PWM
    void LedlightInit(void)
    {
    	/* Compute the prescaler value to have TIM9 counter clock equal to 16000000 Hz */
    	uhPrescalerValue = (uint32_t)(SystemCoreClock / 16000000) - 1;
    	/* Initialize TIMx peripheral as follows:
    	+ Prescaler = (SystemCoreClock / 16000000) - 1
    	+ Period = (666 - 1)
    	+ ClockDivision = 0
    	+ Counter direction = Up
    	*/
    	TimHandle.Instance = TIMxx;
    	TimHandle.Init.Prescaler = uhPrescalerValue;
    	TimHandle.Init.Period = PERIOD_VALUE;
    	TimHandle.Init.ClockDivision = 0;
    	TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
    	if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
    	{
    		/* Initialization Error */
    		Error_Handler();
    	}
    	/*##-2- Configure the PWM channels #########################################*/
    	/* Common configuration for all channels */
    	sConfig.OCMode = TIM_OCMODE_PWM1;
    	sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
    	sConfig.OCFastMode = TIM_OCFAST_DISABLE;
    	sConfig.OCIdleState = TIM_OCIDLESTATE_RESET;
    	/* Set the pulse value for channel 1 */
    	sConfig.Pulse = 0;//PULSE1_VALUE;
    	if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_1) != HAL_OK)
    	{
    		/* Configuration Error */
    		Error_Handler();
    	}
    	/*##-3- Start PWM signals generation #######################################*/
    	/* Start channel 1 */
    	if (HAL_TIM_PWM_Start(&TimHandle, TIM_CHANNEL_1) != HAL_OK)
    	{
    		/* PWM generation Error */
    		Error_Handler();
    	}
    }
    
    1. 高亮 LED 处理函数
    void Ledlight_main(void)
    {
    	char tempBuf[12];
    	LedlightInit();
    	LcdPutString16_8(0,0," LEV0 ",12,1);//CENTER
    	while(1)
    	{
    		KeyScan();
    		DelayMs(10);
    		if((KeyValue==HAL_KEY_UP)||(KeyValue==HAL_KEY_RIGHT))
    		{
    			if(level<4)
    			level+=1;
    			else
    			level=4;
    		}
    		else if((KeyValue==HAL_KEY_DOWN)||(KeyValue==HAL_KEY_LEFT))
    		{
    			if(level>0)
    			level-=1;
    			else
    			level=0;
    		}
    		if(KeyValue!=HAL_KEY_NULL)
    		{
    			sprintf( (void *)tempBuf," LEV%d ",level);
    			LcdPutString16_8(0,0,(uint8_t*)tempBuf,12,1);//CENTER
    			HAL_TIM_PWM_Stop(&TimHandle, TIM_CHANNEL_1);
    			sConfig.Pulse = (uint32_t)pulsevalue_t[level];
    			HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_1);
    			HAL_TIM_PWM_Start(&TimHandle, TIM_CHANNEL_1);
    		}
    	}
    }
    
  • 实验效果:
    复位 NB-IOT 核心模块后,正确识别传感器模块,OLED 模块显示传感器类型" LED-Light"。
    通过向上向下拨动方向按键,MCU 输出不同占空比的 PWM 波形,并驱动点亮不同亮度
    LED。NB-IOT实验练习3——传感器采集及执行器控制_第20张图片

你可能感兴趣的:(单片机,物联网,stm32)