基于stm32f10x.h,stm32f10x_tim.h,stm32f10x_rcc.h,sys.h,delay.h,misc.h

时间: 2025-04-26 09:27:30 浏览: 50
<think>嗯,用户现在想了解基于多个头文件的STM32开发,包括stm32f10x.h、stm32f10x_tim.h、stm32f10x_rcc.h、sys.h、delay.h、misc.h这些。首先,我需要确定用户的需求是什么。可能他们正在使用STM32F1系列微控制器,比如STM32F103,进行项目开发,需要整合这些库文件来实现特定功能。 用户之前已经询问过关于stm32f10x.h的详细介绍,现在扩展到了更多的头文件,说明他们可能在深入开发过程中遇到了问题,或者需要更全面的指导。我需要逐一分析每个头文件的作用,以及它们如何协同工作。 首先,stm32f10x.h是核心头文件,负责寄存器映射和基本外设声明。stm32f10x_rcc.h涉及时钟控制,这在STM32开发中非常关键,因为正确配置时钟是外设正常工作的前提。stm32f10x_tim.h用于定时器配置,可能用户需要用到定时器功能,比如PWM、定时中断等。 接下来,sys.h、delay.h和misc.h可能是用户自定义或第三方库中的文件。sys.h通常包含系统级配置,比如时钟初始化、中断向量表设置。delay.h可能提供延时函数,依赖于系统时钟或定时器。misc.h可能涉及中断和NVIC配置,特别是结合STM32的标准外设库中的misc.c文件。 用户可能的问题包括如何正确配置这些头文件,如何初始化各个外设,以及如何解决编译或运行时的问题。例如,定时器配置是否正确,时钟是否使能,延时函数是否准确等。 需要注意用户是否在使用标准外设库(SPL)还是其他库,比如HAL。根据之前的回答,用户可能在使用SPL,因为提到了stm32f10x系列头文件。同时,需要提醒用户SPL已经不再维护,但对于现有项目仍然有效。 用户可能的具体应用场景包括使用定时器生成PWM控制电机或LED,使用延时函数进行任务调度,或者通过系统时钟配置提高性能。需要提供代码示例,说明如何整合这些头文件,初始化各个模块,并实现具体功能。 另外,常见问题如编译错误、外设不工作等,需要给出解决方法。比如检查头文件路径是否正确,是否缺少必要的源文件,时钟配置是否正确,中断服务函数是否正确定义等。 需要确保回答结构清晰,分模块介绍每个头文件的作用,给出代码示例,并对比不同库的优缺点。同时,强调实际开发中的注意事项,如预定义宏、启动文件的选择、延时函数的实现方式等。 可能还需要提醒用户关于代码效率和维护性的权衡,虽然SPL直接操作寄存器效率高,但HAL库更易于维护和跨系列兼容。根据用户的项目需求,给出合适的建议。 最后,总结这些头文件如何协同工作,帮助用户构建一个完整的STM32项目框架,并指导他们如何进一步扩展功能,比如添加中断、DMA传输等高级应用。</think>--- ### 基于STM32F10x系列头文件的开发详解 以下针对`stm32f10x.h`、`stm32f10x_tim.h`、`stm32f10x_rcc.h`、`sys.h`、`delay.h`和`misc.h`的组合开发进行详细说明,涵盖关键模块功能与典型应用场景。 --- #### 一、核心头文件功能解析 | 头文件 | 核心功能 | |------------------------|--------------------------------------------------------------------------| | **stm32f10x.h** | 定义芯片寄存器地址、外设结构体、位操作宏(如`GPIO_SetBits`) | | **stm32f10x_rcc.h** | 系统时钟控制(HSE/HSI/PLL配置)、外设时钟使能(如`RCC_APB2Periph_GPIOA`)| | **stm32f10x_tim.h** | 定时器配置(PWM/输入捕获/编码器模式)、中断控制 | | **misc.h** | NVIC(嵌套向量中断控制器)配置,优先级分组设置 | | **sys.h** | 自定义系统级配置(时钟频率声明、IO复用映射等) | | **delay.h** | 提供微秒/毫秒级延时函数(通常基于SysTick或定时器实现) | --- #### 二、典型开发流程(以定时器PWM控制LED为例) ##### 1. 系统初始化配置 **sys.h**中需声明系统时钟频率(与实际情况一致): ```c // sys.h #define SYSTEM_CLK_FREQ 72000000 // 72MHz系统时钟 ``` **stm32f10x_rcc.h**配置时钟树: ```c void RCC_Configuration(void) { RCC_DeInit(); RCC_HSEConfig(RCC_HSE_ON); // 启用外部晶振 while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); // 等待HSE就绪 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // HSE*9 = 72MHz RCC_PLLCmd(ENABLE); while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // 等待PLL锁定 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 切换系统时钟到PLL SystemCoreClock = SYSTEM_CLK_FREQ; // 更新系统时钟变量 } ``` ##### 2. 定时器PWM初始化(TIM3_CH2) ```c #include "stm32f10x_tim.h" void TIM3_PWM_Init(void) { TIM_TimeBaseInitTypeDef TIM_BaseStruct; TIM_OCInitTypeDef TIM_OCStruct; // 1. 使能TIM3和GPIOA时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 2. 配置PA7为复用推挽输出(TIM3_CH2) GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); // 3. 配置TIM3时基单元(72MHz / (7200 * 2000) = 5Hz PWM) TIM_BaseStruct.TIM_Period = 1999; // ARR值 TIM_BaseStruct.TIM_Prescaler = 7200 - 1; // PSC值 TIM_BaseStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_BaseStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_BaseStruct); // 4. 配置PWM模式(通道2) TIM_OCStruct.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCStruct.TIM_Pulse = 999; // 初始占空比50% TIM_OCStruct.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM3, &TIM_OCStruct); TIM_Cmd(TIM3, ENABLE); // 启动定时器 } ``` ##### 3. 延时函数实现(delay.h) **delay.h**通常包含两种实现方式: ```c // 方式1:基于SysTick(精确度高) void Delay_us(uint32_t us) { uint32_t temp; SysTick->LOAD = SystemCoreClock / 8000000 * us; // 假设SysTick时钟为72MHz 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; } // 方式2:基于定时器(如TIM4) extern TIM_TypeDef* DELAY_TIM; // 在delay.c中定义 void Delay_ms(uint16_t ms) { TIM_SetCounter(DELAY_TIM, 0); TIM_Cmd(DELAY_TIM, ENABLE); while (TIM_GetCounter(DELAY_TIM) < ms * 1000); // 假设定时器时钟为1MHz TIM_Cmd(DELAY_TIM, DISABLE); } ``` ##### 4. 主函数整合 ```c #include "stm32f10x.h" #include "sys.h" #include "delay.h" #include "misc.h" int main(void) { RCC_Configuration(); // 配置系统时钟 TIM3_PWM_Init(); // 初始化PWM Delay_Init(); // 初始化延时函数(需在delay.h中实现) while(1) { // 呼吸灯效果:占空比从0%到100%渐变 for (uint16_t i = 0; i < 2000; i++) { TIM_SetCompare2(TIM3, i); Delay_ms(1); } for (uint16_t i = 2000; i > 0; i--) { TIM_SetCompare2(TIM3, i); Delay_ms(1); } } } ``` --- #### 三、关键问题排查指南 1. **PWM无输出** - 检查GPIO模式是否为`GPIO_Mode_AF_PP`(复用推挽) - 验证定时器时钟是否使能(`RCC_APB1PeriphClockCmd`) - 测量ARR和PSC计算:$$f_{PWM} = \frac{f_{TIM}}{(ARR + 1) \times (PSC + 1)}$$ 2. **延时函数不准确** - 确认`SystemCoreClock`变量值与实际系统时钟一致 - 检查SysTick时钟源选择(默认使用HCLK的8分频) 3. **中断无法触发** - 在**misc.h**中配置优先级分组: ```c NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 推荐分组2 ``` - 确保中断服务函数名称正确(如`TIM3_IRQHandler`) --- #### 四、代码优化技巧 1. **寄存器级加速** 直接操作寄存器替代库函数,提升执行效率: ```c // 替代TIM_SetCompare2() TIM3->CCR2 = 1000; // 直接写入捕获比较寄存器 ``` 2. **DMA联动** 使用`stm32f10x_dma.h`实现PWM占空比自动更新: ```c DMA_InitTypeDef DMA_InitStruct; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&TIM3->CCR2; DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)pwm_buffer; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST; // 内存到外设 DMA_InitStruct.DMA_BufferSize = 256; DMA_Init(DMA1_Channel5, &DMA_InitStruct); ``` --- #### 五、版本兼容性说明 | 库文件 | 兼容范围 | 注意事项 | |----------------|----------------------------------|-----------------------------------| | **SPL库** | STM32F101/102/103/105/107系列 | 需与固件库版本匹配(如V3.5.0) | | **sys.h** | 需根据具体硬件修改引脚定义 | 注意外部晶振频率声明 | | **delay.h** | 依赖系统时钟配置 | 定时器实现需避免与其他外设冲突 | > **提示**:若需跨平台开发,建议迁移到**HAL库**(通过STM32CubeMX生成代码),但需注意HAL库的函数调用开销较SPL更大。
阅读全文

相关推荐

#include<stm32f10x.h> #include"sys.h" extern unsigned char Rec_Dat_U1; extern unsigned char Rec_String_U1[200]; extern int conut_flag_1; #define in_1(x) x?GPIO_ResetBits(GPIOC , GPIO_Pin_0): GPIO_SetBits(GPIOC , GPIO_Pin_0) #define in_2(x) x?GPIO_ResetBits(GPIOC , GPIO_Pin_1): GPIO_SetBits(GPIOC , GPIO_Pin_1) #define in_3(x) x?GPIO_ResetBits(GPIOB , GPIO_Pin_10): GPIO_SetBits(GPIOB , GPIO_Pin_10) #define in_4(x) x?GPIO_ResetBits(GPIOB , GPIO_Pin_11): GPIO_SetBits(GPIOB , GPIO_Pin_11) #define key_1 GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_12) #define key_2 GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_13) #define key_3 GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_14) #define key_4 GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_15) float Kp_l = 0.82 ; //比例常数 float Ti_l = 0.09 ; //微分时间常数 float Td_l = 0.015 ; //采样周期 float Kp_r = 0.20 ; float Ti_r = 0.09 ; float Td_r = 0.015 ; #define T 0.02 #define Ki_l Kp_l*(T/Ti_l) // Kp Ki Kd #define Kd_l Kp_l*(Td_l/T) #define Ki_r Kp_l*(T/Ti_l) // Kp Ki Kd #define Kd_r Kp_l*(Td_l/T) #define left_b in_1(1); in_2(0); #define left_f in_1(0); in_2(1); #define right_f in_3(1); in_4(0); #define right_b in_1(0); in_2(1); extern float pwm_l; extern float pwm_r; void CAR_GPIO_INIT(void); int main() { // int speed=50; SYS_CONFIG(); CAR_GPIO_INIT(); pwm_init(TIM3_1); pwm_init(TIM3_2); TIM4_PWMINPUT_INIT(0xffff,31); //1M速度采样率 TIM5_PWMINPUT_INIT(0xffff,31); incPIDinit(); PID_set(Kp_l,Ki_l,Kd_l,Kp_r,Ki_r,Kd_r); //void PID_set(float pp_1,float ii_1,float dd_1,float pp_2,float ii_2,float dd_2) right_f left_f // set_pwm_percent(TIM3_1,50) ; // set_pwm_percent(TIM3_2,50) ; PID_setpoint(&PID_l, 160); PID_setpoint(&PID_r, 160); while(1) { printf("%d\r\n",(int)pwm_l); delay_ms(200); } } void CAR_GPIO_INIT() { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOD, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOD, &GPIO_InitStructure); }

