/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2024 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 #include /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ uint8_t dutyCycle = 100; uint32_t startTime = 0; uint16_t p1_threshold = 5; uint16_t p2_threshold = 10; uint16_t p3_threshold = 0; uint16_t p4_threshold = 100; uint32_t p5_threshold = 190; uint32_t p6_threshold = 480; uint32_t p1Count = 0; uint32_t p2Count = 0; uint32_t p3Count = 0; uint32_t p4Count = 0; uint32_t p5Count = 0; uint32_t p6Count = 0; #define AVGLEN 30 //#define ADC_BUFFER_SIZE 9 uint32_t adc_samples = 0; #define ADC_BUFFER_SIZE 9 volatile uint16_t adc_buffer[ADC_BUFFER_SIZE]; //volatile uint16_t adc_buffer[ADC_BUFFER_SIZE]; //uint16_t adc_buffer[8+1]; //uint8_t adcOutputBufferIndex = 0; unsigned char i; uint32_t p1PcsPerCc, p2PcsPerCc, p3PcsPerCc, p4PcsPerCc, p5PcsPerCc, p6PcsPerCc; unsigned int p1CountBufferIndex = 0; unsigned int p2CountBufferIndex = 0; unsigned int p3CountBufferIndex = 0; unsigned int p4CountBufferIndex = 0; unsigned int p5CountBufferIndex = 0; unsigned int p6CountBufferIndex = 0; uint32_t p1CountSnapshot = 0; uint32_t p2CountSnapshot = 0; uint32_t p3CountSnapshot = 0; uint32_t p4CountSnapshot = 0; uint32_t p5CountSnapshot = 0; uint32_t p6CountSnapshot = 0; uint32_t p1CountBuffer[AVGLEN]; uint32_t p2CountBuffer[AVGLEN]; uint32_t p3CountBuffer[AVGLEN]; uint32_t p4CountBuffer[AVGLEN]; uint32_t p5CountBuffer[AVGLEN]; uint32_t p6CountBuffer[AVGLEN]; unsigned int p1CountAverage; unsigned int p2CountAverage; unsigned int p3CountAverage; unsigned int p4CountAverage; unsigned int p5CountAverage; unsigned int p6CountAverage; /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ ADC_HandleTypeDef hadc; DMA_HandleTypeDef hdma_adc; UART_HandleTypeDef huart1; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_ADC_Init(void); static void MX_USART1_UART_Init(void); /* USER CODE BEGIN PFP */ void process_adc_data(void); /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 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_DMA_Init(); MX_ADC_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ // HAL_ADCEx_Calibration_Start(&hadc); // HAL_ADC_Start_DMA(&hadc, (uint32_t*)adc_buffer, ADC_BUFFER_SIZE); HAL_ADC_Start_DMA(&hadc, (uint32_t*)adc_buffer, ADC_BUFFER_SIZE); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ for (i=0; i <= AVGLEN; i++) { p1CountBuffer[i] = 0; p2CountBuffer[i] = 0; p3CountBuffer[i] = 0; p4CountBuffer[i] = 0; p5CountBuffer[i] = 0; p6CountBuffer[i] = 0; } while (1) { // process_adc_data(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* 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_HSI14|RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSI14State = RCC_HSI14_ON; RCC_OscInitStruct.HSI14CalibrationValue = 16; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6; RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1; 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_1) != HAL_OK) { Error_Handler(); } PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1; PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } } /** * @brief ADC Initialization Function * @param None * @retval None */ static void MX_ADC_Init(void) { /* USER CODE BEGIN ADC_Init 0 */ /* USER CODE END ADC_Init 0 */ ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC_Init 1 */ /* USER CODE END ADC_Init 1 */ /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ hadc.Instance = ADC1; hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; hadc.Init.Resolution = ADC_RESOLUTION_12B; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc.Init.LowPowerAutoWait = DISABLE; hadc.Init.LowPowerAutoPowerOff = DISABLE; hadc.Init.ContinuousConvMode = ENABLE; hadc.Init.DiscontinuousConvMode = DISABLE; hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc.Init.DMAContinuousRequests = ENABLE; hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED; if (HAL_ADC_Init(&hadc) != HAL_OK) { Error_Handler(); } /** Configure for the selected ADC regular channel to be converted. */ sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5; if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC_Init 2 */ /* USER CODE END ADC_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; huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; 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_Channel1_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* USER CODE BEGIN MX_GPIO_Init_1 */ /* USER CODE END MX_GPIO_Init_1 */ /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); /*Configure GPIO pin : PA5 */ GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } /* USER CODE BEGIN 4 */ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { // adcOutputBufferIndex += 1; adc_samples++; // if (adcOutputBufferIndex >= 8) // adcOutputBufferIndex = 0; adc_buffer[8] = 0; for (int i = 0; i < 8; i++) adc_buffer[8] += adc_buffer[i]; adc_buffer[8] >>= 3; // Divide by 8 to get the average if (adc_buffer[8] > p1_threshold) p1Count++; if (adc_buffer[8] > p2_threshold) p2Count++; if (adc_buffer[8] >= p3_threshold) p3Count++; if (adc_buffer[8] > p4_threshold) p4Count++; if (adc_buffer[8] > p5_threshold) p5Count++; if (adc_buffer[8] > p6_threshold) p6Count++; if (adc_samples >= 166000) { char uart_data[100]; adc_samples = 0; // Reset the sample count p1CountSnapshot = p1Count; p2CountSnapshot = p2Count; p3CountSnapshot = p3Count; p4CountSnapshot = p4Count; p5CountSnapshot = p5Count; p6CountSnapshot = p6Count; p1Count = 0; p2Count = 0; p3Count = 0; p4Count = 0; p5Count = 0; p6Count = 0; p1CountBuffer[p1CountBufferIndex++] = p1CountSnapshot; p2CountBuffer[p2CountBufferIndex++] = p2CountSnapshot; p3CountBuffer[p3CountBufferIndex++] = p3CountSnapshot; p4CountBuffer[p4CountBufferIndex++] = p4CountSnapshot; p5CountBuffer[p5CountBufferIndex++] = p5CountSnapshot; p6CountBuffer[p6CountBufferIndex++] = p6CountSnapshot; if (p1CountBufferIndex >= AVGLEN ) p1CountBufferIndex = 0; if (p2CountBufferIndex >= AVGLEN ) p2CountBufferIndex = 0; if (p3CountBufferIndex >= AVGLEN ) p3CountBufferIndex = 0; if (p4CountBufferIndex >= AVGLEN ) p4CountBufferIndex = 0; if (p5CountBufferIndex >= AVGLEN ) p5CountBufferIndex = 0; if (p6CountBufferIndex >= AVGLEN ) p6CountBufferIndex = 0; p1CountAverage = 0; p2CountAverage = 0; p3CountAverage = 0; p4CountAverage = 0; p5CountAverage = 0; p6CountAverage = 0; for (i = 0; i < AVGLEN; i++) { p1CountAverage += p1CountBuffer[i]; p2CountAverage += p2CountBuffer[i]; p3CountAverage += p3CountBuffer[i]; p4CountAverage += p4CountBuffer[i]; p5CountAverage += p5CountBuffer[i]; p6CountAverage += p6CountBuffer[i]; } // Calculate P1 and P2 concentrations (before adjustment) p1PcsPerCc = p1CountAverage/(float)AVGLEN; p2PcsPerCc = p2CountAverage/(float)AVGLEN; p3PcsPerCc = p3CountAverage/(float)AVGLEN; p4PcsPerCc = p4CountAverage/(float)AVGLEN; p5PcsPerCc = p5CountAverage/(float)AVGLEN; p6PcsPerCc = p6CountAverage/(float)AVGLEN; sprintf(uart_data, "PQ_1p0: %d\r\nPQ_2p5: %d\r\nPQ_5p0: %d\r\nPQ_10p0: %d\r\n", (int)p3PcsPerCc, (int)p4PcsPerCc, (int)p5PcsPerCc, (int)p6PcsPerCc); HAL_UART_Transmit(&huart1, (uint8_t *)uart_data, strlen(uart_data), HAL_MAX_DELAY); } } //void process_adc_data(void) { // // Process the ADC data, for example, calculate the average value: // uint32_t sum = 0; // adc_samples++; // char uart_data[100]; // adc_buffer[8] = 0; // for (size_t i = 0; i < ADC_BUFFER_SIZE; i++) { // adc_buffer[8] += adc_buffer[i]; // } // adc_buffer[8] >>= 3; //// sprintf(uart_data, "average: %d\r\n",average); //// HAL_UART_Transmit(&huart1, (uint8_t *)uart_data, strlen(uart_data), HAL_MAX_DELAY); // if (adc_buffer[8] > p1_threshold) // p1Count++; // if (adc_buffer[8] > p2_threshold) // p2Count++; // if (adc_buffer[8] >= p3_threshold) // p3Count++; // if (adc_buffer[8] > p4_threshold) // p4Count++; // if (adc_buffer[8] > p5_threshold) // p5Count++; // if (adc_buffer[8] > p6_threshold) // p6Count++; // // if(adc_samples >= 166000) // { // adc_samples = 0; // Reset the sample count // p1CountSnapshot = p1Count; // p2CountSnapshot = p2Count; // p3CountSnapshot = p3Count; // p4CountSnapshot = p4Count; // p5CountSnapshot = p5Count; // p6CountSnapshot = p6Count; // // p1Count = 0; // p2Count = 0; // p3Count = 0; // p4Count = 0; // p5Count = 0; // p6Count = 0; // // p1CountBuffer[p1CountBufferIndex++] = p1CountSnapshot; // p2CountBuffer[p2CountBufferIndex++] = p2CountSnapshot; // p3CountBuffer[p3CountBufferIndex++] = p3CountSnapshot; // p4CountBuffer[p4CountBufferIndex++] = p4CountSnapshot; // p5CountBuffer[p5CountBufferIndex++] = p5CountSnapshot; // p6CountBuffer[p6CountBufferIndex++] = p6CountSnapshot; // // if (p1CountBufferIndex >= AVGLEN ) // p1CountBufferIndex = 0; // // if (p2CountBufferIndex >= AVGLEN ) // p2CountBufferIndex = 0; // // if (p3CountBufferIndex >= AVGLEN ) // p3CountBufferIndex = 0; // // if (p4CountBufferIndex >= AVGLEN ) // p4CountBufferIndex = 0; // // if (p5CountBufferIndex >= AVGLEN ) // p5CountBufferIndex = 0; // // if (p6CountBufferIndex >= AVGLEN ) // p6CountBufferIndex = 0; // // p1CountAverage = 0; // p2CountAverage = 0; // p3CountAverage = 0; // p4CountAverage = 0; // p5CountAverage = 0; // p6CountAverage = 0; // // // for (i = 0; i < AVGLEN; i++) // { // p1CountAverage += p1CountBuffer[i]; // p2CountAverage += p2CountBuffer[i]; // p3CountAverage += p3CountBuffer[i]; // p4CountAverage += p4CountBuffer[i]; // p5CountAverage += p5CountBuffer[i]; // p6CountAverage += p6CountBuffer[i]; // // } // // // Calculate P1 and P2 concentrations (before adjustment) // p1PcsPerCc = p1CountAverage/(float)AVGLEN; // p2PcsPerCc = p2CountAverage/(float)AVGLEN; // p3PcsPerCc = p3CountAverage/(float)AVGLEN; // p4PcsPerCc = p4CountAverage/(float)AVGLEN; // p5PcsPerCc = p5CountAverage/(float)AVGLEN; // p6PcsPerCc = p6CountAverage/(float)AVGLEN; // // sprintf(uart_data, "PQ_1p0: %d\r\nPQ_2p5: %d\r\nPQ_5p0: %d\r\nPQ_10p0: %d\r\n", // (int)p3PcsPerCc, // (int)p4PcsPerCc, (int)p5PcsPerCc, (int)p6PcsPerCc); // // HAL_UART_Transmit(&huart1, (uint8_t *)uart_data, strlen(uart_data), HAL_MAX_DELAY); // } ////yu may want to transfer the reading to the serial port //} /* 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 */