活动介绍

#include "beep.h" /** * @brief 初始化蜂鸣器引脚 */ void Beep_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStruct.GPIO_Pin = BEEP_GPIO_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(BEEP_GPIO_PORT, &GPIO_InitStruct); } /** * @brief 蜂鸣器报警 */ void Beep_Alert(void) { u8 i = 0; while (i < 10) { GPIO_SetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN); Delay_ms(500); GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN); Delay_ms(500); i++; } } /** * @brief 停止蜂鸣器报警 */ void Beep_Stop(void) { GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN); }程序中的函数怎么调用,()里要不要加viod

时间: 2023-12-06 15:43:01 浏览: 167
调用该函数时,需要在函数名后加上括号,括号中填写该函数需要的参数(如果有的话),如果不需要参数,则不需要在括号中填写任何内容。例如: - 调用 Beep_Init 函数时,应该写成 Beep_Init(); - 调用 Beep_Alert 函数时,应该写成 Beep_Alert(); - 调用 Beep_Stop 函数时,应该写成 Beep_Stop(); 在括号中不需要加上 void,因为 void 表示没有实参,而不是函数不需要实参。
相关问题

怎样在这个main.c中实现exti的初始化/** **************************************************************************************************** * @file main.c * @author 正点原子团队(ALIENTEK) * @version V1.0 * @date 2020-04-20 * @brief 外部中断 实验 * @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司 **************************************************************************************************** * @attention * * 实验平台:正点原子 STM32开发板 * 在线视频:www.yuanzige.com * 技术论坛:www.openedv.com * 公司网址:www.alientek.com * 购买地址:openedv.taobao.com * **************************************************************************************************** */ #include "./stm32f1xx_it.h" #include "./SYSTEM/sys/sys.h" #include "./SYSTEM/usart/usart.h" #include "./SYSTEM/delay/delay.h" #include "./BSP/LED/led.h" #include "./BSP/BEEP/beep.h" #include "./BSP/EXTI/exti.h" int main(void) { HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */ delay_init(72); /* 延时初始化 */ usart_init(115200); /* 串口初始化为115200 */ led_init(); /* 初始化LED */ beep_init(); /* 初始化蜂鸣器 */ extix_init(); /* 初始化外部中断输入 */ LED0(0); /* 先点亮红灯 */ while (1) { printf("OK\r\n"); delay_ms(1000); } }

### 回答问题 根据你提供的`main.c`代码,以下是实现外部中断初始化的完整解决方案。我们需要确保`extix_init`函数被正确调用,并且在`BSP/EXTI/exti.c`中实现具体的外部中断初始化逻辑。 以下是修改后的代码: #### `BSP/EXTI/exti.h` 这是外部中断头文件的定义: ```c #ifndef __EXTI_H__ #define __EXTI_H__ #include "stm32f1xx_hal.h" /** * @brief 初始化外部中断 * @param 无 * @retval 无 */ void extix_init(void); #endif /* __EXTI_H__ */ ``` #### `BSP/EXTI/exti.c` 这是外部中断初始化的实现: ```c #include "exti.h" #include "key.h" // 假设key.h中定义了KEY0、KEY1等宏 #include "led.h" // 假设led.h中定义了LED控制函数 /** * @brief 外部中断初始化程序 * @param 无 * @retval 无 */ void extix_init(void) { GPIO_InitTypeDef gpio_init_struct; // 使能GPIO时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); // 配置KEY0为下降沿触发中断 gpio_init_struct.Pin = KEY0_PIN; gpio_init_struct.Mode = GPIO_MODE_IT_FALLING; gpio_init_struct.Pull = GPIO_PULLUP; HAL_GPIO_Init(KEY0_PORT, &gpio_init_struct); // 配置KEY1为下降沿触发中断 gpio_init_struct.Pin = KEY1_PIN; HAL_GPIO_Init(KEY1_PORT, &gpio_init_struct); // 配置WKUP为上升沿触发中断 gpio_init_struct.Pin = WKUP_PIN; gpio_init_struct.Mode = GPIO_MODE_IT_RISING; gpio_init_struct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(WKUP_PORT, &gpio_init_struct); // 设置中断优先级并使能中断 HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); // KEY0抢占优先级0,子优先级0 HAL_NVIC_EnableIRQ(EXTI0_IRQn); HAL_NVIC_SetPriority(EXTI1_IRQn, 1, 0); // KEY1抢占优先级1,子优先级0 HAL_NVIC_EnableIRQ(EXTI1_IRQn); HAL_NVIC_SetPriority(EXTI2_IRQn, 2, 0); // WKUP抢占优先级2,子优先级0 HAL_NVIC_EnableIRQ(EXTI2_IRQn); } ``` #### `main.c` 以下是主函数的实现,确保调用了`extix_init`函数: ```c #include "./stm32f1xx_it.h" #include "./SYSTEM/sys/sys.h" #include "./SYSTEM/usart/usart.h" #include "./SYSTEM/delay/delay.h" #include "./BSP/LED/led.h" #include "./BSP/BEEP/beep.h" #include "./BSP/EXTI/exti.h" int main(void) { HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */ delay_init(72); /* 延时初始化 */ usart_init(115200); /* 串口初始化为115200 */ led_init(); /* 初始化LED */ beep_init(); /* 初始化蜂鸣器 */ extix_init(); /* 初始化外部中断输入 */ LED0(0); /* 先点亮红灯 */ while (1) { printf("OK\r\n"); delay_ms(1000); } } ``` --- ### 代码解释 1. **`exti.h`文件**: - 定义了`extix_init`函数的原型。 - 包含了必要的头文件(如`stm32f1xx_hal.h`),确保可以使用HAL库的功能。 2. **`exti.c`文件**: - 实现了`extix_init`函数,用于初始化外部中断。 - 使用`KEY0_PIN`、`KEY1_PIN`、`WKUP_PIN`等宏来表示按键对应的GPIO引脚,这些宏通常在`key.h`中定义。 - 配置了三个按键的GPIO模式为中断模式,并设置了触发方式(下降沿或上升沿)。 - 使用`HAL_NVIC_SetPriority`设置中断优先级,并通过`HAL_NVIC_EnableIRQ`使能中断。 3. **`main.c`文件**: - 在主函数中调用了`extix_init`函数,确保外部中断被正确初始化。 - 主循环为空,所有逻辑交由中断处理。 --- ###

#include "./SYSTEM/sys/sys.h" #include "./SYSTEM/delay/delay.h" #include "./BSP/LED/led.h" #include "./BSP/BEEP/beep.h" #include "./BSP/KEY/key.h" #include "./BSP/EXTI/exti.h" 在这个格式下修改

