#include "../main/SystemInclude.h" /**************************************************************************************/ /** * @brief 低功耗定时器初始化函数 * @note 需要定义与硬件相关的函数和IO */ //############################################################################## #if(DP2006_VM1000) //############################################################################## //__SAMPLE_STATUS_BIT_TypeDef sampleState; TypeSample sampleProcess; u16 processNextTime, processIndex; // 当前显示单位 static PressureUnitType current_unit = PRESSURE_UNIT_PA; // 默认显示Pa float pressure_value; extern volatile uint8_t display_update_flag; // 显示更新标志 extern volatile uint8_t key_press_flag;//单位按键按下标志 volatile uint8_t display_update_flag = 0; // 显示更新标志 extern volatile Device_StateTypeDef g_device_state; // 初始状态:关机 u8 typecflag=0; extern uint8_t g_auto_shutdown_flag; // 全局变量,用于标记蓝牙是否已经初始化 static uint8_t g_ble_init_done = 0; static uint32_t led_timer = 0; static uint32_t shutdown_timer = 0; /******采集部分***************************************************************************************************************************************************************************************************************/ void FlowRateDealAndOuputSub(void) { ComputeFlowRateIndexAndFlowRate();//计算内码 转换成流量 } void ComputeFlowRateIndexAndFlowRate(void) { voltageDetected[NIDX ]=(u16)sampleProcess.IRHResult; // 强转,只保留低16位数据//IRH 0X8303 voltageDetected[VRHX ]= (u16)sampleProcess.RHypeResult; // 强转,只保留低16位数据//IRR 0X8304 voltageDetected[IVHDX]=(u16) sampleProcess.RDResult; // 强转,只保留低16位数据//URU 0X8305 voltageDetected[RHVOL]= (u16)sampleProcess.BLypeResult; // 强转,只保留低16位数据//URH 0X8306 电池电压/3 voltageDetected[VRHX]=voltageDetected[VRHX]-32768; pressure_value=GetFlowRate(voltageDetected[VRHX],CURVE_1ST); display_update_flag = 1; if( voltageDetected[RHVOL]>50000) { typecflag=1; } } u16 GetAdcGain(u16 gianX) { switch(gianX) { case 1: return GAIN1; case 2: return GAIN2; case 4: return GAIN4; case 8: return GAIN8; case 16: return GAIN16; case 32: return GAIN32; case 64: return GAIN64; case 128: return GAIN128; default: return GetAdcGain(ADC_GAIN_DEFAULT); } } /******采集部分***************************************************************************************************************************************************************************************************************/ void AnalogCircuitInit(void) { sampleProcess.CTypeGain = GetAdcGain(adcGain); //默认采样系数 SampingADCInit(); DisableSamplingInterrupt(); } //void ProcessTimerInterruptCallBack(void) //{ // FlowProcessManagement(); // //} //采样进程中断 void ProcessTimerInterruptCallBack(void) { DisableProcessTimerInterrupt(); HWState.ProcessTimerOut = 1; } //void StartNormolFlowMeasurement(void)//每125ms调用一次 //{ // AnalogCircuitInit();//初始化ADC // HWState.SampledOver = 0;//采样结束标志重置 // StartProcessTimer(32768); //启动比较定时器,开始从0递增计数 // Timer_register_irq_callback(ProcessTimer,ProcessTimerIT, ProcessTimerInterruptCallBack );//注册中断回调函数 // processIndex = 0; // // processNextTime = 0; // FlowProcessManagement();//每个周期运行,开启采样过程 //} void StartNormolFlowMeasurement(void)//开始常规流量测量 { AnalogCircuitInit(); HWState.SampledOver = 0;//采样结束标志重置 StartProcessTimer(64000); // 启动比较定时器,开始从0递增计数 Timer_register_irq_callback(ProcessTimer,ProcessTimerIT, ProcessTimerInterruptCallBack );//注册中断回调函数 sampleProcess.NextRun = 0; sampleProcess.NextTime= 0; FlowProcessManagement();//每个周期运行,开启采样过程 } //static void SetNextProcess(void)//设置采样定时器的下一个进程 //{ // if(processIndex == 0){ // StopProcessTimer();//关闭采集时钟 // return; // } // u32 currentTAR = pTIM1->CNT;//定时器当前计数值 // if(currentTAR > processNextTime) processNextTime = currentTAR + 5; // ResetProcessTimer(processNextTime); //} void SetNextProcess(void)//设置采样定时器的下一个进程 { if(sampleProcess.NextRun == 0){ StopProcessTimer();//关闭采集时钟 return; } // u32 currentTAR = ProcessTimer->CNT;//定时器当前计数值 // if(currentTAR > sampleProcess.NextTime) sampleProcess.NextTime = currentTAR + 5; // ResetProcessTimer(sampleProcess.NextTime); StartProcessTimer(sampleProcess.NextTime); } void SetSystemForADCSample(u16 sampleNum) { sampleProcess.Counter = 0; sampleProcess.CounterMax = sampleNum; StartSamplingADC(); } void ComputeSampleData(u16 sampleNum, u16 sampleShift) { u32 I; sampleProcess.ADC0Result = 0; sampleProcess.ADC1Result = 0; for(I = 0; I> 8) + 32768) & 0xFFFF; sampleProcess.ADC1Result += ((sampleProcess.ADC1Buffer[I] >> 8) + 32768) & 0xFFFF; } sampleProcess.ADC0Result >>= sampleShift; sampleProcess.ADC1Result >>= sampleShift; } /******************************************************************************/ void TurnOffAnalogCircuit(void) { StopSamplingADC(); DisableSamplingInterrupt(); } //void FlowProcessManagement(void)//采样过程管理状态机 //{ // switch(processIndex) // { // case 0: // { // HWState.SampledOver = 0;//采样开始 // SetupRHChannle(); // SetupIRHypeChannle(); // SetSystemForADCSample(16); //开启ADC // processNextTime += 20 * COUNT_VALUE_PER_MS; //20ms 计数值=65535/4000*t = // processIndex=1; // }break; // case 1: // { // TurnOffAnalogCircuit(); // ComputeSampleData(16, 4);//计算样本数据 // sampleProcess.RHypeResult = sampleProcess.ADC0Result;//放入缓存 // sampleProcess.IRHResult = sampleProcess.ADC1Result;//放入缓存 // SetupBLChannle();//设置SIGNAL1 // SetupRDChannle(); // SetSystemForADCSample(16); // processNextTime += 20 * COUNT_VALUE_PER_MS;//20ms // processIndex=2; // }break; // case 2: // { // TurnOffAnalogCircuit(); // ComputeSampleData(16, 4);//计算样本数据; //计算样本数据 // sampleProcess.BLypeResult = sampleProcess.ADC0Result;//放入缓存 // sampleProcess.RDResult = sampleProcess.ADC1Result;//放入缓存 // // HWState.SampledOver = 1; //采样结束 // StopProcessTimer(); // processIndex=3; // }break; // default : processIndex = 0; break; // } // SetNextProcess(); //} void FlowProcessManagement(void)//采样过程管理状态机 { switch(sampleProcess.NextRun) { case 0: { HWState.SampledOver = 0;//采样开始 SetupBLChannle(); SetupRDChannle(); SetSystemForADCSample(SAMPLING_TIMES_IN_DETECT_STAGE);//设置采样个数并开始采样 sampleProcess.NextTime = 20*COUNT_VALUE_PER_MS; sampleProcess.NextRun = 1; }break; case 1: { TurnOffAnalogCircuit(); ComputeSampleData(SAMPLING_TIMES_IN_DETECT_STAGE, SHIFT_IN_DETECT_STAGE); sampleProcess.BLypeResult = sampleProcess.ADC0Result;//放入缓存 sampleProcess.RDResult = sampleProcess.ADC1Result;//放入缓存 // SetupVRHChannle();//设置SIGNAL1 // SetSystemForADCSample(PRESAMPLING_TIMES_IN_1ST_STAGE);//设置采样个数并开始采样 // sampleProcess.NextTime = 20*COUNT_VALUE_PER_MS;//20ms sampleProcess.NextRun = 3; }break; case 2: { TurnOffAnalogCircuit(); ComputeSampleData(PRESAMPLING_TIMES_IN_1ST_STAGE, SHIFT_IN_PRESAMPLING_1ST_STAGE); }break; case 3: { }break; case 4: { }break; case 5: { }break; case 6: { }break; default : sampleProcess.NextRun = 0; break; } SetNextProcess(); } //******************************************************************************/ void CoreInit(void) { SystemGPIOInit(); // ExternCalibratinInput(); TurnOffAnalogCircuit(); } //主程序中断------------------------------------------------------------ //void PrimaryTimer_IRQ_Callback() //{ //// HWState.MainTimerOut = 1; // StartNormolFlowMeasurement(); //} void PrimaryTimer_IRQ_Callback() { HWState.MainTimerOut = 1; // StartNormolFlowMeasurement(); } /******显示部分***************************************************************************************************************************************************************************************************************/ void SwitchPressureUnit(void) { // 1. 计算下一个单位 (循环切换) current_unit = (PressureUnitType)((int)current_unit + 1); if (current_unit > PRESSURE_UNIT_MBAR) { // 【修改】更新为新的最大单位 current_unit = PRESSURE_UNIT_PA; } // 2. 不再需要转换pressure_value,因为它永远是Pa单位 } double ConvertPressure(double value, PressureUnitType targetUnit, PressureUnitType originalUnit) { double valueInPa; if (targetUnit == originalUnit) return value; // --- 第一步:将原始单位转换为标准单位 Pa --- switch (originalUnit) { case PRESSURE_UNIT_MBAR: valueInPa = value * ONE_MBAR_TO_PA; break; case PRESSURE_UNIT_TORR: valueInPa = value * ONE_TORR_TO_PA; break; case PRESSURE_UNIT_MICRONS: valueInPa = value * ONE_MICRONS_TO_PA; break; case PRESSURE_UNIT_PA: valueInPa = value; break; default: return value; // 未知单位,返回原值 } // --- 第二步:将标准单位 Pa 转换为目标单位 --- switch (targetUnit) { case PRESSURE_UNIT_MBAR: return valueInPa * ONE_PA_TO_MBAR; case PRESSURE_UNIT_TORR: return valueInPa * ONE_PA_TO_TORR; case PRESSURE_UNIT_MICRONS: return valueInPa * ONE_PA_TO_MICRONS; case PRESSURE_UNIT_PA: return valueInPa; default: return valueInPa; // 未知目标单位,返回Pa值 } } /** * @brief 计算一个32位无符号整数的位数 * @param num: 要计算的数字 * @retval 数字的位数 */ static u8 GetDigitCount(u32 num) { u8 count = 0; if (num == 0) return 1; // 0 是1位数 while (num != 0) { num /= 10; count++; } return count; } void OLED_DrawRect_Cache(u8 x, u8 y, u8 w, u8 h); void Update_Pressure_Display(void) { // --- 1. 定义显示常量和变量 --- #define FONT_WIDTH 12 #define FONT_HEIGHT 24 #define SCREEN_WIDTH 128 #define RIGHT_ALIGN_MARGIN 2 u8 unit_str_len = 0; const char* unit_str = ""; u32 int_part = 0; u32 decimal_part = 0; u8 num_len = 0; u8 has_decimal = 0; u8 decimal_places = 0; double display_val; u8 current_x; u8 total_num_width; u8 display_x; u8 fixed_erase_start_x; u8 fixed_erase_end_x; // --- 电量显示相关变量 --- u16 battery_adc = 0; u8 battery_level = 0; u8 i = 0; u8 bat_x = 0; u8 bat_y = 0; // 【设置】宽度 22,高度 12 u8 bat_w = 22; u8 bat_h = 12; // --- 2. 换算压力值 --- display_val = ConvertPressure((double)pressure_value / 1000.0, current_unit, PRESSURE_UNIT_PA); // --- 3. 格式化数据 --- has_decimal = 1; switch (current_unit) { case PRESSURE_UNIT_PA: decimal_places = 1; int_part = (u32)(display_val + 0.05f); decimal_part = (u32)(display_val * 10 + 0.5f) % 10; unit_str = "pa"; unit_str_len = 2; break; case PRESSURE_UNIT_MICRONS: decimal_places = 1; int_part = (u32)(display_val + 0.05f); decimal_part = (u32)(display_val * 10 + 0.5f) % 10; unit_str = "mcm"; unit_str_len = 3; break; case PRESSURE_UNIT_TORR: decimal_places = 3; int_part = (u32)(display_val + 0.0005f); decimal_part = (u32)(display_val * 1000 + 0.5f) % 1000; unit_str = "torr"; unit_str_len = 4; break; case PRESSURE_UNIT_MBAR: decimal_places = 2; int_part = (u32)(display_val + 0.0005f); decimal_part = (u32)(display_val * 100 + 0.5f) % 100; unit_str = "mbar"; unit_str_len = 4; break; } num_len = GetDigitCount(int_part); // --- 4. 压力区域刷新逻辑 --- fixed_erase_start_x = 0; fixed_erase_end_x = SCREEN_WIDTH - RIGHT_ALIGN_MARGIN; OLED_FillArea(fixed_erase_start_x, 20, fixed_erase_end_x, 20 + FONT_HEIGHT); // 绘制压力数值... current_x = SCREEN_WIDTH - RIGHT_ALIGN_MARGIN; current_x -= unit_str_len * FONT_WIDTH; OLED_ShowString(current_x, 20, (u8*)unit_str, FONT_HEIGHT, 1); total_num_width = num_len * FONT_WIDTH; if (has_decimal) { total_num_width += FONT_WIDTH; total_num_width += decimal_places * FONT_WIDTH; } current_x -= total_num_width; display_x = current_x; OLED_ShowNum(display_x, 20, int_part, num_len, FONT_HEIGHT, 1); display_x += num_len * FONT_WIDTH; if (has_decimal) { OLED_ShowChar(display_x, 20, '.', FONT_HEIGHT, 1); display_x += FONT_WIDTH; OLED_ShowNum(display_x, 20, decimal_part, decimal_places, FONT_HEIGHT, 1); } // --- 5. 电量显示逻辑--- battery_adc = voltageDetected[RHVOL]; if(battery_adc >= 44761) battery_level = 4; else if(battery_adc >= 43646) battery_level = 3; else if(battery_adc >= 42532) battery_level = 2; else if(battery_adc >= 41418) battery_level = 1; else battery_level = 0; // 2. 确定电池位置 bat_x = 128 - bat_w - 2; bat_y = 0; // 3. 绘制背景和边框 (先清空,再画框) // 画一个大白色实心矩形 OLED_FillRect_White(bat_x, bat_y, bat_x + 22, bat_y + 12); // 中间挖掉一个黑色矩形 (形成空心边框) OLED_FillRect(bat_x + 1, bat_y + 1, bat_x + 21, bat_y + 11); // 4. 根据电量等级绘制电量格 switch(battery_level) { case 4: // 满电:画第4格 OLED_FillRect_White(bat_x + 17, bat_y + 2, bat_x + 20, bat_y + 10); // 注意:这里没有 break,是为了实现“穿透”效果 // 即:如果是4格电,它会继续往下执行画出第3、2、1格 case 3: // 3格电:画第3格 OLED_FillRect_White(bat_x + 12, bat_y + 2, bat_x + 15, bat_y + 10); case 2: // 2格电:画第2格 OLED_FillRect_White(bat_x + 7, bat_y + 2, bat_x + 10, bat_y + 10); case 1: // 1格电:画第1格 OLED_FillRect_White(bat_x + 2, bat_y + 2, bat_x + 5, bat_y + 10); break; // 结束 case 0: // 0格电:只显示空框,不画内部 default: break; } // 5. 画凸起 (在最右侧紧贴) OLED_FillRect_White(bat_x + 22, bat_y + 3, bat_x + 24, bat_y + 9); // --- 6. 差异刷新 --- OLED_Refresh_Line_Diff(0); OLED_Refresh_Line_Diff(1); // 压力区域刷新 OLED_Refresh_Line_Diff(2); OLED_Refresh_Line_Diff(3); OLED_Refresh_Line_Diff(4); OLED_Refresh_Line_Diff(5); } // 辅助函数:绘制矩形边框(不填充) void OLED_DrawRect_Cache(u8 x, u8 y, u8 w, u8 h) { // 上边 OLED_DrawLine(x, y, x + w - 1, y, 1); // 下边 OLED_DrawLine(x, y + h - 1, x + w - 1, y + h - 1, 1); // 左边 OLED_DrawLine(x, y, x, y + h - 1, 1); // 右边 OLED_DrawLine(x + w - 1, y, x + w - 1, y + h - 1, 1); } // 定义一个你自己的函数,比如用来给LED闪烁计时的 void My_Timer2_Callback(void)//每10ms进一次中断 { // LED 逻辑 led_timer++; if(led_timer >= 10) { led_timer = 0; TOGGLE_PIN(LED_PIN_GPIO, LED_PIN); } // 关机逻辑 (独立计数) shutdown_timer++; if(shutdown_timer > 72000) { g_auto_shutdown_flag = 1; } Key_Scan_Task(); Unit_key(); } void SystemPolling(void) { static uint8_t power_off_screen_cleared = 0; if(HWState.MainTimerOut == 1 ) { ManagePrimaryTimeInterval(); // 判断下阶段的工作模式 ModeExitCount(); // 判断各种模式退出 Clear_WDT(); StartNormolFlowMeasurement(); HWState.MainTimerOut = 0; } if(comState.state.ReceivedData) { ReceivedDataProcessing(); } /* 2. 处理界面显示 (根据设备状态分流) */ if(g_device_state == DEVICE_STATE_ON || typecflag == 1) { /* --- 开机/供电状态 --- */ // Update_Pressure_Display(); // 按键是低频事件,立即刷新没问题 // 按键处理:单次触发 if(key_press_flag) { key_press_flag = 0; SwitchPressureUnit(); Update_Pressure_Display(); // 按键是低频事件,立即刷新没问题 } // 数据刷新处理:单次触发 if(display_update_flag) { display_update_flag = 0; // 【关键】立即清除 Update_Pressure_Display(); if(g_ble_init_done==0)//蓝牙未初始化标志位 { BLE_Application_Init();//第一次采集完成后进行蓝牙初始化 g_ble_init_done=1; } } } else { if(!power_off_screen_cleared) { OLED_Clear(); OLED_Refresh(); power_off_screen_cleared = 1; // 标记已清屏,下次不再执行 } } } #endif /****************************************************************************/