#include "stm32f10x.h" // Device header uint16_t AD_Value[2]; //定义用于存放AD转换结果的全局数组 /** * 函 数:AD初始化 * 参 数:无 * 返 回 值:无 */ void AD_Init(void) { /*开启时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //开启DMA1的时钟 /*设置ADC时钟*/ RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz /*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA1和PA2引脚初始化为模拟输入 /*规则组通道配置*/ ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //规则组序列1的位置,配置为通道0 ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); //规则组序列2的位置,配置为通道1 /*ADC初始化*/ ADC_InitTypeDef ADC_InitStructure; //定义结构体变量 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换,使能,每转换一次规则组序列后立刻开始下一次转换 ADC_InitStructure.ADC_ScanConvMode = ENABLE; //扫描模式,使能,扫描规则组的序列,扫描数量由ADC_NbrOfChannel确定 ADC_InitStructure.ADC_NbrOfChannel = 2; //通道数,为2,扫描规则组的前2个通道 ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1 /*DMA初始化*/ DMA_InitTypeDef DMA_InitStructure; //定义结构体变量 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; //外设基地址,给定形参AddrA DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据宽度,选择半字,对应16为的ADC数据寄存器 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址自增,选择失能,始终以ADC数据寄存器为源 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value; //存储器基地址,给定存放AD转换结果的全局数组AD_Value DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据宽度,选择半字,与源数据宽度对应 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器地址自增,选择使能,每次转运后,数组移到下一个位置 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,选择由外设到存储器,ADC数据寄存器转到数组 DMA_InitStructure.DMA_BufferSize = 2; //转运的数据大小(转运次数),与ADC通道数一致 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //模式,选择循环模式,与ADC的连续转换一致 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //存储器到存储器,选择失能,数据由ADC外设触发转运到存储器 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级,选择中等 DMA_Init(DMA1_Channel1, &DMA_InitStructure); //将结构体变量交给DMA_Init,配置DMA1的通道1 /*DMA和ADC使能*/ DMA_Cmd(DMA1_Channel1, ENABLE); //DMA1的通道1使能 ADC_DMACmd(ADC1, ENABLE); //ADC1触发DMA1的信号使能 ADC_Cmd(ADC1, ENABLE); //ADC1使能 /*ADC校准*/ ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准 while (ADC_GetResetCalibrationStatus(ADC1) == SET); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1) == SET); /*ADC触发*/ ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发ADC开始工作,由于ADC处于连续转换模式,故触发一次后ADC就可以一直连续不断地工作 } 根据以上代码且不修改以上代码的情况下,通过stm32f103c8t6芯片内部的过零检测函数,计算出adc两个通道的相位量,代码单独成立.c和.h文件,ai率为0,要求运用代码可以直接在0.96寸oled显示屏上直接显示adc两个通道的相位量和相位差,显示格式为AD1:xxA,AD1的相位量AD2:xxA,AD2的相位量DIFF:xxA,AD1和AD2的相位差,代码要求简洁。把要添加的所以代码全写出来

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