### 修改后的代码 根据你提供的格式,以下是对`exti.h`和`exti.c`文件的修改,确保符合你的项目结构,并实现外部中断初始化功能。 #### `BSP/EXTI/exti.h` 这是外部中断头文件的定义: ```c #ifndef __EXTI_H__ #define __EXTI_H__ #include "stm32f1xx_hal.h" /** * @brief 初始化外部中断 * @param 无 * @retval 无 */ void extix_init(void); #endif /* __EXTI_H__ */ ``` #### `BSP/EXTI/exti.c` 这是外部中断初始化的实现: ```c #include "exti.h" #include "key.h" // 假设key.h中定义了KEY0、KEY1等宏 #include "led.h" // 假设led.h中定义了LED控制函数 /** * @brief 外部中断初始化程序 * @param 无 * @retval 无 */ void extix_init(void) { GPIO_InitTypeDef gpio_init_struct; // 使能GPIO时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); // 配置KEY0为下降沿触发中断 gpio_init_struct.Pin = KEY0_PIN; gpio_init_struct.Mode = GPIO_MODE_IT_FALLING; gpio_init_struct.Pull = GPIO_PULLUP; HAL_GPIO_Init(KEY0_PORT, &gpio_init_struct); // 配置KEY1为下降沿触发中断 gpio_init_struct.Pin = KEY1_PIN; HAL_GPIO_Init(KEY1_PORT, &gpio_init_struct); // 配置WKUP为上升沿触发中断 gpio_init_struct.Pin = WKUP_PIN; gpio_init_struct.Mode = GPIO_MODE_IT_RISING; gpio_init_struct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(WKUP_PORT, &gpio_init_struct); // 设置中断优先级并使能中断 HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); // KEY0抢占优先级0,子优先级0 HAL_NVIC_EnableIRQ(EXTI0_IRQn); HAL_NVIC_SetPriority(EXTI1_IRQn, 1, 0); // KEY1抢占优先级1,子优先级0 HAL_NVIC_EnableIRQ(EXTI1_IRQn); HAL_NVIC_SetPriority(EXTI2_IRQn, 2, 0); // WKUP抢占优先级2,子优先级0 HAL_NVIC_EnableIRQ(EXTI2_IRQn); } ``` --- ### 代码解释 1. **`exti.h`文件**: - 定义了`extix_init`函数的原型。 - 包含了必要的头文件(如`stm32f1xx_hal.h`),确保可以使用HAL库的功能。 2. **`exti.c`文件**: - 实现了`extix_init`函数,用于初始化外部中断。 - 使用`KEY0_PIN`、`KEY1_PIN`、`WKUP_PIN`等宏来表示按键对应的GPIO引脚,这些宏通常在`key.h`中定义。 - 配置了三个按键的GPIO模式为中断模式,并设置了触发方式(下降沿或上升沿)。 - 使用`HAL_NVIC_SetPriority`设置中断优先级,并通过`HAL_NVIC_EnableIRQ`使能中断。 3. **模块化设计**: - 将外部中断的初始化逻辑封装到`BSP/EXTI`目录下,便于管理和复用。 - 通过包含`key.h`和`led.h`等头文件,确保与项目的其他部分无缝集成。 --- ###
阅读全文

相关推荐

