)
一、成品简介1.实物成品成品展示总体展示窗户模型APP软件界面二、项目 简介1.功能详解基于STM32的智能窗控系统蓝牙信号采集DS18B20数字温度传感器、光敏电阻光照传感器、雨滴检测传感器模块分别采集温度、光照强度、降雨状态。DS18B20用单总线去通信、光敏传感器和雨滴传感器通过单片机的ADC通道采集。数据处理低通滤波设置动态的数据缓冲区对温度、光照数据滤波。通过90%上次输出和10%当前采样数据的计算抑制环境干扰、采样波动带来的数据误差。窗户的逻辑控制降雨检测最高优先级其次是光照、温度检测。无降雨、光照强度高于阈值时自动控制窗户开启实现采光通风检测到降雨、光照强度不足或环境温度低于阈值时自动关闭窗户实现防雨保温、避光防护。模式切换按键去参数配置与模式切换支持手动/自动工作模式自定义设置光照阈值、温度上下限阈值手动模式优先级高于自动模式。可视化显示0.96寸OLED单色显示屏界面分为参数设置界面与状态显示界面可展示环境温度、光照强度、降雨状态、窗户运行状态、系统工作模式及各项控制阈值。蓝牙远程控制蓝牙模块手机移远程操控。可远程切换系统手动/自动、控制窗户开闭、远程修改光照、温度控制阈值等。电机驱动TB6612电机驱动模块和TT双轴减速电机通过PWM信号控制电机正反转、速度实现开窗关窗动作。硬件框图流程图2.主要器件STM32F103C8T6 单片机窗户模型DS18B20光敏光照传感器雨滴检测传感器JDY-31蓝牙模块TB6612FNG电机驱动TT双轴减速电机0.96寸OLED显示屏独立按键模组3.3V/5V供电模块3.原理图设计4.PCB设计三、主要模块1.电机驱动电机驱动模块采用TB6612FBG驱动模块和TT双轴减速电机组成。TB6612FNG是东芝半导体推出的一款高性能双H桥直流电机驱动IC可同时独立驱动两台直流电机也可驱动一台步进电机实现正反转、调速等功能。相较于传统的L298N驱动模块体积更小、效率更高工作时发热低无需额外加装散热片TT双轴减速电机是种微型直流有刷电机与减速齿轮箱一体化的动力模组转速适中、扭矩大、驱动简单且价格极低。2.蓝牙模块蓝牙模块采用JDY-31基于蓝牙3.0标准的纯从机的无线透传模块主要用作低成本、低功耗短距离串口数据传输。价格便宜、省电、接线简单不需要复杂的操作适合各种微控制器有较好的性价比。四、写作内容参考1.摘要参考内容传统的窗户虽然在一定程度上起到了通风换气、自然采光、安全防护的作用但是操作起来比较繁琐只能通过人工推拉或者手摇机械结构来控制没有智能感知和自动调节的功能。此时操作不及时、不能对环境的变化做出反应的问题就会出现不但会降低居住体验还会造成财产损失和能源浪费。本系统依托STM32F103C8T6微处理器作为核心控制器融合了多类环境传感器与执行机构开发出一种面向智能化窗户调节领域的创新性系统。该系统能够实时监测室内外环境参数包括降雨情况温度、光照强度、并根据预设条件自动控制窗户的开闭实现防雨、散热、通风等功能。本系统架构由软件与硬件两大核心模块组成。在硬件设计方面采用STM32F103C8T6微控制器作为主控单元并集成DS18B20高精度温度传感器、光敏电阻用于环境光照强度检测、雨滴感知模块、OLED显示屏幕以及直流电机驱动电路等关键组件。以STM32F103C8T6单片机为控制中心处理传感器采集的环境数据液晶屏显示当前环境参数和窗户的状态直流电机做执行机构来控制窗户的开关。软件部分主要是主程序设计以及各个子程序模块的设计用编程的方式实现窗户的智能控制和状态显示的功能。系统仿真研究与实物测试结果表明本智能窗户控制电路在结构设计、测量精确度及运行稳定性方面展现出显著的技术优势。用户可以利用按键来设定工作模式以及控制阈值系统会根据环境的变化自动调节窗户的状态还可以通过蓝牙进行远程控制。本研究所设计的智能窗户控制系统可以提高家居生活舒适度、安全性、便捷性对智能家居有广阔的应用前景。2.目录参考内容五、项目主要源码讲解5.1.电机驱动TB6612FNG接收指令后根据指令类型控制TT减速电机正转或者反转。正转带动窗户打开反转带动窗户关闭。到位后电机停转流程结束返回主循环。使用单片机的定时器打开一个通道的PWM输出然后再使用两个GPIO口就可以控制电机运动。5.2蓝牙模块蓝牙JDY-31模块上电初始化以后会进入到等待连接的状态此时STATE引脚输出低电平LED进行闪烁提示没有连接。手机连接成功之后STATE引脚变为高电平LED一直常亮。模块收到串口指令之后进行解析开窗指令使电机正转关窗指令使电机反转阈值设置指令更新对应参数并保存。执行完之后回到主循环。使用单片机的UART外设初始化出一个串口一般串口的波特率设为9600即可使用串口完成蓝牙传输数据。六、项目主要源码5.1.单片机源码5.1.1主程序#include bsp.h /* TIM1: 1MS TIM2:Delay ADCPA0-CH0-光敏 PA1-CH1 Temperature UART1:TX:PA9 RX:PA10 UART2:TX PA2 RX:PA3 蓝牙 RAIN:PA4 KEY:PA5 PA6 PA7 PB0---KEY1-KEY4 MOTOR:B13-A2 B14-A1 PA8-PWM IIC:SDA-PB7 SCL-PB6 光敏电阻 获取光照 STM32内部温度传感器获取温度 蓝牙模块 修改阈值 雨滴检测器模块 下雨检测 直流电机tb6612 通过电机正反转控制模型打开关闭窗户 0.96显示模块 显示温度 按键1 切换手动自动模式默认自动模式 按键2 修改光照低阈值光照大于阈值开窗 按键3如果是手动模式 开窗户 按键4如果是手动模式关窗户 蓝牙0XAA如果是手动模式 开窗户 蓝牙0XBB如果是手动模式 关窗户 蓝牙0XCC修改光照低阈值光照大于阈值开窗 蓝牙0XDD修改光照低阈值光照大于阈值开窗 蓝牙0XFF切换手动自动模式 开窗-光高于阈值且无雨采光通风 关窗-天气亮或有雨防淋雨 没光天黑关窗户 */ /* UART */ uint8_t rx1; #define TX_SIZE 128 uint8_t txbuffer[TX_SIZE]; /* OLED */ char oled_buffer[32]{0}; /* ADC */ uint16_t ch0_value ; uint16_t ch1_value ; uint16_t temp_value; uint16_t Light; uint16_t Temp; /* Light low */ uint8_t light_low25;uint8_t light_high58; uint8_t temp_low15;uint8_t temp_high40; /* WINDOWS */ uint8_t mode1; uint8_t window_state;//手动 开关 uint8_t window_zidongstate;//自动开关 即使执行又是状态 /* RAIN */ uint8_t rain_flag; /* BLUE */ uint8_t rx2; uint8_t BLE; uint8_t BLEMODE; #define TX_BLE 128 uint8_t txbuffer[TX_BLE]; #define RX_BLE 128 uint8_t rxbuffer[RX_BLE]; void uart_send(char* fmt, ...) ; uint8_t dis_mode;//0-set 1-dis uint8_t dis_mode_set;//0-set 1-dis uint32_t low_pass_filter(uint32_t input); /* */ #define close moror_run(1,1500) #define open moror_run(2,1500) void bsp_init() { HAL_UART_Receive_IT(huart1, rx1, 1); HAL_UART_Receive_IT(huart2, rx2, 1); HAL_TIM_Base_Start_IT(htim1); delay_init(); OLED_Init(); OLED_NewFrame(); MY_ADC_Init(); motor_stop(); close; HAL_Delay(500); OLED_Init(); OLED_NewFrame(); OLED_PrintString(0, 0,状态 ,font16x16, OLED_COLOR_NORMAL); OLED_PrintString(42, 0,温度 ,font16x16, ((dis_mode_set0||dis_mode_set1)?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL)); // OLED_PrintString(84, 0,光照 ,font16x16, ((dis_mode_set2||dis_mode_set3)?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL)); OLED_PrintString(0, 16,上限 ,font16x16, ((dis_mode_set0||dis_mode_set2)?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL)); OLED_PrintString(0, 32,下限 ,font16x16, ((dis_mode_set1||dis_mode_set3)?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL)); sprintf((char *)oled_buffer,%2d,light_low); OLED_PrintString(84, 32,oled_buffer ,font16x16, OLED_COLOR_NORMAL); sprintf((char *)oled_buffer,%2d,light_high); OLED_PrintString(84, 16,oled_buffer ,font16x16, OLED_COLOR_NORMAL); sprintf((char *)oled_buffer,%2d,temp_low); OLED_PrintString(42, 32,oled_buffer ,font16x16, OLED_COLOR_NORMAL); sprintf((char *)oled_buffer,%2d,temp_high); OLED_PrintString(42, 16,oled_buffer ,font16x16, OLED_COLOR_NORMAL); } ; /* */ uint16_t temper; void loop() { temperDS18B20_Get_Temp(); uint8_t key0;uint8_t temp; HAL_Delay(1); //ADC--LightTemp MY_ADC_ReadValues(); ch0_value MY_ADC_GetValue(0); // 通道0值 ch1_value MY_ADC_GetValue(1); // 通道1值 temp_value MY_ADC_GetValue(2); // 温度传感器值 ch0_valuelow_pass_filter(ch0_value);// Light; ch1_valuelow_pass_filter(ch1_value); temp_valuelow_pass_filter(temp_value);// Temp; Light((float)ch0_value)/4095.0*100.0;//read/4095x/100 Light100-Light; Temp ((((float)temp_value * 3.3 / 4095.0 - 1.43) / 0.0043) 25.0)/10; // 温度值摄氏度 Temptemper/10; //RAIN tempHAL_GPIO_ReadPin(RAIN_GPIO_Port, RAIN_Pin); if(temp0){rain_flag1;} else {rain_flag0;} //KEY key1自动mode0 手动模式mode1 key2 设置阈值 3-开 4-关 //window_state 手动 0关 1开 keyKEY_Scan(); switch(key) { case 1:if(dis_mode0){(dis_mode_set(dis_mode_set1)%4);}//切换界面 if(dis_mode1){mode(mode1)%2;} break; //默认自动 case 2:if(dis_mode0) {if(dis_mode_set2){light_highlight_high1;} if(dis_mode_set3){light_lowlight_low1;} if(dis_mode_set0){temp_hightemp_high1;} if(dis_mode_set1){temp_lowtemp_low1;} } // if(dis_mode1){if(mode1) window_state2; } break; case 3:if(dis_mode0) {if(dis_mode_set2){light_highlight_high-1;} if(dis_mode_set3){light_lowlight_low-1;} if(dis_mode_set0){temp_hightemp_high-1;} if(dis_mode_set1){temp_lowtemp_low-1;}} //-- if(dis_mode1){if(mode1) window_state1;} break; case 4: dis_mode(dis_mode1)%2; break; } key0; //OLED //模式自动/手动 自动mode0 手动模式mode1 //光照100% Light //无雨/下雨 10 ℃ rain_flag1下雨 Temp //窗户状态开窗/关窗 window_zidongstate //℃模式自动手光照无下雨窗户状态开关温度速度° if(dis_mode0) { OLED_NewFrame(); OLED_PrintString(0, 0,状态 ,font16x16, OLED_COLOR_NORMAL); OLED_PrintString(42, 0,温度 ,font16x16, ((dis_mode_set0||dis_mode_set1)?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL)); // OLED_PrintString(84, 0,光照 ,font16x16, ((dis_mode_set2||dis_mode_set3)?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL)); OLED_PrintString(0, 16,上限 ,font16x16, ((dis_mode_set0||dis_mode_set2)?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL)); OLED_PrintString(0, 32,下限 ,font16x16, ((dis_mode_set1||dis_mode_set3)?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL)); sprintf((char *)oled_buffer,%2d,light_low); OLED_PrintString(84, 32,oled_buffer ,font16x16, OLED_COLOR_NORMAL); sprintf((char *)oled_buffer,%2d,light_high); OLED_PrintString(84, 16,oled_buffer ,font16x16, OLED_COLOR_NORMAL); sprintf((char *)oled_buffer,%2d,temp_low); OLED_PrintString(42, 32,oled_buffer ,font16x16, OLED_COLOR_NORMAL); sprintf((char *)oled_buffer,%2d,temp_high); OLED_PrintString(42, 16,oled_buffer ,font16x16, OLED_COLOR_NORMAL); OLED_ShowFrame(); } else { OLED_NewFrame(); sprintf((char *)oled_buffer,模式:%s, mode0?自动:手动); OLED_PrintString(0, 0,oled_buffer ,font16x16, OLED_COLOR_NORMAL); sprintf((char *)oled_buffer,%2d℃,Temp); OLED_PrintString(88, 0,oled_buffer ,font16x16, OLED_COLOR_REVERSED); sprintf((char *)oled_buffer,光照:%2d, Light); OLED_PrintString(0, 16,oled_buffer ,font16x16, OLED_COLOR_NORMAL); sprintf((char *)oled_buffer,室外环境:%s , rain_flag1?下雨:无雨); OLED_PrintString(0, 32,oled_buffer ,font16x16, OLED_COLOR_NORMAL); sprintf((char *)oled_buffer,窗户状态:%s, window_zidongstate0?关窗:开窗); OLED_PrintString(0, 48,oled_buffer ,font16x16, OLED_COLOR_NORMAL); OLED_ShowFrame(); } //MOTOR //Blue if(BLE0xAA){BLE0x00;BLEMODE1;} if(BLE0xBB){BLE0x00;BLEMODE2;} if(BLE0xCC){BLE0x00;BLEMODE3;} if(BLE0xDD){BLE0x00;BLEMODE4;} if(BLE0xFF){BLE0x00;BLEMODE5;} if(BLEMODE1){BLEMODE0;if(mode1) window_state1;}//开窗户 前提手动模式 if(BLEMODE2){BLEMODE0;if(mode1) window_state2;}//关窗户前提手动模式 if(BLEMODE3){BLEMODE0;if(light_low80)light_lowlight_low3;}//设置开窗阈值 if(BLEMODE4){BLEMODE0;light_lowlight_low-3;if(light_low200)light_low0;}//设置开窗阈值-- if(BLEMODE5){BLEMODE0;mode(mode1)%2;}//手动自动模式切换 屏幕可看自动mode0手动模式mode1 //windows以及执行逻辑 //window_zidongstate //关窗户 不管是下雨 还是太暗 开窗户必须无雨且亮 //阈值指的是高于这个阈值开窗户 //手机或按键切换模式 手动自动开关 if((Lightlight_lowrain_flag0)mode0window_zidongstate0) {//自动开模式 window_zidongstate1; //开窗户motor_set(uint8_t speed, uint16_t angle); open; }//添加了关窗户冷也关 if((Lightlight_low||rain_flag1||Temptemp_low)mode0window_zidongstate1) {//自动模式关窗户 window_zidongstate0; //关窗户motor_set(uint8_t speed, uint16_t angle); // motor_set(2, -180); close; } if(mode1)//手动模式 { if(window_state1)//开 { if(window_zidongstate0) { window_zidongstate1;window_state0; //开窗户motor_set(uint8_t speed, uint16_t angle); // motor_set(2, 180); open; } } if(window_state2)//关 { if(window_zidongstate1) {//开窗户motor_set(uint8_t speed, uint16_t angle); // motor_set(2, -180); window_state0; window_zidongstate0; close; } } // 当为关闭时候不再打开 当为打开时候不再关闭 停驶修改 } } void uart_send(char* fmt, ...) { memset(txbuffer, 0, TX_SIZE); va_list ap; va_start(ap, fmt); vsprintf((char *)txbuffer, fmt, ap); va_end(ap); uint16_t length strlen((char *)txbuffer); HAL_UART_Transmit(huart1, (uint8_t*)txbuffer, length, 1000); } uint32_t low_pass_filter(uint32_t input) { static uint32_t last_output 0; // 初始值为0可根据需要初始化为首个输入值 // 使用整数加权70% 上次输出 30% 当前输入 uint64_t temp (uint64_t)last_output * 7U (uint64_t)input * 3U; uint32_t output (uint32_t)(temp / 10U); last_output output; // 更新历史值 return output; }5.1.2电机驱动代码#include motor.h //MOTOR:B13-A2 B14-A1 PA8-PWM #define AIN1_ON HAL_GPIO_WritePin(AIN1_GPIO_Port, AIN1_Pin, GPIO_PIN_SET); #define AIN2_ON HAL_GPIO_WritePin(AIN2_GPIO_Port, AIN2_Pin, GPIO_PIN_SET); #define AIN1_OFF HAL_GPIO_WritePin(AIN1_GPIO_Port, AIN1_Pin, GPIO_PIN_RESET); #define AIN2_OFF HAL_GPIO_WritePin(AIN2_GPIO_Port, AIN2_Pin, GPIO_PIN_RESET); #define PWMA_ON HAL_GPIO_WritePin(PWMA_GPIO_Port, PWMA_Pin, GPIO_PIN_SET); #define PWMA_OFF HAL_GPIO_WritePin(PWMA_GPIO_Port, PWMA_Pin, GPIO_PIN_RESET); void motor_stop() { AIN2_OFF;AIN1_OFF;PWMA_OFF; } void moror_run(uint8_t dir,uint16_t time) { if(dir1){AIN1_ON;AIN2_OFF;PWMA_ON;} if(dir2){AIN1_OFF;AIN2_ON;PWMA_ON;} HAL_Delay(time); motor_stop(); }5.1.3ADC驱动代码uint16_t adc_buffer[3] {0}; uint32_t adc_multi_conv_result[3] {0}; // 用于存储多通道转换结果 extern ADC_HandleTypeDef hadc1; /* 在 USER CODE BEGIN 1 区域添加 */ void MY_ADC_Init(void) { ADC_ChannelConfTypeDef sConfig {0}; /* USER CODE BEGIN ADC1_Init 1 */ /* USER CODE END ADC1_Init 1 */ /** Common config */ hadc1.Instance ADC1; hadc1.Init.ScanConvMode DISABLE; hadc1.Init.ContinuousConvMode DISABLE; hadc1.Init.DiscontinuousConvMode DISABLE; hadc1.Init.ExternalTrigConv ADC_SOFTWARE_START; hadc1.Init.DataAlign ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion 3; if (HAL_ADC_Init(hadc1) ! HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel ADC_CHANNEL_0; sConfig.Rank ADC_REGULAR_RANK_1; sConfig.SamplingTime ADC_SAMPLETIME_71CYCLES_5; if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel ADC_CHANNEL_1; sConfig.Rank ADC_REGULAR_RANK_2; if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel ADC_CHANNEL_TEMPSENSOR; sConfig.Rank ADC_REGULAR_RANK_3; if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK) { Error_Handler(); } HAL_ADCEx_Calibration_Start(hadc1); HAL_ADC_Start(hadc1); } /** * brief 读取三个通道的ADC值非DMA非连续模式 * note 按顺序转换每个通道等待转换完成 */ void MY_ADC_ReadValues(void) { ADC_ChannelConfTypeDef sConfig {0}; // 通道0配置 sConfig.Channel ADC_CHANNEL_0; sConfig.Rank 1; sConfig.SamplingTime ADC_SAMPLETIME_55CYCLES_5; HAL_ADC_ConfigChannel(hadc1, sConfig); if (HAL_ADC_Start(hadc1) HAL_OK) { if (HAL_ADC_PollForConversion(hadc1, 10000) HAL_OK) { adc_buffer[0] HAL_ADC_GetValue(hadc1); } } // 通道1配置 sConfig.Channel ADC_CHANNEL_1; HAL_ADC_ConfigChannel(hadc1, sConfig); if (HAL_ADC_Start(hadc1) HAL_OK) { if (HAL_ADC_PollForConversion(hadc1, 10000) HAL_OK) { adc_buffer[1] HAL_ADC_GetValue(hadc1); } } // 通道2配置 sConfig.Channel ADC_CHANNEL_2; HAL_ADC_ConfigChannel(hadc1, sConfig); if (HAL_ADC_Start(hadc1) HAL_OK) { if (HAL_ADC_PollForConversion(hadc1, 10000) HAL_OK) { adc_buffer[2] HAL_ADC_GetValue(hadc1); } } } /** * brief 获取指定通道的ADC值 * param channel 通道号 (0-2) * retval 通道转换值 (0-4095) */ uint16_t MY_ADC_GetValue(uint8_t channel) { if (channel 3) { return adc_buffer[channel]; } else { return 0; // 无效通道返回0 } }5.1.4DS18B20驱动代码#include ds18b20.h // 配置区可根据实际修改 #define DS18B20_GPIO_PORT GPIOA // DS18B20的GPIO端口 #define DS18B20_GPIO_PIN GPIO_PIN_11// DS18B20的GPIO引脚 // /** * brief 设置DS18B20引脚为输出模式 * retval 无 */ static void DS18B20_Set_Output(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin DS18B20_GPIO_PIN; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(DS18B20_GPIO_PORT, GPIO_InitStruct); } /** * brief 设置DS18B20引脚为输入上拉模式 * retval 无 */ static void DS18B20_Set_Input(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin DS18B20_GPIO_PIN; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_PULLUP; HAL_GPIO_Init(DS18B20_GPIO_PORT, GPIO_InitStruct); } // -------------------------- 核心驱动函数 -------------------------- /** * brief 复位DS18B20传感器 * retval 无 */ void DS18B20_Rst(void) { DS18B20_Set_Output(); // 设置为输出模式 HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET); // 拉低总线 delay_us(750); // 拉低750us符合DS18B20复位时序 HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_SET); // 释放总线 delay_us(15); // 等待传感器回应 } /** * brief 检测DS18B20是否存在 * retval 1: 未检测到传感器 | 0: 传感器存在 */ uint8_t DS18B20_Check(void) { uint8_t retry 0; DS18B20_Set_Input(); // 设置为输入模式 // 等待传感器拉低总线超时200us while (HAL_GPIO_ReadPin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN) retry 200) { retry; delay_us(1); }; if (retry 200) return 1; // 无回应传感器不存在 else retry 0; // 等待传感器释放总线超时240us while (!HAL_GPIO_ReadPin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN) retry 240) { retry; delay_us(1); }; if (retry 240) return 1; // 回应超时 return 0; // 传感器存在 } /** * brief 从DS18B20读取1个位数据 * retval 0/1: 读取到的位值 */ uint8_t DS18B20_Read_Bit(void) { uint8_t data 0; DS18B20_Set_Output(); // 设置为输出模式 HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET); // 拉低总线2us delay_us(2); HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_SET); // 释放总线 DS18B20_Set_Input(); // 设置为输入模式 delay_us(12); // 等待数据稳定 if (HAL_GPIO_ReadPin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN)) data 1; // 读取到1 else data 0; // 读取到0 delay_us(50); // 等待时序结束 return data; } /** * brief 从DS18B20读取1个字节数据已修正低位在前拼接 * retval 读取到的字节值 */ uint8_t DS18B20_Read_Byte(void) { uint8_t i, bit, dat 0; for (i 0; i 8; i) // 循环8次读取8个位 { bit DS18B20_Read_Bit(); dat | (bit i); // 修正低位在前依次拼接原代码核心错误 } return dat; } /** * brief 向DS18B20写入1个字节数据 * param dat: 要写入的字节值 * retval 无 */ void DS18B20_Write_Byte(uint8_t dat) { uint8_t j; uint8_t testb; DS18B20_Set_Output(); // 设置为输出模式 for (j 0; j 8; j) // 逐位写入 { testb dat 0x01; // 取最低位 dat dat 1; // 右移准备下一位 if (testb) // 写1拉低2us释放60us { HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET); delay_us(2); HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_SET); delay_us(60); } else // 写0拉低60us释放2us { HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET); delay_us(60); HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_SET); delay_us(2); } } } /** * brief 启动DS18B20温度转换 * retval 无 */ void DS18B20_Start(void) { DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0xcc); // 跳过ROM指令单传感器时用 DS18B20_Write_Byte(0x44); // 启动温度转换指令 } /** * brief 初始化DS18B20传感器 * retval 1: 初始化失败无传感器 | 0: 初始化成功 */ uint8_t DS18B20_Init(void) { // 先初始化引脚为输出模式 DS18B20_Set_Output(); HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_SET); DS18B20_Rst(); // 复位传感器 return DS18B20_Check(); // 检测传感器是否存在 } /** * brief 读取DS18B20温度值已修正系数0.0625 * retval 温度值单位0.1℃范围-550~1250 → -55.0℃~125.0℃ */ short DS18B20_Get_Temp(void) { uint8_t TL, TH; short tem; DS18B20_Start(); // 启动温度转换 // HAL_Delay(750); // 等待转换完成最大750ms DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0xcc); // 跳过ROM DS18B20_Write_Byte(0xbe); // 读取暂存器指令 TL DS18B20_Read_Byte(); // 读取温度低字节 TH DS18B20_Read_Byte(); // 读取温度高字节 // 处理正负温度 if((TH 0xf8) ! 0) // 高5位为1表示负温度 { TL ~TL 1; // 补码转原码 TH ~TH; tem -((TH 8) | TL); } else // 正温度 { tem (TH 8) | TL; } tem (float)tem * 0.0625 * 10; // 修正系数0.0625原代码0.625错误×10转为0.1℃精度 return tem; }六、工程主要内容工程的具体内容包括但不限于原理图、程序代码、流程图等等。完整工程、原理图、APP 源码我已经开源到 Gitee需要的同学可以评论区留言或者私信009--基于STM32的窗控系统(蓝牙)