【STM32开发入门】温湿度监测系统实战:SPI LCD显示、HAL库应用、GPIO配置、UART中断接收、ADC采集与串口通信全解析

简介: SPI(Serial Peripheral Interface)是一种同步串行通信接口,常用于微控制器与外围设备间的数据传输。SPI LCD是指使用SPI接口与微控制器通信的液晶显示屏。这类LCD通常具有较少的引脚(通常4个:MISO、MOSI、SCK和SS),因此在引脚资源有限的系统中非常有用。通过SPI协议,微控制器可以向LCD发送命令和数据,控制显示内容和模式。


目录

技术简单讲解:

SPI的LCD

HAL库

GPIO

UART的接收中断

ADC

串口通信

实现功能:


技术简单讲解:

SPI的LCD

SPI(Serial Peripheral Interface)是一种同步串行通信接口,常用于微控制器与外围设备间的数据传输。SPI LCD是指使用SPI接口与微控制器通信的液晶显示屏。这类LCD通常具有较少的引脚(通常4个:MISO、MOSI、SCK和SS),因此在引脚资源有限的系统中非常有用。通过SPI协议,微控制器可以向LCD发送命令和数据,控制显示内容和模式。

HAL库

HAL(Hardware Abstraction Layer)库是STMicroelectronics为STM32系列微控制器提供的一套软件抽象层,旨在简化硬件访问并提供跨不同STM32产品线的兼容性。它提供了一组高级API,使得开发者可以通过统一的接口访问底层硬件资源,如GPIO、USART、ADC等,而无需直接编写寄存器级的代码。使用HAL库可以加速开发过程,提高代码的可移植性和可维护性。

GPIO

GPIO(General-Purpose Input/Output)通用输入输出,是微控制器中的一种基本功能,允许软件控制引脚的高低电平,实现数字信号的输入或输出。GPIO可用于控制LED、读取按钮状态、与其他外设通信等。在嵌入式系统设计中,GPIO是实现硬件交互的重要手段。

UART的接收中断

UART(Universal Asynchronous Receiver/Transmitter)是一种常用的串行通信接口,支持异步数据传输。接收中断是UART通信中的一个重要特性,允许微控制器在接收到新的串行数据时暂停当前任务,立即处理接收到的数据,然后恢复原先的任务,这样可以提高系统的响应速度和效率。通过配置UART的接收中断,开发者可以编写中断服务例程(ISR)来处理接收到的数据,而无需持续轮询。

ADC

ADC(Analog-to-Digital Converter)模数转换器,是将模拟信号转换为数字信号的电子元件。在嵌入式系统中,ADC用于采集传感器(如温度、光线强度)的模拟信号,并将其转换为微控制器可以处理的数字值。ADC的精度、采样率和分辨率是衡量其性能的重要指标。

串口通信

串口通信是一种常用的设备间通信方式,允许数据在两台设备间以串行比特流的形式传输。常见的串口协议包括UART、RS232、RS485等。在嵌入式系统中,串口通信常用于设备调试、传感器数据传输、远程控制等场景。通过设定波特率、数据位、停止位和校验位,两台设备可以配置成兼容的通信参数,从而实现稳定的数据交换。

实现功能:

1.可以在LCD屏幕上显示温湿度、电压、还有加热片、冷凝片、风机的开关。

2.可以通过串口助手去控制加热片、冷凝片、风机的开关。

3.可以通过五向按键去控阈值,例如向上则令加热片的阈值加1,向下减1。

image.gif 编辑

运用的知识:

SPI的LCD、HAL库、GPIO、UART的接收中断、ADC、串口通信。

我是在这个的代码基础上去写的(网上买的温湿度传感器都会带)

实战配置:

首先是配置STM32CubeMX

根据个人的板子不同去创建新的工程 我这里是G030C8

image.gif 编辑

然后去看LED灯的电路图找到对应的串口

image.gif 编辑

image.gif 编辑

image.gif 编辑

其他两个等则是PB1和PB0

image.gif 编辑

选择打开

image.gif 编辑

image.gif 编辑

image.gif 编辑

打开LCD的灯

打开串口通信

image.gif 编辑

打开ADC通道

image.gif 编辑

设置ADC优先级

image.gif 编辑

接下来是代码实现

源码展示:

