rt_uint16_t humidity_t = (temp_humi_response[3] << 8) + temp_humi_response[4]; rt_uint16_t temperature_t = (temp_humi_response[5] << 8) + temp_humi_response[6]; rt_uint16_t water_t = ( water_response[3] << 8) + water_response[4]; rt_uint16_t smoke_t = ( smoke_response[3] << 8) + smoke_response[4]; rt_uint8_t date_sensor[] = vsnprintf("%d-%d-%d %d:%d:%d\t%.1f\t%.1f\t%.2f\t%d\n", user_time_t->tm_year,user_time_t->tm_mon,user_time_t->tm_mday,user_time_t->tm_hour,user_time_t->tm_min,user_time_t->tm_sec, humidity_t/10.0,temperature_t/10.0,water_t/100.0,smoke_t); 报错了 ../applications/src/sdcard.c:57:66: warning: passing argument 3 of 'vsnprintf' makes pointer from integer without a cast [-Wint-conversion] user_time_t->tm_year,user_time_t->tm_mon,user_time_t->tm_mday,user_time_t->tm_hour,user_time_t->tm_min,user_time_t->tm_sec, ^ In file included from d:\rt-threadstudio\repo\extract\toolchain_support_packages\arm\gnu_tools_for_arm_embedded_processors\5.4.1\arm-none-eabi\include\stdio.h:29:0, from ../applications/src/sdcard.c:2: d:\rt-threadstudio\repo\extract\toolchain_support_packages\arm\gnu_tools_for_arm_embedded_processors\5.4.1\arm-none-eabi\include\stdio.h:268:5: note: expected 'const char * restrict' but argument is of type 'int' int _EXFUN(vsnprintf, (char *__restrict, size_t, const char *__restrict, __VALIST) ^ ../applications/src/sdcard.c:57:86: error: incompatible type for argument 4 of 'vsnprintf' user_time_t->tm_year,user_time_t->tm_mon,user_time_t->tm_mday,user_time_t->tm_hour,user_time_t->tm_min,user_time_t->tm_sec, ^ In file included fr

时间: 2025-07-08 17:22:53 浏览: 12
<think>好的,用户的问题是关于解决vsprintf函数参数类型不匹配的问题,特别是涉及vsnprintf的参数类型错误,其中提到了tm_year、tm_mon等时间结构体成员,以及RT-Thread Studio和arm-none-eabi-gcc的环境。 首先,我需要理解用户的具体问题。用户可能在调用vsnprintf时,传入了时间结构体的成员,而编译器报错参数类型不匹配。常见的错误可能包括将整数类型的tm_year等直接传递给格式化字符串中的%d,或者在结构体成员的数据类型与格式化字符串不匹配。 接下来,我需要回忆C语言中vsnprintf的用法。vsnprintf的函数原型是int vsnprintf(char *str, size_t size, const char *format, va_list ap),它的参数类型由格式化字符串决定。例如,%d对应int,%ld对应long int等。而tm结构体的成员通常是int类型,比如tm_year是从1900年算起的年份,tm_mon是0-11的月份,这些在标准库中定义为int。因此,用户可能在格式化时使用了不正确的格式说明符,比如对于int类型用了%ld,或者反过来。 另外,用户的环境是RT-Thread Studio和arm-none-eabi-gcc,这可能涉及嵌入式系统中的不同数据模型,比如是否使用32位或16位的int。需要确认编译器中int的大小,通常arm-none-eabi-gcc中int是32位的,所以用%d是正确的。但有时开发者可能会误以为某些字段是long类型,导致错误。 然后,用户提到的参数类型错误可能还涉及到可变参数的处理。使用va_arg时,必须确保传入的参数类型与格式化字符串中的期望类型一致,否则会导致未定义行为或错误。例如,如果格式化字符串是“%d”,但实际传递了一个long,就会出错。 可能的解决步骤包括: 1. 检查格式化字符串中的每个格式说明符是否与对应的参数类型匹配。例如,确保tm_year用%d而不是%ld。 2. 确认tm结构体成员的数据类型,通常是int,因此使用%d。 3. 检查是否有其他参数类型不匹配的情况,比如指针类型或不同的整数类型。 4. 使用强制类型转换确保参数类型正确,例如将变量转换为int类型,如果它们被声明为其他类型的话。 另外,用户可能在使用RT-Thread的日志或时间模块时调用了vsnprintf,需要检查具体的调用代码。例如,在格式化时间时,代码可能类似: struct tm *timeinfo; vsnprintf(buffer, size, "Time: %d-%d-%d %d:%d:%d", timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); 这里需要注意,tm_year需要加上1900,tm_mon需要加1,但它们的类型仍然是int,所以用%d是正确的。如果用户在这里用了其他格式说明符,比如%ld,就会导致类型不匹配。 还需要考虑编译器的警告设置,是否开启了-Wformat选项,这可以帮助检测格式化字符串和参数类型的不匹配。建议用户检查编译器的警告信息,根据提示修正格式说明符。 最后,如果用户的问题仍未解决,可能需要查看具体的代码片段,才能更准确地诊断问题所在。但基于常见的情况,上述步骤应该能解决大部分参数类型不匹配的问题。</think>关于`vsnprintf`参数类型错误的问题,主要与`struct tm`结构体成员的数据类型匹配有关。以下是分步解决方案: ### 1. 确认`struct tm`成员类型 在C标准库中,`struct tm`的定义为: ```c struct tm { int tm_sec; // 秒 [0,59] int tm_min; // 分 [0,59] int tm_hour; // 时 [0,23] int tm_mday; // 日 [1,31] int tm_mon; // 月 [0,11] ← 特别注意需要+1 int tm_year; // 年份 = 实际年份-1900 ← 需要+1900 }; ``` ### 2. 参数类型匹配原则 使用`vsnprintf`时,格式说明符必须与参数类型严格对应: - `%d` → `int`类型(用于`tm_year`等成员) - `%02d` → 两位整数(用于时间补零) - 需要特别注意`tm_year`和`tm_mon`的数值转换: ```c tm_year + 1900 // 转换为实际年份 tm_mon + 1 // 转换为实际月份[1,12] ``` ### 3. 典型错误代码示例 ```c // 错误示例:缺少数值转换 sprintf(buffer, "Date:%d-%d", tm.tm_year, tm.tm_mon); // 输出错误值 // 正确示例 sprintf(buffer, "Date:%d-%02d", tm.tm_year + 1900, tm.tm_mon + 1); ``` ### 4. 在RT-Thread中的特别处理 在RT-Thread的日志系统中使用时间戳时,建议采用以下格式: ```c #include <sys/time.h> struct tm now; rt_uint32_t timestamp = time(RT_NULL); localtime_r(&timestamp, &now); rt_kprintf("[%04d-%02d-%02d %02d:%02d:%02d] log\n", now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec); ``` ### 5. 编译器参数检查 建议在编译时启用格式检查: ```makefile CFLAGS += -Wformat=2 # 开启GCC格式字符串检查 ``` 这将提示如下警告: ``` warning: format '%ld' expects argument of type 'long int', but argument 3 has type 'int' [-Wformat=] ``` ### 6. 类型强制转换(特殊场景) 若遇到跨平台数据类型差异(如某些架构的`time_t`为64位),可使用显式转换: ```c rt_uint32_t timestamp = (rt_uint32_t)time(RT_NULL); // 强制转换为32位无符号 ```
阅读全文

相关推荐

#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "PWM.h" #include "Servo.h" #include "stm32f10x.h" #include "Dht11.h" #include "Serial.h" #include "Timer.h" uint8_t temp = 0; uint8_t humi = 0; uint8_t ServoMode = 0; uint8_t ServoTime = 0; uint8_t TH_OVER1 = 10; uint8_t TH_OVER2 = 20; volatile uint8_t servo_update_flag = 0; // 新增全局标志位 volatile uint8_t DHT11_update_flag = 0; // 新增全局标志位 volatile uint8_t DHT11_update = 0; // 新增全局标志位 uint8_t temp_threshold = 25; uint8_t humi_threshold = 40; uint8_t servo_run_time; uint8_t Serial_RxFlag; uint8_t SetTime = 5; int main(void) { Timer_Init(); Servo_Init(); OLED_Init(); Serial_Init(); while(1) { if (Serial_RxFlag) { Serial_RxFlag = 0; AT_Command_Handler(); SetTime = servo_run_time; } if(DHT11_update) { if (DHT11_update) { DHT11_update = 0; uint8_t status = DHT11_Read_Data(&temp, &humi); if (status == 0) { // 阈值检查 int8_t temp_over = temp - temp_threshold; int8_t humi_over = humi - humi_threshold; int8_t max_over = 0; OLED_ShowString(3,1," "); OLED_ShowString(1,1,"temp:"); OLED_ShowString(2,1,"humi:"); OLED_ShowNum(1,6,temp,2); OLED_ShowNum(2,6,humi,3); OLED_ShowString(3,1,"t_line:"); OLED_ShowString(4,1,"h_line:"); OLED_ShowNum(3,8,temp_threshold,2); OLED_ShowNum(4,8,humi_threshold,2); OLED_ShowNum(3,11,ServoTime,2); OLED_ShowNum(4,11,SetTime,2); if (temp_over > 0) { Serial_Printf("Warning,temp over!\r\n"); } if (humi_over > 0) { Serial_Printf("Warning,humi over!\r\n"); } if (temp_over > 0 || humi_over > 0) { max_over = (temp_over > humi_over) ? temp_over : humi_over; if (max_over > TH_OVER2) ServoMode = 3; else if (max_over > TH_OVER1) ServoMode = 2; else ServoMode = 1; } else { ServoMode = 0; } } } } if(servo_update_flag) { servo_update_flag = 0; Servo_Control_

#include "dht11.h" void Delay_us(uint16_t delay) { __HAL_TIM_DISABLE(&htim3); __HAL_TIM_SET_COUNTER(&htim3,0); __HAL_TIM_ENABLE(&htim3); uint16_t curCnt=0; while(1) { curCnt=__HAL_TIM_GET_COUNTER(&htim3); if(curCnt>=delay) break; } __HAL_TIM_DISABLE(&htim3); } void DHT11_OUT(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_8; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } void DHT11_IN(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_8; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } void DHT11_Strat(void) { DHT11_OUT(); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET); HAL_Delay(20); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET); Delay_us(30); } uint8_t DHT11_Check(void) { uint8_t retry = 0 ; DHT11_IN(); while(GPIO_PIN_SET == HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8) && retry <100) { retry++; Delay_us(1);//1us } if(retry>=100) {return 1;} else retry = 0 ; while(GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8) && retry<100) { retry++; Delay_us(1);//1us } if(retry>=100) {return 1;} return 0 ; } uint8_t DHT11_Read_Bit(void) { uint8_t retry = 0 ; while(GPIO_PIN_SET==HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) && retry <100) { retry++; Delay_us(1); } retry = 0 ; while(GPIO_PIN_RESET==HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) && retry<100) { retry++; Delay_us(1); } Delay_us(40); if(GPIO_PIN_SET==HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8)) return 1; else return 0 ; } uint8_t DHT11_Read_Byte(void) { uint8_t i , dat ; dat = 0 ; for(i=0; i<8; i++) { dat <<= 1; dat |= DHT11_Read_Bit(); } return dat ; } uint8_t DHT11_Read_Data(uint8_t* temp , uint8_t* humi) { uint8_t buf[5]; uint8_t i; DHT11_Strat(); if(DHT11_Check() == 0) { for(i=0; i<5; i++) { buf[i] = DHT11_Read_Byte(); } if(buf[0]+buf[1]+buf[2]+buf[3] == buf[4]) { *humi = buf[0]; *temp = buf[2]; } }else return 1; return 0 ; } void func_1() { uint8_t temperature = 1 ; uint8_t humidity = 1; uint8_t aTXbuf[32] ; while(1){ DHT11_Read_Data(&temperature , &humidity); sprintf((char*)aTXbuf,"%d , %d %% \r\n" ,temperature ,humidity); HAL_UART_Transmit(&huart1, aTXbuf, strlen((const char*)aTXbuf), 200); HAL_Delay(5000); } } int temperature_humidity_device_control(protocol_package_t *pk) { printf("temperature_humidity_device_control\r\n"); if(pk->function == 0x16 && pk->data[0] == 0x00) { printf("temperature_humidity_device_control success\r\n"); uint8_t temperature = 1 ; uint8_t humidity = 1; uint8_t aTXbuf[32] ; //DHT11_Read_Data(&temperature , &humidity); pk->data[0] = 0x35; } return 0; }改错

你在网上搜索一下GXHTC3的温湿度芯片,请你帮忙改一下我现在要控制两个相同的GXHTC3芯片,请你帮忙看看要怎么做。#include "GXHTC3.h" #include "delay.h" float GXHTC3_Temperature = 0; float GXHTC3_Humidity = 0; #define write 0 #define read 1 float GXHTC3_temp,GXHTC3_humi,GXHTC3_Temperature,GXHTC3_Humidity; /* * @name CRC_8 * @brief CRC-8校验 * @param Crc_ptr -> 校验数据首地址 LEN -> 校验数据长度 * @retval CRC_Value -> 校验值 */ static uint8_t CRC_8(uint8_t *Crc_ptr,uint8_t LEN) { uint8_t CRC_Value = 0xFF; uint8_t i = 0,j = 0; for(i=0;i<LEN;i++) { CRC_Value ^= *(Crc_ptr+i); for(j=0;j<8;j++) { if(CRC_Value & 0x80) CRC_Value = (CRC_Value << 1) ^ 0x31; else CRC_Value = (CRC_Value << 1); } } return CRC_Value; } /**************************************************************************** * Function Name : GXHTC3_INIT * Description : 初始化GPIO. ****************************************************************************/ void GXHTC3_INIT() { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin = GXHTC3_SDA; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_Init(GPIOA,&GPIO_InitStructure); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin = GXHTC3_SCL; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_Init(GPIOA,&GPIO_InitStructure); GXHTC3_SCL_H; GXHTC3_SDA_H; } /******************************************************************************* * 函 数 名 : GXHTC3_SDA_OUT * 函数功能 : SDA输出配置 *******************************************************************************/ void GXHTC3_SDA_OUT() { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin=GXHTC3_SDA; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD; GPIO_Init(GPIOA,&GPIO_InitStructure); } /******************************************************************************* * 函 数 名 : GXHTC3_SDA_IN * 函数功能 : SDA输入配置 *******************************************************************************/ void GXHTC3_SDA_IN(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin=GXHTC3_SDA; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_OD; GPIO_Init(GPIOA,&GPIO_InitStructure); } void GXHTC3_SDA_in(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin=GXHTC3_SDA; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; GPIO_Init(GPIOA,&GPIO_InitStructure); } /******************************************************************************* * 函 数 名 : GXHTC3_StarT * 函数功能 : 产生起始信号 *******************************************************************************/ void GXHTC3_StarT(void) { GXHTC3_SDA_OUT(); GXHTC3_SDA_H; GXHTC3_SCL_H; delay_us(5); GXHTC3_SDA_L; delay_us(6); GXHTC3_SCL_L; } /******************************************************************************* * 函 数 名 : GXHTC3_StoP * 函数功能 : 产生停止信号 *******************************************************************************/ void GXHTC3_StoP(void) { GXHTC3_SDA_OUT(); GXHTC3_SCL_L; GXHTC3_SDA_L; GXHTC3_SCL_H; delay_us(6); GXHTC3_SDA_H; delay_us(6); } /******************************************************************************* * 函 数 名 : GXHTC3_Ack * 函数功能 : 主机产生应答信号ACK *******************************************************************************/ void GXHTC3_Ack(void) { GXHTC3_SCL_L; GXHTC3_SDA_OUT(); GXHTC3_SDA_L; delay_us(2); GXHTC3_SCL_H; delay_us(5); GXHTC3_SCL_L; } /******************************************************************************* * 函 数 名 : GXHTC3_NAck * 函数功能 : 主机不产生应答信号NACK *******************************************************************************/ void GXHTC3_NAck(void) { GXHTC3_SCL_L; GXHTC3_SDA_OUT(); GXHTC3_SDA_H; delay_us(2); GXHTC3_SCL_H; delay_us(5); GXHTC3_SCL_L; } /******************************************************************************* * 函 数 名 : GXHTC3_Wait_Ack * 函数功能 : 等待从机应答信号 返回值: 1 接收应答失败 0 接收应答成功 *******************************************************************************/ u8 GXHTC3_Wait_Ack(void) { u8 tempTime=0; GXHTC3_SDA_IN(); GXHTC3_SDA_H; delay_us(1); GXHTC3_SCL_H; delay_us(1); while(GPIO_ReadInputDataBit(GPIO_GXHTC3,GXHTC3_SDA)) { tempTime++; delay_us(1); if(tempTime>250) { GXHTC3_StoP(); return 1; } } GXHTC3_SCL_L; delay_us(1); return 0; } /******************************************************************************* * 函 数 名 : GXHTC3_Send_Byte * 函数功能 : GXHTC3 发送一个字节 *******************************************************************************/ void GXHTC3_Send_Byte(u8 txd) { u8 i=0; GXHTC3_SDA_OUT(); GXHTC3_SCL_L;//拉低时钟开始数据传输 for(i=0;i<8;i++) { if((txd&0x80)>0) //0x80 1000 0000 GXHTC3_SDA_H; else GXHTC3_SDA_L; txd<<=1; delay_us(1); GXHTC3_SCL_H; delay_us(2); //发送数据 GXHTC3_SCL_L; delay_us(2); } } /******************************************************************************* * 函 数 名 : GXHTC3_Read_Byte * 函数功能 : GXHTC3 主机读取一个字节 *******************************************************************************/ u8 GXHTC3_Read_Byte(u8 ack) { u8 i=0,receive=0; GXHTC3_SDA_in(); for(i=0;i<8;i++) { GXHTC3_SCL_L; delay_us(2); GXHTC3_SCL_H; while(!GPIO_ReadInputDataBit(GPIO_GXHTC3,GXHTC3_SCL)); receive<<=1; if(GPIO_ReadInputDataBit(GPIO_GXHTC3,GXHTC3_SDA)) receive++; delay_us(1); } if(ack==0) GXHTC3_NAck(); else GXHTC3_Ack(); return receive; } /******************************************************************************* * 函 数 名 : GXHTC3_read_result * 函数功能 : GXHTC3 读6个字节数据 *******************************************************************************/ void GXHTC3_read_result(u8 addr) { u16 tem,hum; unsigned char buff[6]; float Temperature=0; float Humidity=0; GXHTC3_StarT(); GXHTC3_Send_Byte(addr<<1 | write);//写7位GXHTC3设备地址加0作为写取位,1为读取位 GXHTC3_Wait_Ack(); GXHTC3_Send_Byte(0x78); GXHTC3_Wait_Ack(); GXHTC3_Send_Byte(0x66); GXHTC3_Wait_Ack(); GXHTC3_StoP(); delay_ms(15); //数据转换等待时间 GXHTC3_StarT(); GXHTC3_Send_Byte(addr<<1 | read);//写7位GXHTC3设备地址加0作为写取位,1为读取位 if(GXHTC3_Wait_Ack()==0) { GXHTC3_SDA_in(); buff[0]=GXHTC3_Read_Byte(1); buff[1]=GXHTC3_Read_Byte(1); buff[2]=GXHTC3_Read_Byte(1); buff[3]=GXHTC3_Read_Byte(1); buff[4]=GXHTC3_Read_Byte(1); buff[5]=GXHTC3_Read_Byte(0); GXHTC3_StoP(); if(CRC_8(buff, 2) == buff[2] && CRC_8(buff + 3, 2) == buff[5]) { tem = ((buff[0]<<8) | buff[1]);//温度拼接 hum = ((buff[3]<<8) | buff[4]);//湿度拼接 /*转换实际温度*/ Temperature= (175.0*(float)tem/65535.0-45.0) ;// T = -45 + 175 * tem / (2^16-1) Humidity= (100.0*(float)hum/65535.0);// RH = hum*100 / (2^16-1) } else { GXHTC3_temp = 0; GXHTC3_humi = 0; } } if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100))//过滤错误数据 { GXHTC3_temp = Temperature; GXHTC3_humi = Humidity; } tem = 0; hum = 0; } /******************************************************************************* * 函 数 名 : al_float_buffer_sort * 函数功能 : 多次读数值排序取中间值平均 *******************************************************************************/ void al_float_buffer_sort(float *buf, uint8_t length) { uint8_t i, j; float tmp; for (i = 0; i < length; i++) { for (j = i + 1; j < length; j++) { if (buf[j] < buf[i]) { tmp = buf[j]; buf[j] = buf[i]; buf[i] = tmp; } } } } void al_get_gxth30_temp(void) { float buff_temp[10], buff_humi[10]; // 采集10组数据 for(uint8_t i = 0; i < 10; i++) { GXHTC3_read_result(0x70); buff_temp[i] = GXHTC3_temp; buff_humi[i] = GXHTC3_humi; delay_ms(10); // 每次采集间隔10ms } // 数据排序(冒泡排序) al_float_buffer_sort(buff_temp, 10); al_float_buffer_sort(buff_humi, 10); // 取中间两个值求平均(抗干扰处理) GXHTC3_Temperature = (buff_temp[4] + buff_temp[5]) / 2; GXHTC3_Humidity = (buff_humi[4] + buff_humi[5]) / 2; }

现在单片机找不到体温传感器,我预测是通信发生了问题,请你根据我的代码,分析我遇到的问题并且提出解决方案,代码如下#include "AS6221.h" #include "main.h" extern I2C_HandleTypeDef hi2c1; /*************************************************************************************************************** AS6221 Read Command ****************************************************************************************************************/ void AS6221_ReadCommand(uint8_t reg_addr, uint8_t *rev_data, uint8_t length) { HAL_I2C_Mem_Read(&hi2c1, AS6221_I2CADDR << 0x01, reg_addr, 1, rev_data, length, 100); } /*************************************************************************************************************** AS6221 Write Command ****************************************************************************************************************/ void AS6221_WriteCommand(uint8_t reg_addr, uint8_t *send_data, uint16_t len) { HAL_I2C_Mem_Write(&hi2c1, AS6221_I2CADDR << 0x01, reg_addr, 1, send_data, len, 100); } /*************************************************************************************************************** Get Temperature ****************************************************************************************************************/ float AS6221_GetTemperature(void) { uint8_t char_temp[2]; int16_t int_temp = 0; float float_temp = 0.0; AS6221_ReadCommand(0x00, char_temp, 2); int_temp = char_temp[0] << 8 | char_temp[1]; if (int_temp < 0) float_temp = (float)int_temp * 0.0078125; if (int_temp >= 0) float_temp = (float)((int_temp - 1) * 0.0078125) * -1; return float_temp; } /*************************************************************************************************************** Get Low temperature threshold value ****************************************************************************************************************/ float AS6221_GetTLOW(void) { uint8_t char_temp[2]; int16_t int_temp = 0; float float_temp = 0.0; AS6221_ReadCommand(0x02, char_temp, 2); int_temp = char_temp[0] << 8 | char_temp[1]; if (int_temp < 32767) float_temp = (float)int_temp * 0.0078125; if (int_temp >= 32767) float_temp = (float)((int_temp - 1) * 0.0078125) * -1; return float_temp; } /*************************************************************************************************************** Set Low temperature threshold value ****************************************************************************************************************/ void AS6221_SetTLOW(int16_t TLow) { uint8_t char_temp[2] = {0}; char_temp[0] = ((int16_t)(TLow / 0.0078125) >> 8); char_temp[1] = (int16_t)(TLow / 0.0078125) & 0xff; AS6221_WriteCommand(0x02, char_temp, 2); } /*************************************************************************************************************** Get High temperature threshold value ****************************************************************************************************************/ float AS6221_GetTHIGH(void) { uint8_t char_temp[2]; int16_t int_temp = 0; float float_temp = 0.0; AS6221_ReadCommand(0x03, char_temp, 2); int_temp = char_temp[0] << 8 | char_temp[1]; if (int_temp < 32767) float_temp = (float)int_temp * 0.0078125; if (int_temp >= 32767) float_temp = (float)((int_temp - 1) * 0.0078125) * -1; return float_temp; } /*************************************************************************************************************** Set High temperature threshold value ****************************************************************************************************************/ void AS6221_SetTHIGH(int16_t THigh) { uint8_t char_temp[2] = {0}; char_temp[0] = ((int16_t)(THigh / 0.0078125) >> 8); char_temp[1] = (uint16_t)(THigh / 0.0078125) & 0xff; AS6221_WriteCommand(0x03, char_temp, 2); } /*************************************************************************************************************** Get AS6221 Config ****************************************************************************************************************/ uint16_t AS6221_GetConfig(void) { uint8_t char_config[2]; AS6221_ReadCommand(0x01, char_config, 2); return (uint16_t)char_config[0] << 8 | char_config[1]; } /*************************************************************************************************************** Set AS6221 Config ****************************************************************************************************************/ void AS6221_SetConfig(uint16_t config) { uint8_t char_config[2]; char_config[0] = config >> 8; char_config[1] = config & 0xff; AS6221_WriteCommand(0x01, char_config, 2); } /*************************************************************************************************************** AS6221 Init ****************************************************************************************************************/ bool AS6221_Init(void) { if (HAL_OK == HAL_I2C_IsDeviceReady(&hi2c1, AS6221_I2CADDR << 1, 3u, 10u)) return true; else return false; } #ifndef _AS6221_H_ #define _AS6221_H_ #include <stdint.h> #include <stdbool.h> #define AS6221_I2CADDR (0x48) bool AS6221_Init(void); float AS6221_GetTemperature(void); float AS6221_GetTLOW(void); void AS6221_SetTLOW(int16_t TLow); float AS6221_GetTHIGH(void); void AS6221_SetTHIGH(int16_t THigh); uint16_t AS6221_GetConfig(void); void AS6221_SetConfig(uint16_t config); #endif /* _AS6221_H_ */ #include "sys.h" #include "delay.h" #include "led.h" #include "uart1.h" #include "oled.h" #include "dht11.h" #include "adc.h" #include "beep.h" #include "AS6221.h" #include "stm32f1xx_hal.h" //extern const unsigned char shuai_data[]; void SystemClock_Config(void); I2C_HandleTypeDef hi2c1; int main(void) { float smoke_value = 0; float limit_value = 1.7; uint8_t dht11_data[5] = {0}; char temp_str[20] = {0}; char humi_str[20] = {0}; char smoke_str[16] = {0}; char as6221_temp_str[20] = {0}; // AS6221温度字符串 float as6221_temp = 0.0f; // AS6221温度值 HAL_Init(); /* ԵʼۯHALࠢ */ stm32_clock_init(RCC_PLL_MUL9); /* ʨ׃ʱד, 72Mhz */ led_init(); /* ԵʼۯLEDֆ */ uart1_init(115200); oled_init(); adc_dma_init(); beep_init(); if (!AS6221_Init()) { printf("AS6221!\r\n"); oled_show_string(0, 6, "AS6221 Init Fail", 12); HAL_Delay(2000); } else { printf("AS6221!\r\n"); } printf("hello world!\r\n"); //oled_fill(0x00); //oled_write_cmd(0xB0); //oled_write_cmd(0x00); // oled_write_cmd(0x10); //oled_write_data(0x80); // oled_write_data(0x80); // oled_write_data(0x80); // oled_write_data(0x80); // oled_write_data(0x80); // oled_write_data(0x80); // oled_write_data(0x80); // oled_write_data(0x80); // oled_write_data(0x80); // oled_set_cursor(0, 0); // oled_write_data(0x00); // oled_write_data(0x00); // oled_write_data(0xC0); // oled_write_data(0x38); // oled_write_data(0xE0); // oled_write_data(0x00); // oled_write_data(0x00); // oled_write_data(0x00); // // oled_set_cursor(0, 1); // oled_write_data(0x20); // oled_write_data(0x3C); // oled_write_data(0x23); // oled_write_data(0x02); // oled_write_data(0x02); // oled_write_data(0x27); // oled_write_data(0x38); // oled_write_data(0x20); // oled_show_char(0, 0, 'L', 24); // oled_show_char(12, 0, 'X', 24); // oled_show_char(16, 0, '?', 16); // oled_show_char(24, 0, '6', 16); //oled_show_string(0, 0, "humi", 16); //oled_show_string(0,2,"temp",16); oled_show_string(0, 1, "Temp:--.-",12); oled_show_string(60, 1, "Humi:--.-",12); oled_show_string(0, 4, "rTemp: --.- C",12); oled_show_string(0, 6, "Smoke: 0.0 V",12); // uint8_t i; // for(i = 0; i < 5; i++) // oled_show_chinese(i*24, 0, i, 24); // oled_show_image(0, 0, 128, 8, (unsigned char *)shuai_data); while(1) { smoke_value = adc_get_smoke(); sprintf(smoke_str, "Smoke: %.2f V", smoke_value); oled_show_string(0, 6, smoke_str, 12); if(smoke_value > limit_value) { beep_on(); } else { beep_off(); } dht11_read(dht11_data); /* 解析温度和湿度数据 */ uint8_t humidity = dht11_data[0]; /* 湿度整数部分 */ uint8_t temperature = dht11_data[2]; /* 温度整数部分 */ /* 格式化显示字符串 */ sprintf(temp_str, "Temp:%d C", temperature); sprintf(humi_str, "Humi:%d %%", humidity); /* 在OLED上显示 */ oled_show_string(0, 1, temp_str, 12); /* 显示温度 */ oled_show_string(60, 1, humi_str, 12); /* 显示湿度 */ as6221_temp = AS6221_GetTemperature(); sprintf(as6221_temp_str, "rTemp: %.1f C", as6221_temp); oled_show_string(0, 4, as6221_temp_str, 12); HAL_Delay(2000); /* 延时2秒,DHT11采样周期至少1秒 */ } // 读取DHT11数据 //dht11_read(dht11_result); // 格式化温湿度数据为字符串 //sprintf(temp_str, "Temp: %.1f C", ((float)((dht11_result[2] & 0x7F) << 8 | dht11_result[3])) / 10); //sprintf(humi_str, "Humi: %.1f %%", ((float)(dht11_result[0] << 8 | dht11_result[1])) / 10); // 显示温湿度数据 // oled_show_string(0, 2, temp_str, 16); // oled_show_string(0, 4, humi_str, 16); // 显示更新时间提示 // oled_show_string(0, 6, "Update: 2s interval", 12); // HAL_Delay(2000); // 2秒更新一次 }

/** ****************************************************************************** * @file main.c * @author fire * @version V1.0 * @date 2025-05-20 * @brief DHT11温湿度+实时时钟显示实验(智能刷新版) ****************************************************************************** */ #include "stm32f10x.h" #include "./systick/bsp_SysTick.h" #include "./dht11/bsp_dht11.h" #include "./usart/bsp_usart.h" #include "./lcd/bsp_ili9341_lcd.h" #include "./Timbase/bsp_TiMbase.h" #include "./Key/bsp_key.h" #include "./Led/bsp_led.h" /* 全局时间变量 */ volatile uint8_t hours = 9, minutes = 7, seconds = 0; volatile uint8_t time_update_flag = 0; /* 保存上一次的温湿度值 */ static uint8_t last_temp_int = 0xFF, last_humi_int = 0xFF; static uint8_t last_temp_deci = 0xFF, last_humi_deci = 0xFF; /* 函数声明 */ static void Show_Time_On_LCD(void); void TIM6_IRQHandler(void); /********************** 硬件初始化区域 **********************/ /** * @brief 定时器6中断服务程序(用于时钟计时) */ void TIM6_IRQHandler(void) { if (TIM_GetITStatus(BASIC_TIM, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(BASIC_TIM, TIM_IT_Update); /* 时间递增逻辑 */ if (++seconds == 60) { seconds = 0; if (++minutes == 60) { minutes = 0; if (++hours == 24) hours = 0; } } time_update_flag = 1; // 设置更新标志 } } int main(void) { char dispBuff[100]; DHT11_Data_TypeDef DHT11_Data; /* 外设初始化 */ Key_GPIO_Config();//按键端口初始化 SysTick_Init(); ILI9341_Init(); ILI9341_GramScan(6); DHT11_Init(); BASIC_TIM_Init(); // 初始化基础定时器(TIM6) /* 启用定时器中断 */ TIM_ITConfig(BASIC_TIM, TIM_IT_Update, ENABLE); /* 初始化显示 */ ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH); Show_Time_On_LCD(); // 初始时间显示 while(1) { /* 温湿度检测 */ if(DHT11_Read_TempAndHumidity(&DHT11_Data) == SUCCESS) { /* 仅在数据变化时更新显示 */ if(DHT11_Data.temp_int != last_temp_int || DHT11_Data.temp_deci != last_temp_deci || DHT11_Data.humi_int != last_humi_int || DHT11_Data.humi_deci != last_humi_deci) { /* 更新温度显示(不整行清除) */ sprintf(dispBuff,"Temperature: %d.%dC", DHT11_Data.temp_int, DHT11_Data.temp_deci); ILI9341_DispStringLine_EN(LINE(3), dispBuff); // 直接覆盖写入 /* 更新湿度显示(不整行清除) */ sprintf(dispBuff,"Humidity: %d.%d%%", DHT11_Data.humi_int, DHT11_Data.humi_deci); ILI9341_DispStringLine_EN(LINE(4), dispBuff); // 直接覆盖写入 /* 更新最后记录值 */ last_temp_int = DHT11_Data.temp_int; last_temp_deci = DHT11_Data.temp_deci; last_humi_int = DHT11_Data.humi_int; last_humi_deci = DHT11_Data.humi_deci; } } else { /* 错误处理(仅在状态变化时刷新) */ static uint8_t error_flag = 0; if(!error_flag) // 避免重复打印错误信息 { ILI9341_DispStringLine_EN(LINE(3),"Temp/Humi ERROR"); LCD_ClearLine(LINE(4)); error_flag = 1; } } /* 时间更新显示(始终刷新) */ if(time_update_flag) { time_update_flag = 0; Show_Time_On_LCD(); } Delay_ms(1000); // 调整刷新间隔为1秒(匹配DHT11特性) } } /********************** 辅助功能实现 **********************/ /** * @brief 在LCD上显示当前时间(HH:MM:SS) */ static void Show_Time_On_LCD(void) { char time_str[9]; sprintf(time_str, "%02d:%02d:%02d", hours, minutes, seconds); // 强制刷新时间显示(覆盖写入) ILI9341_DispStringLine_EN(LINE(0),"YH Smart Watch"); ILI9341_DispStringLine_EN(LINE(1),"Time:"); ILI9341_DispStringLine_EN(LINE(2),time_str); // 保持温湿度显示位置(不清除,依赖智能刷新) } /*********************************************END OF FILE**********************/ /** ****************************************************************************** * @file main.c * @author fire * @version V1.0 * @date 2025-05-20 * @brief 串口指令控制实验(LED/蜂鸣器/时钟/温湿度) * * 功能列表: * 1. LED灯控制(开/关) * 2. 蜂鸣器控制(开/关) * 3. 实时时钟显示(HH:MM:SS) * 4. DHT11温湿度检测 ****************************************************************************** */ #include "stm32f10x.h" #include "./led/bsp_led.h" #include "./usart/bsp_usart.h" #include "./beep/bsp_beep.h" #include "./Timbase/bsp_TiMbase.h" #include "./key/bsp_exti.h" #include "./systick/bsp_SysTick.h" #include "./dht11/bsp_dht11.h" #include "stm32f10x_tim.h" // 定时器外设 #include "stm32f10x_rcc.h" // 时钟控制 /* 全局时间变量 */ volatile uint8_t hours = 9, minutes = 7, seconds = 0; volatile uint8_t time_update_flag = 0; // 时间更新标志 volatile uint8_t alarm_hours = 10, alarm_minutes = 03; volatile uint8_t alarm_enabled = 0; volatile uint8_t alarm_triggered = 0; volatile uint32_t alarm_duration = 10; // 闹钟持续时间(秒) volatile uint32_t alarm_start_time = 0; #define TEMP_ALERT_THRESHOLD 35 #define HUMI_ALERT_THRESHOLD 45 volatile uint8_t temp_alert_enabled = 1; volatile uint8_t humi_alert_enabled = 1; /* 函数声明 */ static void Show_Message(void); void Send_Time_To_UART(void); void Update_Time(void); // 保留声明但未实现(可根据需要补充) void Check_Alarms(void); void Check_TempHumi_Alerts(DHT11_Data_TypeDef *data); void Handle_Alarm(void); /********************** 硬件初始化区域 **********************/ /** * @brief 定时器6中断服务程序(用于时钟计时) */ void TIM6_IRQHandler(void) { if (TIM_GetITStatus(BASIC_TIM, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(BASIC_TIM, TIM_IT_Update); // 时间递增逻辑 if (++seconds == 60) { seconds = 0; if (++minutes == 60) { minutes = 0; if (++hours == 24) hours = 0; } } time_update_flag = 1; // 设置更新标志 Check_Alarms(); } } /********************** 主函数入口 **********************/ int main(void) { char ch; DHT11_Data_TypeDef DHT11_Data; /* 外设初始化(按功能分组) */ LED_GPIO_Config(); // LED初始化 BEEP_GPIO_Config(); // 蜂鸣器初始化 EXTI_Key_Config(); // 按键中断初始化 USART_Config(); // 串口初始化(115200 8-N-1) BASIC_TIM_Init(); // 基础定时器初始化(TIM6) SysTick_Init(); // 系统滴答定时器初始化 DHT11_Init(); // 温湿度传感器初始化 // 启用定时器中断(确保NVIC配置已完成) TIM_ITConfig(BASIC_TIM, TIM_IT_Update, ENABLE); /* 显示操作提示 */ Show_Message(); while(1) { Handle_Alarm(); /* 串口指令接收 */ if(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) != RESET) { ch = USART_ReceiveData(DEBUG_USARTx); printf("接收到字符:%c\n", ch); /* 指令处理 */ switch(ch) { case '1': // LED控制 LED_RED; break; case '2': LED_RGBOFF; break; case '3': // 蜂鸣器控制 BEEP(BEEP_ON); break; case '4': BEEP(BEEP_OFF); break; case '5': // 时间显示 if (time_update_flag) { time_update_flag = 0; Send_Time_To_UART(); } break; case '6': // 温湿度检测 if(DHT11_Read_TempAndHumidity(&DHT11_Data) == SUCCESS) { printf("\r\n读取DHT11成功!\r\n"); printf("湿度:%d.%d %%RH 温度:%d.%d ℃\r\n", DHT11_Data.humi_int, DHT11_Data.humi_deci, DHT11_Data.temp_int, DHT11_Data.temp_deci); // 检查温湿度警报 Check_TempHumi_Alerts(&DHT11_Data); } else { printf("DHT11读取失败!\r\n"); } Delay_ms(2000); break; case '7': // 设置闹钟时间 (格式: HHMM) { // 变量声明 char time_str[5] = {0}; uint8_t i = 0; uint8_t new_hours = 0; uint8_t new_minutes = 0; printf("请输入闹钟时间(HHMM,24小时制): "); // 等待接收4位数字 while(i < 4) { if(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) != RESET) { char c = USART_ReceiveData(DEBUG_USARTx); if(c >= '0' && c <= '9') { time_str[i++] = c; printf("%c", c); // 回显输入的数字 } } } printf("\r\n"); // 解析输入的时间 new_hours = (time_str[0] - '0') * 10 + (time_str[1] - '0'); new_minutes = (time_str[2] - '0') * 10 + (time_str[3] - '0'); // 验证时间有效性 if(new_hours < 24 && new_minutes < 60) { alarm_hours = new_hours; alarm_minutes = new_minutes; alarm_enabled = 1; // 设置后自动启用闹钟 printf("闹钟已设置为: %02d:%02d\r\n", alarm_hours, alarm_minutes); } else { printf("错误: 无效的时间格式!\r\n"); } break; } case '8': //关闭/开启闹钟 alarm_enabled = !alarm_enabled; if(alarm_enabled) { printf("闹钟已开启\r\n"); } else { printf("闹钟已关闭\r\n"); // 如果闹钟正在响,关闭它 if(alarm_triggered) { BEEP(BEEP_OFF); LED_RGBOFF; alarm_triggered = 0; } } break; case '9': // 关闭/开启警报 temp_alert_enabled = !temp_alert_enabled; printf("温度警报已%s\r\n", temp_alert_enabled ? "开启" : "关闭"); break; case '0': // 关闭/开启警报 humi_alert_enabled = !humi_alert_enabled; printf("湿度警报已%s\r\n", humi_alert_enabled ? "开启" : "关闭"); break; case 'a': // 关闭闹钟 (新增功能) if(alarm_triggered) { BEEP(BEEP_OFF); LED_RGBOFF; alarm_triggered = 0; printf("闹钟已关闭\r\n"); } else { printf("当前没有响铃的闹钟\r\n"); } break; default: // 无效指令提示 Show_Message(); break; } } } } /********************** 辅助功能实现 **********************/ /** * @brief 显示操作提示信息 */ static void Show_Message(void) { printf("\r\n=== STM32智能手环实验 ===\r\n"); printf("USART配置:%d 8-N-1\r\n", DEBUG_USART_BAUDRATE); printf("指令列表:\r\n"); printf("1 - 打开LED\r\n"); printf("2 - 关闭LED\r\n"); printf("3 - 打开蜂鸣器\r\n"); printf("4 - 关闭蜂鸣器\r\n"); printf("5 - 显示当前时间\r\n"); printf("6 - 显示温湿度\r\n"); printf("7 - 设置闹钟时间(HHMM)\r\n"); printf("8 - 开启/关闭闹钟\r\n"); printf("9 - 开启/关闭温度警报\r\n"); printf("0 - 开启/关闭湿度警报\r\n"); printf("a - 关闭正在响铃的闹钟\r\n"); } /** * @brief 发送时间到串口(HH:MM:SS格式) */ void Send_Time_To_UART(void) { char time_str[9]; sprintf(time_str, "%02d:%02d:%02d\r\n", hours, minutes, seconds); Usart_SendString(DEBUG_USARTx, time_str); } void Check_Alarms(void) { // 只有当闹钟启用且未触发时才检查 if (alarm_enabled && !alarm_triggered) { // 检查是否到达闹钟时间 if (hours == alarm_hours && minutes == alarm_minutes && seconds == 0) { alarm_triggered = 1; alarm_start_time = seconds; // 记录开始时间 printf("闹钟时间到! %02d:%02d\r\n", alarm_hours, alarm_minutes); } } } void Handle_Alarm(void) { if (alarm_triggered) { // 闹钟持续响铃 BEEP(BEEP_ON); LED_RED; // LED闪烁效果 // 检查是否超过闹钟持续时间 if ((seconds - alarm_start_time) >= alarm_duration) { BEEP(BEEP_OFF); LED_RGBOFF; alarm_triggered = 0; printf("闹钟自动关闭\r\n"); } } } void Check_TempHumi_Alerts(DHT11_Data_TypeDef *data) { uint8_t alert_triggered = 0; // 检查温度警报 if (temp_alert_enabled && data->temp_int >= TEMP_ALERT_THRESHOLD) { if (!alert_triggered) { printf("温度警报! 当前温度: %d.%d ℃\r\n", data->temp_int, data->temp_deci); alert_triggered = 1; } BEEP(BEEP_ON); // 触发警报 } // 检查湿度警报 if (humi_alert_enabled && data->humi_int >= HUMI_ALERT_THRESHOLD) { if (!alert_triggered) { printf("湿度警报! 当前湿度: %d.%d %%RH\r\n", data->humi_int, data->humi_deci); alert_triggered = 1; } BEEP(BEEP_ON); // 触发警报 } // 如果没有警报,关闭蜂鸣器 if (!alert_triggered) { BEEP(BEEP_OFF); } } 将两个代码整理到一个代码里,不要删减以前的内容,同时包含串口和LCD的功能

#include "stm32f10x.h" #include "DELAY.H" #include "OLED.H" #include "LED.H" #include "SERIAL.H" #include "DHT11.H" #include "string.h" #include "adc.h" #include "Key.h" #include "NMOS.h" #include "DeviceControl.h" #include <stdint.h> #include <stdio.h> #define USERNAME "test1&a1nf8DUjYs0" //用户名 #define PASSWORD "cf60b82b0590c08947dff8085094da1d8df5eabdd56c981be2fb82bbc1f91006" //密码 #define CLIENTID "a1nf8DUjYs0.test1|securemode=2\\,signmethod=hmacsha256\\,timestamp=1738827903310|" //设备名称 #define PRODUCTID "a1nf8DUjYs0" //产品ID #define DOMAINNAME "a1nf8DUjYs0.iot-as-mqtt.cn-shanghai.aliyuncs.com" //域名 #define DEVICENAME "test1" // 全局变量 int Humi_Min = 30; int Humi_Max = 40; int S_H_Min = 30; int S_H_Max = 40; uint8_t selectedOption = 0; // 0: Humi_Min, 1: Humi_Max, 2: S_H_Min, 3: S_H_Max uint8_t currentPage = 1; // 1: Page1, 2: Page2 uint8_t wifiConnected = 0; // WiFi 连接状态标志位 uint8_t cloudControlEnabled = 0; // 标志位:是否正在执行阿里云下发的命令 int8_t temperature = 0; // 全局变量:温度 uint8_t humidity = 0; // 全局变量:湿度 uint8_t soilHumi = 0; // 全局变量:土壤湿度 void DisplayRealTimeData(void); // 显示第一页内容 void ShowPage1(void) { OLED_Clear(); // 初始化显示内容 OLED_ShowCC_F16x16(1, 1, 2); // 温 OLED_ShowCC_F16x16(1, 3, 4); // 度 OLED_ShowChar(1, 5, ':'); OLED_ShowCC_F16x16(1, 14, 0); // ℃ OLED_ShowCC_F16x16(2, 1, 3); // 湿 OLED_ShowCC_F16x16(2, 3, 4); // 度 OLED_ShowChar(2, 5, ':'); OLED_ShowCC_F16x16(2, 14, 1); // % OLED_ShowCC_F16x16(3, 1, 5); // 土 OLED_ShowCC_F16x16(3, 3, 6); // 壤 OLED_ShowCC_F16x16(3, 5, 3); // 湿 OLED_ShowCC_F16x16(3, 7, 4); // 度 OLED_ShowChar(3, 9, ':'); OLED_ShowCC_F16x16(3, 14, 1); // % OLED_ShowString(4, 1, "WIFI_STA:"); // 显示WiFi连接状态 // 如果 WiFi 已连接,显示 "ok" if (wifiConnected) { OLED_ShowString(4, 12, "ok"); } // 显示实时数据 DisplayRealTimeData(); // 调用函数显示温湿度和土壤湿度 } // 显示第二页内容 void ShowPage2(void) { OLED_Clear(); // 显示 HUN_min

#include "stm32f10x.h" // Device header #include <stdio.h> #include <stdarg.h> #include <string.h> // 新增字符串处理头文件 #include "Dht11.h" #include "Servo.h" //char Serial_RxPacket[100]; //定义接收数据包数组,数据包格式"@MSG\r\n" //uint8_t Serial_RxFlag; //定义接收数据包标志位 // 修改后的AT指令缓冲区定义 #define AT_CMD_MAX_LEN 64 char Serial_RxPacket[AT_CMD_MAX_LEN]; // AT指令缓冲区 uint8_t Serial_RxFlag = 0; // 接收完成标志 // 新增全局变量(阈值和舵机控制) int temp_high = 30, temp_low = 20; int humi_high = 60, humi_low = 40; uint32_t servo_active_time = 0; uint32_t servo_active_counter = 0; // 舵机运行时间计数器 uint8_t threshold_check_flag = 0; // 阈值检测触发标志 /** * 函 数:串口初始化 * 参 数:无 * 返 回 值:无 */ void Serial_Init(void) { /*开启时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //开启USART1的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟 /*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA9引脚初始化为复用推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA10引脚初始化为上拉输入 /*USART初始化*/ USART_InitTypeDef USART_InitStructure; //定义结构体变量 USART_InitStructure.USART_BaudRate = 9600; //波特率 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制,不需要 USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //模式,发送模式和接收模式均选择 USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶校验,不需要 USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位,选择1位 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长,选择8位 USART_Init(USART1, &USART_InitStructure); //将结构体变量交给USART_Init,配置USART1 /*中断输出配置*/ USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启串口接收数据的中断 /*NVIC中断

重新生成,注意使用的是标准库,结合主函数int main(void) { /*模块初始化*/ OLED_Init(); //OLED初始化 LightSensor_Init(); //光敏传感器初始化 DHT11_Init(); //DHT11初始化 //USART2_Init(115200);//初始化串口 int light; uint8_t temp = 0; uint8_t humi = 0; char temp_str[10] = {0}; char humi_str[10] = {0}; char lux_str[10] = {0}; // 新增光照强度字符串 DHT11_Init();//再次初始化DHT11 while (1) { // 读取温湿度 DHT11_Read_Data(&temp, &humi); sprintf(temp_str, "Temp:%d C", temp); sprintf(humi_str, "Humi:%d %RH", humi); OLED_ShowString(2, 1, temp_str); OLED_ShowString(3, 1, humi_str); // 读取光照强度并显示 float lux = LightSensor_GetLux(); sprintf(lux_str, "Lux:%.1f", lux); OLED_ShowString(1, 1, lux_str); Delay_s(1); // 1. 配置ESP8266为STA模式 ESP8266_SendCmd("AT+CWMODE=1\r\n"); // 2. 连接Wi-Fi ESP8266_SendCmd("AT+CWJAP=\"t-Magic\",\"zhw890000\"\r\n"); // 3. 配置MQTT参数 ESP8266_SendCmd("AT+MQTTUSERCFG=0,1,\"67ceedd88e04aa0690bc1fe3_000001_0_1_2025031206\",\"67ceedd88e04aa0690bc1fe3_000001\",\"f674952c905f16e8cb83ff7e40f11a041220391d6bca3098ba41e76b1878d2cb\",0,0,\"\"\r\n"); // 4. 连接华为云MQTT服务器 ESP8266_SendCmd("AT+MQTTCONN=0,\"529d6c98f1.st1.iotda-device.cn-north-4.myhuaweicloud.com\",1883,1\r\n"); // 5. 订阅主题(例如属性上报) ESP8266_SendCmd("AT+MQTTSUB=0,\"$oc/devices/deviceId/sys/properties/report\",1\r\n"); sprintf(temp_str, "{\"services\":[{\"agriculture\":\"basic\",\"properties\":{\"temperature\":25}}]}"); ESP8266_SendCmd("AT+MQTTPUB=0,\"$oc/devices/67ceedd88e04aa0690bc1fe3_000001/sys/properties/report\",\"%s\",1,0\r\n", temp_str); Delay_ms(5); } }

/*************************************************** This is a library for the SHT31 Digital Humidity & Temp Sensor Designed specifically to work with the SHT31 Digital sensor from Adafruit ----> https://www.adafruit.com/products/2857 These displays use I2C to communicate, 2 pins are required to interface Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Limor Fried/Ladyada for Adafruit Industries. BSD license, all text above must be included in any redistribution ****************************************************/ #include "Adafruit_SHT31.h" Adafruit_SHT31::Adafruit_SHT31() { } boolean Adafruit_SHT31::begin(uint8_t i2caddr) { Wire.begin(); _i2caddr = i2caddr; reset(); //return (readStatus() == 0x40); return true; } uint16_t Adafruit_SHT31::readStatus(void) { writeCommand(SHT31_READSTATUS); Wire.requestFrom(_i2caddr, (uint8_t)3); uint16_t stat = Wire.read(); stat <<= 8; stat |= Wire.read(); //Serial.println(stat, HEX); return stat; } void Adafruit_SHT31::reset(void) { writeCommand(SHT31_SOFTRESET); delay(10); } void Adafruit_SHT31::heater(boolean h) { if (h) writeCommand(SHT31_HEATEREN); else writeCommand(SHT31_HEATERDIS); } float Adafruit_SHT31::readTemperature(void) { if (! readTempHum()) return NAN; return temp; } float Adafruit_SHT31::readHumidity(void) { if (! readTempHum()) return NAN; return humidity; } boolean Adafruit_SHT31::readTempHum(void) { uint8_t readbuffer[6]; writeCommand(SHT31_MEAS_HIGHREP); delay(500); Wire.requestFrom(_i2caddr, (uint8_t)6); if (Wire.available() != 6) return false; for (uint8_t i=0; i<6; i++) { readbuffer[i] = Wire.read(); // Serial.print("0x"); Serial.println(readbuffer[i], HEX); } uint16_t ST, SRH; ST = readbuffer[0]; ST <<= 8; ST |= readbuffer[1]; if (readbuffer[2] != crc8(readbuffer, 2)) return false; SRH = readbuffer[3]; SRH <<= 8; SRH |= readbuffer[4]; if (readbuffer[5] != crc8(readbuffer+3, 2)) return false; // Serial.print("ST = "); Serial.println(ST); double stemp = ST; stemp *= 175; stemp /= 0xffff; stemp = -45 + stemp; temp = stemp; // Serial.print("SRH = "); Serial.println(SRH); double shum = SRH; shum *= 100; shum /= 0xFFFF; humidity = shum; return true; } void Adafruit_SHT31::writeCommand(uint16_t cmd) { Wire.beginTransmission(_i2caddr); Wire.write(cmd >> 8); Wire.write(cmd & 0xFF); Wire.endTransmission(); } uint8_t Adafruit_SHT31::crc8(const uint8_t *data, int len) { /* * * CRC-8 formula from page 14 of SHT spec pdf * * Test data 0xBE, 0xEF should yield 0x92 * * Initialization data 0xFF * Polynomial 0x31 (x8 + x5 +x4 +1) * Final XOR 0x00 */ const uint8_t POLYNOMIAL(0x31); uint8_t crc(0xFF); for ( int j = len; j; --j ) { crc ^= *data++; for ( int i = 8; i; --i ) { crc = ( crc & 0x80 ) ? (crc << 1) ^ POLYNOMIAL : (crc << 1); } } return crc; } /*********************************************************************/解释代码并将其用HAL库重写

完成一个仓储环境监测的模拟系统。具体要求如下: 1. DHT11模块完成温湿度测量,5s更新,数值显示于数码管,同时打印到串口。温度超过阈值触发蜂鸣器短鸣,同时启动风扇小马达; 2. LDR模块完成环境照度测量,4s更新,数值显示于数码管,同时打印到串口。照度超过阈值启动PWM调光(高、中、低三级调光)。 3. 按键循环切换显示模式,按第1下固定显示温度,按第二下固定显示照度,按第三下恢复默认的自动显示模式。按键用外部中断实现 int main(void) { systick_init(72); led_init(); usart1_init(115200); display_init(); tim4_init(1000,72); // 1ms的定时间隔 TIM3_CH2_PWM_Init(500-1,72-1); dht11_init(); ldr_init(); //key_init(); while(1) { // 轮询DHT11的状态 if(dht11.state == WORK) { if(dht11.getData(&dht11.temp, &dht11.humi) == SUCCESS) // DHT11温湿度数据更新 { printf("temperature:%d℃ humidity(RH):%d \r\n", dht11.temp, dht11.humi); dsp.interface = TEMP; dht11.onTempChange(dht11.temp_threshold); // 温度超过阈值的处理 } dht11.state = STANDBY; } // 轮询LDR的状态 if(ldr.state == WORK) { ldr.light = ldr.getData(); printf("light intensity:%d \r\n", ldr.light); dsp.interface = LIGHT; ldr.onLightChange(ldr.high_threshold,ldr.low_threshold); // 照度超过阈值的处理 ldr.state = STANDBY; } // 轮询数码管界面状态 switch(dsp.interface) { case LIGHT: setLightValue(&dsp,1); break; case TEMP: setTempValue(&dsp,1); break; case HUMI: setHumiValue(&dsp,1); break; default: break; } } }#include "systick.h" static u8 fac_us=0; //us延时倍乘数 static u16 fac_ms=0; //ms延时倍乘数 //初始化延迟函数 //SYSTICK的时钟固定为AHB时钟的1/8 //SYSCLK:系统时钟频率 void systick_init(u8 SYSCLK) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); fac_us = SYSCLK/8; fac_ms = (u16)fac_us * 1000; } //延时nus //nus为要延时的us数. void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nus*fac_us; //时间加载 SysTick->VAL=0x00; //清空计数器 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick->VAL =0X00; //清空计数器 } //延时nms //注意nms的范围 //SysTick->LOAD为24位寄存器,所以,最大延时为: //nms<=0xffffff*8*1000/SYSCLK //SYSCLK单位为Hz,nms单位为ms //对72M条件下,nms<=1864 void delay_ms(u16 nms) { u32 temp; SysTick->LOAD = (u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit) SysTick->VAL = 0x00; //清空计数器 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick->CTRL; } while((temp&0x01) && !(temp&(1<<16))); //等待时间到达 SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick->VAL = 0x00; //清空计数器 } #include "display.h" DisplayStruct dsp; void segDisplay(void); // 共阴极数码管,阴极位选(0有效),阳极段选(1有效) const u16 segCode[11] = { /* 0 1 2 3 4 5 6 7 */ 0x003F, 0x0006, 0x005B, 0x004F, 0x0066, 0x006D, 0x007D, 0x0007, /* 8 9 off */ 0x007F, 0x006F, 0x0000 }; /******************************************************************************* * @brief 初始化数码管用到的GPIO端口和dsp结构体 * @param None * @retval None *******************************************************************************/ void display_init(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE); // PA0~PA7: 段选(分别连接引脚A~G); // PB12~PB15:位选(分别连接引脚D1~D4) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); dsp.currDigit = 1; // dsp结构体的初始化 dsp.SegDisplay = segDisplay; } /*********************************************************************************** * @brief 设置数码管要显示的4位数值。 * @param dsp:数码管结构体指针;value[4]:4位数值;dotBit:小数点位置(没有小数点则置0) * @retval None ***********************************************************************************/ void setValue(DisplayStruct *dsp, u8 value[4], u8 dotBit) { dsp->digit[0] = value[0]; dsp->digit[1] = value[1]; dsp->digit[2] = value[2]; dsp->digit[3] = value[3]; dsp->dotDigit = dotBit; } void setLightValue(DisplayStruct *dsp, u8 dotBit) { dsp->digit[0] = 1; // 参数编号 dsp->digit[1] = 10; // 第二位空缺 dsp->digit[2] = ldr.light/10; dsp->digit[3] = ldr.light%10; // dsp->dotDigit = dotBit; // 小数点位置 } void setTempValue(DisplayStruct *dsp, u8 dotBit) { dsp->digit[0] = 2; dsp->digit[1] = 10; dsp->digit[2] = dht11.temp/10; dsp->digit[3] = dht11.temp%10; dsp->dotDigit = dotBit; } void setHumiValue(DisplayStruct *dsp, u8 dotBit) { dsp->digit[0] = 3; dsp->digit[1] = 10; dsp->digit[2] = dht11.humi/10; dsp->digit[3] = dht11.humi%10; dsp->dotDigit = dotBit; } /******************************************************************************* * @简 介 段选,让某一位数码管显示指定的数字 * @输入参数 value:段码数组的序号(0~9),代表要显示的数字 * @retval * 备注:只操作PA的低8位,不要影响高8位。 ********************************************************************************/ void seg(uint8_t value) { if(value < sizeof(segCode)) // 避免数组溢出 { GPIOA->ODR &= 0xFF00; GPIOA->ODR |= segCode[value]; } } /******************************************************************************** * 简 介 位选,一次只能选一位。 * 输入参数 com:位数(取值1~4,从左到右) * 返回值 无 * 备注:只操作PB的高4位(置0),不要影响其他位。 ********************************************************************************/ void com(uint8_t currDigit) { // 数码管位选(0有效) GPIOB->ODR |= 0xF000; GPIOB->ODR &= ~(0x1000<<(currDigit-1)); } /******************************************************************************** * 简介 在数码管上逐位显示其段码(由Timer中断服务函数调用) * 参数 无 * 返回值 无 ********************************************************************************/ void segDisplay(void) { seg(10); // 消隐之前的显示内容 com(dsp.currDigit); // 位选,从COM1到COM4逐次移位,实现动态显示 if(dsp.currDigit != dsp.dotDigit) // 当前位不显示小数点 seg(dsp.digit[dsp.currDigit-1]); else // 当前位要显示小数点 { GPIO_Write(GPIOA, segCode[dsp.digit[dsp.currDigit-1]]| 0x0080); //GPIOA->ODR &= 0xFF00; //GPIOA->ODR |= (segCode[dsp.currDigit-1]|0x0080); } if(++dsp.currDigit > DSP_DIGIT) // 从当前位右移到下一位 dsp.currDigit = 1; } #include "usart.h" int fputc(int ch,FILE *p) //函数默认的,在使用printf函数时自动调用 { USART_SendData(USART1,(u8)ch); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); return ch; } //串口1中断服务程序 //注意,读取USARTx->SR能避免莫名其妙的错误 u8 USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节. //接收状态 //bit15, 接收完成标志 //bit14, 接收到0x0d //bit13~0, 接收到的有效字节数目 u16 USART1_RX_STA=0; //接收状态标记 /******************************************************************************* * 函 数 名 : USART1_Init * 函数功能 : USART1初始化函数 * 输 入 : bound:波特率 * 输 出 : 无 *******************************************************************************/ void usart1_init(u32 baud) { //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); /* 配置GPIO的模式和IO口 */ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; //串口输出TX:PA9 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; //串口输入RX:PA10 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入 GPIO_Init(GPIOA,&GPIO_InitStructure); //USART1 初始化设置 USART_InitStructure.USART_BaudRate = baud; //波特率设置 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位 USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 USART_Init(USART1, &USART_InitStructure); //初始化串口1 USART_Cmd(USART1, ENABLE); //使能串口1 USART_ClearFlag(USART1, USART_FLAG_TC); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断 //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、 } /******************************************************************************* * 函 数 名 : USART1_IRQHandler * 函数功能 : USART1中断函数 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void USART1_IRQHandler(void) //串口1中断服务程序 { u8 r; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断 { r =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据 if((USART1_RX_STA&0x8000)==0)//接收未完成 { if(USART1_RX_STA&0x4000)//接收到了0x0d { if(r!=0x0a)USART1_RX_STA=0;//接收错误,重新开始 else USART1_RX_STA|=0x8000; //接收完成了 } else //还没收到0X0D { if(r==0x0d)USART1_RX_STA|=0x4000; else { USART1_RX_BUF[USART1_RX_STA&0X3FFF]=r; USART1_RX_STA++; if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//接收数据错误,重新开始接收 } } } } } #include "timer.h" #include "beep.h" volatile uint16_t beep_time; /******************************************************************************* * 函 数 名 : tim4_init * 函数功能 : TIM4初始化函数 * 输 入 : per:重装载值 psc:分频系数 * 输 出 : 无 *******************************************************************************/ void tim4_init(u16 per,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); // 使能TIM4的时钟 // 配置TIM的时基参数 TIM_TimeBaseInitStructure.TIM_Period = per; // 自动装载值 TIM_TimeBaseInitStructure.TIM_Prescaler = psc; // 分频系数 TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 设置向上计数模式 TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure); // 设置参数生效 // 配置中断参数 TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); // 开启定时器的更新中断 TIM_ClearITPendingBit(TIM4,TIM_IT_Update); // 中断标志位清零 // 配置NVIC NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 中断优先级分组(组2) NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; // 定时器4的中断通道(30号通道) NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 响应优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 中断通道使能 NVIC_Init(&NVIC_InitStructure); // NVIC设置参数生效 TIM_Cmd(TIM4,ENABLE); // 使能Timer4 } /******************************************************************************* * 函 数 名 : TIM4_IRQHandler * 函数功能 : TIM4中断函数 * 输 入 : 无 * 输 出 : 无 * 备 注 : 定时间隔1ms ** *****************************************************************************/ void TIM4_IRQHandler(void) { static u16 cnt_dht11; static u16 cnt_ldr; // 蜂鸣器时间处理 if(beep_time > 0) { beep_time--; if(beep_time == 0) { BEEP_OFF(); } } if(TIM_GetITStatus(TIM4,TIM_IT_Update)) // 检查更新中断是否产生 { // 处理定时任务 if(++cnt_dht11 == dht11.period) { if(dht11.state == STANDBY) { dht11.state = WORK; // DHT11状态从STANDBY切换到WORK } cnt_dht11 = 0; } if(++cnt_ldr == ldr.period) { if (ldr.state == STANDBY) { ldr.state = WORK; // LDR状态从STANDBY切换到WORK } cnt_ldr = 0; } // 刷新数码管显示 dsp.SegDisplay(); } TIM_ClearITPendingBit(TIM4,TIM_IT_Update); // 手动清除中断标志位 } #include "dht11.h" #include "relay.h" #include "beep.h" Dht11Struct dht11 = {0}; void SET_DHT11_IO_OUT(void); void SET_DHT11_IO_IN(void); void DHT11_RequestData(void); u8 DHT11_RespondRequest(void); u8 DHT11_Read_Data(u8 *temp, u8 *humi); void DHT11_OnTempChange(u8 temp_threshold); // DHT11_PIN初始化 // 返回值: 无 extern void dht11_init() { GPIO_InitTypeDef GPIO_InitStructure; // 数据引脚初始化 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 数据引脚 GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(DHT11_PORT, &GPIO_InitStructure); GPIO_SetBits(DHT11_PORT, DHT11_PIN); // 初始输出状态:高电平 // 结构体初始化 dht11.period = DHT11_PERIOD; dht11.temp_threshold = TEMP_THRESHOLD; dht11.getData = DHT11_Read_Data; // 获取温湿度数据的函数 dht11.onTempChange = DHT11_OnTempChange; // 温度超过阈值的处理函数 // 做一次数据请求测试,检查设备状态 DHT11_RequestData(); if (DHT11_RespondRequest() == SUCCESS) { dht11.state = STANDBY; printf("DHT11 Init OK!\r\n"); } else { dht11.state = FAIL; printf("DHT11 Check Error!\r\n"); } } // 复位DHT11,单片机向DHT11发起数据采集请求 // 时序图的黑线部分 static void DHT11_RequestData() { SET_DHT11_IO_OUT(); // 数据引脚配置为输出模式 DHT11_DQ_OUT = 0; delay_ms(20); // 低电平持续至少18ms DHT11_DQ_OUT = 1; delay_us(30); // 高电平持续20~40us } // DHT11响应单片机的数据请求 // 返回值:SUCCESS or FAILURE static u8 DHT11_RespondRequest() { u8 retry=0; SET_DHT11_IO_IN(); // 数据引脚设为输入模式,接收DHT11的响应 while (DHT11_DQ_IN && retry<100) // 等待输入由高变低 { retry++; if(retry >= 100) return FAILURE; // 等待时间过长,返回异常。 delay_us(1); } retry=0; while (!DHT11_DQ_IN && retry<100) // 低电平持续时间80us { retry++; if(retry >= 100) return FAILURE; // 低电平持续时间过长,返回异常。 delay_us(1); } return SUCCESS; } //DHT11输出模式配置 static void SET_DHT11_IO_OUT() { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(DHT11_PORT,&GPIO_InitStructure); } //DHT11输入模式配置 static void SET_DHT11_IO_IN() { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入模式,最小系统板和DHT11之间并未接上拉电阻 GPIO_Init(DHT11_PORT,&GPIO_InitStructure); } //从DHT11读取一位 //返回值:bit 1或0 //注:此函数处并未做高低电平持续时间异常的处理,因DHT11自身有校验和,即便读错1位也不会造成最终数据的错误。 // 严格来讲,除了正常情况下返回“1”或“0”,还应增加异常情况的返回值(比如“2”)。 static u8 DHT11_Read_Bit(void) { u8 retry=0; while(DHT11_DQ_IN && retry<100) // 等待输入电平由高变低(低电平持续50us) { retry++; delay_us(1); } retry=0; while(!DHT11_DQ_IN && retry<100) // 等待输入电平由低变高 { retry++; delay_us(1); } delay_us(40); // 等待40us(高电平持续26~28us表示0,持续70us表示1) if(DHT11_DQ_IN) return 1; // 40us后如果输入仍为高电平,则表示读入1;否则表示读入0。 else return 0; } //从DHT11读取一个字节 //返回值:读到的8位数据 static u8 DHT11_Read_Byte(void) { u8 i,byte; byte = 0; for (i=0;i<8;i++) { byte <<= 1; // 先前读取的数据(不足8位)全部左移一位 byte |= DHT11_Read_Bit(); // 最低位填入新读取的1位 } return byte; } //从DHT11读取一次完整的数据 //temp:温度值(整数,范围:0~50°) //humi:湿度值(整数,范围:20%~90%) //返回值:0,正常; 1,失败 static u8 DHT11_Read_Data(u8 *temp, u8 *humi) { u8 buf[5]; u8 i; DHT11_RequestData(); if(DHT11_RespondRequest() == SUCCESS) { for(i=0;i<5;i++) // 读取5组共40位数据 { buf[i] = DHT11_Read_Byte(); } if((buf[0]+buf[1]+buf[2]+buf[3]) == buf[4]) // 数据校验 { *humi = buf[0]; // 湿度整数部分 *temp = buf[2]; // 温度整数部分 return SUCCESS; } } return FAILURE; } // 采集DHT11数据并打印至串口 void dht11DataCollect() { u8 temp; u8 humi; if (DHT11_Read_Data(&temp, &humi) == SUCCESS) printf("temperature:%d℃ humidity(RH):%d \r\n", temp, humi); // 输出到串口(重定向) else printf("DHT11 data error! \r\n"); } // 温度阈值处理 void DHT11_OnTempChange(u8 temp_threshold) { if (dht11.temp > temp_threshold) { // 启动风扇(继电器低电平触发) Relay_Low(); // 蜂鸣器短鸣(100ms) BEEP_ON(); beep_time = 100; // 100ms } else { // 关闭风扇 Relay_High(); } } #include "ldr.h" LdrStruct ldr; static u8 getLightIntensity(void); static void OnLightChange(u8 hiLight, u8 loLight); /******************************************************************************* * 函 数 名 : adc_init * 函数功能 : ADC外设的初始化 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ static void adc_init(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; // 1.打开相关外设的总线时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE); // 2.信号引脚的参数配置 GPIO_InitStructure.GPIO_Pin=LDR_PIN; // 信号引脚:PB0 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; // 设置模拟输入模式 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz; // 设置传输速率 GPIO_Init(LDR_PORT,&GPIO_InitStructure); // 3. 输入时钟降频(<14MHz) RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 分频因子6,输入时钟为72M/6=12MHz // 4. 初始化ADC参数 ADC_InitStructure.ADC_Mode=ADC_Mode_Independent; //独立模式 ADC_InitStructure.ADC_ScanConvMode=DISABLE; //单次扫描 ADC_InitStructure.ADC_ContinuousConvMode=DISABLE; //单次转换 ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //软件触发 ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right; //数据右对齐 ADC_InitStructure.ADC_NbrOfChannel=1; //只有1个通道 ADC_Init(ADC1,&ADC_InitStructure); // 5. 使能ADC ADC_Cmd(ADC1,ENABLE); // 6. ADC校准 ADC_ResetCalibration(ADC1); //复位校准 while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); //开启并完成校准 while(ADC_GetCalibrationStatus(ADC1)); } // LDR的设备初始化 extern void ldr_init() { adc_init(); ldr.period = LDR_PERIOD; ldr.high_threshold = HI_THRESHOLD; ldr.low_threshold = LO_THRESHOLD; ldr.getData = getLightIntensity; ldr.onLightChange = OnLightChange; ldr.state = STANDBY; } /******************************************************************************* * 函 数 名 : GET_ADC_Value * 函数功能 : 获取通道ch的转换值,测量times次,取平均值 * 输 入 : ch:通道编号,Rank:规则序列中的第几个转换,取值1~16; times:测量次数 * 输 出 : 通道ch的times次转换结果的平均值 *******************************************************************************/ static u16 Get_ADC_Value(u8 ch, u8 times) //获取ADC1通道ch的转换值 { u8 i; u32 Temp_val=0; ADC_RegularChannelConfig(ADC1,ch,1,ADC_SampleTime_239Cycles5); for(i=0;i<times;i++) { ADC_SoftwareStartConvCmd(ADC1,ENABLE); // 开始转换 while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)); // 等待至单次转换结束 Temp_val += ADC_GetConversionValue(ADC1); delay_ms(10); } return Temp_val/times; } /******************************************************************************* * 函 数 名 : getLightIntensity * 函数功能 : 将ADC转换值解读为光照强度 * 输 入 : 无 * 输 出 : 光照照度值(0~100, 0:照度最低;100:照度最高) *******************************************************************************/ static u8 getLightIntensity(void) //通过ADC1 通道0的值获取亮度值 { u16 value = 0; u8 lightvalue = 0; value = Get_ADC_Value(ADC_Channel_8,20); lightvalue = 100 - (u16)(value/40.95); return lightvalue; } // 添加PWM控制LED功能 static void set_led_brightness(u8 level) { switch(level) { case 0: // 低档 TIM_SetCompare2(TIM3, 125); // 25%占空比 break; case 1: // 中档 TIM_SetCompare2(TIM3, 250); // 50%占空比 break; case 2: // 高档 TIM_SetCompare2(TIM3, 375); // 75%占空比 break; } } /******************************************************************************* * 函 数 名 : OnLightChange * 函数功能 : 照度超过阈值(高阈值和低阈值)的处理措施 * 输 入 : hiLight-高阈值; loLight-低阈值 * 输 出 : 无 *******************************************************************************/ static void OnLightChange(u8 hiLight, u8 loLight) { if (ldr.light > hiLight) { set_led_brightness(0);// 照度过高,降低亮度 } else if (ldr.light < loLight) { set_led_brightness(2); // 照度过低,提升亮度 } else // 正常范围 { set_led_brightness(1); // 中等亮度 } } #include "key.h" #include "pwm.h" /******************************************************************************* * 函 数 名 : TIM3_CH2_PWM_Init * 函数功能 : TIM3通道2 PWM初始化函数 * 输 入 : per:重装载值 * psc:分频系数 * 输 出 : 无 *******************************************************************************/ void TIM3_CH2_PWM_Init(u16 per,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* 开启时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE); // PB5引脚启用复用模式 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); // 选择TIM3部分重映射 GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); /* PB5作为PWM的输出引脚 */ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOB,&GPIO_InitStructure); // 初始化TIM3 TIM_TimeBaseInitStructure.TIM_Period=per; //自动装载值 TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure); // 设置TIM3_CH2的PWM模式,使能CH2输出,呈现出PPT展示的PWM波形 // PWM1即mode1,先输出有效电平,再输出无效电平;PWM2即mode2则正好相反。 TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; // 设置有效电平为低电平(此案例中低电平点亮D2) TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low; TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; TIM_OC2Init(TIM3,&TIM_OCInitStructure); //输出比较通道2初始化 TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能TIM3在 CCR2 上的预装载寄存器 TIM_Cmd(TIM3,ENABLE); //使能定时器 } #include "relay.h" void Relay_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); //默认输出低电平 } void Relay_High(void) { GPIO_SetBits(GPIOA, GPIO_Pin_11); } void Relay_Low(void) { GPIO_ResetBits(GPIOA, GPIO_Pin_11); } #ifndef _RELAY_H_ #define _RELAY_H_ #include "main.h" #define RELAY_HIGH 1 #define RELAY_LOW 0 void Relay_Init(void); void Relay_High(void); void Relay_Low(void); #endif #ifndef __PWM_H #define __PWM_H #include "main.h" void TIM3_CH2_PWM_Init(u16 per,u16 psc); #endif #ifndef __LDR_H #define __LDR_H #include "main.h" #define LDR_PIN GPIO_Pin_0 #define LDR_PORT GPIOB #define LDR_PERIOD 4000 // ADC转换周期:4000ms #define HI_THRESHOLD 70 // 照度高阈值 #define LO_THRESHOLD 30 // 照度低阈值 typedef struct{ u8 light; // 光照强度(相对强度:0~100) u16 period; // 重复测量周期(s) u8 high_threshold; // 高亮阈值 u8 low_threshold; // 低亮阈值 SensorState state; // 工作状态 u8 (*getData)(void); // 获取光照强度数据 void (*onLightChange)(u8 hiLight, u8 loLight); // 亮度变化的响应操作 } LdrStruct; void ldr_init(void); extern LdrStruct ldr; #endif #ifndef __DHT11_H #define __DHT11_H #include "main.h" #define DHT11_PIN GPIO_Pin_12 #define DHT11_PORT GPIOA #define DHT11_DQ_IN PCin(12) // 输入 #define DHT11_DQ_OUT PCout(12) // 输出 #define SUCCESS 0 #define FAILURE 1 #define DHT11_PERIOD 5000 // 数据采集周期:5000ms #define TEMP_THRESHOLD 28 // 温度阈值(℃) // 定义DHT11结构体 typedef struct{ u8 temp; // 温度值 u8 humi; // 湿度值 u16 period; // 重复测量周期(s) u8 temp_threshold; // 温度阈值 u8 humi_threshold; // 湿度阈值 SensorState state; // 设备状态 u8 (*getData)(u8 *temp, u8 *humi); // 获取温湿度数据 void (*onTempChange)(u8 temp_threshold); // 高温的响应操作 } Dht11Struct; void dht11_init(void); extern Dht11Struct dht11; #endif #ifndef _usart_H #define _usart_H #include "main.h" #define USART1_REC_LEN 200 //定义最大接收字节数 200 extern u8 USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 extern u16 USART1_RX_STA; //接收状态标记 void usart1_init(u32 baud); #endif #ifndef __TIM_H #define __TIM_H #include "main.h" //#include "stm32f10x.h" void tim4_init(u16 per,u16 psc); #endif #ifndef __DISPLAY_H #define __DISPLAY_H #include "main.h" #define DSP_DIGIT 4 // 4位数码管 typedef enum{LIGHT, TEMP, HUMI} DSP_Interface; // 数码管界面 typedef struct { u16 digit[DSP_DIGIT]; // 数码管的4位数字 u8 currDigit; // 当前显示位(1~4) u8 dotDigit; // 小数点位置(0~4,0代表不显示小数点) DSP_Interface interface; // 界面显示哪个测量值 void(*SegDisplay)(void); }DisplayStruct; void display_init(void); void segDisplay(void); //void setValue(DisplayStruct *dsp, u8 value[4], u8 dotBit); void setLightValue(DisplayStruct *dsp, u8 dotBit); void setTempValue(DisplayStruct *dsp, u8 dotBit); void setHumiValue(DisplayStruct *dsp, u8 dotBit); extern DisplayStruct dsp; #endif 在已有代码上完善该任务,STM32F103C8t6,用标准库

#include "ADC_Config.h" #define ADCIP_CTRL (*(uint32_t*)(0x40020800+0x60)) /* ADC时钟: 14MHZ 声音范围:20Hz~20KHz TIME触发ADC:TIM频率 128K ADC采样时间 = (71.5 +12.5)/14 采样频率:128K 采样个数: 125ms=8HZ 128K/8Hz=16000次, 512K/8HZ=64000 64000/256=250 BUFF0大小256 BUFF1大小128,DMA HT中断,即要中断16000/128=125次 每125次求和 PA1:ADC_IN1 30-70DB PA2: ADC_IN2 70-100DB PA3:ADC_IN3 100-130DB 采样125ms: 共要计算 16000组数据 采样1s: 共要计算 16000*8=128000组数据 设置DMA BUFF大小 256组 HT中断 中断时间1ms 中断程序耗费8.8us 那么 采样125ms就需要中断 125000/1=125次 9K的信号能采样14组 那么 采样1s就需要中断 125*8=1000次 DMA_MEM 从开始到计算结束 用时140us 不会超过一次ADC DMA中断时间 数据不会被覆盖 */ ADC_BUFF Noise_Data; DMA_InitType DMA_InitStructure, DMA_InitStructure_MEM; u8 USB_Busy ; ADC_InitType ADC_InitStructure; extern uint16_t DMA_Test_Value[5], DMA_Test_Value1[5]; void TIM2_ETR_Config(void) { TIM_TimeBaseInitType TIM_TimeBaseStructure; OCInitType TIM_OCInitStructure; RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM2, ENABLE); TIM_TimeBaseStructure.Period = TRG_FREQ_USER - 1; //64k TIM_TimeBaseStructure.Prescaler = 0; TIM_TimeBaseStructure.ClkDiv = TIM_CLK_DIV1; TIM_TimeBaseStructure.CntMode = TIM_CNT_MODE_UP; TIM_InitTimeBase(TIM2, &TIM_TimeBaseStructure); TIM_OCInitStructure.OcMode = TIM_OCMODE_PWM1; TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE; TIM_OCInitStructure.Pulse = TRG_FREQ_USER / 2 - 1; TIM_OCInitStructure.OcPolarity = TIM_OC_POLARITY_LOW; TIM_InitOc2(TIM2, &TIM_OCInitStructure); TIM_ConfigInt(TIM2, TIM_INT_CC2, ENABLE); /* TIM2 enable counter */ TIM_Enable(TIM2, ENABLE); TIM_EnableCtrlPwmOutputs(TIM2, ENABLE); } /** * @brief Configures the different system clocks. */ void RCC_Configuration(void) { /* Enable peripheral clocks ------------------------------------------------*/ /* Enable DMA clocks */ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE); /* Enable GPIOC clocks */ RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE); /* Enable ADC clocks */ RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC, ENABLE); /* RCC_ADCHCLK_DIV16*/ ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB, RCC_ADCHCLK_DIV2);//96/2=48M RCC_ConfigAdc1mClk(RCC_ADC1MCLK_SRC_HSE, RCC_ADC1MCLK_DIV12); //selsect HSE as RCC ADC1M CLK Source } /** * @brief Configures the different GPIO ports. */ void GPIO_Configuration(void) { GPIO_InitType GPIO_InitStructure; GPIO_InitStruct(&GPIO_InitStructure); /* Configure GPIO_PIN_WIFI_RST GPIO_PIN_WIFI_CEN GPIO_PIN_WIFI_RX GPIO_PIN_WIFI_TX as analog input ---------*/ GPIO_InitStructure.Pin = GPIO_PIN_WIFI_RST | GPIO_PIN_WIFI_CEN | GPIO_PIN_WIFI_RX | GPIO_PIN_WIFI_TX | GPIO_PIN_BATT; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Analog; GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure); } //配置DMA中断 void NVIC_DMA_Config(void) { NVIC_InitType NVIC_InitStructure; //DMA通道6中断设置 NVIC_InitStructure.NVIC_IRQChannel = DMA_Channel1_IRQn;// DMA1_Channel2_3_IRQn NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能 NVIC_Init(&NVIC_InitStructure); } void Change_Addr_MEM(MEA_GROUP_TypeDef MeaGroup) { DMA_EnableChannel(DMA_CH6, DISABLE); switch(MeaGroup) { case GROUP0: DMA_InitStructure_MEM.PeriphAddr = (uint32_t)Noise_Data.Buff0; break; case GROUP1: DMA_InitStructure_MEM.PeriphAddr = (uint32_t)(&Noise_Data.Buff0[DMA_BUFF_SIZE / 2]); break; } DMA_Init(DMA_CH6, &DMA_InitStructure_MEM); if(USB_Busy == 0) //对EEPROM数据进行释放锁后才去打开DMA3 { DMA_EnableChannel(DMA_CH6, ENABLE ); } else { DMA_EnableChannel(DMA_CH6, DISABLE ); } } void ADC_DMA_Cfg(void) { SysData.DMA_Group = 0; /* System clocks configuration ---------------------------------------------*/ RCC_Configuration(); /* GPIO configuration ------------------------------------------------------*/ GPIO_Configuration(); NVIC_DMA_Config(); /* DMA channel1 configuration ----------------------------------------------*/ DMA_DeInit(DMA_CH1); DMA_InitStructure.PeriphAddr = (uint32_t)&ADC->DAT; DMA_InitStructure.MemAddr = (uint32_t)Noise_Data.Buff0; DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC; DMA_InitStructure.BufSize = DMA_BUFF_SIZE; DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE; DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE; DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD; DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.CircularMode = DMA_MODE_NORMAL;//DMA_MODE_CIRCULAR; DMA_InitStructure.Priority = DMA_PRIORITY_HIGH; DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE; DMA_Init(DMA_CH1, &DMA_InitStructure); DMA_RequestRemap(DMA_REMAP_ADC1, DMA, DMA_CH1, ENABLE); DMA_ClrIntPendingBit(DMA_INT_TXC1, DMA); // DMA_ClrIntPendingBit(DMA_INT_HTX1,DMA); DMA_ConfigInt(DMA_CH1, DMA_INT_TXC, ENABLE); // DMA_ConfigInt(DMA_CH1,DMA_INT_HTX,ENABLE); /* Enable DMA channel1 */ DMA_EnableChannel(DMA_CH1, ENABLE); ADC_DeInit(ADC); /* ADC1 configuration ------------------------------------------------------*/ ADC_InitStructure.MultiChEn = ENABLE; ADC_InitStructure.ContinueConvEn = DISABLE; ADC_InitStructure.ExtTrigSelect = ADC_EXT_TRIGCONV_T2_CC2; ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R; ADC_InitStructure.ChsNumber = 4; ADC_Init(ADC, &ADC_InitStructure); ADCIP_CTRL = 0x28; //在ADC使能前配置这个 ADC_EnableTempSensorVrefint( ENABLE); /* ADC1 regular channel13 configuration */ ADC_ConfigRegularChannel(ADC, ADC_CH_1_PA0, 1, ADC_SampleTime_User);//WIFI_RST ADC_ConfigRegularChannel(ADC, ADC_CH_2_PA1, 2, ADC_SampleTime_User);//WIFI_CEN ADC_ConfigRegularChannel(ADC, ADC_CH_3_PA2, 3, ADC_SampleTime_User);//WIFI_RX ADC_ConfigRegularChannel(ADC, ADC_CH_4_PA3, 4, ADC_SampleTime_User);//WIFI_TX ADC_EnableExternalTrigConv(ADC, ENABLE); ADC_ConfigInt(ADC, ADC_INT_ENDC, ENABLE); /* Enable ADC DMA */ ADC_EnableDMA(ADC, ENABLE); /* Enable ADC */ ADC_Enable(ADC, ENABLE); /* Check ADC Ready */ while(ADC_GetFlagStatusNew(ADC, ADC_FLAG_RDY) == RESET); /* Start ADC1 calibration */ ADC_StartCalibration(ADC); /* Check the end of ADC1 calibration */ while (ADC_GetCalibrationStatus(ADC)); } #ifndef __ADC_CONFIG_H #define __ADC_CONFIG_H #include "main.h" #define ADC1_DR_Address 0x40012440 #define TRG_FREQ_1M 72 #define TRG_FREQ_500K 144 #define TRG_FREQ_600K 120 #define TRG_FREQ_300K 240 #define TRG_FREQ_50K 1440 //#define TRG_FREQ_64K 1125 //#define TRG_FREQ_32K 1125*2 #define TRG_FREQ_128K 1125 #define TRG_FREQ_64K 750 #define TRG_FREQ_USER TRG_FREQ_64K #define ADC_SampleTime_User ADC_SAMP_TIME_71CYCLES5 //要求大于 64*4=256K 48/(71.5+12.5+16)=480K >256K #define DMA_CAL_BUFF_SIZE 3200 //125ms*64*4=32000=3200*10= DMA_CAL_BUFF_SIZE*SMP_DMA_CNT 3200/64=50ms 中断一次 #define DMA_BUFF_SIZE DMA_CAL_BUFF_SIZE typedef enum { GROUP0 = 0x00, GROUP1 = 0x01, } MEA_GROUP_TypeDef; typedef struct { //ADC DMA 用 u16 Buff0[DMA_CAL_BUFF_SIZE]; u16 Buff1[DMA_CAL_BUFF_SIZE]; } ADC_BUFF; extern ADC_BUFF Noise_Data; void ADC_Config(MEA_RANGE_TypeDef MeaRange); void DMA_Config(void); void NVIC_DMA_Config(void); void DMA_Config_MEM(void); void TIM2_ETR_Config(void); void Change_Addr_MEM(MEA_GROUP_TypeDef MeaGroup); void ADC_DMA_Cfg(void); #endif /***************************************************************************** * Copyright (c) 2022, Nations Technologies Inc. * * All rights reserved. * **************************************************************************** * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Nations' name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /** * @file n32g43x_it.c * @author Nations * @version v1.2.0 * * @copyright Copyright (c) 2022, Nations Technologies Inc. All rights reserved. */ #include "n32g43x_it.h" #include "n32g43x.h" #include "main.h" #include "usb_istr.h" /** @addtogroup N32G43X_StdPeriph_Template * @{ */ extern __IO uint32_t CurrDataCounterEnd; /******************************************************************************/ /* Cortex-M4 Processor Exceptions Handlers */ /******************************************************************************/ /** * @brief This function handles NMI exception. */ void NMI_Handler(void) { } /** * @brief This function handles Hard Fault exception. */ void HardFault_Handler(void) { /* Go to infinite loop when Hard Fault exception occurs */ while (1) { } } /** * @brief This function handles Memory Manage exception. */ void MemManage_Handler(void) { /* Go to infinite loop when Memory Manage exception occurs */ while (1) { } } /** * @brief This function handles Bus Fault exception. */ void BusFault_Handler(void) { /* Go to infinite loop when Bus Fault exception occurs */ while (1) { } } /** * @brief This function handles Usage Fault exception. */ void UsageFault_Handler(void) { /* Go to infinite loop when Usage Fault exception occurs */ while (1) { } } /** * @brief This function handles SVCall exception. */ void SVC_Handler(void) { } /** * @brief This function handles Debug Monitor exception. */ void DebugMon_Handler(void) { } /** * @brief This function handles DMA interrupt request defined in main.h . */ void DMA_IRQ_HANDLER(void) { } /** * @brief This function handles USB_LP_IRQHandler Handler. */ void USB_LP_IRQHandler(void) { USB_Istr(); } /** * @brief This function handles USB WakeUp interrupt request. */ void USBWakeUp_IRQHandler(void) { EXTI_ClrITPendBit(EXTI_LINE17); } void DMA_Channel1_IRQHandler(void) { //国民芯片在一个DMA通道里面 配置另一个DMA通道会导致当前通道顺序异常 //这里配置 2us完成 ADC 一次的时间是15.4us 足够赶上下一次ADC完成 if(DMA_GetIntStatus(DMA_INT_TXC1, DMA) != RESET) //全传输完 { DMA_ClrIntPendingBit(DMA_INT_TXC1, DMA); //国民芯片 建议传输完成 重新配置TXNUM 否则可能出现顺序错乱 DMA_CH1->CHCFG &= (uint16_t)(~DMA_CHCFG1_CHEN); DMA_CH1->TXNUM = DMA_BUFF_SIZE; SysData.DMA_Group = !SysData.DMA_Group; DMA_CH1->MADDR = (uint32_t)Noise_Data.Buff0; if(SysData.DMA_Group != 0) { DMA_CH1->MADDR = (uint32_t)Noise_Data.Buff1; } DMA_CH1->CHCFG |= DMA_CHCFG1_CHEN; SysFlag.DMA_OK = 1; } } void DMA_Channel6_IRQHandler(void) { if(DMA_GetIntStatus(DMA_INT_TXC6, DMA) != RESET) { DMA_ClrIntPendingBit(DMA_INT_TXC6, DMA); // Get_AD_SUM(); } } void ADC_IRQHandler(void) { if(ADC_GetIntStatus(ADC, ADC_INT_ENDC) != RESET) { ADC_ClearIntPendingBit(ADC, ADC_INT_ENDC); // LED1_Turn(); } } void TIM2_IRQHandler(void) { if(TIM_GetFlagStatus(TIM2, TIM_FLAG_CC2) == SET) { TIM_ClearFlag(TIM2, TIM_FLAG_CC2); // LED1_Turn(); // test1++; } } void TIM3_IRQHandler(void) { if(TIM_GetFlagStatus(TIM3, TIM_FLAG_UPDATE) == SET) { TIM_ClearFlag(TIM3, TIM_FLAG_UPDATE); // Clock_150++; // Clock_500++; // Clock_750++; // SysClock++; // // Buzzer_Process(); } } void TIM4_IRQHandler(void) { if(TIM_GetFlagStatus(TIM4, TIM_FLAG_UPDATE) == SET) { TIM_ClearFlag(TIM4, TIM_FLAG_UPDATE); Clock_150++; Clock_500++; Clock_750++; SysClock++; LED1_Turn(); Buzzer_Process(); } } void EXTI9_5_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_LINE8) != RESET) { EXTI_ClrITPendBit(EXTI_LINE8); SysFlag.PWD = 1; Clock_500 = 0; if((SysFlag.EraseDoing) && (SysInfo.PWRON_Erase == 0)) { SysInfo.PWRON_Erase = 1; Save_Param(&SysInfo.PWRON_Erase, sizeof(SysInfo.PWRON_Erase)); } } } /** * @brief This function handles SysTick Handler. */ u32 Time_1ms = 0; void SysTick_Handler(void) { Time_1ms++; } /******************************************************************************/ /* N32G43X Peripherals Interrupt Handlers */ /* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */ /* available peripheral interrupt handler's name please refer to the startup */ /* file (startup_n32g43x.s). */ /******************************************************************************/ /** * @brief This function handles PPP interrupt request. */ /*void PPP_IRQHandler(void) { }*/ /** * @} */ void Get_AD_SUM(void) { uint64_t Sum[3] = {0, 0, 0}; //这里有3种计算,分别是sum[0],sum[1],sum[2] u8 Ratio; u16 loopi, *Data; u32 Temp; Data = Noise_Data.Buff1;//将DMA移过来的地址给Data if(SysData.DMA_Group != 0) Data = Noise_Data.Buff0;//将DMA移过来的地址给Data SysData.BattCnt = 0; //sum[0] for(loopi = 0; loopi < DMA_CAL_BUFF_SIZE; loopi += 4) //循环480/3=150次 { Temp = (u32)(*Data); //将Noise_Data.Buff1的值给Temp Data++;//地址++ if(Temp > ADC_HLimit) SysData.OverCntt[0]++; //如果Temp>2482,数据溢出的标志位++,这个数据溢出的标志位也有3种,用数组来表示 Temp = Temp + (s32)SysInfo.Cal_Adc[0];// 这个应该是存放校准后的ADC if(Temp > 0x80000000)Temp = 0; Temp = Temp * Temp; //不知道平方一次是用来干啥的 Sum[0] += (uint64_t)Temp; //计算总和,存到sum[0] //sum[1] Temp = (u32)(*Data); Data++; if(Temp > ADC_HLimit_H) SysData.OverCntt[1]++; Temp = Temp + (s32)SysInfo.Cal_Adc[1]; if(Temp > 0x80000000)Temp = 0; Temp = Temp * Temp; Sum[1] += (uint64_t)Temp; //计算总和,存到sum[1] //sum[2] Temp = (u32)(*Data); Data++; Temp = Temp + (s32)SysInfo.Cal_Adc[2]; if(Temp > 0x80000000) Temp = 0; Temp = Temp * Temp; Sum[2] += (uint64_t)Temp; //计算总和,存到sum[2] if(SysData.BattCnt < 64) { SysData.BattBuff[SysData.BattCnt++] = *Data; } Data++; } SysData.Batt = 0; for(loopi = 0; loopi < 64; loopi++) { SysData.Batt += SysData.BattBuff[loopi]; } SysData.Batt = SysData.Batt / 64; // //报警时低于3.3V不关机问题,电源检测这里添加关机 // if(SysData.Batt < BattSHUT) // { // Shut_Down(); // } //将计算的总和,存到SysData.ADC_VALUE SysData.ADC_VALUE[0] += (double)Sum[0]; SysData.ADC_VALUE[1] += (double)Sum[1]; SysData.ADC_VALUE[2] += (double)Sum[2]; SysData.ADC_CNT++; Ratio = SysData.Freq_Resp * 7 + 1; //不知道这2句是干嘛的 if(SysData.ADC_CNT >= (SMP_DMA_CNT * Ratio)) { SysData.ADC_CNT = 0; // if(SysData.Cal_Mode == 0) // { // if(SysData.OverCntt[0] < MIN_OVER_CNT) //溢出计数判断 // { // SysData.Adc_Range = RANG_70DB; // } // else if(SysData.OverCntt[1] < MIN_OVER_CNT) // { // SysData.Adc_Range = RANG_100DB; // } // else // { // SysData.Adc_Range = RANG_130DB; // } // } SysData.ADC_Sum_Value = (SysData.ADC_VALUE[SysData.Adc_Range] / (float)Ratio) + SysInfo.Cal_Adc_Squ[SysData.Adc_Range]; if(SysData.ADC_Sum_Value < 0) { ; } else { // Get_Noise_Data(); } SysData.ADC_VALUE[0] = 0; SysData.ADC_VALUE[1] = 0; SysData.ADC_VALUE[2] = 0; SysData.OverCntt[0] = 0; SysData.OverCntt[1] = 0; SysData.OverCntt[2] = 0; } } void Get_Noise_Data(void) { Phasea = SysData.ADC_Sum_Value; /* 523公式:10*log10(SysData.ADC_Sum_Value) *10 //是为了扩大10倍 用于获取小数部分,来显示 */ Phasea = log10(Phasea); Phasea = Phasea * 1000; Phaseb = (u32)Phasea; SysData.CAL_INT_Value = Phaseb + SysInfo.Cal_DB[SysData.Adc_Range]; SysData.ADC_INT_Value = SysData.CAL_INT_Value / 10; if(SysData.Cal_Mode == 0) { if(SysData.ADC_TAB_CNT == 0) { SysData.ADC_TAB_CNT = 1; SysData.ADC_INT_Value_TAB[1] = SysData.ADC_INT_Value; SysData.ADC_INT_Value_TAB[2] = SysData.ADC_INT_Value; SysData.ADC_INT_Value_TAB[3] = SysData.ADC_INT_Value; } else { SysData.ADC_INT_Value_TAB[3] = SysData.ADC_INT_Value_TAB[2]; SysData.ADC_INT_Value_TAB[2] = SysData.ADC_INT_Value_TAB[1]; SysData.ADC_INT_Value_TAB[1] = SysData.ADC_INT_Value_TAB[0]; } SysData.ADC_INT_Value_TAB[0] = SysData.ADC_INT_Value; } else { SysData.CalEn = 1; if(SysData.Adc_Range == RANG_130DB) { if(SysData.ADC_INT_Value == 1300) { SysFlag.FlickEn = 1; } else { SysFlag.FlickEn = 0; } } } } 保留温湿度和电压,去除噪音

/** ****************************************************************************** * @file main.c * @author embedfire * @version V1.0 * @date 2024 * @brief 标准库模板 ****************************************************************************** * @attention * * 实验平台 :野火 STM32F103C8T6-STM32开发板 * 论坛 :http://www.firebbs.cn * 官网 :https://embedfire.com/ * 淘宝 :https://yehuosm.tmall.com/ * ****************************************************************************** */ #include "stm32f10x.h" // Device header #include "delay/bsp_delay.h" #include "stm32f10x.h" #include "OLED/OLED.h" /* DHT11驱动部分 */ #define DHT11_GPIO_PORT GPIOA #define DHT11_GPIO_PIN GPIO_Pin_9 void DHT11_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = DHT11_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStructure); GPIO_SetBits(DHT11_GPIO_PORT, DHT11_GPIO_PIN); } uint8_t DHT11_Read_Data(float *temp, float *humi) { uint8_t buf[5]; // 启动信号时序代码 GPIO_ResetBits(DHT11_GPIO_PORT, DHT11_GPIO_PIN); Rough_Delay_Ms(18); GPIO_SetBits(DHT11_GPIO_PORT, DHT11_GPIO_PIN); Rough_Delay_Us(30); // 数据接收处理代码 // ...(完整时序处理代码) // 校验数据 if(buf[0] + buf[1] + buf[2] + buf[3] == buf[4]) { *humi = buf[0] + buf[1]*0.1; *temp = buf[2] + buf[3]*0.1; return 0; } return 1; } ///* OLED驱动部分 */ //void OLED_Write_Cmd(uint8_t cmd) { // I2C_Start(); // I2C_Write_Byte(0x78); // 器件地址 // I2C_Write_Byte(0x00); // 命令模式 // I2C_Write_Byte(cmd); // I2C_Stop(); //} //void OLED_Init(void) { // // 初始化序列 // OLED_Write_Cmd(0xAE); // 关闭显示 // OLED_Write_Cmd(0xD5); // 设置显示时钟分频比 // OLED_Write_Cmd(0x80); // // ...其他初始化命令 // OLED_Write_Cmd(0xAF); // 开启显示 //} /* 主程序逻辑 */ int main(void) { float temperature, humidity; SystemInit(); DHT11_Init(); OLED_Init(); while(1) { if(DHT11_Read_Data(&temperature, &humidity) == 0) { OLED_ShowString(0, 0, "Temp:"); OLED_ShowNum(48, 0, (uint16_t)temperature, 2); OLED_ShowString(0, 2, "Humi:"); OLED_ShowNum(48, 2, (uint16_t)humidity, 2); } Rough_Delay_Ms(2000); } }.\Objects\Fire_F103.axf: Error: L6200E: Symbol OLED_F8x16 multiply defined (by oled.o and main.o).

最新推荐

recommend-type

contos7依赖包,免费下载 某些人真恶心拿着资源抢分抢钱 此处也有免费下载:http://mirrors.aliyun.com/centos/7/os/x86-64/Packages/

bzip2-devel-1.0.6-13.el7.i686.rpm centos-release-scl-2-3.el7.centos.noarch.rpm centos-release-scl-rh-2-3.el7.centos.noarch.rpm cloog-ppl-0.15.7-1.2.el6.x86_64.rpm cpp-4.4.7-4.el6.x86_64.rpm cpp-4.8.5-44.el7.x86_64.rpm dejavu-fonts-common-2.33-6.el7.noarch.rpm dejavu-sans-fonts-2.33-6.el7.noarch.rpm fontconfig-2.13.0-4.3.el7.x86_64.rpm fontpackages-filesystem-1.44-8.el7.noarch.rpm freetype-2.8-14.el7.src.rpm freetype-2.8-14.el7.x86_64.rpm freetype-devel-2.8-14.el7.x86_64.rpm gcc-4.4.7-4.el6.x86_64.rpm gcc-4.8.5-44.el7.x86_64.rpm gcc-c++-4.4.7-4.el6.x86_64.rpm gcc-c++-4.8.5-44.el7.x86_64.rpm gcc-gfortran-4.8.5-44.el7.x86_64.rpm glibc-2.17-307.el7.1.x86_64.rpm glibc-2.17-317.el7.x86_64.rpm glibc-common-2.17-317.el7.x86_64.rpm glibc-devel-2.12-1.132.el6.x86_64.rpm glibc-devel-2.17-307.el7.1.x8
recommend-type

实现Struts2+IBatis+Spring集成的快速教程

### 知识点概览 #### 标题解析 - **Struts2**: Apache Struts2 是一个用于创建企业级Java Web应用的开源框架。它基于MVC(Model-View-Controller)设计模式,允许开发者将应用的业务逻辑、数据模型和用户界面视图进行分离。 - **iBatis**: iBatis 是一个基于 Java 的持久层框架,它提供了对象关系映射(ORM)的功能,简化了 Java 应用程序与数据库之间的交互。 - **Spring**: Spring 是一个开源的轻量级Java应用框架,提供了全面的编程和配置模型,用于现代基于Java的企业的开发。它提供了控制反转(IoC)和面向切面编程(AOP)的特性,用于简化企业应用开发。 #### 描述解析 描述中提到的“struts2+ibatis+spring集成的简单例子”,指的是将这三个流行的Java框架整合起来,形成一个统一的开发环境。开发者可以利用Struts2处理Web层的MVC设计模式,使用iBatis来简化数据库的CRUD(创建、读取、更新、删除)操作,同时通过Spring框架提供的依赖注入和事务管理等功能,将整个系统整合在一起。 #### 标签解析 - **Struts2**: 作为标签,意味着文档中会重点讲解关于Struts2框架的内容。 - **iBatis**: 作为标签,说明文档同样会包含关于iBatis框架的内容。 #### 文件名称列表解析 - **SSI**: 这个缩写可能代表“Server Side Include”,一种在Web服务器上运行的服务器端脚本语言。但鉴于描述中提到导入包太大,且没有具体文件列表,无法确切地解析SSI在此的具体含义。如果此处SSI代表实际的文件或者压缩包名称,则可能是一个缩写或别名,需要具体的上下文来确定。 ### 知识点详细说明 #### Struts2框架 Struts2的核心是一个Filter过滤器,称为`StrutsPrepareAndExecuteFilter`,它负责拦截用户请求并根据配置将请求分发到相应的Action类。Struts2框架的主要组件有: - **Action**: 在Struts2中,Action类是MVC模式中的C(控制器),负责接收用户的输入,执行业务逻辑,并将结果返回给用户界面。 - **Interceptor(拦截器)**: Struts2中的拦截器可以在Action执行前后添加额外的功能,比如表单验证、日志记录等。 - **ValueStack(值栈)**: Struts2使用值栈来存储Action和页面间传递的数据。 - **Result**: 结果是Action执行完成后返回的响应,可以是JSP页面、HTML片段、JSON数据等。 #### iBatis框架 iBatis允许开发者将SQL语句和Java类的映射关系存储在XML配置文件中,从而避免了复杂的SQL代码直接嵌入到Java代码中,使得代码的可读性和可维护性提高。iBatis的主要组件有: - **SQLMap配置文件**: 定义了数据库表与Java类之间的映射关系,以及具体的SQL语句。 - **SqlSessionFactory**: 负责创建和管理SqlSession对象。 - **SqlSession**: 在执行数据库操作时,SqlSession是一个与数据库交互的会话。它提供了操作数据库的方法,例如执行SQL语句、处理事务等。 #### Spring框架 Spring的核心理念是IoC(控制反转)和AOP(面向切面编程),它通过依赖注入(DI)来管理对象的生命周期和对象间的依赖关系。Spring框架的主要组件有: - **IoC容器**: 也称为依赖注入(DI),管理对象的创建和它们之间的依赖关系。 - **AOP**: 允许将横切关注点(如日志、安全等)与业务逻辑分离。 - **事务管理**: 提供了一致的事务管理接口,可以在多个事务管理器之间切换,支持声明式事务和编程式事务。 - **Spring MVC**: 是Spring提供的基于MVC设计模式的Web框架,与Struts2类似,但更灵活,且与Spring的其他组件集成得更紧密。 #### 集成Struts2, iBatis和Spring 集成这三种框架的目的是利用它们各自的优势,在同一个项目中形成互补,提高开发效率和系统的可维护性。这种集成通常涉及以下步骤: 1. **配置整合**:在`web.xml`中配置Struts2的`StrutsPrepareAndExecuteFilter`,以及Spring的`DispatcherServlet`。 2. **依赖注入配置**:在Spring的配置文件中声明Struts2和iBatis的组件,以及需要的其他bean,并通过依赖注入将它们整合。 3. **Action和SQL映射**:在Struts2中创建Action类,并在iBatis的SQLMap配置文件中定义对应的SQL语句,将Struts2的Action与iBatis的映射关联起来。 4. **事务管理**:利用Spring的事务管理功能来管理数据库操作的事务。 5. **安全和服务层**:通过Spring的AOP和IoC功能来实现业务逻辑的解耦合和事务的管理。 ### 结语 通过上述的整合,开发者可以有效地利用Struts2处理Web层的展示和用户交互,使用iBatis简化数据库操作,同时借助Spring强大的依赖注入和事务管理功能,创建一个结构良好、可维护性强的应用。这种集成方式在许多企业级Java Web应用中非常常见,是Java开发人员必须掌握的知识点。
recommend-type

【数据融合技术】:甘肃土壤类型空间分析中的专业性应用

# 摘要 数据融合技术作为一种集成多源数据信息的方法,在土壤类型空间分析中发挥着关键作用。本文介绍了数据融合技术的基本概念及其理论基础,阐述了数据预处理、同步整合及冲突解决等关键技术,并详细描述了甘肃土壤类型数据准备的流程,包括数据采集、质量评估、空间化处理及融合实践准备。通过具体案例分析,展示了数据融合在土壤类型空间分布分析、土壤质量评估及土壤保护规划中的应用。同时,文
recommend-type

Waymo使用稀疏图卷积处理LiDAR点云,目标检测精度提升15%

<think>好的,用户让我介绍一下Waymo使用稀疏图卷积处理LiDAR点云,目标检测精度提升15%的具体情况。我需要先回忆之前提供的回答中提到的相关案例,然后深入展开。 首先,用户可能已经知道稀疏图卷积的基本概念,但需要更详细的应用案例。他们可能对Waymo如何具体应用该技术感兴趣,比如技术细节、实现方式、提升的具体指标等。需要确保回答结构清晰,分点说明,同时保持技术准确性。 要考虑到用户可能的背景,可能是研究或工程领域的,需要技术细节,但避免过于复杂的数学公式,除非必要。之前回答中提到了应用案例,现在需要扩展这个部分。需要解释为什么稀疏图卷积在这里有效,比如处理LiDAR点云的稀疏性
recommend-type

Dwr实现无刷新分页功能的代码与数据库实例

### DWR简介 DWR(Direct Web Remoting)是一个用于允许Web页面中的JavaScript直接调用服务器端Java方法的开源库。它简化了Ajax应用的开发,并使得异步通信成为可能。DWR在幕后处理了所有的细节,包括将JavaScript函数调用转换为HTTP请求,以及将HTTP响应转换回JavaScript函数调用的参数。 ### 无刷新分页 无刷新分页是网页设计中的一种技术,它允许用户在不重新加载整个页面的情况下,通过Ajax与服务器进行交互,从而获取新的数据并显示。这通常用来优化用户体验,因为它加快了响应时间并减少了服务器负载。 ### 使用DWR实现无刷新分页的关键知识点 1. **Ajax通信机制:**Ajax(Asynchronous JavaScript and XML)是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。通过XMLHttpRequest对象,可以与服务器交换数据,并使用JavaScript来更新页面的局部内容。DWR利用Ajax技术来实现页面的无刷新分页。 2. **JSON数据格式:**DWR在进行Ajax调用时,通常会使用JSON(JavaScript Object Notation)作为数据交换格式。JSON是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。 3. **Java后端实现:**Java代码需要编写相应的后端逻辑来处理分页请求。这通常包括查询数据库、计算分页结果以及返回分页数据。DWR允许Java方法被暴露给前端JavaScript,从而实现前后端的交互。 4. **数据库操作:**在Java后端逻辑中,处理分页的关键之一是数据库查询。这通常涉及到编写SQL查询语句,并利用数据库管理系统(如MySQL、Oracle等)提供的分页功能。例如,使用LIMIT和OFFSET语句可以实现数据库查询的分页。 5. **前端页面设计:**前端页面需要设计成能够响应用户分页操作的界面。例如,提供“下一页”、“上一页”按钮,或是分页条。这些元素在用户点击时会触发JavaScript函数,从而通过DWR调用Java后端方法,获取新的分页数据,并动态更新页面内容。 ### 数据库操作的关键知识点 1. **SQL查询语句:**在数据库操作中,需要编写能够支持分页的SQL查询语句。这通常涉及到对特定字段进行排序,并通过LIMIT和OFFSET来控制返回数据的范围。 2. **分页算法:**分页算法需要考虑当前页码、每页显示的记录数以及数据库中记录的总数。SQL语句中的OFFSET计算方式通常为(当前页码 - 1)* 每页记录数。 3. **数据库优化:**在分页查询时,尤其是当数据量较大时,需要考虑到查询效率问题。可以通过建立索引、优化SQL语句或使用存储过程等方式来提高数据库操作的性能。 ### DWR无刷新分页实现的代码要点 1. **DWR配置:**在实现DWR无刷新分页时,首先需要配置DWR,以暴露Java方法给前端JavaScript调用。 2. **JavaScript调用:**编写JavaScript代码,使用DWR提供的API发起Ajax调用。这些调用将触发后端Java方法,并接收返回的分页数据。 3. **数据展示:**在获取到新的分页数据后,需要将这些数据显示在前端页面的相应位置。这通常需要操作DOM元素,将新数据插入到页面中。 ### 结论 通过结合上述知识点,可以使用DWR技术实现一个无刷新分页的动态Web应用。DWR简化了Ajax通信过程,让开发者可以专注于业务逻辑的实现。通过熟练掌握Java后端处理、数据库查询和前端页面设计的相关技术,便能高效地完成无刷新分页的开发任务。
recommend-type

【空间分布规律】:甘肃土壤类型与农业生产的关联性研究

# 摘要 本文对甘肃土壤类型及其在农业生产中的作用进行了系统性研究。首先概述了甘肃土壤类型的基础理论,并探讨了土壤类型与农业生产的理论联系。通过GIS技术分析,本文详细阐述了甘肃土壤的空间分布规律,并对其特征和影响因素进行了深入分析。此外,本文还研究了甘肃土壤类型对农业生产实际影响,包括不同区域土壤改良和作物种植案例,以及土壤养分、水分管理对作物生长周期和产量的具体影响。最后,提出了促进甘肃土壤与农业可持续发展的策略,包括土壤保护、退化防治对策以及土壤类型优化与农业创新的结合。本文旨在为
recommend-type

缓存延迟双删的实际解决方案通常怎么实现

<think>嗯,用户问的是关于缓存延迟双删的最佳实践和实际解决方案。首先,我需要回忆一下延迟双删的基本概念。根据引用[1]和[2],延迟双删主要是为了解决数据库和缓存之间的数据不一致问题,尤其是在分布式系统中。核心步骤应该是先删除缓存,再更新数据库,然后延迟一段时间再次删除缓存。但具体怎么操作呢? 用户可能已经知道延迟双删的基本思想,但需要更详细的步骤和注意事项。比如,为什么要延迟?延迟多久合适?这些都需要解释清楚。引用[3]提到先更新数据库再删除缓存是推荐的方法,但延迟双删可能是在某些特定场景下的优化。 接下来,我得考虑实现延迟双删的具体步骤。首先,第一次删除缓存是为了避免旧数据被后续
recommend-type

企业内部文档管理平台使用Asp.net技术构建

标题和描述中提到的知识点相当丰富,涉及到多个层面的IT技术和管理机制,具体如下: 1. Asp.net技术框架:Asp.net是微软公司开发的一个用于构建动态网站和网络应用程序的服务器端技术。它基于.NET平台,支持使用C#、VB.NET等多种编程语言开发应用程序。Asp.net企业信息文档管理系统使用Asp.net框架,意味着它将利用这一技术平台的特性,比如丰富的类库、集成开发环境(IDE)支持和面向对象的开发模型。 2.TreeView控件:TreeView是一种常用的Web控件,用于在网页上显示具有层次结构的数据,如目录、文件系统或组织结构。该控件通常用于提供给用户清晰的导航路径。在Asp.net企业信息文档管理系统中,TreeView控件被用于实现树状结构的文档管理功能,便于用户通过树状目录快速定位和管理文档。 3.系统模块设计:Asp.net企业信息文档管理系统被划分为多个模块,包括类别管理、文档管理、添加文档、浏览文档、附件管理、角色管理和用户管理等。这些模块化的设计能够让用户根据不同的功能需求进行操作,从而提高系统的可用性和灵活性。 4.角色管理:角色管理是企业信息管理系统中非常重要的一个部分,用于定义不同级别的用户权限和职责。在这个系统中,角色可以进行添加、编辑(修改角色名称)、删除以及上下移动(改变排列顺序)。这些操作满足了对用户权限细分和动态调整的需求。 5.操作逻辑:描述中详细说明了角色管理的操作步骤,如通过按钮选择进行角色的移动、修改和删除,提供了明确的用户交互流程,体现了系统设计的直观性。 6.系统安全性:系统提供了默认的管理帐号和密码(均为51aspx),这通常是一种简便的部署时临时设置。但在实际部署过程中,出于安全考虑,这些默认信息需要立即更改,并定期更新密码以避免潜在的安全风险。 7.文件结构:文件名称列表揭示了系统的文件结构和主要组成部分,比如Global.asax负责应用程序级别的事件处理,Default.aspx和Default.aspx.cs分别对应于系统的默认页面和后台代码文件,Web.Config用于存储和配置应用程序的设置,DocumentManager.sln和DocumentManager.suo分别指出了解决方案文件和解决方案用户选项文件,表明这是一个完整的Visual Studio解决方案。 通过上述知识点的梳理,我们可以看出Asp.net企业信息文档管理系统是一个集成了多个模块,具有良好用户体验设计、清晰操作逻辑和基本安全措施的IT解决方案。它不仅可以提高企业文档管理的效率,还能通过角色的权限管理确保信息的安全性和访问控制的合理性。同时,该系统还遵循了一定的软件工程实践,如模块化设计和配置文件的使用,以保障系统的可维护性和可扩展性。
recommend-type

【制图技术】:甘肃高质量土壤分布TIF图件的成图策略

# 摘要 本文针对甘肃土壤分布数据的TIF图件制作进行了系统研究。首先概述了甘肃土壤的分布情况,接着介绍了TIF图件的基础知识,包括其格式特点、空间数据表达以及质量控制方法。随后,文中构建了成图策略的理论框架,分析了土壤分布图的信息需求与数据处理流程,并探讨了成图原则与标准。在实践操作部分,详细阐述了制图软
recommend-type

化学结构式手写识别的第三方 API

<think>好的,我需要帮助用户找到能够识别化学结构式手写输入的第三方API。首先,用户的需求是化学结构式的手写识别,这比一般的文字识别复杂,因为化学结构式包含复杂的图形和符号,比如环状结构、键线式等。我需要先了解有哪些API支持这种专门的识别功能。 首先,我应该回忆一下常见的OCR(光学字符识别)服务,比如Google Cloud Vision API、Microsoft Azure Computer Vision,但这些可能主要用于普通文字或简单图形的识别,可能无法处理化学结构式。需要更专业的工具。 接下来,考虑化学信息学或化学领域的特定工具。比如ChemDraw有强大的结构式识别功