这是main.c和usart.c的代码,看看能不能将数字0.1.2正确发送给串口3。main.c代码“#include "./SYSTEM/sys/sys.h" #include "./SYSTEM/usart/usart.h" #include "./SYSTEM/delay/delay.h" #include "./USMART/usmart.h" #include "./BSP/LED/led.h" #include "./BSP/LCD/lcd.h" #include "./BSP/ADC/adc.h" #include "./stm32f1xx_it.h" #include "./BSP/BEEP/beep.h" #include "./BSP/KEY/key.h" #include "./BSP/EXTI/exti.h" #include <math.h> #include <string.h> // 字符串处理 #include <stdarg.h> // 添加变参支持 // 蓝牙相关定义 #define BLE_USART USART3 // 蓝牙使用USART3 #define BLE_BAUDRATE 115200 // 蓝牙模块波特率 #define BLE_CONNECTED_GPIO GPIOA #define BLE_CONNECTED_PIN GPIO_PIN_4 // STA状态引脚PA4 // 震动模式定义(数字形式) #define VIBRATION_OFF 0 // 停止震动 #define VIBRATION_SHORT 1 // 短震动 #define VIBRATION_LONG 2 // 长震动 // 标准定义 #define ADC_DMA_BUF_SIZE 200 /* ADC DMA采集 BUF大小 */ // 震动马达控制引脚定义 #define VIBRATION_MOTOR_PORT GPIOC #define VIBRATION_MOTOR_PIN GPIO_PIN_0 // 震动状态变量 static uint8_t current_vibration_mode = VIBRATION_OFF; static uint32_t last_vibration_time = 0; uint16_t g_adc_dma_buf[ADC_DMA_BUF_SIZE]; /* ADC DMA BUF */ uint8_t sendbuf[20]; uint8_t alert_status = 0; // 0=正常, 1=警告, 2=报警 uint16_t i; uint16_t adc_CO; uint32_t sum; float temp; uint16_t THRESHOLD=100; // 报警阈值 (根据实际传感器量程调整) uint16_t WARN=2; extern uint8_t g_adc_dma_sta; /* DMA传输状态标志, 0,未完成; 1, 已完成 */ //功能 void Check_Alerts(void); void button(void); void ControlVibrationMotor(uint8_t mode); void VibrationMotor_Init(void); void BLE_Init(void); // 蓝牙初始化函数 //void BLE_SendCommand(char cmd); // 蓝牙发送命令函数 uint8_t Is_BLE_Connected(void); // 蓝牙连接状态检测 float adc_to_eField(uint16_t adc_value, float cal_slope, float cal_offset, float v_ref) { // 1. ADC转电压(带数字滤波) static float filtered_voltage = 0.0f; // 滤波后电压值 const float filter_factor = 0.2f; // 低通滤波系数 float raw_voltage = (float)adc_value / 4095.0f * v_ref; filtered_voltage = filtered_voltage * (1 - filter_factor) + raw_voltage * filter_factor; // 2. 应用校准公式(线性转换) float e_field = (filtered_voltage - 0.8) * 100; // 修正零点偏移 // 3. 灵敏度增强处理 const float noise_threshold = 0.05f; // 噪声阈值 if(fabsf(e_field) < noise_threshold) { e_field = 0.0f; // 抑制微小波动 } // 4. 确保物理有效性 e_field = (e_field < 0.0f) ? 0.0f : e_field; return e_field; } void VibrationMotor_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // 使能GPIOC时钟 __HAL_RCC_GPIOC_CLK_ENABLE(); // 配置PC0为推挽输出 GPIO_InitStruct.Pin = VIBRATION_MOTOR_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(VIBRATION_MOTOR_PORT, &GPIO_InitStruct); // 初始状态关闭 HAL_GPIO_WritePin(VIBRATION_MOTOR_PORT, VIBRATION_MOTOR_PIN, GPIO_PIN_RESET); } // 控制震动马达 (简化版) void ControlVibrationMotor(uint8_t mode) { uint32_t current_time = HAL_GetTick(); switch(mode) { case VIBRATION_OFF: HAL_GPIO_WritePin(VIBRATION_MOTOR_PORT, VIBRATION_MOTOR_PIN, GPIO_PIN_RESET); break; case VIBRATION_SHORT: if(current_time - last_vibration_time > 1000) { // 短震动 - 200ms开启 HAL_GPIO_WritePin(VIBRATION_MOTOR_PORT, VIBRATION_MOTOR_PIN, GPIO_PIN_SET); last_vibration_time = current_time; } else if(current_time - last_vibration_time > 200) { HAL_GPIO_WritePin(VIBRATION_MOTOR_PORT, VIBRATION_MOTOR_PIN, GPIO_PIN_RESET); } break; case VIBRATION_LONG: // 长震动 - 持续开启 HAL_GPIO_WritePin(VIBRATION_MOTOR_PORT, VIBRATION_MOTOR_PIN, GPIO_PIN_SET); break; } } // 蓝牙初始化 void BLE_Init(void) { usart_init(115200); /* 串口初始化为115200 */ delay_ms(100); //发送AT指令配置蓝牙模块 u3_printf("AT+UART=115200,8,0,1\r\n"); delay_ms(100); u3_printf("AT+MODE=M\r\n"); // 设置为主设备模式 delay_ms(100); u3_printf("AT+CONNADD=3CAB726F689C\r\n"); // 连接从机MAC地址(需替换) delay_ms(100); u3_printf("AT+AUTOCONN=ON\r\n"); // 开启自动重连*/ } // 发送蓝牙命令 /*void BLE_SendCommand(char cmd) { USART3_RX_STA = 0; if ((uint32_t)cmd <= 0XFF) { while ((USART3->SR & 0X40) == 0); //等待上一次数据发送完成 USART3->DR = (uint32_t)cmd; } else u3_printf("%s\r\n", cmd);//发送命令 }*/ // 检测蓝牙连接状态 uint8_t Is_BLE_Connected(void) { // 当STA引脚为高电平时表示已连接 return HAL_GPIO_ReadPin(BLE_CONNECTED_GPIO, BLE_CONNECTED_PIN); } void Ble_IoInit_Enhanced(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_AFIO_CLK_ENABLE(); __HAL_AFIO_REMAP_SWJ_NOJTAG();// 禁用JTAG但保留SWD调试接口 // WKUP引脚配置PA15 GPIO_InitStruct.Pin = GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // STA引脚配置PA4 GPIO_InitStruct.Pin = GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 唤醒序列 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET); HAL_Delay(50); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET); HAL_Delay(100); usart_init(115200); /* 串口初始化为115200 */ } //主函数 int main(void) { HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */ delay_init(72); /* 延时初始化 */ usart_init(115200); /* 串口初始化为115200 */ // usart3_init(115200); led_init(); /* 初始化LED */ lcd_init(); /* 初始化LCD */ adc_init(); extix_init(); /* 初始化外部中断输入 */ beep_init(); /* 初始化蜂鸣器 */ key_init(); /* 初始化按键 */ VibrationMotor_Init(); BLE_Init(); // 初始化蓝牙模块 Ble_IoInit_Enhanced(); Ble_ReceData(); /* 优化中断优先级设置 */ HAL_NVIC_SetPriority(ADC_ADCX_DMACx_IRQn, 0, 0); // ADC最高优先级 HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 1, 0); // DMA中等优先级 HAL_NVIC_SetPriority(USART3_IRQn, 2, 0); // 蓝牙最低优先级 HAL_NVIC_EnableIRQ(USART3_IRQn); /* 初始化ADC DMA采集 */ adc_dma_init((uint32_t)&g_adc_dma_buf); /* LCD显示初始化 */ lcd_show_string(30, 50, 300, 24, 24, "The system is working.", RED); lcd_show_string(30, 90, 300, 24, 24, "WARN:2 v/m ", BLUE); lcd_show_string(30, 130, 300, 24, 24, "THRESHOLD= 100v/m ", BLUE); lcd_show_string(30, 170, 300, 32, 24, "VALUE: v/m", BLUE); /* 启动ADC DMA采集 */ adc_dma_enable(ADC_DMA_BUF_SIZE); while (1) { Check_Alerts(); button(); ControlVibrationMotor(current_vibration_mode); /* 计算DMA采集到的ADC数据的平均值 */ if (g_adc_dma_sta == 1) { sum = 0; for (i = 0; i < ADC_DMA_BUF_SIZE; i++) /* 累加 */ { sum += g_adc_dma_buf[i]; } adc_CO = sum / ADC_DMA_BUF_SIZE; /* 取平均值 */ temp = adc_to_eField(adc_CO, 0.8f, // 校准斜率 (uT/V) 100.0f, // 校准偏移 (uT) 3.3f); // ADC参考电压 /* 显示结果 */ lcd_show_xnum(120, 170, temp, 4, 24, 0, RED); /* 显示电磁场强度值 */ g_adc_dma_sta = 0; /* 清除DMA采集完成状态标志 */ adc_dma_enable(ADC_DMA_BUF_SIZE); /* 启动下一次ADC DMA采集 */ } HAL_Delay(100); } } void Check_Alerts(void) { char *num0 = "0"; char *num1 = "1"; char *num2 = "2"; if (temp > THRESHOLD) // 超过临界值 { LED0(0); // 红灯亮 current_vibration_mode = VIBRATION_LONG; // 长震动模式 //USART_SendData(USART3, '2');//向串口3发送数据 HAL_UART_Transmit(& g_uart3_handle, (uint8_t*)num2, strlen(num2), 100); while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET); } else if (temp >= WARN && temp <= THRESHOLD) // 警告范围内 { LED1(1); // 绿灯灭 LED0(0); // 红灯亮 current_vibration_mode = VIBRATION_SHORT; // 短震动模式 //USART_SendData(USART3, '1');//向串口3发送数据 HAL_UART_Transmit(& g_uart3_handle, (uint8_t*)num1, strlen(num1), 100); while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET); } else // 正常范围 { LED1(0); // 绿灯亮 LED0(1); // 红灯灭 current_vibration_mode = VIBRATION_OFF; // 停止震动 //USART_SendData(USART3, '0');//向串口3发送数据 HAL_UART_Transmit(& g_uart3_handle, (uint8_t*)num0, strlen(num0), 100); while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET); } // 控制蜂鸣器(可选) if (temp > THRESHOLD) { //BEEP(1); // 报警时蜂鸣器响 } else { BEEP(0); // 正常时蜂鸣器关闭 } } void button(void) { if (KEY1 == 0) // 按键1按下,增加阈值 { HAL_Delay(50); if(THRESHOLD < 150) { THRESHOLD += 10; if(THRESHOLD > 150) THRESHOLD = 150; } lcd_show_xnum(185, 130, THRESHOLD, 4, 24, 0, BLUE); // 更新显示 while (!KEY1); // 等待按键释放 } else if (KEY0 == 0) // 按键0按下,减小阈值 { HAL_Delay(50); if(THRESHOLD > 1) { THRESHOLD -= 10; if(THRESHOLD < 1) THRESHOLD = 1; } lcd_show_xnum(185, 130, THRESHOLD, 4, 24, 0, BLUE); // 更新显示 while (!KEY0); // 等待按键释放 } }”和“#include "./SYSTEM/sys/sys.h" #include "./SYSTEM/usart/usart.h" #include <string.h> #include <stdio.h> #include <stdarg.h> #include "./SYSTEM/delay/delay.h" #define USART_FLAG_CTS ((uint16_t)0x0200) #define USART3_MAX_RECV_LEN 1024 #define USART3_MAX_SEND_LEN 600 uint8_t USART3_RX_BUF[USART3_MAX_RECV_LEN] = {0}; uint8_t USART3_TX_BUF[USART3_MAX_SEND_LEN] = {0}; uint16_t USART3_RX_STA = 0; uint8_t alarm_data = 0; volatile uint8_t usart3_tx_busy; /* 如果使用os,则包括下面的头文件即可. */ #if SYS_SUPPORT_OS #include "os.h" /* os 使用 */ #endif /******************************************************************************************/ /* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */ #if 1 #if (__ARMCC_VERSION >= 6010050) /* 使用AC6编译器时 */ __asm(".global __use_no_semihosting\n\t"); /* 声明不使用半主机模式 */ __asm(".global __ARM_use_no_argv \n\t"); /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */ #else /* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */ #pragma import(__use_no_semihosting) struct __FILE { int handle; }; #endif /* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */ int _ttywrch(int ch) { ch = ch; return ch; } /* 定义_sys_exit()以避免使用半主机模式 */ void _sys_exit(int x) { x = x; } char *_sys_command_string(char *cmd, int len) { return NULL; } /* FILE 在 stdio.h里面定义. */ FILE __stdout; /* MDK下需要重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */ int fputc(int ch, FILE *f) { while ((USART_UX->SR & 0X40) == 0); /* 等待上一个字符发送完成 */ USART_UX->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */ return ch; } #endif /******************************************************************************************/ void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)//给串口发送数据的函数 { assert_param(IS_USART_ALL_PERIPH(USART3)); assert_param(IS_USART_DATA(Data)); USART3->DR = (Data & (uint16_t)0x01FF); } FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)//状态检测函数 { FlagStatus bitstatus = RESET; assert_param(IS_USART_ALL_PERIPH(USART3)); assert_param(IS_USART_FLAG(USART_FLAG)); if (USART_FLAG == USART_FLAG_CTS) { assert_param(IS_USART_123_PERIPH(USART3)); } if ((USART3->SR & USART_FLAG) != (uint16_t)RESET) { bitstatus = SET; } else { bitstatus = RESET; } return bitstatus; } void u3_printf(char *fmt, ...) { uint16_t i, j; va_list ap; va_start(ap, fmt); vsprintf((char *)USART3_TX_BUF, fmt, ap); va_end(ap); i = strlen((const char *)USART3_TX_BUF); //此次发送数据的长度 for (j = 0; j < i; j++) //循环发送数据 { while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET); //循环发送,直到发送完毕 USART_SendData(USART3, USART3_TX_BUF[j]); } } void Ble_ReceData(void)//蓝牙接收数据处理 { uint16_t i = 0; uint16_t len = 0; //有数据来了 if (USART3_RX_STA & 0x8000) { len = USART3_RX_STA & 0X7FFF; USART3_RX_BUF[len] = 0; //添加结束符 USART3_RX_STA = 0; printf("R:"); for (i = 0; i < len; i++) { while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET); //循环发送,直到发送完毕 USART_SendData(USART3, USART3_RX_BUF[i]); } memset((char *)USART3_RX_BUF, 0x00, len); //串口接收缓冲区清0 u3_printf("\r\n"); } } //////////////////////////////////////////////////////////////////// #if USART_EN_RX /*如果使能了接收*/ /* 接收缓冲, 最大USART_REC_LEN个字节. */ uint8_t g_usart_rx_buf[USART_REC_LEN]; uint16_t g_usart_rx_sta = 0; uint8_t g_rx_buffer[RXBUFFERSIZE]; /* HAL库使用的串口接收缓冲 */ UART_HandleTypeDef g_uart3_handle; /* UART句柄 */ /*串口X初始化函数*/ void usart_init(uint32_t baudrate) { /*UART 初始化设置*/ g_uart3_handle.Instance = USART_UX; /* USART_UX */ g_uart3_handle.Init.BaudRate = baudrate; /* 波特率 */ g_uart3_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */ g_uart3_handle.Init.StopBits = UART_STOPBITS_1; /* 一个停止位 */ g_uart3_handle.Init.Parity = UART_PARITY_NONE; /* 无奇偶校验位 */ g_uart3_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */ g_uart3_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */ HAL_UART_Init(&g_uart3_handle); /* HAL_UART_Init()会使能UART1 */ /* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */ HAL_UART_Receive_IT(&g_uart3_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE); } /** * @brief UART底层初始化函数 * @param huart: UART句柄类型指针 * @note 此函数会被HAL_UART_Init()调用 * 完成时钟使能,引脚配置,中断配置 * @retval 无 */ void HAL_UART_MspInit(UART_HandleTypeDef *huart) { GPIO_InitTypeDef gpio_init_struct; if (huart->Instance == USART_UX) /* 如果是串口3,进行串口3 MSP初始化 */ { USART_TX_GPIO_CLK_ENABLE(); /* 使能串口TX脚时钟 */ USART_RX_GPIO_CLK_ENABLE(); /* 使能串口RX脚时钟 */ USART_UX_CLK_ENABLE(); /* 使能串口时钟 */ gpio_init_struct.Pin = USART_TX_GPIO_PIN; /* 串口发送引脚号 */ gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */ gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* IO速度设置为高速 */ HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Pin = USART_RX_GPIO_PIN; /* 串口RX脚 模式设置 */ gpio_init_struct.Mode = GPIO_MODE_AF_INPUT; HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct); /* 串口RX脚 必须设置成输入模式 */ #if USART_EN_RX HAL_NVIC_EnableIRQ(USART_UX_IRQn); /* 使能USART3中断通道 */ HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3); /* 组2,最低优先级:抢占优先级3,子优先级3 */ #endif } } /** * @brief 串口数据接收回调函数 数据处理在这里进行 * @param huart:串口句柄 * @retval 无 */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { uint8_t usart3_tx_busy = 0; // 发送状态标志 if (huart->Instance == USART_UX) /* 如果是串口1 */ { if ((g_usart_rx_sta & 0x8000) == 0) /* 接收未完成 */ { if (g_usart_rx_sta & 0x4000) /* 接收到了0x0d(即回车键) */ { if (g_rx_buffer[0] != 0x0a) /* 接收到的不是0x0a(即不是换行键) */ { g_usart_rx_sta = 0; /* 接收错误,重新开始 */ } else /* 接收到的是0x0a(即换行键) */ { g_usart_rx_sta |= 0x8000; /* 接收完成了 */ } } else /* 还没收到0X0d(即回车键) */ { if (g_rx_buffer[0] == 0x0d) g_usart_rx_sta |= 0x4000; else { g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0]; g_usart_rx_sta++; if (g_usart_rx_sta > (USART_REC_LEN - 1)) { g_usart_rx_sta = 0; /* 接收数据错误,重新开始接收 */ } } } } usart3_tx_busy = 0; // 清除发送忙标志 HAL_UART_Receive_IT(&g_uart3_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE); } } // 发送完成回调函数 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART3) { usart3_tx_busy = 0; // 清除发送忙标志 } } /** * @brief 串口1中断服务函数 * @param 无 * @retval 无 */ void USART_UX_IRQHandler(void) { #if SYS_SUPPORT_OS /* 使用OS */ OSIntEnter(); #endif HAL_UART_IRQHandler(&g_uart3_handle); /* 调用HAL库中断处理公用函数 */ #if SYS_SUPPORT_OS /* 使用OS */ OSIntExit(); #endif } #endif”

