自己diy的一个小项目,还有很多可以开发!
Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)
单片机源程序如下:
- /* Includes ------------------------------------------------------------------*/
- #include "main.h"
- #include "adc.h"
- #include "i2c.h"
- #include "rtc.h"
- #include "tim.h"
- #include "usart.h"
- #include "gpio.h"
- /* Private includes ----------------------------------------------------------*/
- /* USER CODE BEGIN Includes */
- #include "oled.h" // OLED显示屏头文件
- #include "stdio.h" // 标准输入输出头文件
- #include "rtc.h" // 实时时钟头文件
- #include "led.h" // LED控制头文件
- #include "key.h" // 按键控制头文件
- #include "ds18B20.h" // DS18B20温度传感器头文件
- #include "eeprom.h" // EEPROM存储器头文件
- //#include "adc0832.h" // ADC0832模数转换器头文件
- #include "string.h" // 字符串处理头文件
- /* USER CODE END Includes */
- /* Private typedef -----------------------------------------------------------*/
- /* USER CODE BEGIN PTD */
- /* USER CODE END PTD */
- /* Private define ------------------------------------------------------------*/
- /* USER CODE BEGIN PD */
- #define SAMPLE_COUNT 20 // 采样次数,调整此值以改变采样率
- uint8_t screen = 0; // 当前显示的界面:0表示第一个界面,1表示第二个界面,2表示第三个界面
- /* USER CODE END PD */
- /* Private macro -------------------------------------------------------------*/
- /* USER CODE BEGIN PM */
- /* USER CODE END PM */
- /* Private variables ---------------------------------------------------------*/
- /* USER CODE BEGIN PV */
- RTC_DateTypeDef GetData; // 获取日期结构体
- RTC_TimeTypeDef GetTime; // 获取时间结构体
- uint32_t key_Tick; // 按键时间标志
- uint16_t adc_value; // ADC读取值
- uint8_t saveEEPROM = 0; // 保存EEPROM标志
- uint8_t showEEPROM = 0; // 显示EEPROM标志
- uint8_t eepromDisplayed = 0; // 新增变量,用于标记EEPROM值是否已显示
- uint8_t measureInProgress = 0; // 测量进行中的标志
- uint16_t highPressure = 0; // 高压值
- uint16_t lowPressure = 0; // 低压值
- uint16_t adc_values[SAMPLE_COUNT]; // ADC采集的值数组
- /* 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 */
- void KEY_Process() // 按键功能处理函数
- {
- if (uwTick - key_Tick < 20) return; // 防抖处理,避免误触发
- key_Tick = uwTick; // 记录当前时间
- Key_Read(); // 读取按键状态
- if (Trg & 0x01) // 按键1按下
- {
- HAL_UART_Transmit(&huart3, (uint8_t*)"B", 1, 50); // 通过串口发送字符'B',语音播报:测量中,不要移动和说话
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
- screen = 1; // 切换到第2个界面
- measureInProgress = 1; // 开始测量
- eepromDisplayed = 0; // 重置EEPROM显示标记
- }
- if (Trg & 0x02) // 按键2按下
- {
- screen = 2; // 切换到第3个界面
- HAL_UART_Transmit(&huart3, (uint8_t*)"C", 1, 50);
- showEEPROM = 1; // 设置显示EEPROM标志
- eepromDisplayed = 0; // 重置EEPROM显示标记
- }
- if (Trg & 0x04) // 按键3按下
- {
- OLED_Clear();
- screen = 0; // 切换到第1个界面
- HAL_UART_Transmit(&huart3, (uint8_t*)"A", 1, 50); // 通过串口发送字符'A',语音播报:欢迎使用便携式电子血压计
- }
- if (Trg & 0x08) // 按键4按下
- {
- OLED_Clear();
- screen = 3; // 切换到第1个界面
- HAL_UART_Transmit(&huart3, (uint8_t*)"F", 1, 50); // 通过串口发送字符'F',语音播报:时间播报
- }
- }
- void ADC_Process(uint8_t is_high_pressure)
- {
- uint32_t adc_sum = 0;
- uint16_t max_value = 0;
- uint16_t min_value = 0xFFFF;
- for (int i = 0; i < SAMPLE_COUNT; i++) // 采样SAMPLE_COUNT次
- {
- HAL_ADC_Start(&hadc1); // 启动ADC
- HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); // 等待转换完成
- uint16_t value = HAL_ADC_GetValue(&hadc1); // 获取ADC值
- adc_values[i] = value; // 存储ADC值
- adc_sum += value; // 累加ADC值
- if (value > max_value) max_value = value; // 更新最大值
- if (value < min_value) min_value = value; // 更新最小值
- HAL_ADC_Stop(&hadc1); // 停止ADC
- HAL_Delay(100); // 100ms延时
-
- // Count++;
- // if(Count >= 80)
- // {
- // HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET);//气阀开始放气
- // Count = 0;
- // }
- }
-
- // 使用去掉最大值和最小值后的均值
- adc_sum -= max_value + min_value;
- uint16_t average_value = adc_sum / (SAMPLE_COUNT - 2);
-
- // float voltage = average_value * 3.3 / 4095.0;
- float voltage = average_value * 3.3 / 1150.0;
- float pressure = ((voltage - 0.5) * 300.0) / 4.0;
- if (is_high_pressure)
- {
- highPressure = (int)(pressure * 1.2); // 保存高压值
- // highPressure = average_value; // 保存高压值
- }
- else
- {
- lowPressure = (int)(pressure * 0.8); // 保存低压值
- // lowPressure = average_value; // 保存低压值
- }
- }
- /*
- void Measure_Pressure()
- {
- measureInProgress = 1; // 开始测量
-
- if(measureInProgress == 1)
- {
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET);//气阀开始充气
-
- for (int i = 0; i < 5; i++) // 总共采集5次数据
- {
- if (i < 3) // 前3次采集低压值
- {
- ADC_Process(0);
- }
- else // 后2次采集高压值
- {
- ADC_Process(1);
- }
- }
- measureInProgress = 0; // 测量完成
- }
- // HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET);//气阀开始充气
-
- // for (int i = 0; i < 5; i++) // 总共采集5次数据
- // {
- // if (i < 3) // 前3次采集低压值
- // {
- // ADC_Process(0);
- // }
- // else // 后2次采集高压值
- // {
- //
- // ADC_Process(1);
- //
- // }
- // }
- // measureInProgress = 0; // 测量完成
- if(measureInProgress == 0)
- {
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET);//气阀开始放气
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
- if((highPressure >= 85) && (highPressure <= 130) && (lowPressure >= 60) && (lowPressure <= 85))
- {
- HAL_UART_Transmit(&huart1, (uint8_t*)"D", 1, 50);
- }
- else
- {
- HAL_UART_Transmit(&huart1, (uint8_t*)"E", 1, 50);
- }
- }
- }
- */
- void Measure_Pressure()
- {
- measureInProgress = 1; // 开始测量
- uint32_t startTick = HAL_GetTick(); // 记录开始时间
- int lowPressureSamples = 0; // 低压样本计数
- int highPressureSamples = 0; // 高压样本计数
- // 前6秒充气
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET); // 开始充气
- while ((HAL_GetTick() - startTick) < 6000) // 在7秒内
- {
- if (lowPressureSamples < 3) // 前3次采集低压值
- {
- ADC_Process(0);
- lowPressureSamples++;
- }
- else if (highPressureSamples < 2) // 后2次采集高压值
- {
- ADC_Process(1);
- highPressureSamples++;
- }
- }
- // 停止充气
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET);
- // 如果6秒内没有采集到足够的数据,继续采集直到满足条件
- while (lowPressureSamples < 3 || highPressureSamples < 2)
- {
- if (lowPressureSamples < 3) // 前3次采集低压值
- {
- ADC_Process(0);
- lowPressureSamples++;
- }
- else if (highPressureSamples < 2) // 后2次采集高压值
- {
- ADC_Process(1);
- highPressureSamples++;
- }
- }
- // 等待最后2秒放气
- while ((HAL_GetTick() - startTick) < 7000) // 总共6秒
- {
- // 等待
- }
- // 最后2秒放气
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // 开始放气
- // 等待测量完成
- while ((HAL_GetTick() - startTick) < 10000) // 总共10秒
- {
- // 等待
- }
- measureInProgress = 0; // 测量完成
- // 检查血压值并发送相应的串口消息
- if((highPressure >= 85) && (highPressure <= 130) && (lowPressure >= 60) && (lowPressure <= 85))
- {
- HAL_UART_Transmit(&huart3, (uint8_t*)"D", 1, 50);
- LED1_Off();
- LED2_Off();
- LED3_On();
- }
- else
- {
- HAL_UART_Transmit(&huart3, (uint8_t*)"E", 1, 50);
- LED1_Off();
- LED2_On();
- LED3_Off();
- }
- }
- void Save_Pressure_To_EEPROM()
- {
- uint8_t highPressureLow = highPressure & 0xFF;
- uint8_t highPressureHigh = (highPressure >> 8) & 0xFF;
- At24c02_Write_Byte(0x00, &highPressureLow);
- At24c02_Write_Byte(0x01, &highPressureHigh);
- uint8_t lowPressureLow = lowPressure & 0xFF;
- uint8_t lowPressureHigh = (lowPressure >> 8) & 0xFF;
- At24c02_Write_Byte(0x02, &lowPressureLow);
- At24c02_Write_Byte(0x03, &lowPressureHigh);
- saveEEPROM = 0;
- }
- void Show_EEPROM_On_OLED()
- {
- uint8_t highPressureLow = 0, highPressureHigh = 0;
- uint8_t lowPressureLow = 0, lowPressureHigh = 0;
- At24c02_Read_Byte(0x00, &highPressureLow);
- At24c02_Read_Byte(0x01, &highPressureHigh);
- uint16_t savedHighPressure = (highPressureHigh << 8) | highPressureLow;
- At24c02_Read_Byte(0x02, &lowPressureLow);
- At24c02_Read_Byte(0x03, &lowPressureHigh);
- uint16_t savedLowPressure = (lowPressureHigh << 8) | lowPressureLow;
- char highPressureString[20];
- char lowPressureString[20];
- snprintf(highPressureString, sizeof(highPressureString), "High: %u mmHg", savedHighPressure);
- snprintf(lowPressureString, sizeof(lowPressureString), "Low : %u mmHg", savedLowPressure);
- OLED_ShowString(2, 2, highPressureString, 16, 0);
- OLED_ShowString(2, 4, lowPressureString, 16, 0);
- showEEPROM = 0;
- }
- //串口重定义函数
- int fputc(int ch, FILE *f)
- {
- HAL_UART_Transmit(&huart3, (unsigned char*)ch, 1, 50); // 通过串口发送字符
- return ch; // 返回字符
- }
- /* 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_I2C1_Init();
- MX_RTC_Init();
- MX_TIM1_Init();
- MX_TIM6_Init();
- MX_USART3_UART_Init();
- MX_ADC1_Init();
- /* USER CODE BEGIN 2 */
- OLED_Init(); // 初始化OLED显示屏
- LED_Init(); // 初始化LED
- DS18B20_Init(); // 初始化DS18B20温度传感器
-
- /* 设置RTC时间 */
- RTC_set_time(24, 6, 15, 16, 22, 00, RTC_FORMAT_BIN);
-
- HAL_UART_Transmit(&huart3, (uint8_t*)"A", 1, 50); // 通过串口发送字符'A',语音播报:欢迎使用便携式电子血压计
-
- /* USER CODE END 2 */
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- if (HAL_GetTick() % 300 == 0) // 每300ms执行一次
- {
- if (screen == 0) // 显示时间和日期的界面
- {
- // HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN); // 获取日期
- // HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN); // 获取时间
- // char timeString[20];
- // snprintf(timeString, sizeof(timeString), "Time: %02d:%02d:%02d", GetTime.Hours, GetTime.Minutes, GetTime.Seconds); // 格式化时间字符串
- // char dateString[20];
- // snprintf(dateString, sizeof(dateString), "Date: %02d-%02d-%02d", GetData.Year, GetData.Month, GetData.Date); // 格式化日期字符串
- // 第一行显示12x12大小的汉字
- OLED_ShowCHinese(2, 0, 0, 12, 0); // 显示汉字"欢"
- OLED_ShowCHinese(14, 0, 1, 12, 0); // 显示汉字"迎"
- OLED_ShowCHinese(26, 0, 2, 12, 0); // 显示汉字"使"
- OLED_ShowCHinese(38, 0, 3, 12, 0); // 显示汉字"用"
- OLED_ShowCHinese(50, 0, 4, 12, 0); // 显示汉字"便"
- OLED_ShowCHinese(62, 0, 5, 12, 0); // 显示汉字"携"
- OLED_ShowCHinese(74, 0, 6, 12, 0); // 显示汉字"式"
- OLED_ShowCHinese(86, 0, 7, 12, 0); // 显示汉字"血"
- OLED_ShowCHinese(98, 0, 8, 12, 0); // 显示汉字"压"
- OLED_ShowCHinese(110, 0, 9, 12, 0); // 显示汉字"计"
- // 第二行显示16x16大小的汉字
- OLED_ShowCHinese(2, 2, 0, 16, 0); // 显示汉字"温"
- OLED_ShowCHinese(18, 2, 1, 16, 0); // 显示汉字"度"
- OLED_ShowCHinese(34, 2, 2, 16, 0); // 显示汉字"值"
- OLED_ShowCHinese(98, 2, 3, 16, 0); // 显示汉字"℃"
- float temperature = DS18B20_Get_Temperature(); // 获取温度
- char tempString[20];
- snprintf(tempString, sizeof(tempString), ":%.2f", temperature); // 格式化温度字符串
- OLED_ShowString(50, 2, tempString, 16, 0); // 显示温度
- char pressureString[20];
- snprintf(pressureString, sizeof(pressureString), "000mmHg");
- OLED_ShowString(2, 4, pressureString, 16, 0); // 显示默认的血压值
- }
- else if (screen == 1) // 显示测量血压的界面
- {
- if (measureInProgress) // 测量进行中
- {
- LED1_On();
- HAL_Delay(200);
- LED1_Off();
- HAL_Delay(200);
- HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_7);
- OLED_Clear();
- OLED_ShowCHinese(40, 2, 4, 16, 0); // 显示"测量中"的中文字符
- OLED_ShowCHinese(56, 2, 5, 16, 0);
- OLED_ShowCHinese(72, 2, 6, 16, 0);
-
-
- Measure_Pressure(); // 调用测量血压函数,一直等待测量,测量完才进行下列代码
- OLED_Clear();
- OLED_ShowCHinese(2, 2, 7, 16, 0); // 显示高压和低压的中文字符
- OLED_ShowCHinese(18, 2, 8, 16, 0);
- OLED_ShowCHinese(2, 4, 9, 16, 0);
- OLED_ShowCHinese(18, 4, 10, 16, 0);
- char highPressureString[20];
- snprintf(highPressureString, sizeof(highPressureString), ": %u mmHg", highPressure); // 格式化高压字符串
- OLED_ShowString(36, 2, highPressureString, 16, 0); // 显示高压
- char lowPressureString[20];
- snprintf(lowPressureString, sizeof(lowPressureString), ": %u mmHg", lowPressure); // 格式化低压字符串
- OLED_ShowString(36, 4, lowPressureString, 16, 0); // 显示低压
- Save_Pressure_To_EEPROM(); // 保存血压值到EEPROM
- eepromDisplayed = 1; // 标记EEPROM已显示
- }
- }
- else if (screen == 2) // 显示EEPROM数据的界面
- {
- if (!eepromDisplayed) // 如果EEPROM数据尚未显示
- {
- OLED_Clear();
- Show_EEPROM_On_OLED(); // 显示EEPROM中的血压数据
- eepromDisplayed = 1; // 标记EEPROM已显示
- }
- }
- else if(screen == 3)
- {
- HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN); // 获取当前日期
- HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN); // 获取当前时间
-
- char timeString[20];
- snprintf(timeString, sizeof(timeString), "Time: %02d:%02d:%02d", GetTime.Hours, GetTime.Minutes, GetTime.Seconds); // 格式化时间字符串
- char dateString[20];
- snprintf(dateString, sizeof(dateString), "Date: %02d-%02d-%02d", GetData.Year, GetData.Month, GetData.Date); // 格式化日期字符串
-
- /* 显示界面 */
- OLED_ShowCHinese(28, 0, 12, 16, 0); // 显示“时”
- OLED_ShowCHinese(44, 0, 13, 16, 0); // 显示“间”
- OLED_ShowCHinese(60, 0, 14, 16, 0); // 显示“显”
- OLED_ShowCHinese(76, 0, 15, 16, 0); // 显示“示”
- OLED_ShowString(5, 4, timeString, 16, 0); // 显示时间
- OLED_ShowString(5, 2, dateString, 16, 0); // 显示日期
- }
- }
- KEY_Process(); // 按键处理
- }
- /* 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_OSCILLATORTYPE_LSE;
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
- RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
- RCC_OscInitStruct.LSEState = RCC_LSE_ON;
- 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)
- {
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
资料51hei附件下载:
程序源码.7z
(436.66 KB, 下载次数: 22)
PCB Project.7z
(3.41 MB, 下载次数: 24)
|