/* 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" #include "adc.h" #include "dma.h" #include "usart.h" #include "rtc.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include #include "stdio.h" #include "iic.h" #include "SC7A20.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define BUFFER_SIZE 4 uint8_t dataReceive1[BUFFER_SIZE]; uint8_t dataReceiveLPUART1[BUFFER_SIZE]; volatile uint8_t rtcReady = 0; volatile uint8_t uart1DataReady = 0; volatile uint8_t lpuart1DataReady = 0; volatile uint8_t rtc_wakeup = 0; volatile uint8_t lpuart1_wakeup = 0 ; volatile uint8_t Hallvalue ; volatile uint32_t uintadcv; volatile uint16_t uintadc_vol; volatile uint8_t Accelerationvalue; /* 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 */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ uint16_t CalculateCRC(uint8_t *data, uint16_t length) { uint16_t crc = 0xFFFF; for (uint16_t i = 0; i < length; i++) { crc ^= data[i]; for (uint16_t j = 0; j < 8; j++) { if (crc & 0x0001) { crc = (crc >> 1) ^ 0xA001; } else { crc >>= 1; } } } return crc; } /* 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_USART1_UART_Init(); // MX_RTC_Init(); MX_LPUART1_UART_Init(); MX_ADC1_Init(); /* USER CODE BEGIN 2 */ SC7A20_Init(); // HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); memset(dataReceiveLPUART1, 0, sizeof(dataReceiveLPUART1)); __HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_IDLE); HAL_UART_Receive_DMA(&hlpuart1, dataReceiveLPUART1, BUFFER_SIZE); // 启动LPUART1的DMA接收 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);//拉低500ms重启复位 HAL_Delay(500); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);//拉低后再拉回 printf("lp_V45\n"); HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)"AT+TRANMD=1", strlen("AT+TRANMD=1")); HAL_Delay(3000); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);//拉高睡眠 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ Enter_LPStop2Mode();//低功耗Stop2模式 if (lpuart1DataReady) { lpuart1DataReady = 0; if (dataReceiveLPUART1[0] == 0x03 && dataReceiveLPUART1[1] == 0x01)//读取霍尔ADC { uint16_t crcReceived = (dataReceiveLPUART1[3] << 8) | dataReceiveLPUART1[2]; uint16_t crcCalculated = CalculateCRC(dataReceiveLPUART1, 2); if (crcReceived == crcCalculated) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);//拉低唤醒 Hallvalue = ReadHallSensor(); uintadcv = ReadADCValue(); uintadc_vol = CalculateBatteryLevel(uintadcv); uint8_t response[6]; response[0] = 0xF1; response[1] = Hallvalue; response[2] = 0xF2; response[3] = uintadc_vol & 0xFF; uint16_t responseCrc = CalculateCRC(response, 4); response[4] = responseCrc & 0xFF; response[5] = (responseCrc >> 8) & 0xFF; HAL_UART_Transmit_DMA(&hlpuart1, response, sizeof(response)); } } if (dataReceiveLPUART1[0] == 0x03 && dataReceiveLPUART1[1] == 0x02)//读取加速度 { uint16_t crcReceived = (dataReceiveLPUART1[3] << 8) | dataReceiveLPUART1[2]; uint16_t crcCalculated = CalculateCRC(dataReceiveLPUART1, 2); if (crcReceived == crcCalculated) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);//拉低唤醒 Accelerationvalue = ReadSC7A20Sensor(); uint8_t response[4]; response[0] = 0xF3; response[1] = Accelerationvalue; uint16_t responseCrc = CalculateCRC(response, 2); response[2] = responseCrc & 0xFF; response[3] = (responseCrc >> 8) & 0xFF; HAL_UART_Transmit_DMA(&hlpuart1, response, sizeof(response)); HAL_Delay(100); Enter_LPStop2Mode();//低功耗Stop2模式 } } HAL_UART_Receive_DMA(&hlpuart1, dataReceiveLPUART1, BUFFER_SIZE); // 启动LPUART1的DMA接收 HAL_Delay(10); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);//拉高睡眠 HAL_Delay(10); } } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) { Error_Handler(); } /** Configure LSE Drive Capability */ HAL_PWR_EnableBkUpAccess(); __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = 0; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_8; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; 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_MSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } /** Enable MSI Auto calibration */ HAL_RCCEx_EnableMSIPLLMode(); } /* USER CODE BEGIN 4 */ /** PB9 * @brief 读取霍尔传感器忿 * @retval 霍尔传感器忼?0000?0001? */ uint8_t ReadHallSensor(void) { uint8_t hallValue = 0x00; hallValue = (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_9) == GPIO_PIN_RESET) ? 0x00 : 0x01; return hallValue; } /** PA1 * @brief 读取电池电量 * @retval 电池电量(范围:0000?0064? */ uint32_t ReadADCValue(void) { uint32_t adcValue = 0; const int numSamples = 10; // 样本数量 uint32_t totalAdcValue = 0; for (int i = 0; i < numSamples; i++) { HAL_ADC_Start(&hadc1); if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) == HAL_OK) { totalAdcValue += HAL_ADC_GetValue(&hadc1); } HAL_ADC_Stop(&hadc1); } adcValue = totalAdcValue / numSamples; return adcValue; } uint16_t CalculateBatteryLevel(uint32_t adcValue) { float batteryVoltage = 0.0f; const float ADC_MAX_VALUE = 4095.0f; const float VREF = 3.78f; // ADC参迃电县 const float MIN_BATTERY_VOLTAGE = 2.75f; // 电池完全放电电压 const float MAX_BATTERY_VOLTAGE = 4.2f; // 电池完全充电电压 // 将ADC值转换为电压? batteryVoltage = ((float)adcValue / ADC_MAX_VALUE) * VREF/0.474f; // 将电压忼转换为百分毿 if (batteryVoltage <= MIN_BATTERY_VOLTAGE) { return 0; // 电池电量低于或等于完全放电电压时,电量为0% } else if (batteryVoltage >= MAX_BATTERY_VOLTAGE) { return 100; // 电池电量高于或等于完全充电电压时,电量为100% } else { // 计算电池电量百分? return (uint16_t)(((batteryVoltage - MIN_BATTERY_VOLTAGE) / (MAX_BATTERY_VOLTAGE - MIN_BATTERY_VOLTAGE)) * 100); } } /*读取加鿟度数? */ uint8_t ReadSC7A20Sensor(void) { int16_t x1, y1, z1; int16_t x2, y2, z2; uint8_t output = 0x00; // 第一次读取,直到读到有效? do { SC7A20_ReadXYZ(&x1, &y1, &z1); // printf("X1: %d, Y1: %d, Z1: %d\r\n", x1, y1, z1); } while (x1 == 1693 && y1 == 48 && z1 == 952); // 第二次读取,直到读到有效? do { SC7A20_ReadXYZ(&x2, &y2, &z2); // printf("X2: %d, Y2: %d, Z2: %d\r\n", x2, y2, z2); } while (x2 == 1693 && y2 == 48 && z2 == 952); if ((x2 - x1) > 16 || (x1 - x2) > 16 || (z2 - z1) > 15 || (z1 - z2) > 15) { output = 0x01; } // printf("SC7A20Output: 0x%02X\r\n", output); return output; } void Configure_GPIOs_For_LowPower(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // 启用?? GPIO 端口的时? // __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); // __HAL_RCC_ADC_CLK_ENABLE(); __HAL_RCC_USART1_CLK_ENABLE(); GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;// 配置为模拟模式,禁用上拉/下拉 GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Pin = GPIO_PIN_All & ~(GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3); HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);// 配置 GPIOA GPIO_InitStruct.Pin = GPIO_PIN_All;// 配置 GPIOB HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All;// 配置 GPIOC HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All; // 配置 GPIOH HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); // 关闭?? GPIO 端口的时? // __HAL_RCC_GPIOA_CLK_DISABLE(); __HAL_RCC_GPIOB_CLK_DISABLE(); __HAL_RCC_GPIOC_CLK_DISABLE(); __HAL_RCC_GPIOH_CLK_DISABLE(); // 关闭外设时钟 __HAL_RCC_ADC_CLK_DISABLE(); __HAL_RCC_USART1_CLK_DISABLE(); } void Enter_LPStop2Mode(void) { // printf("Entering Stop2\n"); Configure_GPIOs_For_LowPower(); SysTick->CTRL &= (~SysTick_CTRL_TICKINT_Msk); // 暂停SYSTICK中断,以免影响STOP进入 SysTick->CTRL &= (~SysTick_CTRL_ENABLE_Msk); // 暂停SYSTICK计数,以免影响STOP进入 __HAL_RCC_PWR_CLK_ENABLE(); __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); // 配置唤醒时钟源为MSI UART_WakeUpTypeDef UART_WakeUpStruct = {0}; // 初始化UART唤醒类型结构使 UART_WakeUpStruct.WakeUpEvent = UART_WAKEUP_ON_STARTBIT; // 设置为接收开始位时唤醿 // 配置 LPUART1 使能唤醒功能 HAL_UARTEx_StopModeWakeUpSourceConfig(&hlpuart1, UART_WakeUpStruct); // LPUART1同样使用接收弿始位唤醒 __HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_IDLE); // 弿启LPUART1 IDLE中断 __HAL_RCC_LPUART1_CONFIG(RCC_LPUART1CLKSOURCE_LSE); // 使用LSE作为LPUART1时钟溿 HAL_UARTEx_EnableClockStopMode(&hlpuart1); // 启用LPUART1时钟停止模式 HAL_UARTEx_EnableStopMode(&hlpuart1); // 启用LPUART1停止模式 hlpuart1.Instance->CR1 |= USART_CR1_UESM; // 使能LPUART1在STOP模式下的唤醒功能 hlpuart1.Instance->CR3 |= USART_CR3_WUFIE; // 使能仿 STOP 模式唤醒的中斿 // HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE2); // 配置调压器为低功耗模弿 HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); // 进入STOP2模式 // HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); // 配置调压器为正常模式 SysTick->CTRL |=(~SysTick_CTRL_TICKINT_Msk);//唤醒后恢复SYSTICK中断的使? SysTick->CTRL |=(~SysTick_CTRL_ENABLE_Msk);//唤醒后恢复SYSTICK中断的使? HAL_Delay(10); SystemClock_Config(); MX_GPIO_Init(); HAL_ADC_DeInit(&hadc1); MX_ADC1_Init(); // HAL_UART_DeInit(&huart1); HAL_UART_DeInit(&hlpuart1); // MX_USART1_UART_Init(); MX_LPUART1_UART_Init(); // printf("Stop2 wakeup\n"); } /* 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 */