/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /* 作者:嗨小易(QQVIP群2:570487280) B站:https://space.bilibili.com/444388619/video 版权:本教程版权归嗨小易所有,未经授权不得转载、摘编或用于其他商业用途!!! 一经发现,后果自负!!! */ #include "key.h" #include "SysTick.h" /******************************************************************************* * 函 数 名 : KEY_Init * 函数功能 : 按键初始化 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void KEY_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitStructure.GPIO_Pin=KEY1_PIN|KEY2_PIN|KEY3_PIN|KEY4_PIN; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉输入 GPIO_Init(KEY_PORT,&GPIO_InitStructure); } /******************************************************************************* * 函 数 名 : KEY_Scan * 函数功能 : 按键扫描检测 * 输 入 : mode=0:单次按下按键 mode=1:连续按下按键 * 输 出 : 0:未有按键按下 KEY_UP_PRESS:KEY_UP键按下 KEY0_PRESS:KEY0键按下 KEY1_PRESS:KEY1键按下 KEY2_PRESS:KEY2键按下 *******************************************************************************/ u8 KEY_Scan(u8 mode) { static u8 key=1; if(mode==1) //连续按键按下 key=1; if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0)) //任意一个按键按下 { delay_ms(1); //消抖 key=0; if(KEY1==0) return KEY1_PRESS; else if(KEY2==0) return KEY2_PRESS; else if(KEY3==0) return KEY3_PRESS; else if(KEY4==0) return KEY4_PRESS; } else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1) //无按键按下 key=1; return 0; } //矩阵按键端口初始化 void key_matrix_init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); 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_Mode=GPIO_Mode_IPU; GPIO_Init(GPIOA,&GPIO_InitStructure); } /******************************************************************************* * 函 数 名 : key_matrix_flip_scan * 函数功能 : 使用线翻转扫描方法,检测矩阵按键是否按下,按下则返回对应键值 * 输 入 : 无 * 输 出 : key_value:1-16,对应S1-S16键, 0:按键未按下 *******************************************************************************/ u8 key_matrix_flip_scan(void) { static u8 key_value=0; KEY_MATRIX_PORT_OUT(0x0f);//给所有行赋值0,列全为1 if(KEY_MATRIX_PORT_READ!=0x0f)//判断按键是否按下 { delay_10us(1000);//消抖 if(KEY_MATRIX_PORT_READ!=0x0f) { //测试列 KEY_MATRIX_PORT_OUT(0x0f); switch(KEY_MATRIX_PORT_READ)//保存行为0,按键按下后的列值 { case 0x07: key_value=1;break; case 0x0b: key_value=2;break; case 0x0d: key_value=3;break; case 0x0e: key_value=4;break; } //测试行 KEY_MATRIX_PORT_OUT(0xf0); switch(KEY_MATRIX_PORT_READ)//保存列为0,按键按下后的键值 { case 0x70: key_value=key_value;break; case 0xb0: key_value=key_value+4;break; case 0xd0: key_value=key_value+8;break; case 0xe0: key_value=key_value+12;break; } while(KEY_MATRIX_PORT_READ!=0xf0);//等待按键松开 } } else key_value=0; return key_value; } /* 作者:嗨小易(QQVIP群2:570487280) B站:https://space.bilibili.com/444388619/video 版权:本教程版权归嗨小易所有,未经授权不得转载、摘编或用于其他商业用途!!! 一经发现,后果自负!!! */ #include "smg.h" #include "SysTick.h" //共阴极数码管显示0~F的段码数据 u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //数码管端口初始化 void smg_init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(LSA_PORT_RCC,ENABLE); RCC_APB2PeriphClockCmd(LSB_PORT_RCC,ENABLE); RCC_APB2PeriphClockCmd(LSC_PORT_RCC,ENABLE); RCC_APB2PeriphClockCmd(SMG_DATAPORT_PORT_RCC,ENABLE); GPIO_InitStructure.GPIO_Pin=LSA_PIN; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(LSA_PORT,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=LSB_PIN; GPIO_Init(LSB_PORT,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=LSC_PIN; GPIO_Init(LSC_PORT,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=SMG_DATAPORT_PIN; GPIO_Init(SMG_DATAPORT_PORT,&GPIO_InitStructure); } /******************************************************************************* * 函 数 名 : smg_display * 函数功能 : 动态数码管显示 * 输 入 : dat:要显示的数据 pos:从左开始第几个位置开始显示,范围1-8 * 输 出 : 无 *******************************************************************************/ void smg_display(u8 dat[],u8 pos) { u8 i=0; u8 pos_temp=pos-1; for(i=pos_temp;i<8;i++) { switch(i)//位选 { case 0: LSC=1;LSB=1;LSA=1;break; case 1: LSC=1;LSB=1;LSA=0;break; case 2: LSC=1;LSB=0;LSA=1;break; case 3: LSC=1;LSB=0;LSA=0;break; case 4: LSC=0;LSB=1;LSA=1;break; case 5: LSC=0;LSB=1;LSA=0;break; case 6: LSC=0;LSB=0;LSA=1;break; case 7: LSC=0;LSB=0;LSA=0;break; } SMG_DATAPORT(dat[i-pos_temp]);//传送段选数据 delay_10us(100);//延时一段时间,等待显示稳定 // SMG_DATAPORT(0x00);//消音 } } /* 作者:嗨小易(QQVIP群2:570487280) B站:https://space.bilibili.com/444388619/video 版权:本教程版权归嗨小易所有,未经授权不得转载、摘编或用于其他商业用途!!! 一经发现,后果自负!!! */ #include "beep.h" #include "SysTick.h" /******************************************************************************* * 函 数 名 : BEEP_Init * 函数功能 : 蜂鸣器初始化 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void BEEP_Init(void) //端口初始化 { GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量,用来初始化GPIO RCC_APB2PeriphClockCmd(BEEP_PORT_RCC,ENABLE); /* 开启GPIO时钟 */ /* 配置GPIO的模式和IO口 */ GPIO_InitStructure.GPIO_Pin=BEEP_PIN; //选择你要设置的IO口 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //设置推挽输出模式 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率 GPIO_Init(BEEP_PORT,&GPIO_InitStructure); /* 初始化GPIO */ GPIO_SetBits(BEEP_PORT,BEEP_PIN); } /******************************************************************************* * 函 数 名 : beep_alarm * 函数功能 : 蜂鸣器报警函数 * 输 入 : time:报警持续时间 fre:报警频率 * 输 出 : 无 *******************************************************************************/ void beep_alarm(u16 time,u16 fre) { while(time--) { BEEP=!BEEP; delay_10us(fre); } BEEP=1; } 将这些代码整合到上述工程中,以实现简易计算器,主要功能如下: 1、加减乘除运算 2、小数显示 3、按键提示音 4、数码管显示