Main主程序 #include "sys.h" #include "delay.h" #include "adc.h" #include "gpio.h" #include "OLED_I2C.h" #include "stmflash.h" #include "ds18b20.h" #include "timer.h" #include "usart1.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #define FLASH_SAVE_ADDR ((u32)0x0800F000) //设置FLASH 保存地址(必须为偶数) #define STM32_RX1_BUF Usart1RecBuf #define STM32_Rx1Counter RxCounter #define STM32_RX1BUFF_SIZE USART1_RXBUFF_SIZE extern const unsigned char BMP1[]; extern const unsigned char BMP2[]; char display[16]; //显示缓存区 short temperature=0; //温度 u8 setTempValue = 40; //温度上限 u8 setSmokeValue = 60; //烟雾上限 u8 sendSmsFlag = 0; //发送短信标志 u8 alarmFlag = 0x00; //蜂鸣器报警标志 u16 smoke=0; //烟雾 u8 setn=0; //记录设置按键按下的次数 bool shanshuo=0; bool shuaxin=0; bool fangdao=0; char PhoneNumber[11];//手机号码 char uniPhoneNum[44];//手机号码转码后存放数组 void UsartRx1BufClear(void) { memset(STM32_RX1_BUF, 0, STM32_RX1BUFF_SIZE);//清除缓存 STM32_Rx1Counter = 0; } /***********************************************************************************************/ /****************************** 以下为SIM800相关部分 ****************************************/ /***********************************************************************************************/ void PhoneNumChangeUnicode(char *str1,char *str2) //手机号转码 { u8 i; char *buf = str1; for(i = 0;i < 11;i ++) //发送中文短信手机号必须转码,前面需要加上003 { str2[i*4+0] = '0'; str2[i*4+1] = '0'; str2[i*4+2] = '3'; str2[i*4+3] = buf[i]; } } void gsm_atcmd_send(char *at)//GSM AT指令发送函数 { unsigned short waittry;//延时变量 do { gsm_rev_start = 0;//接收开始标志清零 gsm_rev_okflag = 0;//接收完成标志清零 waittry = 0;//延时变量清零 uart1_send((unsigned char *)at,0xFF);//串口发送内容 while(waittry ++ < 3000)//进入while延时 { if (gsm_rev_okflag == 1)//等待GSM返回OK { return;//返回出去 } delay_ms(1); } } while(gsm_rev_okflag == 0); } void gsm_init(void)//gsm初始化 { gsm_atcmd_send("AT\r\n");//测试用的 delay_ms(1000); gsm_atcmd_send("AT+CSCS=\"UCS2\"\r\n");//设置为unicode编码 delay_ms(1000); gsm_atcmd_send("AT+CMGF=1\r\n");//设置为文本模式 delay_ms(1000); gsm_atcmd_send("AT+CNMI=2,1\r\n");//来短信时提示,并存储到模块内存 delay_ms(1000); gsm_atcmd_send("AT+CMGD=1,4\r\n");//清除短信 delay_ms(1000); gsm_atcmd_send("AT+CSMP=17,0,2,25\r\n");//设置短信保留为5分钟,发送中文 } /* *number 为对方手机号 */ void gsm_send_msg(const char*number,char * content) { u8 len; unsigned char gsm_at_txbuf[60];//GSM AT命令缓存区 memset(gsm_at_txbuf, 0, 60);//缓存清零 strncpy((char *)gsm_at_txbuf,"AT+CMGS=\"",9);//将AT+CMGS=\",复制到gsm_at_txbuf memcpy(gsm_at_txbuf + 9, number, 44);//将手机号码复制到AT+CMGS=\"之后 len = strlen((char *)gsm_at_txbuf);//获取gsm_at_txbuf字符串长度 gsm_at_txbuf[len] = '"'; // AT+CMGS=\"12345678901\" gsm_at_txbuf[len + 1] = '\r'; gsm_at_txbuf[len + 2] = '\n';//gsm_at_txbuf最终的格式"AT+CMGS=\"手机号码\"\r\n" uart1_send(gsm_at_txbuf,0xFF);//发送需要接受短信的手机号码 delay_ms(1000); uart1_send((unsigned char *)content,0xFF); //发短信内容 delay_ms(100); printf("%c",0x1a); //发送结束符号 delay_ms(10); } /* *content 为短信内容 */ void sim800_send_sms(char *content) { bool send_error = 0; u16 send_count = 0; gsm_rev_okflag = 0; OLED_ShowStr(32,2,"Send Sms... ",2,0); PhoneNumChangeUnicode(PhoneNumber,uniPhoneNum); //在发送短信前,先将手机号转码 gsm_send_msg(uniPhoneNum,content);//发送短信 delay_ms(1000);//延时1秒 while(gsm_rev_okflag == 0)//等待返回OK指令 { if(send_count++ > 8000) { send_count = 0; send_error = 1; break; } delay_ms(1); }; gsm_rev_okflag = 0; if(send_error == 1) OLED_ShowStr(32,2,"Send Fail! ",2,0);//显示发送超时 else OLED_ShowStr(32,2," Send OK! ",2,0); UsartRx1BufClear(); delay_ms(1000);//延时1秒 OLED_ShowStr(32,2," ",2,0); } /***********************************************************************************************/ /****************************** end ****************************************/ /***********************************************************************************************/ void STM32_FlashCheck(void) // 检查是否是新的单片机,是的话清空存储区,否则保留 { u8 comper_str[6],i; STMFLASH_Read(FLASH_SAVE_ADDR + 0x10,(u16*)comper_str,5); comper_str[5] = '\0'; if(strstr((char *)comper_str,"FDYDZ") == NULL) //新的单片机 { STMFLASH_Write(FLASH_SAVE_ADDR + 0x10,(u16*)"FDYDZ",5); //写入“FDYDZ”,方便下次校验 delay_ms(50); STMFLASH_Write(FLASH_SAVE_ADDR + 0x40,(u16*)"12345678910",11);//存入初始手机号 delay_ms(50); } STMFLASH_Read(FLASH_SAVE_ADDR + 0x40,(u16*)PhoneNumber,11); //读出手机号 for(i = 0; i < 11 ; i++) { if(PhoneNumber[i]<'0' || PhoneNumber[i]>'9') { break; } } if(i != 11) { memset(PhoneNumber, 0 , 11); //清除缓存 sprintf(PhoneNumber,"12345678910"); } delay_ms(100); } void display_mode(void) { u8 i; //显示中文: 防盗模式 if(fangdao==1){for(i = 0;i < 4;i ++)OLED_ShowCN(i*16+32,0,i+0,1);}else {for(i = 0;i < 4;i ++)OLED_ShowCN(i*16+32,0,i+24,1);} } void displayInitInterface(void) //显示初始页面 { u8 i; for(i = 0;i < 2;i ++)OLED_ShowCN(i*16,4,i+6,0); //显示中文: 温度 for(i = 0;i < 2;i ++)OLED_ShowCN(i*16,6,i+8,0); //显示中文: 烟雾 OLED_ShowChar(32,0,':',2,0); OLED_ShowChar(32,4,':',2,0); OLED_ShowChar(32,6,':',2,0); display_mode(); } void Get_Temperature(void) //获取温度 { temperature=ReadTemperature(); if(temperature>=setTempValue) { if(!(alarmFlag&0x01)) { alarmFlag|=0x01; shanshuo = 0; sendSmsFlag = 2; //发送短信标志 } } else { alarmFlag&=0xFE; } if(temperature>=setTempValue && shanshuo) { OLED_ShowStr(40, 4," ", 2,0); } else { sprintf(display," %d",temperature); OLED_ShowStr(40, 4, (u8*)display, 2,0);//显示温度 OLED_ShowCentigrade(68, 4); //显示摄氏度 } } void Get_Smoke(void) //获取烟雾浓度 { u16 test_adc=0; /* 获取烟雾浓度 */ test_adc = Get_Adc_Average(ADC_Channel_9,10);//读取通道9的10次AD平均值 smoke = test_adc*99/4096;//转换成0-99百分比 if(smoke>=setSmokeValue) { if(!(alarmFlag&0x02)) { alarmFlag|=0x02; shanshuo = 0; sendSmsFlag = 3; //发送短信标志 } } else { alarmFlag&=0xFD; } if(smoke>=setSmokeValue && shanshuo) { OLED_ShowStr(40, 6," ", 2,0); } else { sprintf(display," %02d %%",smoke); OLED_ShowStr(40, 6, (u8*)display, 2,0);//显示温度 } } void displaySetValue(void) //显示设置值 { u8 add=2,i; if(setn==1) { OLED_ShowChar(56,4,setTempValue%100/10+'0',2,0);//显示 OLED_ShowChar(64,4,setTempValue%10+'0',2,0);//显示 } if(setn==2) { OLED_ShowChar(56,4,setSmokeValue%100/10+'0',2,0);//显示 OLED_ShowChar(64,4,setSmokeValue%10+'0',2,0);//显示 OLED_ShowChar(72,4,'%',2,0); } if(setn>=3) { for(i = 0;i < 11;i ++) { OLED_ShowChar((add++)*8,4,PhoneNumber[i],2,(setn+1)-(3+i));//显示手机号码 } } } void keyscan(void) //按键扫描 { u8 i; if(KEY1 == 0) //设置键 { delay_ms(20); if(KEY1 == 0) { while(KEY1 == 0); setn ++; if(setn == 1) { OLED_CLS();//清屏 for(i = 0;i < 4;i ++)OLED_ShowCN(i*16+32,0,i+10,0);//显示中文:设置温度 OLED_ShowCentigrade(75, 4); //显示摄氏度 } if(setn == 2) { for(i = 0;i < 4;i ++)OLED_ShowCN(i*16+32,0,i+14,0);//显示中文:设置烟雾 OLED_ShowChar(80,4,' ',2,0); } if(setn == 3) { for(i = 0;i < 6;i ++)OLED_ShowCN(i*16+16,0,i+18,0);//显示中文:设置手机号码 } if(setn >= 14) { setn = 0; OLED_CLS();//清屏 displayInitInterface(); STMFLASH_Write(FLASH_SAVE_ADDR + 0x40,(u16*)PhoneNumber,11); //退出设置,存入设置的手机号 } displaySetValue(); } } if(KEY2 == 0) //加键 { delay_ms(80); if(KEY2 == 0) { if(setTempValue < 99 && setn==1)setTempValue++; if(setSmokeValue < 99 && setn==2)setSmokeValue++; if(setn>=3) { PhoneNumber[setn-3]++; if(PhoneNumber[setn-3]>'9')PhoneNumber[setn-3]='0'; } displaySetValue(); } } if(KEY3 == 0) //减键 { delay_ms(80); if(KEY3 == 0) { if(setn==0) { fangdao=!fangdao; display_mode(); } if(setTempValue > 0 && setn==1)setTempValue--; if(setSmokeValue > 0 && setn==2)setSmokeValue--; if(setn>=3) { PhoneNumber[setn-3]--; if(PhoneNumber[setn-3]<'0')PhoneNumber[setn-3]='9'; } displaySetValue(); } } } int main(void) { bool flameFlag=0; bool SomebodyFlag=0; char SEND_BUF[400]; //发送短信缓存 delay_init(); //延时函数初始化 NVIC_Configuration(); //中断优先级配置 I2C_Configuration(); //IIC初始化 STM32_FlashCheck(); //FLASH初始化 delay_ms(200); OLED_Init(); //OLED液晶初始化 OLED_CLS(); //清屏 OLED_ShowStr(0,2," GSM Init... ",2,0); uart1_Init(9600); gsm_init();//gsm初始化 OLED_CLS();//清屏 Adc_Init(); //adc初始化 KEY_GPIO_Init(); //按键引脚初始化 SR501_GPIO_Init(); //人体红外初始化 DS18B20_GPIO_Init(); //温度初始化 DS18B20_Init(); //初始化显示 displayInitInterface(); //显示初始界面 TIM3_Init(99,719); //定时器初始化,定时1ms //Tout = ((arr+1)*(psc+1))/Tclk ; //Tclk:定时器输入频率(单位MHZ) //Tout:定时器溢出时间(单位us) while(1) { keyscan(); //按键扫描 if(setn == 0) { if(shuaxin == 1) //大概300ms刷新一次数据 { Get_Temperature(); //获取温度 Get_Smoke(); //获取烟雾 shuaxin = 0; } if(FLAME == 0) //检测到火焰 { delay_ms(10); if(FLAME == 0) { if(flameFlag == 0) { OLED_DrawBMP(88,4,120,8,(unsigned char *)BMP1); //显示火焰图片 sendSmsFlag = 1; //发送短信标志 } flameFlag = 1; } } else { if(flameFlag == 1) { OLED_ShowStr(88, 4, " ", 2,0); OLED_ShowStr(88, 6, " ", 2,0); } flameFlag = 0; } if(fangdao==1&&SR501==1) //在防盗模式下检测到有人 { if(SomebodyFlag==0) { OLED_DrawBMP(0,0,32,4,(unsigned char *)BMP2); //图显示 sendSmsFlag = 4; //发送短信标志 SomebodyFlag = 1; } } else { if(SomebodyFlag==1) { OLED_ShowStr(0, 0, " ", 2,0); OLED_ShowStr(0, 2, " ", 2,0); SomebodyFlag = 0; } } if(temperature>=setTempValue || smoke>=setSmokeValue || flameFlag || SomebodyFlag)BEEP=1;else BEEP=0; //检测到温度烟雾超标火焰蜂鸣器报警 if(temperature>=setTempValue)FAN=1;else FAN=0; //温度超标都开启风扇 if(smoke>=setSmokeValue || flameFlag)RELAY = 1; else RELAY = 0; //检测到有火或者烟雾超标,开启水泵 if(sendSmsFlag != 0) //发送短信 { char TEMP_BUF[100]; /*******************************************************************************************/ /*******************以下为短信内容处理部分,发送中文短信必须转换为Unicode码**************/ /******************************************************************************************/ memset(SEND_BUF,0,sizeof(SEND_BUF)); //清空缓冲区 switch(sendSmsFlag) { case(1): strcat(SEND_BUF,"8B66544AFF0168C06D4B5230706B7130FF01"); break; //警告!检测到火焰! case(2): strcat(SEND_BUF,"8B66544AFF016E295EA68FC79AD8FF01"); break; //警告!温度过高! case(3): strcat(SEND_BUF,"8B66544AFF0170DF96FE6D535EA68FC79AD8FF01"); break; //警告!烟雾浓度过高! case(4): strcat(SEND_BUF,"8B66544AFF0168C06D4B523067094EBAFF01"); break; //警告!检测到有人! default: break; } if(sendSmsFlag!=4) { memset(TEMP_BUF,0,sizeof(TEMP_BUF)); //清空缓冲区 sprintf(TEMP_BUF,"6E295EA6003A003%1d003%1d2103FF0C70DF96FE003A003%1d003%1d0025",temperature/10,temperature%10,smoke/10,smoke%10); strcat(SEND_BUF,TEMP_BUF); } sim800_send_sms((char *)SEND_BUF);//发送短信 sendSmsFlag = 0; /*******************************************************************************************/ /*************************** end *****************************/ /******************************************************************************************/ } } delay_ms(10); } } void TIM3_IRQHandler(void)//定时器3中断服务程序,用于记录时间 { static u16 timeCount1 = 0; if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除中断标志位 timeCount1++; if(timeCount1 >= 300) //300ms { timeCount1 = 0; shanshuo = !shanshuo; shuaxin = 1; } } } ADC初始化程序 #include "adc.h" #include "delay.h" //初始化ADC //这里我们仅以规则通道为例 //我们默认将开启通道0~3 void Adc_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_ADC1 , ENABLE ); //使能ADC1通道时钟 RCC_ADCCLKConfig(RCC_PCLK2_Div8); //设置ADC分频因子6 72M/8=9,ADC最大时间不能超过14M GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚 GPIO_Init(GPIOB, &GPIO_InitStructure); ADC_DeInit(ADC1); //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式 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数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目 ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1 ADC_ResetCalibration(ADC1); //使能复位校准 while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束 ADC_StartCalibration(ADC1); //开启AD校准 while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束 } //获得ADC值 //ch:通道值 9 u16 Get_Adc(u8 ch) { //设置指定ADC的规则组通道,一个序列,采样时间 ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_71Cycles5 ); //ADC1,ADC通道,采样时间为13.5周期 ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束 return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果 } u16 Get_Adc_Average(u8 ch,u8 times) { u32 temp_val=0; u8 t; for(t=0;t<times;t++) { temp_val+=Get_Adc(ch); delay_ms(5); } return temp_val/times; } #ifndef __ADC_H #define __ADC_H #include "sys.h" void Adc_Init(void); u16 Get_Adc(u8 ch); u16 Get_Adc_Average(u8 ch,u8 times); #endif GPIO引脚初始化程序 #include "gpio.h" ////////////////////////////////////////////////////////////////////////////////// //按键舵机的GPIO设置 ////////////////////////////////////////////////////////////////////////////////// void KEY_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE); //使能PABC端口时钟 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //关闭JTAG模式 使PB3,PB4变成普通IO口 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; // 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; // 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_ResetBits(GPIOC,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //输出0 } void SR501_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉输入 GPIO_Init(GPIOA, &GPIO_InitStructure); } #ifndef __GPIO_H #define __GPIO_H #include "sys.h" #define KEY1 PBin(12) #define KEY2 PBin(13) #define KEY3 PBin(14) #define FLAME PBin(15) #define BEEP PCout(13) #define FAN PCout(14) #define RELAY PCout(15) #define SR501 PAin(0) void KEY_GPIO_Init(void);//引脚初始化 void SR501_GPIO_Init(void); #endif OLED驱动程序 /************************************************************************************ * * Description:128*64点阵的OLED显示屏驱动文件SD1306驱动IIC通信方式显示屏 * * Others: none; * * Function List: * 1. void I2C_Configuration(void) -- 配置CPU的硬件I2C * 2. void I2C_WriteByte(uint8_t addr,uint8_t data) -- 向寄存器地址写一个byte的数据 * 3. void WriteCmd(unsigned char I2C_Command) -- 写命令 * 4. void WriteDat(unsigned char I2C_Data) -- 写数据 * 5. void OLED_Init(void) -- OLED屏初始化 * 6. void OLED_SetPos(unsigned char x, unsigned char y) -- 设置起始点坐标 * 7. void OLED_Fill(unsigned char fill_Data) -- 全屏填充 * 8. void OLED_CLS(void) -- 清屏 * 9. void OLED_ON(void) -- 唤醒 * 10. void OLED_OFF(void) -- 睡眠 * 11. void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize) -- 显示字符串(字体大小有6*8和8*16两种) * 12. void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N) -- 显示中文(中文需要先取模,然后放到codetab.h中) * 13. void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]) -- BMP图片 * * History: none; * *************************************************************************************/ #include "OLED_I2C.h" #include "delay.h" #include "codetab.h" /* 定义I2C总线连接的GPIO端口, 用户只需要修改下面4行代码即可任意改变SCL和SDA的引脚 */ #define RCC_I2C_PORT RCC_APB2Periph_GPIOB /* GPIO端口时钟 */ #define PORT_I2C_SCL GPIOB /* GPIO端口 */ #define PIN_I2C_SCL GPIO_Pin_6 /* GPIO引脚 */ #define PORT_I2C_SDA GPIOB /* GPIO端口 */ #define PIN_I2C_SDA GPIO_Pin_7 /* GPIO引脚 */ #define I2C_SCL_PIN GPIO_Pin_6 /* 连接到SCL时钟线的GPIO */ #define I2C_SDA_PIN GPIO_Pin_7 /* 连接到SDA数据线的GPIO */ /* 定义读写SCL和SDA的宏 */ #define I2C_SCL_1() PORT_I2C_SCL->BSRR = I2C_SCL_PIN /* SCL = 1 */ #define I2C_SCL_0() PORT_I2C_SCL->BRR = I2C_SCL_PIN /* SCL = 0 */ #define I2C_SDA_1() PORT_I2C_SDA->BSRR = I2C_SDA_PIN /* SDA = 1 */ #define I2C_SDA_0() PORT_I2C_SDA->BRR = I2C_SDA_PIN /* SDA = 0 */ #define I2C_SDA_READ() ((PORT_I2C_SDA->IDR & I2C_SDA_PIN) != 0) /* 读SDA口线状态 */ #define I2C_SCL_READ() ((PORT_I2C_SCL->IDR & I2C_SCL_PIN) != 0) /* 读SCL口线状态 */ /* ********************************************************************************************************* * 函 数 名: bsp_InitI2C * 功能说明: 配置I2C总线的GPIO,采用模拟IO的方式实现 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void bsp_InitI2C_2(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE); /* 打开GPIO时钟 */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; /* 开漏输出模式 */ GPIO_InitStructure.GPIO_Pin = PIN_I2C_SCL; GPIO_Init(PORT_I2C_SCL, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = PIN_I2C_SDA; GPIO_Init(PORT_I2C_SDA, &GPIO_InitStructure); /* 给一个停止信号, 复位I2C总线上的所有设备到待机模式 */ i2c_Stop_2(); } /* ********************************************************************************************************* * 函 数 名: i2c_Start * 功能说明: CPU发起I2C总线启动信号 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void i2c_Start_2(void) { /* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */ I2C_SDA_1(); I2C_SCL_1(); delay_us(4); I2C_SDA_0(); delay_us(4); I2C_SCL_0(); } /* ********************************************************************************************************* * 函 数 名: i2c_Start * 功能说明: CPU发起I2C总线停止信号 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void i2c_Stop_2(void) { /* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */ I2C_SDA_0(); I2C_SCL_1(); delay_us(4); I2C_SDA_1(); delay_us(4); } /* ********************************************************************************************************* * 函 数 名: i2c_SendByte * 功能说明: CPU向I2C总线设备发送8bit数据 * 形 参: _ucByte : 等待发送的字节 * 返 回 值: 无 ********************************************************************************************************* */ void i2c_SendByte_2(uint8_t _ucByte) { uint8_t i; /* 先发送字节的高位bit7 */ for (i = 0; i < 8; i++) { if (_ucByte & 0x80) { I2C_SDA_1(); } else { I2C_SDA_0(); } delay_us(2); I2C_SCL_1(); delay_us(2); I2C_SCL_0(); _ucByte <<= 1; /* 左移一个bit */ delay_us(2); } } /* ********************************************************************************************************* * 函 数 名: i2c_ReadByte * 功能说明: CPU从I2C总线设备读取8bit数据 * 形 参: 无 * 返 回 值: 读到的数据 ********************************************************************************************************* */ uint8_t i2c_ReadByte_2(void) { uint8_t i; uint8_t value; /* 读到第1个bit为数据的bit7 */ value = 0; for (i = 0; i < 8; i++) { value <<= 1; I2C_SCL_1();//SCL在高电平期间,数据必须保持稳定 delay_us(2); if (I2C_SDA_READ()) { value++; } I2C_SCL_0(); delay_us(1); } return value; } /* ********************************************************************************************************* * 函 数 名: i2c_WaitAck * 功能说明: CPU产生一个时钟,并读取器件的ACK应答信号 * 形 参: 无 * 返 回 值: 返回0表示正确应答,1表示无器件响应 ********************************************************************************************************* */ uint8_t i2c_WaitAck_2(void) { uint8_t tempTime; I2C_SDA_1(); /* CPU释放SDA总线 */ delay_us(1); I2C_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */ delay_us(1); while(I2C_SDA_READ()) { tempTime++; if(tempTime>250) { i2c_Stop_2(); return 1; } } I2C_SCL_0(); return 0; } /* ********************************************************************************************************* * 函 数 名: i2c_Ack * 功能说明: CPU产生一个ACK信号 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void i2c_Ack_2(void) { I2C_SDA_0(); /* CPU驱动SDA = 0 */ delay_us(5); I2C_SCL_1(); /* CPU产生1个时钟 */ delay_us(5); I2C_SCL_0(); delay_us(5); I2C_SDA_1(); /* CPU释放SDA总线 */ } /* ********************************************************************************************************* * 函 数 名: i2c_NAck * 功能说明: CPU产生1个NACK信号 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void i2c_NAck_2(void) { I2C_SDA_1(); /* CPU驱动SDA = 1 */ delay_us(5); I2C_SCL_1(); /* CPU产生1个时钟 */ delay_us(5); I2C_SCL_0(); delay_us(5); } void I2C_Configuration(void) { bsp_InitI2C_2(); } void I2C_WriteByte(uint8_t addr,uint8_t data) { /* 第1步:发起I2C总线启动信号 */ i2c_Start_2(); /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */ i2c_SendByte_2(OLED_ADDRESS | I2C_WR); /* 此处是写指令 */ /* 第3步:发送ACK */ i2c_WaitAck_2(); /* 第4步:发送字节地址 */ i2c_SendByte_2(addr); i2c_WaitAck_2(); /* 第5步:开始写入数据 */ i2c_SendByte_2(data); /* 第6步:发送ACK */ i2c_WaitAck_2(); /* 发送I2C总线停止信号 */ i2c_Stop_2(); } void WriteCmd(unsigned char I2C_Command)//写命令 { I2C_WriteByte(0x00, I2C_Command); } void WriteDat(unsigned char I2C_Data)//写数据 { I2C_WriteByte(0x40, I2C_Data); } void OLED_Init(void) { delay_ms(100); //这里的延时很重要 WriteCmd(0xAE); //display off WriteCmd(0x20); //Set Memory Addressing Mode WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7 WriteCmd(0xc8); //Set COM Output Scan Direction WriteCmd(0x00); //---set low column address WriteCmd(0x10); //---set high column address WriteCmd(0x40); //--set start line address WriteCmd(0x81); //--set contrast control register WriteCmd(0xff); //亮度调节 0x00~0xff WriteCmd(0xa1); //--set segment re-map 0 to 127 WriteCmd(0xa6); //--set normal display WriteCmd(0xa8); //--set multiplex ratio(1 to 64) WriteCmd(0x3F); // WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content WriteCmd(0xd3); //-set display offset WriteCmd(0x00); //-not offset WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency WriteCmd(0xf0); //--set divide ratio WriteCmd(0xd9); //--set pre-charge period WriteCmd(0x22); // WriteCmd(0xda); //--set com pins hardware configuration WriteCmd(0x12); WriteCmd(0xdb); //--set vcomh WriteCmd(0x20); //0x20,0.77xVcc WriteCmd(0x8d); //--set DC-DC enable WriteCmd(0x14); // WriteCmd(0xaf); //--turn on oled panel } void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标 { WriteCmd(0xb0+y); WriteCmd(((x&0xf0)>>4)|0x10); WriteCmd((x&0x0f)|0x01); } void OLED_Fill(unsigned char fill_Data)//全屏填充 { unsigned char m,n; for(m=0;m<8;m++) { WriteCmd(0xb0+m); //page0-page1 WriteCmd(0x00); //low column start address WriteCmd(0x10); //high column start address for(n=0;n<128;n++) { WriteDat(fill_Data); } } } void OLED_CLS(void)//清屏 { OLED_Fill(0x00); } //-------------------------------------------------------------- // Prototype : void OLED_ON(void) // Calls : // Parameters : none // Description : 将OLED从休眠中唤醒 //-------------------------------------------------------------- void OLED_ON(void) { WriteCmd(0X8D); //设置电荷泵 WriteCmd(0X14); //开启电荷泵 WriteCmd(0XAF); //OLED唤醒 } //-------------------------------------------------------------- // Prototype : void OLED_OFF(void) // Calls : // Parameters : none // Description : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA //-------------------------------------------------------------- void OLED_OFF(void) { WriteCmd(0X8D); //设置电荷泵 WriteCmd(0X10); //关闭电荷泵 WriteCmd(0XAE); //OLED休眠 } //在指定位置显示一个字符,包括部分字符 //x:0~127 //y:0~7 //chr:显示的字符 //TextSize:字符大小(1:6*8 ; 2:8*16) //mode:1,反白显示;0,正常显示 void OLED_ShowChar(unsigned char x,unsigned char y,unsigned char chr,unsigned char TextSize,u8 mode) { unsigned char c=0,i=0; c=chr-' ';//得到偏移后的值 if(TextSize == 2) { if(x>120){x=0;y++;} OLED_SetPos(x,y); for(i=0;i<8;i++) if(mode==1)WriteDat(~(F8X16[c*16+i]));else WriteDat(F8X16[c*16+i]); OLED_SetPos(x,y+1); for(i=0;i<8;i++) if(mode==1)WriteDat(~(F8X16[c*16+i+8]));else WriteDat(F8X16[c*16+i+8]); } else { if(x>126){x=0;y++;} OLED_SetPos(x,y); for(i=0;i<6;i++) if(mode==1)WriteDat(~(F6x8[c][i])); else WriteDat(F6x8[c][i]); } } //-------------------------------------------------------------- // Prototype : void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize) // Calls : // Parameters : x,y -- 起始点坐标(x:0~127, y:0~7); ch[] -- 要显示的字符串; TextSize -- 字符大小(1:6*8 ; 2:8*16) // Description : 显示codetab.h中的ASCII字符,有6*8和8*16可选择 //-------------------------------------------------------------- void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize,u8 mode) { unsigned char c = 0,i = 0,j = 0; switch(TextSize) { case 1: { while(ch[j] != '\0') { c = ch[j] - 32; if(x > 126) { x = 0; y++; } OLED_SetPos(x,y); for(i=0;i<6;i++) if(mode==1)WriteDat(~(F6x8[c][i])); else WriteDat(F6x8[c][i]); x += 6; j++; } }break; case 2: { while(ch[j] != '\0') { c = ch[j] - 32; if(x > 120) { x = 0; y++; } OLED_SetPos(x,y); for(i=0;i<8;i++) if(mode==1)WriteDat(~(F8X16[c*16+i])); else WriteDat(F8X16[c*16+i]); OLED_SetPos(x,y+1); for(i=0;i<8;i++) if(mode==1)WriteDat(~(F8X16[c*16+i+8])); else WriteDat(F8X16[c*16+i+8]); x += 8; j++; } }break; } } //-------------------------------------------------------------- // Prototype : void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N) // Calls : // Parameters : x,y -- 起始点坐标(x:0~127, y:0~7); N:汉字在codetab.h中的索引 // Description : 显示codetab.h中的汉字,16*16点阵 //mode:1,反白显示;0,正常显示 //-------------------------------------------------------------- void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N,u8 mode) { unsigned char wm=0; unsigned int adder=32*N; OLED_SetPos(x , y); for(wm = 0;wm < 16;wm++) { if(mode==1)WriteDat(~(F16x16[adder]));else WriteDat(F16x16[adder]); adder += 1; } OLED_SetPos(x,y + 1); for(wm = 0;wm < 16;wm++) { if(mode==1)WriteDat(~(F16x16[adder]));else WriteDat(F16x16[adder]); adder += 1; } } //-------------------------------------------------------------- // Prototype : void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]); // Calls : // Parameters : x0,y0 -- 起始点坐标(x0:0~127, y0:0~7); x1,y1 -- 起点对角线(结束点)的坐标(x1:1~128,y1:1~8) // Description : 显示BMP位图 //-------------------------------------------------------------- void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]) { unsigned int j=0; unsigned char x,y; if(y1%8==0) y = y1/8; else y = y1/8 + 1; for(y=y0;y<y1;y++) { OLED_SetPos(x0,y); for(x=x0;x<x1;x++) { WriteDat(BMP[j++]); } } } void OLED_ShowCentigrade(unsigned char x, unsigned char y)//显示℃ { unsigned char wm=0; unsigned char BUF[]={ 0x10,0x28,0x10,0xC0,0x20,0x10,0x10,0x10,0x20,0x70,0x00,0x00,0x00,0x00,0x00,0x07, 0x08,0x10,0x10,0x10,0x10,0x08,0x04,0x00,/*"℃"*/ }; OLED_SetPos(x , y); for(wm = 0;wm < 12;wm++) { WriteDat(BUF[wm]); } OLED_SetPos(x,y + 1); for(wm = 0;wm < 12;wm++) { WriteDat(BUF[wm+12]); } } #ifndef __OLED_I2C_H #define __OLED_I2C_H #include "stm32f10x.h" #define OLED_ADDRESS 0x78 //通过调整0R电阻,屏可以0x78和0x7A两个地址 -- 默认0x78 #define I2C_WR 0 /* 写控制bit */ #define I2C_RD 1 /* 读控制bit */ void bsp_InitI2C_2(void); void i2c_Start_2(void); void i2c_Stop_2(void); void i2c_SendByte_2(uint8_t _ucByte); uint8_t i2c_ReadByte_2(void); uint8_t i2c_WaitAck_2(void); void i2c_Ack_2(void); void i2c_NAck_2(void); void I2C_Configuration(void); void I2C_WriteByte(uint8_t addr,uint8_t data); void WriteCmd(unsigned char I2C_Command); void WriteDat(unsigned char I2C_Data); void OLED_Init(void); void OLED_SetPos(unsigned char x, unsigned char y); void OLED_Fill(unsigned char fill_Data); void OLED_CLS(void); void OLED_ON(void); void OLED_OFF(void); void OLED_ShowChar(unsigned char x,unsigned char y,unsigned char chr,unsigned char TextSize,u8 mode); void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize,u8 mode); void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N,u8 mode); void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]); void OLED_ShowCentigrade(unsigned char x, unsigned char y); #endif TIME定时器程序 #include "timer.h" //通用定时器中断初始化 //这里时钟选择为APB1的2倍,而APB1为36M //arr:自动重装值。 //psc:时钟预分频数 //这里使用的是定时器3! void TIM3_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_ITConfig( //使能或者失能指定的TIM中断 TIM3, //TIM3 TIM_IT_Update , ENABLE //使能 ); NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级0级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级2级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 TIM_Cmd(TIM3, ENABLE); //使能定时器3 } #ifndef __TIMER_H #define __TIMER_H #include "sys.h" void TIM3_Init(u16 arr,u16 psc); #endif DS18B20温度程序 #include "ds18b20.h" #include "delay.h" /******************************************************************************* 函数名:DS18B20_GPIO_Init 功能:初始化DS18B20引脚 输入: 输出: 返回值: 备注: *******************************************************************************/ void DS18B20_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_DS18B20_PORT, ENABLE); //使能PORTA口时钟 GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure); GPIO_SetBits(DS18B20_GPIO_PORT,DS18B20_GPIO_PIN); //输出1 } /******************************************************************************* 函数名:DS18B20_Init 功能:初始化DS18B20 输入: 输出: 返回值:初始化成功为0,不成功为1 备注: *******************************************************************************/ u8 DS18B20_Init(void) { unsigned char wait=0; DS18B20_IO_OUT(); //输出模式 DS18B20_OUT_0; //拉低 delay_us(750); //至少延时480us DS18B20_OUT_1; //拉高 delay_us(15); //15us DS18B20_IO_IN(); //输入模式 while(READ_DS18B20_IO && wait++<200)delay_us(1);//等待高电平结束 if(wait>=200)return 1; else wait=0; while(!READ_DS18B20_IO && wait++<240)delay_us(1);//等待低电平结束 if(wait>=240)return 1; else return 0; } /******************************************************************************* 函数名:DS18B20_ReadByte 功能:从DS18B20读一个字节 输入: 输出: 返回值:读取到的字节 备注: *******************************************************************************/ unsigned char DS18B20_ReadByte(void) { unsigned char i; unsigned char dat = 0; for (i=0; i<8; i++) //8位计数器 { dat >>= 1; DS18B20_IO_OUT(); //输出模式 DS18B20_OUT_0; //开始时间片 delay_us(2); //延时等待 DS18B20_OUT_1; //准备接收 DS18B20_IO_IN(); //输入模式 delay_us(12); //接收延时 if(READ_DS18B20_IO) dat |= 0x80; //读取数据 delay_us(60); //等待时间片结束 } return dat; } /******************************************************************************* 函数名:DS18B20_WriteByte 功能:写一个字节 输入:unsigned char dat 输出: 返回值: 备注: *******************************************************************************/ void DS18B20_WriteByte(unsigned char dat) { unsigned char i; unsigned char temp; DS18B20_IO_OUT();//输出模式 for (i=1; i<=8; i++) { temp = dat & 0x01; dat = dat >> 1; if (temp) { DS18B20_OUT_0; delay_us(2); DS18B20_OUT_1; //写1 delay_us(60); } else { DS18B20_OUT_0;//写0 delay_us(60); DS18B20_OUT_1; delay_us(2); } } } /************************************** 从DS18B20中获取温度值得浮点值 参数: 空 返回值: 读取到的温度值(有效范围-55.0~125.0) **************************************/ float ReadTemperature(void) { unsigned char TPH; //存放温度值的高字节 unsigned char TPL; //存放温度值的低字节 short i16=0; float f32=0; DS18B20_Init(); DS18B20_WriteByte(0xCC); //跳过ROM命令 DS18B20_WriteByte(0x44); //开始转换命令 DS18B20_Init(); DS18B20_WriteByte(0xCC); //跳过ROM命令 DS18B20_WriteByte(0xBE); //读暂存存储器命令 TPL = DS18B20_ReadByte(); //读温度低字节 TPH = DS18B20_ReadByte(); //读温度高字节 i16 = 0; i16 = (TPH<<8) |TPL; // 将高位(MSB)与低位(LSB)合并 f32 = i16 * 0.0625; // 12bit精度时温度值计算 return(f32); // 返回读取到的温度数值(float型) } #ifndef __DS18B20_H #define __DS18B20_H #include "sys.h" //如果想要修改引脚,只需修改下面的宏 #define RCC_DS18B20_PORT RCC_APB2Periph_GPIOA /* GPIO端口时钟 */ #define DS18B20_GPIO_PIN GPIO_Pin_11 #define DS18B20_GPIO_PORT GPIOA //IO方向设置(CRL寄存器对应引脚0~7,CRH寄存器对应引脚8~15) //DS18B20_GPIO_PORT->CRH&=0xFFFFFFF0为PA8引脚输出模式对应的寄存器清空 //DS18B20_GPIO_PORT->CRH|=0x00000008将(CNF8[1:0]设置为10:上拉/下拉输入模式,MODE8[1;0]设置为00:输入模式) //DS18B20_GPIO_PORT->CRH|=0x00000003将(CNF8[1:0]设置为00:通用推挽输出模式 ,MODE8[1;0]设置为11:最大50MHZ) #define DS18B20_IO_IN() {DS18B20_GPIO_PORT->CRH&=0xFFFF0FFF;DS18B20_GPIO_PORT->CRH|=0x00008000;} #define DS18B20_IO_OUT() {DS18B20_GPIO_PORT->CRH&=0xFFFF0FFF;DS18B20_GPIO_PORT->CRH|=0x00003000;} #define DS18B20_OUT_0 GPIO_ResetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN)//IO为低电平 #define DS18B20_OUT_1 GPIO_SetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN)//IO为高电平 #define READ_DS18B20_IO GPIO_ReadInputDataBit(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN)//读取IO电平 void DS18B20_GPIO_Init(void); u8 DS18B20_Init(void); //初始化DS18B20 float ReadTemperature(void); //获取温度值 #endif 修改代码中使用OLED的部分,改为使用LCD1602实现

