This project realizes the real-time monitoring of air temperature, soil humidity, and light intensity in the soil environment, and is displayed through the STONE serial port display screen. Intelligent sensor-based HMI solution for environmental monitoring.
The STONE serial port display screen can immediately control various controls and windows on the screen by sending instructions through the serial port. Curve controls are also added to the GUI of this external project, which can facilitate long-term data analysis and data comparison for users.
Hardware preparation:
- 3.5-inch STONE serial port display screen
- STM32f103c8t6
- JLINK simulator
- Temperature and humidity sensor
- Light sensor
- Soil moisture sensor
Software preparation:
- STONE Designer
- STM32 CubeMX
- Keil uVision5
Intelligent sensor-based HMI solution for environmental monitoring GUI production process:
1. For the new GUI project, the third option needs to be selected according to the screen size. This project uses a 3.5-inch screen, so the resolution is 320 * 240.
2. Then place the controls and add the background image. The button control, label control, chart view control and image control are mainly used in this project. The design process is simple and easy to use. There are two buttons on the left side of the home page. One is to jump to the real-time parameter display page, and the other is the weekly data recording page.
During the design, just drag the button control in the top control bar to the central drawing area, and then change some background images or press effects in the attribute area on the right according to your own needs, The smiling expression is that the image control is also dragged to the center, and then the properties are changed. The effect is as follows:
3. Then right-click the project name in the left project area to create a new blank window
4. The design steps of the previous page complete the placement of some label controls and image controls. The effects are as follows:
5. A chart view control is placed in the third page, and the effect is as follows:
6. After the project is designed, click the donwload button under the debug menu in the upper left corner, and then select the output directory according to the prompt. The software will automatically generate system files. The effects are as follows:
7. You can update the effect in the USB flash drive by downloading it to the default folder on the USB port, and then output it to the following:
Intelligent sensor-based HMI solution for environmental monitoring Program making process:
1. Open the stm32cubemx software, select the MCU model as stm32f103c8t6, and then configure the external high-speed and low-speed clock source for RCC selection first, then configure the clock tree, use the external high-speed crystal oscillator, and the maximum frequency modulation is 72m The effect is as follows:
2. Then open the debugging port, and the effect is as follows:
3. Then configure the serial port, select usart1 and asynchronous mode here, add DMA channels for TX and Rx respectively, and then turn on the global interrupt of usart1. Other attributes are default, and the effect is as follows:
4. Then configure ADC to collect the ad value of soil humidity sensor and photosensitive sensor. These two sensors are in the power supply range of 3.3v-5v, and the output signal is analog signal. Therefore, open two ad channels to receive data. Here, open in1 and in2 of ADC1. Do not use DMA, and read data through intermittent + scanning mode. In this configuration, pay attention to open discontinuous conversion mode and set the number of channels to 2.
5. DHT11 module is used for temperature acquisition, and microsecond signal is required when driving it. Therefore, a 1MHz timer can be configured through timer TIM2. According to the previous clock configuration, timer clocks is 72mhz on apb2 bus, so the prescaled frequency here is 72-1 = 71, and the overload value is set to the maximum 65535. The effects are as follows:
6. Then set the output configuration, select MDK, version V5, and generate the code. The effect is as follows:
7. After the project is generated, there are two folders under the core directory of the output path. Inc stores the header file and Src stores the source file. We can add the library file of the STONE serial port screen here to facilitate the interaction between instructions and the screen. The directory is as follows:
8. The library file of STONE has a link on the official website. Enter the official website of STONE first, and then click the serial port library link address at the bottom left of the figure below, as follows:
9. In the new page, you can see the same folders Inc and SRC, as well as some examples and instructions. Then migrate the library to the local project according to the steps of the instruction document, link as follows:
10. Since it is not set to generate independent files for each peripheral when configuring stm32cubemx, the configuration of peripheral is also in main C, so main is attached directly at the end C. document content:
HMI design for environmental monitoring code:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "dht11.h"
#include "STONE.h"
/* 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 */
extern unsigned char transport_over_flage;
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
TIM_HandleTypeDef htim2;
UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_tx;
DMA_HandleTypeDef hdma_usart1_rx;
/* USER CODE BEGIN PV */
uint8_t hal_tim1_flag;
uint32_t ADC_Value[2];
float ad1,ad2;
int ad2_32;
uint16_t temperature;
uint16_t humidity;
char humi_text[3],temp_text[4];
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_DMA_Init(void);
static void MX_TIM2_Init(void);
/* USER CODE BEGIN PFP */
void delay_us(uint16_t us);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int humi_calc(int value){
int reference_value,value2;
reference_value = 3299;
value2 = reference_value - value;
if (value2 > 0)
{
div_t a = div(value2, 20);
if(a.quot>=100)return 100;
return a.quot;
}
else return 0;
}
/* 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_ADC1_Init();
MX_USART1_UART_Init();
MX_DMA_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1);
// HAL_TIM_Base_Start_IT(&htim1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while(DHT11_Init()){
HAL_Delay(500);
}
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(1000);
for(uint8_t i=0;i<2;i++)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1,0xffff);
ADC_Value[i]=HAL_ADC_GetValue(&hadc1);
}
HAL_ADC_Stop(&hadc1);
DHT11_Read_Data(&temperature,&humidity);
ad1 = (float)(ADC_Value[0]&0xFFF)*3.3/4096;
ad2 = (float)(ADC_Value[1]&0xFFF)*3.3/4096;
ad2_32=ad2*1000+0.5;
ad2_32=humi_calc(ad2_32);
sprintf(humi_text,"%d",ad2_32);
sprintf(temp_text,"%d",temperature>>8);
if(ad1<2)
set_text("label", "light", "light");
if(ad1>2)
set_text("label", "light", "lightless");
set_text("label", "humi", humi_text);
set_text("label", "temp", temp_text);
}
/* 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};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
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_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief ADC1 Initialization Function
* @param None
* @retval None
*/
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = ENABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
/**
* @brief TIM2 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 71;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 65535;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel4_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
/* DMA1_Channel5_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
/*Configure GPIO pin : PA10 */
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : PB5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (STONE_uart_get_flag(USER_UART))
transport_over_flage = 1;
}
void delay_us(uint16_t us){
uint16_t differ = 0xffff-us-5;
__HAL_TIM_SET_COUNTER(&htim2,differ);
HAL_TIM_Base_Start(&htim2);
while(differ < 0xffff-5){
differ = __HAL_TIM_GET_COUNTER(&htim2);
}
HAL_TIM_Base_Stop(&htim2);
}
//void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
//{
// if (htim == (&htim1)) //1s
// {
//// DHT11_Read_Data(&temperature,&humidity);
// for(uint8_t i=0;i<2;i++)
// {
// HAL_ADC_Start(&hadc1);
// HAL_ADC_PollForConversion(&hadc1,0xffff);
// ADC_Value[i]=HAL_ADC_GetValue(&hadc1);
// }
// HAL_ADC_Stop(&hadc1);
// ad1 = (float)(ADC_Value[0]&0xFFF)*3.3/4096;
// ad2 = (float)(ADC_Value[1]&0xFFF)*3.3/4096;
// hal_tim1_flag = 1;
// }
//}
/* 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 */