现在的情况还是。把程序下载到实物中后,酒精浓度一开始不能显示到初始值,而是直接到达44,而且传感器数值增加明显(过于灵敏),不能 实时的显示具体酒精浓度,例如我用医用浓度为70~75%酒精浓度的棉片进行检测,但是过于靠近传感器的话会直接把酒精浓度飙到100,以下是我的主程序,我应该怎样进行修改和优化来解决这几个问题:/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : 主程序文件 ****************************************************************************** * @attention * 硬件配置:STM32F103C8T6最小系统板 + 酒精传感器 + 4位独立键盘 + OLED显示屏 + 蜂鸣器 ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ /* 头文件引用 */ #include "main.h" #include "adc.h" #include "tim.h" #include "usart.h" #include "gpio.h" /* 自定义头文件 */ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "./HAL/key/key.h" // 键盘驱动 #include "./HAL/OLED/OLED_NEW.H" // OLED驱动 #include "./HAL/DELAY/delay.h" // 延时函数 #include "./HAL/ds18b20/ds18b20.h" // 温度传感器驱动(当前未使用) #include <stdlib.h> // 添加 abs 函数声明 /* USER CODE END Includes */ /*---------------------------- 函数声明 --------------------------------*/ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ void Key_function(void); //按键设置函数 void Monitor_function(void); //传感器监测函数 void Display_function(void); //OLED显示函数 void Manage_function(void); //报警处理函数 /* USER CODE END PTD */ /*---------------------------- 宏定义与硬件抽象 ------------------------*/ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define RELAY(a) (a?HAL_GPIO_WritePin(RELAY_GPIO_Port, RELAY_Pin, GPIO_PIN_SET):HAL_GPIO_WritePin(RELAY_GPIO_Port, RELAY_Pin, GPIO_PIN_RESET)) //继电器控制宏(当前未启用) #define BEEP(a) HAL_GPIO_WritePin(BEEP_GPIO_Port, BEEP_Pin, (a) ? GPIO_PIN_RESET : GPIO_PIN_SET) //蜂鸣器控制宏(低电