#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "lcd.h" #include "dac.h" #include "adc.h" #include "timer.h" #include "stm32f10x_it.h" #include "key.h" #include "stm32f10x.h" #include "math.h" //数值可以用int u8 最大256 int fangbo[512]={ 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, }; int sin_table[512]= { 128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173, 176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215,218,220,222,224,226, 228,230,232,234,235,237,238,240,241,243,244,245,246,248,249,250,250,251,252,253,253, 254,254,254,255,255,255,255,255,255,255,254,254,254,253,253,252,251,250,250,249,248, 246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,220,218,215,213,211, 208,206,203,201,198,196,193,190,188,185,182,179,176,173,170,167,165,162,158,155,152, 149,146,143,140,137,134,131,128,124,121,118,115,112,109,106,103,100,97,93,90,88,85, 82,79,76,73,70,67,65,62,59,57,54,52,49,47,44,42,40,37,35,33,31,29,27,25,23,21,20,18, 17,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11, 12,14,15,17,18,20,21,23,25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,65,67,70,73, 76,79,82,85,88,90,93,97,100,103,106,109,112,115,118,121,124,128,131,134,137,140,143,146, 149,152,155,158,162,165,167,170,173,176,179,182,185,188,190,193,196,198,201,203,206,208, 211,213,215,218,220,222,224,226,228,230,232,234,235,237,238,240,241,243,244,245,246,248, 249,250,250,251,252,253,253,254,254,254,255,255,255,255,255,255,255,254,254,254,253,253, 252,251,250,250,249,248,246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222, 220,218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,176,173,170,167,165, 162,158,155,152,149,146,143,140,137,134,131,128,124,121,118,115,112,109,106,103,100,97, 93,90,88,85,82,79,76,73,70,67,65,62,59,57,54,52,49,47,44,42,40,37,35,33,31,29,27,25,23, 21,20,18,17,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9, 10,11,12,14,15,17,18,20,21,23,25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,65,67,70, 73,76,79,82,85,88,90,93,97,100,103,106,109,112,115,118,121,124}; int Triangle[256]={ 136,137,138, 139,140,141,142,143,144,145,146,147,148, 149,150,151,152,153,154,155,156,157,158, 159,160,161,162,163,164,165,166,167,168, 169,170,171,172,173,174,175,176,177,178, 179,180,181,182,183,184,185,186,187,188, 189,190,191,192,193,194,195,196,197,198, 199,200,199,198,197,196,195,194,193,192, 191,190,189,188,187,186,185,184,183,182, 181,180,179,178,177,176,175,174,173,172, 171,170,169,168,167,166,165,164,163,162, 161,160,159,158,157,156,155,154,153,152, 151,150,149,148,147,146,145,144,143,142, 141,140,139,138,137, 136,137,138, 139,140,141,142,143,144,145,146,147,148, 149,150,151,152,153,154,155,156,157,158, 159,160,161,162,163,164,165,166,167,168, 169,170,171,172,173,174,175,176,177,178, 179,180,181,182,183,184,185,186,187,188, 189,190,191,192,193,194,195,196,197,198, 199,200,199,198,197,196,195,194,193,192, 191,190,189,188,187,186,185,184,183,182, 181,180,179,178,177,176,175,174,173,172, 171,170,169,168,167,166,165,164,163,162, 161,160,159,158,157,156,155,154,153,152, 151,150,149,148,147,146,145,144,143,142, 141,140,139,138,137 }; int main(void) { // u8 ping=0; u8 pinglv=99; u8 yanshi=1; u8 zkb=50;u8 zkbbef=50; u8 t,len; u16 iii=0; u16 i; u16 adcx,adcxtemp,adcxtemp1; //float temp; u8 jishu=0; u8 jishu1=0; u16 ii=0; u8 key=0; //u8 key1=0; // u8 x; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2 delay_init(); //初始化延时函数 uart_init(115200); //初始化串口波特率为115200 LED_Init(); //初始化LED LCD_Init(); //初始化LCD KEY_Init(); LED0 = 0; Adc_Init(); //ADC初始化 Dac1_Init(); //DAC初始化 //usmart_dev.init(72); //初始化USMART ??串口用 (DAC_Align_12b_R, 0);//初始值为0 POINT_COLOR=BLUE;//设置字体为蓝色 LCD_ShowString(60,280,200,16,16,"Freq(HZ): 0."); LCD_ShowString(60,300,200,16,16,"Duty Cycle(%):"); while(1) { //串口功能 我是单片机 接受 :电脑串口发给我 发送:我发给串口电脑 if(USART_RX_STA&0x8000) // USART_RX_STA|=0x8000; 接收完成了 一次大循环接受一个u8(一个数字或者字符),存入BUF 再存入res中 { printf("\r\n您发送的频率0.1-0.99Hz占空比2位0-99%\r\n\r\n"); //频率范围 单位hz len=USART_RX_STA&0x3fff;//得到此次接收到的数据长? for(t=0;t<len;t++) { USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数? 先进来的存在? buf0中,,,, //u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.一个字节8b len个数组 整型数组 pinglv=10*(USART_RX_BUF[0]-48)+(USART_RX_BUF[1]-48); zkb=10*(USART_RX_BUF[2]-48)+(USART_RX_BUF[3]-48); zkb=100-zkb; while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束 } printf("\r\n\r\n");//插入换行 USART_RX_STA=0;//??/接收状态标记 } key=KEY_Scan(0); //得到键值 修改通过一个按键切换三种波形 //返回1,KEY0按下 if(key==KEY0_PRES) { jishu1=jishu; jishu++; } switch(jishu%3) { case 0: //正弦 if(jishu!=jishu1) { jishu1=jishu; ii=0;iii=0; LCD_Clear(WHITE); LCD_ShowString(60,280,200,16,16,"Freq(HZ): 0."); LCD_ShowString(60,300,200,16,16,"Duty Cycle(%):"); } //LCD_Fast_DrawPoint(ii,sin_table[2*ii],BLACK);//打点 Dac1_Set_Vol(sin_table[2*ii]);//DA输出 pA4输出da转模拟值 pa1输入模拟值转ad if(ii>=1) LCD_DrawLine(ii,sin_table[2*ii],ii-1,sin_table[2*ii-2]);//画线 ii++; if(ii==255) {ii=0;} break; case 1: //三角 if(jishu!=jishu1) {jishu1=jishu; ii=0;iii=0; LCD_Clear(WHITE); LCD_ShowString(60,280,200,16,16,"Freq(HZ): 0."); LCD_ShowString(60,300,200,16,16,"Duty Cycle(%):"); } LCD_Fast_DrawPoint(ii,Triangle[ii],BLACK); Dac1_Set_Vol(Triangle[ii]);//DA输出 ii++; if(ii==255) {ii=0;} break; case 2: //方波 一个周期128点 低64 高64 if(jishu!=jishu1) {jishu1=jishu; iii=0;ii=0; LCD_Clear(WHITE); LCD_ShowString(60,280,200,16,16,"Freq(HZ): 0."); LCD_ShowString(60,300,200,16,16,"Duty Cycle(%):"); } // LCD_Fast_DrawPoint(ii,fangbo[2*ii],BLACK); //修改占空比zkb 0-99 修改数组值 if(zkb!=zkbbef) //检测zkb是否改变 如果改变再重新赋值数组fangbo { zkbbef=zkb; for(i=0;i<128*zkb/100*2;i++)//zkb给的是整数 { fangbo[i]=255; fangbo[i+256]=255; //fangbo[256-(int)(128*zkb/100*2)]=128; fangbo[512-i-1]=128; } for(i=(int)(128*zkb/100*2);i<256;i++) { fangbo[i]=1; fangbo[i+256]=1; //fangbo[256-(int)(128*zkb/100*2)]=128; fangbo[512-i-1]=128; } } if (ii>=1) LCD_DrawLine(ii,fangbo[2*ii],ii-1,fangbo[2*ii-2]);//画线 ii++; if(ii==255) {ii=0; } Dac1_Set_Vol(fangbo[2*ii]);//DA输出 break; } //adc输出后再清屏 adcx=Get_Adc(ADC_Channel_1); // adcx=Get_Adc_Average(ADC_Channel_1,1); //10-1 //采样1次 输出ad平均值 LCD_ShowxNum(156,280,pinglv,4,16,0);//显示频率 LCD_ShowxNum(156,300,100-zkb,4,16,0);//显示zkb值 // LCD_ShowxNum(156,320,yanshi,4,16,0); adcxtemp1=adcxtemp; adcxtemp=(int)(adcx*0.03125+284); //384 //显示在下半屏幕 // LCD_Fast_DrawPoint(iii,adcxtemp,255); //打点 if(iii>=1) LCD_DrawLine(iii,adcxtemp,iii-1,adcxtemp1);//画线 iii++; if(iii==255) { iii=0; LCD_Clear(WHITE); LCD_ShowString(60,280,200,16,16,"Freq(HZ): 0."); LCD_ShowString(60,300,200,16,16,"Duty Cycle(%)"); }//显示zkb } //clear 前面ii=255不清屏 iii=255清屏 yanshi=100-pinglv; // delay_ms(yanshi); /* 输入pinglv=1000hz T=0.001 一个点yanshi? us 正弦128 方波一个周期128 三角128 pinglv=100 t=0.01 10 0.1 18359x 5 0.2 1 1 2382 0.5 2 */ } } 修改代码:改为频率范围为1~10k赫兹