main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "dht11.h"
#include <stdio.h>
#include "lcd.h"
#include <string.h>
static uint32_t fac_us = 0; //us延时倍乘数
void delay_init(uint8_t SYSCLK)
{
  fac_us = SYSCLK;
}
void delay_us(uint32_t nus)//100  6800
{
  uint32_t ticks;
  uint32_t told, tnow, tcnt = 0;
  uint32_t reload = SysTick->LOAD; //LOAD的值
  ticks = nus * fac_us;            //需要的节拍数
  told = SysTick->VAL;             // 24  刚进入时的计数器值
  while (1)
  {
    tnow = SysTick->VAL;//22  20  0
    if (tnow != told)
    {
      if (tnow < told)
        tcnt += told - tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.
      else
        tcnt += reload - tnow + told;
      told = tnow;
      if (tcnt >= ticks)
        break; //时间超过/等于要延迟的时间,则退出.
    }
  };
}
void delay_ms(uint16_t nms)
{
  uint32_t i;
  for (i = 0; i < nms; i++)
    delay_us(1000);
}
/* USER CODE END 4 */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
uint8_t humiH;
uint8_t humiL;
uint8_t tempH;
uint8_t tempL;
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
float vol = 0;// 电压
int d = 0;// 标志位
uint8_t buf4[32];//接收中断字符串
/* USER CODE END 0 */
/**
  * @brief  The application entry point.
  * @retval int
  */
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_USART1_UART_Init();
  MX_ADC1_Init();
  /* USER CODE BEGIN 2 */
  delay_init(64);
  FS_DHT11_Init();
  float temp;
  int a = 28;//低温阈值
  int b = 35;//高温阈值
  int c = 35;//湿度阈值
  Lcd_Init();//初始LCD
  Lcd_Clear(BLACK);//增加底色
  uint8_t buf[32] = {0};// 接收ADC管道字符串
  char buf1[32];//温度字符串
  char buf2[32];//湿度字符串
  char buf3[32];//电压字符串
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    HAL_UART_Receive_IT(&huart1,buf4,6);//中断接收函数,如果接收到四个或者四个以上的字符都会跳到rxcallback函数
    HAL_ADC_Start(&hadc1);//开始转换
    while(!(ADC1->ISR & 1<<2)){}
    buf[0]=HAL_ADC_GetValue(&hadc1);//电压值
    HAL_ADC_Stop(&hadc1);//停止转换
    vol = (float)buf[0];//赋值
    if(d == 0)//开始是自动的,如果一旦进入手动控制就不会再自动了一直在手动控制里
    {
    if(temp < a)//如果温度小于阈值
    {
      HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);//绿灯亮
      printf("加热片已开启\n");
      Gui_DrawFont_GBK16(0,100,NULL,WHITE,(uint8_t *)"Heating open");//LCD显示
    }
    else
    {
      HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);//绿灯关
      Gui_DrawFont_GBK16(0,100,NULL,WHITE,(uint8_t *)"Heating close");
    }
    
    if(temp > b)
    {
      HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
      printf("冷凝片启动\n");
      Gui_DrawFont_GBK16(0,80,NULL,WHITE,(uint8_t *)"Condente open");
    }
    else
    {
      HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
      Gui_DrawFont_GBK16(0,80,NULL,WHITE,(uint8_t *)"Condente close");
    }
    
    if(humiH > c)
    {
      HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
      printf("风机启动\n");
      Gui_DrawFont_GBK16(0,60,NULL,WHITE,(uint8_t *)"Draught open");
    }
    else
    {
      HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
      Gui_DrawFont_GBK16(0,60,NULL,WHITE,(uint8_t *)"Draught close");
    }
    
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
       DHT11_Read_Data(&humiH,&humiL,&tempH,&tempL);
       temp = tempH + tempL*0.1;
           //拼接字符串 将温湿度和电压都拼接到字符串里
       sprintf(buf1,"temp = %.2f",temp);
       sprintf(buf2,"humI= %d",humiH);
       sprintf(buf3,"vol = %.2f%%",(vol/4096)*100);
           //打在屏幕上
       Gui_DrawFont_GBK16(0,0,NULL,WHITE,(uint8_t *)buf1);
       Gui_DrawFont_GBK16(0,20,NULL,WHITE,(uint8_t *)buf2);
       Gui_DrawFont_GBK16(0,40,NULL,WHITE,(uint8_t *)buf3);
       HAL_Delay(1000);
       printf("temp = %.2fC  humi = %d%%  vol = %.2f",temp,humiH,vol);
  }
}
  /* USER CODE END 3 */
}
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
  RCC_OscInitStruct.PLL.PLLN = 12;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV3;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the peripherals clocks
  */
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_ADC;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
  PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_SYSCLK;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}