/* USER CODE BEGIN Header */ /** ****************************************************************************** * File Name : freertos.c * Description : Code for freertos applications ****************************************************************************** * @attention * *
© Copyright (c) 2025 STMicroelectronics. * All rights reserved.
* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "FreeRTOS.h" #include "task.h" #include "main.h" #include "cmsis_os.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include <stdio.h> extern TIM_HandleTypeDef htim3; /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN Variables */ /* USER CODE END Variables */ osThreadId defaultTaskHandle; osThreadId myTask_KEYHandle; osThreadId myTask01Handle; osThreadId myTask02Handle; osThreadId myTask_ButtonHandle; osThreadId myTask_EventHanHandle; osMessageQId myQueue01Handle; osMessageQId EventQueueHandle; /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN FunctionPrototypes */ /* USER CODE END FunctionPrototypes */ void StartDefaultTask(void const * argument); void StartTask_KEY(void const * argument); void StartTask01(void const * argument); void StartTask02(void const * argument); void StartTask_Button(void const * argument); void StartTask_EventHandler(void const * argument); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ /* GetIdleTaskMemory prototype (linked to static allocation support) */ void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ); /* USER CODE BEGIN GET_IDLE_TASK_MEMORY */ static StaticTask_t xIdleTaskTCBBuffer; static StackType_t xIdleStack[configMINIMAL_STACK_SIZE]; void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) { *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer; *ppxIdleTaskStackBuffer = &xIdleStack[0]; *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* place for user code */ } /* USER CODE END GET_IDLE_TASK_MEMORY */ /** * @brief FreeRTOS initialization * @param None * @retval None */ void MX_FREERTOS_Init(void) { /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* USER CODE BEGIN RTOS_MUTEX */ /* add mutexes, ... */ /* USER CODE END RTOS_MUTEX */ /* USER CODE BEGIN RTOS_SEMAPHORES */ /* add semaphores, ... */ /* USER CODE END RTOS_SEMAPHORES */ /* USER CODE BEGIN RTOS_TIMERS */ /* start timers, add new ones, ... */ /* USER CODE END RTOS_TIMERS */ /* Create the queue(s) */ /* definition and creation of myQueue01 */ osMessageQDef(myQueue01, 16, uint32_t); myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL); /* definition and creation of EventQueue */ osMessageQDef(EventQueue, 16, uint32_t); EventQueueHandle = osMessageCreate(osMessageQ(EventQueue), NULL); /* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ /* USER CODE END RTOS_QUEUES */ /* Create the thread(s) */ /* definition and creation of defaultTask */ osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128); defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL); /* definition and creation of myTask_KEY */ osThreadDef(myTask_KEY, StartTask_KEY, osPriorityHigh, 0, 128); myTask_KEYHandle = osThreadCreate(osThread(myTask_KEY), NULL); /* definition and creation of myTask01 */ osThreadDef(myTask01, StartTask01, osPriorityNormal, 0, 128); myTask01Handle = osThreadCreate(osThread(myTask01), NULL); /* definition and creation of myTask02 */ osThreadDef(myTask02, StartTask02, osPriorityLow, 0, 128); myTask02Handle = osThreadCreate(osThread(myTask02), NULL); /* definition and creation of myTask_Button */ osThreadDef(myTask_Button, StartTask_Button, osPriorityNormal, 0, 128); myTask_ButtonHandle = osThreadCreate(osThread(myTask_Button), NULL); /* definition and creation of myTask_EventHan */ osThreadDef(myTask_EventHan, StartTask_EventHandler, osPriorityHigh, 0, 128); myTask_EventHanHandle = osThreadCreate(osThread(myTask_EventHan), NULL); /* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ if (myTask_EventHanHandle == NULL) { printf("事件处理任务创建失败!\n"); } else { printf("事件处理任务创建成功!\n"); } /* USER CODE END RTOS_THREADS */ } /* USER CODE BEGIN Header_StartDefaultTask */ /** * @brief Function implementing the defaultTask thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartDefaultTask */ void StartDefaultTask(void const * argument) { /* USER CODE BEGIN StartDefaultTask */ /* Infinite loop */ for(;;) { osDelay(1); } /* USER CODE END StartDefaultTask */ } /* USER CODE BEGIN Header_StartTask_KEY */ /** * @brief Function implementing the myTask_KEY thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartTask_KEY */ void StartTask_KEY(void const * argument) { /* USER CODE BEGIN StartTask_KEY */ uint32_t ProducerValue = 0; DataGroup myDataGroup_t = {10, 20, 30}; ProducerValue = (uint32_t)&myDataGroup_t; /* Infinite loop */ for(;;) { if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) { osDelay(10); // 消抖 if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) { if (osMessagePut(myQueue01Handle, ProducerValue, 0) != osOK) { osThreadSuspendAll(); printf("发送失败\r\n"); osThreadResumeAll(); } else { osThreadSuspendAll(); printf("发送成功\r\n"); osThreadResumeAll(); } while (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) { osDelay(10); // 等待按键释放 } } } osDelay(10); } /* USER CODE END StartTask_KEY */ } /* USER CODE BEGIN Header_StartTask01 */ /** * @brief Function implementing the myTask01 thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartTask01 */ void StartTask01(void const * argument) { /* USER CODE BEGIN StartTask01 */ DataGroup *myDataGroup_r; osEvent event; /* Infinite loop */ for(;;) { event = osMessagePeek(myQueue01Handle, osWaitForever); if (event.status == osEventMessage) { myDataGroup_r = (DataGroup *)event.value.p; osThreadSuspendAll(); printf("任务1读取数据:var1 = %lu, var2 = %lu, var3 = %lu\r\n", myDataGroup_r->var1, myDataGroup_r->var2, myDataGroup_r->var3); osThreadResumeAll(); } osDelay(100); // 延时避免刷屏 } /* USER CODE END StartTask01 */ } /* USER CODE BEGIN Header_StartTask02 */ /** * @brief Function implementing the myTask02 thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartTask02 */ void StartTask02(void const * argument) { /* USER CODE BEGIN StartTask02 */ osEvent event; DataGroup *myDataGroup_r; /* Infinite loop */ for(;;) { event = osMessageGet(myQueue01Handle, osWaitForever); if (event.status == osEventMessage) { myDataGroup_r = (DataGroup *)event.value.p; osThreadSuspendAll(); printf("任务2读取数据:var1 = %lu, var2 = %lu, var3 = %lu\r\n", myDataGroup_r->var1, myDataGroup_r->var2, myDataGroup_r->var3); osThreadResumeAll(); } osDelay(100); // 延时避免刷屏; } /* USER CODE END StartTask02 */ } /* USER CODE BEGIN Header_StartTask_Button */ /** * @brief Function implementing the myTask_Button thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartTask_Button */ void StartTask_Button(void const * argument) { /* USER CODE BEGIN StartTask_Button */ // uint8_t key_state = 1; /* Infinite loop */ for(;;) { if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_14) == GPIO_PIN_RESET) { osDelay(20); // 消抖 if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_14) == GPIO_PIN_RESET) { // 简单轮流发送两种事件 static uint8_t toggle = 0; EventType evt; switch (toggle) { case 0: evt = EVENT_LED_ON; break; case 1: evt = EVENT_LED_OFF; break; case 2: evt = EVENT_BUZZER_BEEP; break; } toggle = (toggle + 1) % 3; osMessagePut(EventQueueHandle, (uint32_t)evt, 0); printf("按键按下,发送事件:%d\n", evt); while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_14) == GPIO_PIN_RESET) osDelay(10); } } osDelay(10); } /* USER CODE END StartTask_Button */ } /* USER CODE BEGIN Header_StartTask_EventHandler */ /** * @brief Function implementing the myTask_EventHan thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartTask_EventHandler */ void StartTask_EventHandler(void const * argument) { /* USER CODE BEGIN StartTask_EventHandler */ printf("事件处理任务启动!\n"); // 确认任务是否真正运行 osDelay(10); // 给输出时间 osEvent event; /* Infinite loop */ for(;;) { event = osMessageGet(EventQueueHandle, osWaitForever); if (event.status == osEventMessage) { EventType evt = (EventType)event.value.v; printf("接收到事件值:%d\n", evt); // 新增打印 osDelay(10); // 给串口输出缓冲点时间 switch (evt) { case EVENT_LED_ON: HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); printf("事件:LED ON\n"); break; case EVENT_LED_OFF: HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); printf("事件:LED OFF\n"); break; case EVENT_BUZZER_BEEP: printf("事件:蜂鸣器响\n"); break; default: printf("未知事件:%d\n", evt); // 如果是未定义的值会打印这里 break; } } osDelay(10); } /* USER CODE END StartTask_EventHandler */ } /* Private application code --------------------------------------------------*/ /* USER CODE BEGIN Application */ /* USER CODE END Application */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 添加事件3蜂鸣器响一下的程序

完成一个仓储环境监测的模拟系统。具体要求如下: 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,用标准库

最新推荐

recommend-type

基于西门子S7-300 PLC的全自动生产线包装机设计与实现

基于西门子S7-300 PLC的全自动生产线包装机的设计与实现。主要内容涵盖硬件配置、IO表设计、源程序编写、单机组态以及一些实用技巧。文中特别强调了心跳检测机制、机械手定位精度控制、硬件连接质量对系统稳定性的影响,以及IO信号滤波参数设置的重要性。通过具体的代码实例展示了如何确保系统的可靠性和稳定性。 适合人群:从事工业自动化领域的工程师和技术人员,特别是那些需要深入了解PLC控制系统设计的人群。 使用场景及目标:适用于希望提升PLC编程技能、优化自动化生产线性能的专业人士。目标是帮助读者掌握从硬件选型到软件编程的全流程设计方法,提高生产效率和产品质量。 其他说明:本文不仅提供了详细的理论解释,还分享了许多实践经验,如心跳检测代码、机械手定位控制、信号滤波等,有助于解决实际项目中遇到的问题。
recommend-type

西门子S7-1516 CPU控制的博途热力发电厂汽轮机WINCC 7.5画面案例

内容概要:本文介绍了西门子S7-1516 CPU和WINCC 7.5在热力发电厂汽轮机控制系统中的具体应用。首先展示了工艺流程图,详细解释了汽轮机的工作过程及其控制逻辑。接着解析了电仪设计EPLAN图,展示了传感器和执行器的布局及连接方式。随后分析了控制逻辑代码,说明了如何根据蒸汽参数(如压力、流量和温度)调整电机功率。最后介绍了博图版本V16的强大功能,强调其在监控、控制、数据分析和故障诊断方面的作用。 适合人群:从事工业自动化领域的工程师和技术人员,特别是熟悉西门子产品线的专业人士。 使用场景及目标:适用于需要详细了解热力发电厂汽轮机控制系统的设计、实施和维护的技术人员。目标是帮助他们掌握最新的技术和方法,提高系统的稳定性和效率。 其他说明:文中不仅提供了详细的理论分析,还有实际操作案例,有助于读者更好地理解和应用相关技术。
recommend-type

BLDC无刷直流电机Simulink转速电流双闭环调速系统仿真设计

BLDC无刷直流电机在Matlab Simulink环境下的仿真设计,特别是针对转速和电流双闭环调速系统的建模与仿真。首先解释了为什么需要进行BLDC电机的仿真设计及其优势,接着简述了Simulink仿真环境的特点和功能。然后重点讲解了双闭环调速系统的具体设计方法,包括转速外环的PID控制器和电流内环的PWM技术。最后展示了仿真过程中的关键步骤和结果分析,并附带了一些简单的代码片段供参考。 适合人群:从事电机控制系统研究或开发的技术人员,尤其是对BLDC电机感兴趣的研究者和工程师。 使用场景及目标:适用于希望深入了解BLDC电机控制机制的人群,旨在帮助他们掌握如何使用Simulink进行电机仿真的技能,从而提高实际项目中的设计能力。 其他说明:文中提供的代码片段仅为示例,实际操作时需参照完整文档和技术手册。此外,随着技术进步,BLDC电机的应用范围将进一步扩大,其仿真技术和控制策略也会持续改进。
recommend-type

Visual C++.NET编程技术实战指南

根据提供的文件信息,可以生成以下知识点: ### Visual C++.NET编程技术体验 #### 第2章 定制窗口 - **设置窗口风格**:介绍了如何通过编程自定义窗口的外观和行为。包括改变窗口的标题栏、边框样式、大小和位置等。这通常涉及到Windows API中的`SetWindowLong`和`SetClassLong`函数。 - **创建六边形窗口**:展示了如何创建一个具有特殊形状边界的窗口,这类窗口不遵循标准的矩形形状。它需要使用`SetWindowRgn`函数设置窗口的区域。 - **创建异形窗口**:扩展了定制窗口的内容,提供了创建非标准形状窗口的方法。这可能需要创建一个不规则的窗口区域,并将其应用到窗口上。 #### 第3章 菜单和控制条高级应用 - **菜单编程**:讲解了如何创建和修改菜单项,处理用户与菜单的交互事件,以及动态地添加或删除菜单项。 - **工具栏编程**:阐述了如何使用工具栏,包括如何创建工具栏按钮、分配事件处理函数,并实现工具栏按钮的响应逻辑。 - **状态栏编程**:介绍了状态栏的创建、添加不同类型的指示器(如文本、进度条等)以及状态信息的显示更新。 - **为工具栏添加皮肤**:展示了如何为工具栏提供更加丰富的视觉效果,通常涉及到第三方的控件库或是自定义的绘图代码。 #### 第5章 系统编程 - **操作注册表**:解释了Windows注册表的结构和如何通过程序对其进行读写操作,这对于配置软件和管理软件设置非常关键。 - **系统托盘编程**:讲解了如何在系统托盘区域创建图标,并实现最小化到托盘、从托盘恢复窗口的功能。 - **鼠标钩子程序**:介绍了钩子(Hook)技术,特别是鼠标钩子,如何拦截和处理系统中的鼠标事件。 - **文件分割器**:提供了如何将文件分割成多个部分,并且能够重新组合文件的技术示例。 #### 第6章 多文档/多视图编程 - **单文档多视**:展示了如何在同一个文档中创建多个视图,这在文档编辑软件中非常常见。 #### 第7章 对话框高级应用 - **实现无模式对话框**:介绍了无模式对话框的概念及其应用场景,以及如何实现和管理无模式对话框。 - **使用模式属性表及向导属性表**:讲解了属性表的创建和使用方法,以及如何通过向导性质的对话框引导用户完成多步骤的任务。 - **鼠标敏感文字**:提供了如何实现点击文字触发特定事件的功能,这在阅读器和编辑器应用中很有用。 #### 第8章 GDI+图形编程 - **图像浏览器**:通过图像浏览器示例,展示了GDI+在图像处理和展示中的应用,包括图像的加载、显示以及基本的图像操作。 #### 第9章 多线程编程 - **使用全局变量通信**:介绍了在多线程环境下使用全局变量进行线程间通信的方法和注意事项。 - **使用Windows消息通信**:讲解了通过消息队列在不同线程间传递信息的技术,包括发送消息和处理消息。 - **使用CriticalSection对象**:阐述了如何使用临界区(CriticalSection)对象防止多个线程同时访问同一资源。 - **使用Mutex对象**:介绍了互斥锁(Mutex)的使用,用以同步线程对共享资源的访问,保证资源的安全。 - **使用Semaphore对象**:解释了信号量(Semaphore)对象的使用,它允许一个资源由指定数量的线程同时访问。 #### 第10章 DLL编程 - **创建和使用Win32 DLL**:介绍了如何创建和链接Win32动态链接库(DLL),以及如何在其他程序中使用这些DLL。 - **创建和使用MFC DLL**:详细说明了如何创建和使用基于MFC的动态链接库,适用于需要使用MFC类库的场景。 #### 第11章 ATL编程 - **简单的非属性化ATL项目**:讲解了ATL(Active Template Library)的基础使用方法,创建一个不使用属性化组件的简单项目。 - **使用ATL开发COM组件**:详细阐述了使用ATL开发COM组件的步骤,包括创建接口、实现类以及注册组件。 #### 第12章 STL编程 - **list编程**:介绍了STL(标准模板库)中的list容器的使用,讲解了如何使用list实现复杂数据结构的管理。 #### 第13章 网络编程 - **网上聊天应用程序**:提供了实现基本聊天功能的示例代码,包括客户端和服务器的通信逻辑。 - **简单的网页浏览器**:演示了如何创建一个简单的Web浏览器程序,涉及到网络通信和HTML解析。 - **ISAPI服务器扩展编程**:介绍了如何开发ISAPI(Internet Server API)服务器扩展来扩展IIS(Internet Information Services)的功能。 #### 第14章 数据库编程 - **ODBC数据库编程**:解释了ODBC(开放数据库互联)的概念,并提供了使用ODBC API进行数据库访问的示例。 - **ADO编程**:介绍了ADO(ActiveX Data Objects)技术,讲解了如何使用ADO进行数据库的增删改查等操作。 #### 第15章 HTML帮助系统编程 - **创建HTML帮助文件**:讲解了如何创建HTML帮助文件(.chm),这是微软帮助系统的一种形式。 - **区分上下文帮助**:提供了在应用程序中实现上下文敏感帮助的技术示例。 #### 第16章 安装和部署项目 - **用安装程序向导创建安装项目**:介绍了如何使用Visual Studio中的安装和部署项目向导,快速创建安装程序。 - **部署应用程序**:阐述了部署应用程序到目标系统的过程,以及如何确保应用程序的正确安装和运行。 以上内容涵盖了Visual C++.NET编程技术体验一书中涉及的各个技术点,并对每个章节中的示例做了详细的说明。这些知识点对于理解和掌握Visual C++.NET编程非常重要,并能够帮助读者在实际项目开发中应用这些技术。
recommend-type

HarmonyOS内核深度探秘:优化自由行旅游系统的策略

# 1. HarmonyOS内核概述与旅游系统需求分析 ## 1.1 HarmonyOS内核概述 HarmonyOS(鸿蒙操作系统)是由华为开发的一个分布式操作系统,旨在提供跨多种设备的无缝体验。其内核设计理念强调高效、安全和模块化,以微内核架构和分布式能力
recommend-type

tkinter模块所有控件

<think>好的,我现在需要回答用户关于Tkinter模块中所有控件列表的问题。首先,我需要回忆Tkinter的基础知识,确保自己了解各个控件的名称和用途。用户希望得到所有支持的控件列表,所以必须全面覆盖,不能遗漏。 首先,我应该从Tkinter的标准控件开始。常见的控件包括Label、Button、Entry这些基础部件。然后是Frame,用于布局,还有Canvas用于绘图。接下来是Checkbutton、Radiobutton,这些属于选择类控件。Listbox和Scrollbar通常一起使用,处理滚动内容。还有Scale(滑块)、Spinbox、Menu、Menubutton这些可能
recommend-type

局域网五子棋游戏:娱乐与聊天的完美结合

标题“网络五子棋”和描述“适合于局域网之间娱乐和聊天!”以及标签“五子棋 网络”所涉及的知识点主要围绕着五子棋游戏的网络版本及其在局域网中的应用。以下是详细的知识点: 1. 五子棋游戏概述: 五子棋是一种两人对弈的纯策略型棋类游戏,又称为连珠、五子连线等。游戏的目标是在一个15x15的棋盘上,通过先后放置黑白棋子,使得任意一方先形成连续五个同色棋子的一方获胜。五子棋的规则简单,但策略丰富,适合各年龄段的玩家。 2. 网络五子棋的意义: 网络五子棋是指可以在互联网或局域网中连接进行对弈的五子棋游戏版本。通过网络版本,玩家不必在同一地点即可进行游戏,突破了空间限制,满足了现代人们快节奏生活的需求,同时也为玩家们提供了与不同对手切磋交流的机会。 3. 局域网通信原理: 局域网(Local Area Network,LAN)是一种覆盖较小范围如家庭、学校、实验室或单一建筑内的计算机网络。它通过有线或无线的方式连接网络内的设备,允许用户共享资源如打印机和文件,以及进行游戏和通信。局域网内的计算机之间可以通过网络协议进行通信。 4. 网络五子棋的工作方式: 在局域网中玩五子棋,通常需要一个客户端程序(如五子棋.exe)和一个服务器程序。客户端负责显示游戏界面、接受用户输入、发送落子请求给服务器,而服务器负责维护游戏状态、处理玩家的游戏逻辑和落子请求。当一方玩家落子时,客户端将该信息发送到服务器,服务器确认无误后将更新后的棋盘状态传回给所有客户端,更新显示。 5. 五子棋.exe程序: 五子棋.exe是一个可执行程序,它使得用户可以在个人计算机上安装并运行五子棋游戏。该程序可能包含了游戏的图形界面、人工智能算法(如果支持单机对战AI的话)、网络通信模块以及游戏规则的实现。 6. put.wav文件: put.wav是一个声音文件,很可能用于在游戏进行时提供声音反馈,比如落子声。在网络环境中,声音文件可能被用于提升玩家的游戏体验,尤其是在局域网多人游戏场景中。当玩家落子时,系统会播放.wav文件中的声音,为游戏增添互动性和趣味性。 7. 网络五子棋的技术要求: 为了确保多人在线游戏的顺利进行,网络五子棋需要具备一些基本的技术要求,包括但不限于稳定的网络连接、高效的数据传输协议(如TCP/IP)、以及安全的数据加密措施(如果需要的话)。此外,还需要有一个良好的用户界面设计来提供直观和舒适的用户体验。 8. 社交与娱乐: 网络五子棋除了是一个娱乐游戏外,它还具有社交功能。玩家可以通过游戏内的聊天系统进行交流,分享经验和策略,甚至通过网络寻找新的朋友。这使得网络五子棋不仅是一个个人娱乐工具,同时也是一种社交活动。 总结来说,网络五子棋结合了五子棋游戏的传统魅力和现代网络技术,使得不同地区的玩家能够在局域网内进行娱乐和聊天,既丰富了人们的娱乐生活,又加强了人际交流。而实现这一切的基础在于客户端程序的设计、服务器端的稳定运行、局域网的高效通信,以及音效文件增强的游戏体验。
recommend-type

自由行旅游新篇章:HarmonyOS技术融合与系统架构深度解析

# 1. HarmonyOS技术概述 ## 1.1 HarmonyOS的起源与发展 HarmonyOS(鸿蒙操作系统)由华为公司开发,旨在构建全场景分布式OS,以应对不同设备间的互联问题。自从2019年首次发布以来,HarmonyOS迅速成长,并迅速应用于智能手机、平板、智能穿戴、车载设备等多种平台。该系
recommend-type

足底支撑相到达73%是什么问题

<think>好的,我现在要处理用户的问题:“足底支撑相达到73%可能的原因及影响”。首先,需要理解用户提到的“足底支撑相73%”具体指什么。足底支撑相通常指步态周期中脚与地面接触的时间占比,正常范围大约在60%-62%左右。如果达到73%,明显超出正常范围,可能意味着步态异常。 接下来,需要确定可能的原因。可能的原因包括生物力学异常,比如足弓异常(扁平足或高弓足)、踝关节活动度受限,或者肌肉力量不足,特别是小腿和足部肌肉。另外,神经系统疾病如脑卒中或帕金森病可能影响步态控制。骨骼关节问题如关节炎、髋膝关节病变也可能导致支撑时间延长。还有代偿性步态,比如因疼痛或受伤而改变步态模式。 然后是
recommend-type

宾馆预约系统开发与优化建议

宾馆预约系统是一个典型的在线服务应用,它允许用户通过互联网平台预定宾馆房间。这种系统通常包含多个模块,比如用户界面、房态管理、预订处理、支付处理和客户评价等。从技术层面来看,构建一个宾馆预约系统涉及到众多的IT知识和技术细节,下面将详细说明。 ### 标题知识点 - 宾馆预约系统 #### 1. 系统架构设计 宾馆预约系统作为一个完整的应用,首先需要进行系统架构设计,决定其采用的软件架构模式,如B/S架构或C/S架构。此外,系统设计还需要考虑扩展性、可用性、安全性和维护性。一般会采用三层架构,包括表示层、业务逻辑层和数据访问层。 #### 2. 前端开发 前端开发主要负责用户界面的设计与实现,包括用户注册、登录、房间搜索、预订流程、支付确认、用户反馈等功能的页面展示和交互设计。常用的前端技术栈有HTML, CSS, JavaScript, 以及各种前端框架如React, Vue.js或Angular。 #### 3. 后端开发 后端开发主要负责处理业务逻辑,包括用户管理、房间状态管理、订单处理等。后端技术包括但不限于Java (使用Spring Boot框架), Python (使用Django或Flask框架), PHP (使用Laravel框架)等。 #### 4. 数据库设计 数据库设计对系统的性能和可扩展性至关重要。宾馆预约系统可能需要设计的数据库表包括用户信息表、房间信息表、预订记录表、支付信息表等。常用的数据库系统有MySQL, PostgreSQL, MongoDB等。 #### 5. 网络安全 网络安全是宾馆预约系统的重要考虑因素,包括数据加密、用户认证授权、防止SQL注入、XSS攻击、CSRF攻击等。系统需要实现安全的认证机制,比如OAuth或JWT。 #### 6. 云服务和服务器部署 现代的宾馆预约系统可能部署在云平台上,如AWS, Azure, 腾讯云或阿里云。在云平台上,系统可以按需分配资源,提高系统的稳定性和弹性。 #### 7. 付款接口集成 支付模块需要集成第三方支付接口,如支付宝、微信支付、PayPal等,需要处理支付请求、支付状态确认、退款等业务。 #### 8. 接口设计与微服务 系统可能采用RESTful API或GraphQL等接口设计方式,提供服务的微服务化,以支持不同设备和服务的接入。 ### 描述知识点 - 这是我个人自己做的 请大家帮忙修改哦 #### 个人项目经验与团队合作 描述中的这句话暗示了该宾馆预约系统可能是由一个个人开发者创建的。个人开发和团队合作在软件开发流程中有着显著的不同。个人开发者需要关注的方面包括项目管理、需求分析、代码质量保证、测试和部署等。而在团队合作中,每个成员会承担不同的职责,需要有效的沟通和协作。 #### 用户反馈与迭代 描述还暗示了该系统目前处于需要外部反馈和修改的阶段。这表明系统可能还处于开发或测试阶段,需要通过用户的实际使用反馈来不断迭代改进。 ### 标签知识点 - 200 #### 未提供信息 “200”这个标签可能指的是HTTP状态码中表示请求成功(OK)的200状态码。但是,由于没有提供更多的上下文信息,无法进一步分析其在本例中的具体含义。 ### 压缩包子文件的文件名称列表知识点 - 1111 #### 文件命名与管理 “1111”这个文件名称可能是一个版本号、日期标记或者是一个简单的标识符。文件命名应当遵循一定的规则,以确保文件的可追溯性和管理的便利性。在软件开发过程中,合理组织文件和版本控制(如使用Git)是必不可少的。 综上所述,宾馆预约系统的开发是一项复杂的工程,它涉及前后端的开发、数据库设计、系统安全、接口设计等多个方面。开发者在开发过程中需要不断学习和应用各类IT知识,以确保系统能够安全、高效、稳定地运行。而对于个人开发项目,如何合理利用有限资源、高效地管理和优化项目过程也是至关重要的。