大家在看

recommend-type

密码::unlocked::sparkles::locked:创新,方便,安全的加密应用程序

隐身者 创新,方便,安全的加密应用程序。 加密无限位。 只记得一点。 Crypter是一款跨平台的加密应用程序,它使加密和解密变得很方便,同时仍然保持强大的安全性。 它解决了当今大多数安全系统中最弱的链接之一-弱密码。 它简化了安全密码的生成和管理,并且只需要记住一个位-MasterPass。 是一个加密应用程序,可以解密和加密包括文件和文件夹在内的任意数据。 该版本已发布,并针对macOS(OSX),Linux(适用于所有通过发行的发行版)和Windows(32和64位)进行了全面测试。 所有核心模块(提供核心功能的模块)都经过了全面测试。 会将MasterPass保存在操作系统的钥匙串中,因此您不必在每次打开应用程序时都输入它。 为了帮助加快开发速度,请发送PR剩下的内容做 如果您有任何建议,请打开一个问题,并通过PR进行改进! 还要签出 ( )一个分散的端到端加密消息传递应用程序。 链接到此自述文件: : 内容 安装 适用于所有主要平台的所有预构建二进制文件都可以在。 Crypter也适用于macOS的 。 因此,要安装它,只需在终端中运行以下命令:
recommend-type