/* USER CODE BEGIN 4 */
//输出函数
int fputc(int ch,FILE *p)
{
    while(!(USART1->ISR &(1<<7))){}
    USART1->TDR = ch;
    return ch;
}
//接收中断函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  d++;//标志位
//比较接受来的字符串来执行相应的函数
if(!strcmp(buf4,"1aopen"))
  {
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    printf("加热片已开启\n");
    Gui_DrawFont_GBK16(0,100,NULL,WHITE,(uint8_t *)"Heating open");
    memset(buf4,0,sizeof(buf4));
  }
  else if(!strcmp(buf4,"1close"))
  {
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    Gui_DrawFont_GBK16(0,100,NULL,WHITE,(uint8_t *)"Heating close");
    memset(buf4,0,sizeof(buf4));
    
  }
  
  if(!strcmp(buf4,"2aopen"))
  {
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    printf("冷凝片启动\n");
    Gui_DrawFont_GBK16(0,80,NULL,WHITE,(uint8_t *)"Condente open");
    memset(buf4,0,sizeof(buf4));
    
  }
  else if(!strcmp(buf4,"2close"))
  {
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
    Gui_DrawFont_GBK16(0,80,NULL,WHITE,(uint8_t *)"Condente close");
    memset(buf4,0,sizeof(buf4));
    
  }
  
  if(!strcmp(buf4,"3aopen"))
  {
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    printf("风机启动\n");
    Gui_DrawFont_GBK16(0,60,NULL,WHITE,(uint8_t *)"Draught open");
    memset(buf4,0,sizeof(buf4));
    
  }
  else if(!strcmp(buf4,"3close"))
  {
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    Gui_DrawFont_GBK16(0,60,NULL,WHITE,(uint8_t *)"Draught close");
    memset(buf4,0,sizeof(buf4));
    
  }
  }
/* USER CODE END 4 */
/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

image.gif


相关文章
|
6月前
|
传感器 数据采集 算法
STM32的SPI双机通信实现
STM32的SPI双机通信实现
746 0
|
机器学习/深度学习 文字识别 监控
安全监控系统:技术架构与应用解析
该系统采用模块化设计,集成了行为识别、视频监控、人脸识别、危险区域检测、异常事件检测、日志追溯及消息推送等功能,并可选配OCR识别模块。基于深度学习与开源技术栈(如TensorFlow、OpenCV),系统具备高精度、低延迟特点,支持实时分析儿童行为、监测危险区域、识别异常事件,并将结果推送给教师或家长。同时兼容主流硬件,支持本地化推理与分布式处理,确保可靠性与扩展性,为幼儿园安全管理提供全面解决方案。
540 3
|
人工智能 API 开发者
HarmonyOS Next~鸿蒙应用框架开发实战:Ability Kit与Accessibility Kit深度解析
本书深入解析HarmonyOS应用框架开发,聚焦Ability Kit与Accessibility Kit两大核心组件。Ability Kit通过FA/PA双引擎架构实现跨设备协同,支持分布式能力开发;Accessibility Kit提供无障碍服务构建方案,优化用户体验。内容涵盖设计理念、实践案例、调试优化及未来演进方向,助力开发者打造高效、包容的分布式应用,体现HarmonyOS生态价值。
781 27
|
数据采集 安全 数据挖掘
淘宝天猫宝贝详情页面商品评论采集接口全解析
淘宝天猫商品评论采集接口为电商数据挖掘提供了重要工具。通过分析海量评论,消费者可获取购买决策参考,商家能优化产品与服务,市场研究者则能洞察行业趋势与竞品表现。该接口支持Python请求,助力开发者构建智能分析应用,推动电商生态中各方价值提升。使用时需遵守平台规则,确保数据安全与合法利用。
371 15
|
数据采集 机器学习/深度学习 存储
可穿戴设备如何重塑医疗健康:技术解析与应用实战
可穿戴设备如何重塑医疗健康:技术解析与应用实战
568 4
|
存储 弹性计算 安全
阿里云服务器ECS通用型规格族解析:实例规格、性能基准与场景化应用指南
作为ECS产品矩阵中的核心序列,通用型规格族以均衡的计算、内存、网络和存储性能著称,覆盖从基础应用到高性能计算的广泛场景。通用型规格族属于独享型云服务器,实例采用固定CPU调度模式,实例的每个CPU绑定到一个物理CPU超线程,实例间无CPU资源争抢,实例计算性能稳定且有严格的SLA保证,在性能上会更加稳定,高负载情况下也不会出现资源争夺现象。本文将深度解析阿里云ECS通用型规格族的技术架构、实例规格特性、最新价格政策及典型应用场景,为云计算选型提供参考。
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
1214 29
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
507 4
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
移动开发 前端开发 JavaScript
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。

推荐镜像

更多
  • DNS