mfc 打印机打印图片

mfc,小程序,关于打印机的操作 像文字输出,图片输出,设备管理
recommend-type

libusb资料

包含libusb驱动程序libusb-win32-bin-1.2.2.0以及delphi环境下的libusb使用的例子以及一篇libusb说明文档。
recommend-type

Kvaser CANLIB API.pdf

Kvaser CANLIB是Kvaser 的CAN测试设备提供的API
recommend-type

嵌入桌面的搜索工具

该程序的窗体是不规则,父窗口是桌面窗口(桌面实际上有3层的可视窗口)。点击 显示桌面,该窗口也不会被最小化。用C#实现,有代码。工程在VS 2008下建的,.NET Framework 为2.0。

最新推荐

recommend-type

wx群导航源码简单漂亮轻量级2.0.zip

wx群导航源码简单漂亮轻量级2.0
recommend-type

模拟电子技术基础学习指导与习题精讲

模拟电子技术是电子技术的一个重要分支,主要研究模拟信号的处理和传输,涉及到的电路通常包括放大器、振荡器、调制解调器等。模拟电子技术基础是学习模拟电子技术的入门课程,它为学习者提供了电子器件的基本知识和基本电路的分析与设计方法。 为了便于学习者更好地掌握模拟电子技术基础,相关的学习指导与习题解答资料通常会包含以下几个方面的知识点: 1. 电子器件基础:模拟电子技术中经常使用到的电子器件主要包括二极管、晶体管、场效应管(FET)等。对于每种器件,学习指导将会介绍其工作原理、特性曲线、主要参数和使用条件。同时,还需要了解不同器件在电路中的作用和性能优劣。 2. 直流电路分析:在模拟电子技术中,需要掌握直流电路的基本分析方法,这包括基尔霍夫电压定律和电流定律、欧姆定律、节点电压法、回路电流法等。学习如何计算电路中的电流、电压和功率,以及如何使用这些方法解决复杂电路的问题。 3. 放大电路原理:放大电路是模拟电子技术的核心内容之一。学习指导将涵盖基本放大器的概念,包括共射、共基和共集放大器的电路结构、工作原理、放大倍数的计算方法,以及频率响应、稳定性等。 4. 振荡电路:振荡电路能够产生持续的、周期性的信号,它在模拟电子技术中非常重要。学习内容将包括正弦波振荡器的原理、LC振荡器、RC振荡器等类型振荡电路的设计和工作原理。 5. 调制与解调:调制是将信息信号加载到高频载波上的过程,解调则是提取信息信号的过程。学习指导会介绍调幅(AM)、调频(FM)、调相(PM)等调制方法的基本原理和解调技术。 6. 模拟滤波器:滤波器用于分离频率成分不同的信号。模拟滤波器一般可分为低通、高通、带通和带阻滤波器。学习指导会涉及到模拟滤波器的设计原理、特性曲线和应用。 7. 电源技术:电源电路是电子设备中不可或缺的部分,它主要为电子设备提供稳定的直流电压和电流。在模拟电子技术基础学习指导中,会讲解线性稳压电源和开关稳压电源的设计原理及其实现方法。 8. 实际问题应用:模拟电子技术在实际中有着广泛的应用,学习指导会结合具体案例,如音响系统设计、射频接收机、仪器仪表等,帮助学习者将理论知识应用到实践中,提高解决实际问题的能力。 9. 习题解答:为了帮助学习者巩固理论知识和分析问题的能力,相关习题解答资料将提供大量精选习题,并给出详细的解答步骤和答案。习题类型涵盖选择题、填空题、计算题和设计题,旨在帮助学习者全面掌握知识点。 学习模拟电子技术需要具备一定的数学、物理基础,尤其是对电路分析的理解。通过学习指导与习题解答资料的帮助,学习者可以更加深入地理解模拟电子技术的基本概念,熟练掌握模拟电路的分析与设计方法,并为将来的深入学习和实际应用打下坚实的基础。
recommend-type

【5G通信背后的秘密】:极化码与SCL译码技术的极致探索

# 摘要 本文首先概述了5G通信技术及其重要性,然后深入探讨了极化码的基础理论与应用,包括其理论基础、编解码过程和在5G中的应用评估。接着,文章详细解析了SCL译码技术的原理、改进方法以及实现和优化策略。在第四章中,分析了极化码与SCL译码技术在5G通信中的实践挑战、优化案例,以及未来的发展趋势。最后一章展望了极化码与S
recommend-type

谷歌浏览器中如何使用hackbar

<think>我们正在处理用户关于在Google Chrome浏览器中安装和使用HackBar插件的请求。根据引用[1]和引用[2]的信息,我们可以总结出安装步骤。注意,引用中提到了两种安装方法:一种是直接拖放crx文件(但可能会遇到问题),另一种是将crx文件改为rar格式再安装。同时,引用[2]还提到了Firefox的安装方法,但用户只关心Chrome。 由于Chrome浏览器对扩展程序的安全性要求提高,直接从第三方下载的crx文件可能会被阻止安装。因此,我们需要提供一种可行的安装方法。 根据引用[2]的步骤,我们可以这样安装: 1. 下载HackBar_v2.2.6插件(通常是一个c
recommend-type

一步搞定局域网共享设置的超级工具

在当前信息化高速发展的时代,局域网共享设置成为了企业、学校甚至家庭用户在资源共享、网络协同办公或学习中不可或缺的一部分。局域网共享不仅能够高效地在本地网络内部分发数据,还能够在保护网络安全的前提下,让多个用户方便地访问同一资源。然而,对于部分用户而言,局域网共享设置可能显得复杂、难以理解,这时一款名为“局域网共享设置超级工具”的软件应运而生,旨在简化共享设置流程,使得即便是对网络知识了解不多的用户也能够轻松配置。 ### 局域网共享知识点 #### 1. 局域网基础 局域网(Local Area Network,LAN)指的是在一个较小的地理范围内,如一座建筑、一个学校或者一个家庭内部,通过电缆或者无线信号连接的多个计算机组成的网络。局域网共享主要是指将网络中的某台计算机或存储设备上的资源(如文件、打印机等)对网络内其他用户开放访问权限。 #### 2. 工作组与域的区别 在Windows系统中,局域网可以通过工作组或域来组织。工作组是一种较为简单的组织方式,每台电脑都是平等的,没有中心服务器管理,各个计算机间互为对等网络,共享资源只需简单的设置。而域模式更为复杂,需要一台中央服务器(域控制器)进行集中管理,更适合大型网络环境。 #### 3. 共享设置的要素 - **共享权限:**决定哪些用户或用户组可以访问共享资源。 - **安全权限:**决定了用户对共享资源的访问方式,如读取、修改或完全控制。 - **共享名称:**设置的名称供网络上的用户通过网络邻居访问共享资源时使用。 #### 4. 共享操作流程 在使用“局域网共享设置超级工具”之前,了解传统手动设置共享的流程是有益的: 1. 确定需要共享的文件夹,并右键点击选择“属性”。 2. 进入“共享”标签页,点击“高级共享”。 3. 勾选“共享此文件夹”,可以设置共享名称。 4. 点击“权限”按钮,配置不同用户或用户组的共享权限。 5. 点击“安全”标签页配置文件夹的安全权限。 6. 点击“确定”,完成设置,此时其他用户可以通过网络邻居访问共享资源。 #### 5. 局域网共享安全性 共享资源时,安全性是一个不得不考虑的因素。在设置共享时,应避免公开敏感数据,并合理配置访问权限,以防止未授权访问。此外,应确保网络中的所有设备都安装了防病毒软件和防火墙,并定期更新系统和安全补丁,以防恶意软件攻击。 #### 6. “局域网共享设置超级工具”特点 根据描述,该软件提供了傻瓜式的操作方式,意味着它简化了传统的共享设置流程,可能包含以下特点: - **自动化配置:**用户只需简单操作,软件即可自动完成网络发现、权限配置等复杂步骤。 - **友好界面:**软件可能具有直观的用户界面,方便用户进行设置。 - **一键式共享:**一键点击即可实现共享设置,提高效率。 - **故障诊断:**可能包含网络故障诊断功能,帮助用户快速定位和解决问题。 - **安全性保障:**软件可能在设置共享的同时,提供安全增强功能,如自动更新密码、加密共享数据等。 #### 7. 使用“局域网共享设置超级工具”的注意事项 在使用该类工具时,用户应注意以下事项: - 确保安装了最新版本的软件以获得最佳的兼容性和安全性。 - 在使用之前,了解自己的网络安全政策,防止信息泄露。 - 定期检查共享设置,确保没有不必要的资源暴露在网络中。 - 对于不熟悉网络共享的用户,建议在专业人士的指导下进行操作。 ### 结语 局域网共享是实现网络资源高效利用的基石,它能大幅提高工作效率,促进信息共享。随着技术的进步,局域网共享设置变得更加简单,各种一键式工具的出现让设置过程更加快捷。然而,安全性依旧是不可忽视的问题,任何时候在享受便捷的同时,都要确保安全措施到位,防止数据泄露和网络攻击。通过合适的工具和正确的设置,局域网共享可以成为网络环境中一个强大而安全的资源。
recommend-type

PBIDesktop在Win7上的终极安装秘籍:兼容性问题一次性解决!

# 摘要 PBIDesktop作为数据可视化工具,其在Windows 7系统上的安装及使用备受企业关注。本文首先概述了PBIDesktop的安装过程,并从理论上探讨了其兼容性问题,包括问题类型、原因以及通用解决原则。通过具体
recommend-type

#include "stm32f10x.h" #include "delay.h" #include "OLED.h" #include "dht11.h" #include "FMQ.h" #include "Serial.h" #include "esp8266.h" #include "stm32f10x_it.h" // 系统时钟配置 void SystemClock_Config(void) { SystemInit(); RCC_DeInit(); RCC_HSEConfig(RCC_HSE_ON); // 添加HSE启动检测 if(!RCC_WaitForHSEStartUp()) { while(1); // HSE启动失败,陷入死循环 } FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); FLASH_SetLatency(FLASH_Latency_2); RCC_HCLKConfig(RCC_SYSCLK_Div1); RCC_PCLK1Config(RCC_HCLK_Div2); RCC_PCLK2Config(RCC_HCLK_Div1); RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); RCC_PLLCmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); while(RCC_GetSYSCLKSource() != 0x08); } // 全局变量 u8 temp, humi; int main(void) { // 系统初始化 SystemClock_Config(); Delay_Init(); OLED_Init(); DHT11_Init(); mfq_Init(); Serial_Init(); // 用于调试的串口 // 显示初始化 OLED_ShowCN(0, 0, "温度:"); // 修改为正确的中文字库函数 OLED_ShowCN(0, 16, "湿度:"); OLED_ShowCN(64, 16, "RH"); OLED_ShowCN(64, 0, "C"); OLED_Update(); // 初始化ESP8266为AP模式 ESP8266_Init(); printf("ESP8266 AP Mode Ready\r\n"); printf("Connect to WiFi: ESP8266wd, Password:123456789\r\n"); printf("Then connect to TCP Server: 192.168.4.1:8080\r\n"); uint32_t lastSendTime = 0; while(1) { // 读取温湿度 if(DHT11_Read_Data(&temp, &humi)) { // 更新显示 OLED_ShowNum(47, 0, temp, 2, OLED_8X16); OLED_ShowNum(47, 16, humi, 2, OLED_8X16); OLED_Update(); // 控制蜂鸣器 fmq(temp, humi); // 串口输出信息 printf("temp=%d, humi=%d RH\r\n", temp, humi); // 准备WiFi发送数据 sprintf(wifi_data, "Temp:%d,Humi:%d\r\n", temp, humi); ESP8266_SendData(wifi_data); } delay_ms(5000); // 5秒更新一次 } } /** ****************************************************************************** * @file Project/STM32F10x_StdPeriph_Template/stm32f10x_conf.h * @author MCD Application Team * @version V3.5.0 * @date 08-April-2011 * @brief Library configuration file. ****************************************************************************** * @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2> ****************************************************************************** */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __STM32F10x_CONF_H #define __STM32F10x_CONF_H /* Includes ------------------------------------------------------------------*/ /* Uncomment/Comment the line below to enable/disable peripheral header file inclusion */ #include "stm32f10x_adc.h" #include "stm32f10x_bkp.h" #include "stm32f10x_can.h" #include "stm32f10x_cec.h" #include "stm32f10x_crc.h" #include "stm32f10x_dac.h" #include "stm32f10x_dbgmcu.h" #include "stm32f10x_dma.h" #include "stm32f10x_exti.h" #include "stm32f10x_flash.h" #include "stm32f10x_fsmc.h" #include "stm32f10x_gpio.h" #include "stm32f10x_i2c.h" #include "stm32f10x_iwdg.h" #include "stm32f10x_pwr.h" #include "stm32f10x_rcc.h" #include "stm32f10x_rtc.h" #include "stm32f10x_sdio.h" #include "stm32f10x_spi.h" #include "stm32f10x_tim.h" #include "stm32f10x_usart.h" #include "stm32f10x_wwdg.h" #include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Uncomment the line below to expanse the "assert_param" macro in the Standard Peripheral Library drivers code */ /* #define USE_FULL_ASSERT 1 */ /* Exported macro ------------------------------------------------------------*/ #ifdef USE_FULL_ASSERT /** * @brief The assert_param macro is used for function's parameters check. * @param expr: If expr is false, it calls assert_failed function which reports * the name of the source file and the source line number of the call * that failed. If expr is true, it returns no value. * @retval None */ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) /* Exported functions ------------------------------------------------------- */ void assert_failed(uint8_t* file, uint32_t line); #else #define assert_param(expr) ((void)0) #endif /* USE_FULL_ASSERT */ #endif /* __STM32F10x_CONF_H */ /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ /** ****************************************************************************** * @file Project/STM32F10x_StdPeriph_Template/stm32f10x_it.c * @author MCD Application Team * @version V3.5.0 * @date 08-April-2011 * @brief Main Interrupt Service Routines. * This file provides template for all exceptions handler and * peripherals interrupt service routine. ****************************************************************************** * @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2> ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x_it.h" volatile uint32_t sysTickUptime = 0; // 添加在文件顶部 /** @addtogroup STM32F10x_StdPeriph_Template * @{ */ /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /******************************************************************************/ /* Cortex-M3 Processor Exceptions Handlers */ /******************************************************************************/ /** * @brief This function handles NMI exception. * @param None * @retval None */ void NMI_Handler(void) { } /** * @brief This function handles Hard Fault exception. * @param None * @retval None */ void HardFault_Handler(void) { /* Go to infinite loop when Hard Fault exception occurs */ while (1) { } } /** * @brief This function handles Memory Manage exception. * @param None * @retval None */ void MemManage_Handler(void) { /* Go to infinite loop when Memory Manage exception occurs */ while (1) { } } /** * @brief This function handles Bus Fault exception. * @param None * @retval None */ void BusFault_Handler(void) { /* Go to infinite loop when Bus Fault exception occurs */ while (1) { } } /** * @brief This function handles Usage Fault exception. * @param None * @retval None */ void UsageFault_Handler(void) { /* Go to infinite loop when Usage Fault exception occurs */ while (1) { } } /** * @brief This function handles SVCall exception. * @param None * @retval None */ void SVC_Handler(void) { } /** * @brief This function handles Debug Monitor exception. * @param None * @retval None */ void DebugMon_Handler(void) { } /** * @brief This function handles PendSVC exception. * @param None * @retval None */ void PendSV_Handler(void) { } /** * @brief This function handles SysTick Handler. * @param None * @retval None */ void SysTick_Handler(void) { // 添加SysTick中断处理 sysTickUptime++; } /******************************************************************************/ /* STM32F10x 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_stm32f10x_xx.s). */ /******************************************************************************/ /** * @brief This function handles USART3 global interrupt request. * @param None * @retval None */ void USART2_IRQHandler(void) { // 调用ESP8266模块的中断处理函数 extern void ESP8266_IRQHandler(void); ESP8266_IRQHandler(); } uint32_t HAL_GetTick(void) { return sysTickUptime; } /** * @} */ /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ /** ****************************************************************************** * @file Project/STM32F10x_StdPeriph_Template/stm32f10x_it.h * @author MCD Application Team * @version V3.5.0 * @date 08-April-2011 * @brief This file contains the headers of the interrupt handlers. ****************************************************************************** * @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2> ****************************************************************************** */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __STM32F10x_IT_H #define __STM32F10x_IT_H #ifdef __cplusplus extern "C" { #endif /* Includes ------------------------------------------------------------------*/ #include "stm32f10x.h" extern volatile uint32_t sysTickUptime; uint32_t HAL_GetTick(void); /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Exported macro ------------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ void NMI_Handler(void); void HardFault_Handler(void); void MemManage_Handler(void); void BusFault_Handler(void); void UsageFault_Handler(void); void SVC_Handler(void); void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); #ifdef __cplusplus } #endif #endif /* __STM32F10x_IT_H */ /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ #include "esp8266.h" #include <string.h> #include "stm32f10x_usart.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" // 发送AT指令 void ESP8266_SendCmd(char* cmd, char* resp, uint16_t timeout) { USART_ClearFlag(ESP8266_USARTx, USART_FLAG_TC); // 发送命令 while(*cmd) { USART_SendData(ESP8266_USARTx, *cmd++); while(USART_GetFlagStatus(ESP8266_USARTx, USART_FLAG_TC) == RESET); } // 等待响应 uint32_t start = HAL_GetTick(); while(strstr((const char*)USART_RxBuffer, resp) == NULL) { if(HAL_GetTick() - start > timeout) { break; } } delay_ms(50); } // 初始化ESP8266为AP模式 void ESP8266_Init(void) { // 初始化USART2 USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; // 配置USART2 Tx (PA2) 为复用推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置USART2 Rx (PA3) 为浮空输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = ESP8266_USART_BAUDRATE; USART_InitStructure.USART_WordLength = USART_WordLength_8b; 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(ESP8266_USARTx, &USART_InitStructure); USART_Cmd(ESP8266_USARTx, ENABLE); // 添加NVIC中断配置 NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // 配置ESP8266为AP模式 Delay_ms(1000); // 等待模块启动 ESP8266_SendCmd("AT+RST\r\n", "OK", 2000); ESP8266_SendCmd("AT+CWMODE=2\r\n", "OK", 2000); // 设置为AP模式 ESP8266_SendCmd("AT+CWSAP=\"ESP8266_AP\",\"12345678\",1,4\r\n", "OK", 2000); // 设置AP参数 ESP8266_SendCmd("AT+CIPMUX=1\r\n", "OK", 2000); // 允许多连接 ESP8266_SendCmd("AT+CIPSERVER=1,8080\r\n", "OK", 2000); // 开启TCP服务器 } // 发送数据到TCP客户端 u8 ESP8266_SendData(char* data) { char cmd[64]; sprintf(cmd, "AT+CIPSEND=0,%d\r\n", strlen(data)); ESP8266_SendCmd(cmd, "OK", 1000); // 等待OK响应 ESP8266_SendCmd(data, ">", 1000); // 等待>提示符 ESP8266_SendCmd((char*)0x1A, "SEND OK", 1000); // 发送Ctrl+Z return 0; } // esp8266.h #ifndef __ESP8266_H #define __ESP8266_H #include "stm32f10x.h" #include "stm32f10x_usart.h" #include "delay.h" #define ESP8266_USARTx USART2 #define ESP8266_USART_BAUDRATE 115200 void ESP8266_Init(void); void ESP8266_SendCmd(char* cmd); u8 ESP8266_SendData(char* data); #endif 将代码修改正确

<think>好的,我需要帮助用户修改他们的代码。首先,我得仔细阅读用户提供的代码,找出其中的问题。用户提到他们使用STM32F10x系列的MCU,结合DHT11、OLED、ESP8266等外设,但可能存在错误需要修正。 首先看主函数部分。在SystemClock_Config函数中,用户调用了SystemInit(),然后进行RCC_DeInit(),这可能有问题,因为SystemInit()已经初始化了系统时钟,而RCC_DeInit()会将RCC寄存器复位,可能导致冲突。正确的做法应该是在SystemInit()之后不再调用RCC_DeInit(),或者在配置前先确保时钟设置正确。
recommend-type

PC-lint 8.0升级至'a'级的patch安装指南

从提供的文件信息中,我们可以推断出以下知识点: 标题中提到的“PCLint 8.0patch”是指PCLint软件的某个版本的补丁更新。PCLint是一款由美国软件公司Gimpel Software开发的用于C和C++语言的静态代码分析工具。它主要被用来检测软件开发中的编程错误、不符合编码标准的代码以及可能引起bug的问题。该工具广泛用于嵌入式软件开发、遵循MISRA(Motor Industry Software Reliability Association)标准的项目中,以确保代码的高质量和可靠性。PCLint可以集成到多种集成开发环境(IDEs)中,例如Eclipse、Visual Studio等。 描述中指出补丁级别的推断方法,即通过后续的字母表示补丁的版本。在这里,补丁级别的“a”是紧随版本号“8.00”之后的第一个字母,暗示补丁“a”是最初发布的补丁。随后,描述中提到如果要更新到补丁级别“c”,则需要下载特定的文件。 从补丁级别更新的描述来看,这表明PCLint版本8.0的后续更新遵循了一个版本控制逻辑,其中补丁级别是按字母顺序递增的。这意味着“a”后面应该是“b”,然后是“c”等。这种命名模式可以帮助用户轻松识别补丁的更新顺序,从而能够获取到最新的错误修复和功能改进。 标签“PClint”是对软件名称的直接引用,并且用于文件管理、检索或者分类时,它能够帮助用户快速定位与PCLint相关的资源或讨论。 在提供的文件信息中,唯一列出的文件“PATCH.EXE”是一个可执行文件,很可能是用于安装PCLint补丁的安装程序。在软件开发和维护过程中,补丁或更新通常会以可执行文件或安装包的形式提供给用户,以便能够自动化安装过程,并确保补丁正确地应用到软件中。当用户下载此PATCH.EXE文件并运行时,程序会执行必要的更新步骤,这通常包括替换旧文件、添加新文件以及更新配置信息等。 为了使用PATCH.EXE更新PCLint,用户可能需要按照如下步骤操作: 1. 访问Gimpel Software的官方网站或获取更新通知。 2. 确认当前安装的PCLint版本,以确保补丁的兼容性。 3. 下载相应版本的补丁文件PATCH.EXE。 4. 关闭所有正在运行的IDE或其他相关程序。 5. 运行PATCH.EXE,通常会有一个向导引导用户完成安装过程。 6. 重启相关开发环境,以确保补丁生效。 7. 运行PCLint,进行检查以确保更新正确应用。 通过这样的更新过程,开发者可以确保他们的静态代码分析工具始终处于最新状态,从而帮助他们保持代码质量,并符合行业标准或公司政策。
recommend-type

【TMR技术的突破】:如何克服传感器设计的挑战,巩固现代科技地位

# 1. TMR技术概述 在信息技术飞速发展的今天,隧道磁阻(TMR)技术作为一种前沿的磁性传感器技术,正逐渐成为业界关注的焦点。TMR传感器以其高灵敏度、低功耗和小尺寸的特点,为磁性检测领域带来革命性的改变。本章节将深入探讨TMR技术的基础知识,包括它的基本原理、工作方式以及在现代电子设备中的应用前景。通过理解这些基础知识,我们可以更好地把握TMR技术的内
recommend-type

java单例的特性

<think>首先,用户的问题是:“我想了解Java中单例模式的特性 请问Java 单例模式的特点和实现方式”。所以,我需要专注于Java单例模式的特点和实现方式。 从系统级指令: - 所有行内数学表达式必须使用$...$格式,但在这个上下文中,可能没有数学表达式,因为主题是Java单例模式,而不是数学。所以,我应该避免不必要的数学,除非有相关部分。 - 独立公式必须使用$$...$$格式并单独成段,同样,可能不适用。 - LaTeX语法正确:确保任何LaTeX正确。 - 使用中文回答:整个回答必须用中文。 - 生成相关问题:在回答后,添加相关问题。 - 回答中引用的段落末尾自然地添加引用标