基于STM32F407ZET6的环境温湿度监控系统(粤嵌GEC-M4)
注意使用事项:
开发板如下
由于外部晶振是8M,需要修改setup和stm32f4头文件的晶振值。
操作如下:
system_stm32f4xx.c的254行
#define PLL_M 8
stm32f4xx.h的127行
#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
基于STM32F407ZET6的环境温湿度监控系统
- 工程文件下载如下
- 功能介绍和使用说明
- 如下代码
- 目录如下
- main.c
- system.c
- system.h
- KEY.c
- KEY.h
- LED.c
- LED.h
- BEEP.c
- BEEP.h
- UART.c
- UART.h
- CODED_LOCK.c
- CODED_LOCK.h
- TIMER.c
- TIMER.h
- DHT11.c
- DHT11.h
- ADC.c
- ADC.h
工程文件下载如下
下载点这里
功能介绍和使用说明
下载程序后打开串口调试助手,按一下复位按键,如图。
通过按键输入1234进入,或者输入指令open#
进入系统,密码错误会连响两下,正确会长响一下,进入之后如图。
到了控制界面,通过输入指令mode0
或者mode1
切换手动模式和自动模式,手动模式可以使用滑动变阻器控制LED1亮度,自动模式可以由光敏电阻调节灯光亮度。
温度阈值和湿度阈值是温度和湿度的临界值,当温度高于临界值,LED3亮,否则灭,当湿度高于临界值,LED2亮。
灯光亮度是滑动变阻器值,光照值是光敏电阻值。
温度阈值可以由指令txx
修改,比如t20
就是修改到20
湿度阈值可以由指令hxx
修改,比如h20
就是修改到20
最后输入off#
退出系统
如下代码
目录如下
main.c
#include "CODED_LOCK.h"int main(void)
{while(1){CODED_LOCK_Open();}
}
system.c
#include "system.h"void System_Init(void)
{LED_Init();KEY_Init();BEEP_Init();UART1_Init(115200);//TIM3_Init(10000,8400);//ADC1_Init();adc_init();adc3_init();TIM14_init();TIM_SetCompare1(TIM14,95);
}//软件延时
void delay_us(uint32_t nus)
{SysTick->CTRL = 0; // Disable SysTick,关闭系统时钟后才能设置寄存器SysTick->LOAD = SystemCoreClock/8/1000000*nus; //设置计数值SysTick->VAL = 0; // Clear current value as well as count flag,清空当前值还有标志位SysTick->CTRL = 1; // Enable SysTick timer with processor clock,使能系统定时器开始计算,且使用8分频的时钟while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set,等待计数完成SysTick->CTRL = 0; // Disable SysTick,关闭系统时钟代表说不再进行定时计数 }void delay_ms(uint32_t nms)
{while(nms --){SysTick->CTRL = 0; // Disable SysTick,关闭系统时钟后才能设置寄存器SysTick->LOAD = SystemCoreClock/8/1000; // 设置计数值SysTick->VAL = 0; // Clear current value as well as count flag,清空当前值还有标志位SysTick->CTRL = 1; // Enable SysTick timer with processor clock,使能系统定时器开始计算,且使用8分频的时钟while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set,等待计数完成SysTick->CTRL = 0; // Disable SysTick,关闭系统时钟代表说不再进行定时计数 }
}
system.h
#ifndef __system_H_
#define __system_H_#include "stm32f4xx.h"
#include "LED.h"
#include "BEEP.h"
#include "KEY.h"
#include "UART.h"
#include "TIMER.h"
#include "DHT11.h"
#include "ADC.h"
#include "string.h"//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).M4同M3类似,只是寄存器地址变了.
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+\((addr & 0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))//把值类型转成地址类型
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr (GPIOB_BASE+20) //0x40020414
#define GPIOC_ODR_Addr (GPIOC_BASE+20) //0x40020814
#define GPIOD_ODR_Addr (GPIOD_BASE+20) //0x40020C14
#define GPIOE_ODR_Addr (GPIOE_BASE+20) //0x40021014
#define GPIOF_ODR_Addr (GPIOF_BASE+20) //0x40021414
#define GPIOG_ODR_Addr (GPIOG_BASE+20) //0x40021814
#define GPIOH_ODR_Addr (GPIOH_BASE+20) //0x40021C14
#define GPIOI_ODR_Addr (GPIOI_BASE+20) //0x40022014 #define GPIOA_IDR_Addr (GPIOA_BASE+16) //0x40020010
#define GPIOB_IDR_Addr (GPIOB_BASE+16) //0x40020410
#define GPIOC_IDR_Addr (GPIOC_BASE+16) //0x40020810
#define GPIOD_IDR_Addr (GPIOD_BASE+16) //0x40020C10
#define GPIOE_IDR_Addr (GPIOE_BASE+16) //0x40021010
#define GPIOF_IDR_Addr (GPIOF_BASE+16) //0x40021410
#define GPIOG_IDR_Addr (GPIOG_BASE+16) //0x40021810
#define GPIOH_IDR_Addr (GPIOH_BASE+16) //0x40021C10
#define GPIOI_IDR_Addr (GPIOI_BASE+16) //0x40022010 //IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入 #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入 #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入 #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入 #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入#define PHout(n) BIT_ADDR(GPIOH_ODR_Addr,n) //输出
#define PHin(n) BIT_ADDR(GPIOH_IDR_Addr,n) //输入#define PIout(n) BIT_ADDR(GPIOI_ODR_Addr,n) //输出
#define PIin(n) BIT_ADDR(GPIOI_IDR_Addr,n) //输入void System_Init(void);
void delay_us(uint32_t nus);
void delay_ms(uint32_t nms);#endif
KEY.c
#include "KEY.h" void KEY_Init(void)
{GPIO_InitTypeDef gpio;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOE,ENABLE);gpio.GPIO_Mode=GPIO_Mode_IN; gpio.GPIO_PuPd=GPIO_PuPd_UP;gpio.GPIO_Pin=GPIO_Pin_0;GPIO_Init(GPIOA,&gpio);gpio.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; GPIO_Init(GPIOE,&gpio);
}
KEY.h
#ifndef __KEY_H_
#define __KEY_H_#include "system.h" #define KEY0 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)
#define KEY2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)
#define KEY3 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)
#define KEY ((KEY0)|(KEY1<<1)|(KEY2<<2)|(KEY3<<3))void KEY_Init(void);
//unsigned char KEY_Scan(void);#endif
LED.c
#include "LED.h" void LED_Init(void)
{GPIO_InitTypeDef gpio;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF|RCC_AHB1Periph_GPIOE,ENABLE);gpio.GPIO_Mode=GPIO_Mode_OUT; gpio.GPIO_PuPd=GPIO_PuPd_UP;gpio.GPIO_Speed=GPIO_Speed_100MHz;gpio.GPIO_OType=GPIO_OType_PP;gpio.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;GPIO_Init(GPIOF,&gpio);gpio.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_14; GPIO_Init(GPIOE,&gpio);GPIO_SetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);GPIO_SetBits(GPIOE,GPIO_Pin_13|GPIO_Pin_14);
}
LED.h
#ifndef __LED_H_
#define __LED_H_#include "system.h"
void LED_Init(void);#endif
BEEP.c
#include "BEEP.h" void BEEP_Init(void)
{GPIO_InitTypeDef gpio;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);gpio.GPIO_Mode=GPIO_Mode_OUT; gpio.GPIO_PuPd=GPIO_PuPd_UP;gpio.GPIO_Speed=GPIO_Speed_100MHz;gpio.GPIO_OType=GPIO_OType_PP;gpio.GPIO_Pin=GPIO_Pin_8;GPIO_Init(GPIOF,&gpio);GPIO_ResetBits(GPIOF,GPIO_Pin_8);
}
BEEP.h
#ifndef __BEEP_H_
#define __BEEP_H_#include "system.h"
void BEEP_Init(void);#endif
UART.c
#include "UART.h"void UART1_Init(uint32_t baudrate)
{GPIO_InitTypeDef GPIO_InitStruct;USART_InitTypeDef USART_InitStruct;NVIC_InitTypeDef NVIC_InitStructure;// 使能USART1和GPIOA的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);// 配置USART1的引脚GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; // PA9(TX), PA10(RX)GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;GPIO_Init(GPIOA, &GPIO_InitStruct);// 将引脚复用为USART1GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); // TXGPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); // RX// 配置USART1USART_InitStruct.USART_BaudRate = baudrate;USART_InitStruct.USART_WordLength = USART_WordLength_8b;USART_InitStruct.USART_StopBits = USART_StopBits_1;USART_InitStruct.USART_Parity = USART_Parity_No;USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_Init(USART1, &USART_InitStruct);/* 配置中断参数--使能中断 */NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);//设置中断条件---接收缓冲区有数据就产生中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);// 使能USART1USART_Cmd(USART1, ENABLE);}int fputc(int ch, FILE *f)
{/* 发送一个字节数据到串口 */USART_SendData(USART1, (uint8_t) ch);/* 等待发送完毕 */while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); return (ch);
}///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{/* 等待串口输入数据 */while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);return (int)USART_ReceiveData(USART1);
}
extern uint8_t usart_recv[1024];//接受串口数据---字符串
extern int recv_i;//接收数组下标
extern int recv_end;//接收标记 0 没有完 1 完了void USART1_IRQHandler(void)//"hello#"
{uint8_t d;//检测中断是否产生if(USART_GetITStatus(USART1, USART_IT_RXNE)==SET){d =USART_ReceiveData(USART1);if(recv_i < 1024&& d != '#'&& recv_end ==0){usart_recv[recv_i++] = d;}else{recv_end = 1;}//把接收的数据回发给发送方//USART_SendData(USART1,d); //h//while(USART_GetFlagStatus( USART1,USART_FLAG_TXE)==0);//等待上一个数据发送完毕}//把中断标志位清空,方便接收下一次中断USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
UART.h
#ifndef __UART_H_
#define __UART_H_#include <stdio.h>
#include "system.h"void UART1_Init(uint32_t baudrate) ;#endif
CODED_LOCK.c
#include "CODED_LOCK.h"uint8_t pass_num[4]={1,2,3,4};
uint8_t input_num[4]={0,0,0,0};
uint8_t open=0;
uint8_t dht_data[5];
int ret = 0;
uint32_t adc_val;
int adc_vol;
uint32_t light_val;
int light_vol;unsigned char mode=0;uint8_t usart_recv[1024]={0};//接受串口数据---字符串
int recv_i = 0;//接收数组下标
int recv_end = 0;//接收标记 0 没有完 1 完了int byte_light=40;
int byte_temp=40;
int byte_humi=90;
char display=1;
void CODED_LOCK_Open(void)
{System_Init();while(1){if(recv_end ==1){if(strncmp((char *)usart_recv,"open",6)== 0){//打开D1input_num[0]=1;input_num[1]=2;input_num[2]=3;input_num[3]=4;}else if(strncmp((char *)usart_recv,"mode1",6)== 0)mode=1;else if(strncmp((char *)usart_recv,"mode0",6)== 0)mode=0;else if(strncmp((char *)usart_recv,"display",7)== 0)display=1;else if(strncmp((char *)usart_recv,"off",7)== 0)open=0;else if(usart_recv[0]==116){//printf("recv is %d ,%d\n",usart_recv[1]-48,usart_recv[2]-48);byte_temp=(usart_recv[1]-48)*10+(usart_recv[2]-48);}else if(usart_recv[0]==104){//printf("recv is %d ,%d\n",usart_recv[1]-48,usart_recv[2]-48);byte_humi=(usart_recv[1]-48)*10+(usart_recv[2]-48);}memset(usart_recv,0,1024);//清空接收缓冲区数组recv_end = 0;//接收标志置零,方便下一个字符串的接收recv_i = 0;//下标清零display=1;}
// USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
// TIM_ITConfig(TIM3,TIM_IT_Update , DISABLE);ADC_SoftwareStartConv(ADC1);//等待转换完成while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)!=SET);//获取ADC1的转换结果adc_val=ADC_GetConversionValue(ADC1);//将结果值转换为电压值adc_vol=adc_val*100/4095;ADC_SoftwareStartConv(ADC3);//等待转换完成while(ADC_GetFlagStatus(ADC3,ADC_FLAG_EOC)!=SET);//获取ADC1的转换结果light_val=ADC_GetConversionValue(ADC3);//将结果值转换为电压值light_vol=light_val*100/4095;
// TIM_ITConfig(TIM3,TIM_IT_Update , ENABLE);
// USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); if((mode==1)&&(open==1)){TIM_SetCompare1(TIM14,90-light_vol);}else if((mode==0)&&(open==1)){TIM_SetCompare1(TIM14,110-adc_vol);} if(open==1){if(dht_data[0]<byte_humi)PFout(10)=1;else PFout(10)=0;if(dht_data[2]<byte_temp)PEout(13)=1;else PEout(13)=0;}ret = Get_DHT11_Data(dht_data);KEY_Scan();if((input_num[0]!=0)&&(input_num[1]!=0)&&(input_num[2]!=0)&&(input_num[3]!=0)){if((input_num[0]==pass_num[0])&&(input_num[1]==pass_num[1])&&(input_num[2]==pass_num[2])&&(input_num[3]==pass_num[3])){PFout(8)=1;delay_ms(1000);PFout(8)=0;open=1;display=1;}else{PFout(8)=1;delay_ms(500);PFout(8)=0;delay_ms(500);PFout(8)=1;delay_ms(500);PFout(8)=0;printf("密码错误,请重新输入\r\n");open=0;}input_num[0]=input_num[1]=input_num[2]=input_num[3]=0;}if((open==1)&&(display==1)){display=0;printf("/**************温湿度控制界面******************/\r\n");if(mode==0)printf("/*****模式:手动\r\n");if(mode==1)printf("/*****模式:自动\r\n");printf("/*****当前湿度:%d/\r\n",dht_data[0]);printf("/*****当前温度:%d/\r\n",dht_data[2]);printf("/*****灯光亮度:%d/\r\n",adc_vol);printf("/*****光照值:%d/\r\n",110-light_vol);printf("/*****湿度阈值:%d/\r\n",byte_humi);printf("/*****温度阈值:%d/\r\n",byte_temp);printf("/**********************************************/\r\n");}if((open==0)&&(display==1)){display=0;printf("/**************密码输入界面******************/\r\n");printf("密码:%d %d %d %d\r\n",input_num[0],input_num[1],input_num[2],input_num[3]);printf("/**********************************************/\r\n");} }
}void Input_Data(char data)
{if(input_num[0]==0){input_num[0]=data;display=1;}else if(input_num[1]==0){input_num[1]=data;display=1;}else if(input_num[2]==0){input_num[2]=data;display=1;}else if(input_num[3]==0){input_num[3]=data;display=1;}
}void KEY_Scan(void)
{static char keybyte=0;static char key=0x0f;//static char return_num=0;//if(KEY==0x0f)return 1;if((KEY!=0x0f)&&(keybyte==0)){key=0x0f;key &=KEY;keybyte=1;}if((KEY==0x0f)&&(keybyte==1)){keybyte=0;switch(key){case 0x0e:Input_Data(1);break;case 0x0d:Input_Data(2);break;case 0x0b:Input_Data(3);break;case 0x07:Input_Data(4);break;//default: return 0;}}
}
CODED_LOCK.h
#ifndef __CODED_LOCK_H_
#define __CODED_LOCK_H_#include "system.h"
void CODED_LOCK_Init(void);
void CODED_LOCK_Open(void);
void KEY_Scan(void);
void Input_Data(char data);#endif
TIMER.c
#include "TIMER.h"//tim3初始化
void TIM3_Init(uint32_t period,uint32_t Prescaler)
{//period=5000 Prescaler=8400TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;/* 打开TIM3时钟 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//定时器参数配置:频率 计数值 方向。。。。。中断间隔500ms 中断频率 2hzTIM_TimeBaseStructure.TIM_Period = period;//计数值10000 时间就过去1s 10时间过去1msTIM_TimeBaseStructure.TIM_Prescaler = Prescaler;//设置频率 分频值 84000 000hz/8400 10000hz 1s数10000个数TIM_TimeBaseStructure.TIM_ClockDivision = 0;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);/* 配置定时器3的中断参数 */NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);/* 设置中断条件 */TIM_ITConfig(TIM3,TIM_IT_Update , ENABLE);/*启动定时器计数*/TIM_Cmd(TIM3, ENABLE);}//定时器14 通道1 初始化
void TIM14_init(void)
{TIM_OCInitTypeDef TIM_OCInitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;GPIO_InitTypeDef GPIO_InitStructure;/* 定时器14的时钟使能*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);/*定时器的基本配置,用于配置定时器的输出脉冲的频率为200Hz */TIM_TimeBaseStructure.TIM_Period = 10000/200-1; //设置定时脉冲的频率TIM_TimeBaseStructure.TIM_Prescaler = 8400-1; //第一次分频,简称为预分频TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //第二次分频,当前实现1分频,也就是不分频TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure);/* 配置PF9 引脚为复用模式 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //第9根引脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //设置复用模式GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽模式,增加驱动电流GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //设置IO的速度为100MHz,频率越高性能越好,频率越低,功耗越低GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //不需要上拉电阻GPIO_Init(GPIOF, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_TIM14);/* 让定时器14 PWM 的通道 1 工作在模式 1*///PWM 模式 1, 在递增模式下, 只要TIMx_CNT < TIMx_CCR1, 通道 1 便为有效状态(高电平), 否则为无效状态(低电平)。TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //允许输出TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效的时候, 输出高电平TIM_OC1Init(TIM14, &TIM_OCInitStructure);//TIMx_CCR1比较值的设置是由TIM_SetCompare1、TIM_SetCompare2、TIM_SetCompare3、TIM_SetCompare4来进行设置TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable); //自动重载初值, 不断输出 PWM 脉冲TIM_ARRPreloadConfig(TIM14, ENABLE); //自动重载初值使能/* 使能定时器 14 工作 */TIM_Cmd(TIM14, ENABLE);
}
TIMER.h
#ifndef __TIMER_H_
#define __TIMER_H_#include "system.h"void TIM3_Init(uint32_t period,uint32_t Prescaler);
void TIM14_init(void);#endif
DHT11.c
#include "DHT11.h"//PG9输出模式
void DHT11_Out()
{GPIO_InitTypeDef GPIO_InitStructure;/* 打开GPIOG的时钟 */RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);/* 选择引脚编号PF9 PF10,配置为输出模式 */GPIO_InitStructure.GPIO_Pin =GPIO_Pin_9;//9号引脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出模式GPIO_Init(GPIOG, &GPIO_InitStructure); PGout(9) = 1;
}//PG9输入模式
void DHT11_In()
{GPIO_InitTypeDef GPIO_InitStructure;/* 打开GPIOG的时钟 */RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);GPIO_InitStructure.GPIO_Pin =GPIO_Pin_9;//0号引脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入模式GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//添加上拉电阻GPIO_Init(GPIOG, &GPIO_InitStructure);
}//读取一个字节(8bit)的数据
uint8_t Read_DHT11_Byte()//1101 0000
{uint8_t byte = 0;//0000 0000 int i = 0;for(i = 0;i<8;i++){//等待低电平时隙结束while(PGin(9) == 0);delay_us(40);if(PGin(9) == 1){//当前数据就是1 byte = byte|(1<<(7-i));//等待为1时70us的高电平结束while(PGin(9) == 1);} }return byte;
}//获取一次温湿度数据
int Get_DHT11_Data(uint8_t *DHT11_Data)
{int i = 0;int t = 0;//1.32芯片发送开始信号//PG9输出模式DHT11_Out();PGout(9) = 0;delay_ms(20);PGout(9) = 1;delay_us(30);//2.32芯片等待回响信号---dht11发送响应信号//PG9输入模式DHT11_In();while(PGin(9) == 1)//等待响应信号到来{delay_us(1);t++;if(t >200){return 1;} }t= 0;while(PGin(9) == 0)//等待响应信号低电平结束{delay_us(1);t++;if(t >200){return 2;} }t = 0;while(PGin(9) == 1)//等待响应信号高电平结束{delay_us(1);t++;if(t >200){return 3;} }//3.32芯片接收温湿度数据---dht11发送温湿度数据 (40bit)for(i = 0;i <5; i++){//获取8bit(一个字节)的数据DHT11_Data[i] = Read_DHT11_Byte();}//4.校验数据是否正常if(DHT11_Data[0]+DHT11_Data[1]+DHT11_Data[2]+DHT11_Data[3] == DHT11_Data[4]){return 0;}}
DHT11.h
#ifndef __DHT11_H_
#define __DHT11_H_#include "system.h"int Get_DHT11_Data(uint8_t *DHT11_Data);
void DHT11_Out();
void DHT11_In();
uint8_t Read_DHT11_Byte();#endif
ADC.c
#include "ADC.h"void adc_init(void)
{GPIO_InitTypeDef GPIO_InitStructure;ADC_InitTypeDef ADC_InitStructure;ADC_CommonInitTypeDef ADC_CommonInitStructure;ADC_StructInit(&ADC_InitStructure);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//初始化PA5引脚为模拟模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;GPIO_Init(GPIOA, &GPIO_InitStructure);/* ADC常规的初始化*/ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式,只使用一个ADC硬件进行工作ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; //ADC硬件的频率=84MHz/2=42MHzADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //取消DMA访问模式//ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; //如果采用了多个ADC硬件对某个通道进行采样的,那么这个时间就是他们硬件工作的相隔时间ADC_CommonInit(&ADC_CommonInitStructure); /* ADC1初始化*/ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //12bit精度,非常重要[*]ADC_InitStructure.ADC_ScanConvMode = DISABLE; //因不需要多个ADC硬件对某个通道进行采样,则不需要连续扫描ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换,就是ADC硬件一直进行转换输出结果,否则只得到一个结果ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //禁止外部脉冲触发ADC硬件工作//ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //存储的结构使用右对齐的存储方式[*]//ADC_InitStructure.ADC_NbrOfConversion = 1; //这个是在DMA模式生效的,转换的结果总数数量是放到内存当中 ADC_Init(ADC1, &ADC_InitStructure);/* ADC1的通道5的配置指定ADC1的通道5,它的优先级为最高1(范围:1~16),采样时间为3个ADC时钟周期=3*1/f=3*(1/42MHz)*/ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_3Cycles);/* 使能ADC工作 */ADC_Cmd(ADC1, ENABLE);}void adc3_init(void)
{GPIO_InitTypeDef GPIO_InitStructure;ADC_InitTypeDef ADC_InitStructure;ADC_CommonInitTypeDef ADC_CommonInitStructure;ADC_StructInit(&ADC_InitStructure);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);//初始化PA5引脚为模拟模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;GPIO_Init(GPIOF, &GPIO_InitStructure);/* ADC常规的初始化*/ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式,只使用一个ADC硬件进行工作ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; //ADC硬件的频率=84MHz/2=42MHzADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //取消DMA访问模式//ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; //如果采用了多个ADC硬件对某个通道进行采样的,那么这个时间就是他们硬件工作的相隔时间ADC_CommonInit(&ADC_CommonInitStructure); /* ADC1初始化*/ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //12bit精度,非常重要[*]ADC_InitStructure.ADC_ScanConvMode = DISABLE; //因不需要多个ADC硬件对某个通道进行采样,则不需要连续扫描ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换,就是ADC硬件一直进行转换输出结果,否则只得到一个结果ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //禁止外部脉冲触发ADC硬件工作//ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //存储的结构使用右对齐的存储方式[*]//ADC_InitStructure.ADC_NbrOfConversion = 1; //这个是在DMA模式生效的,转换的结果总数数量是放到内存当中 ADC_Init(ADC3, &ADC_InitStructure);/* ADC1的通道5的配置指定ADC1的通道5,它的优先级为最高1(范围:1~16),采样时间为3个ADC时钟周期=3*1/f=3*(1/42MHz)*/ADC_RegularChannelConfig(ADC3, ADC_Channel_5, 1, ADC_SampleTime_3Cycles);/* 使能ADC工作 */ADC_Cmd(ADC3, ENABLE);}
ADC.h
#ifndef __ADC_H_
#define __ADC_H_#include "system.h" //void ADC1_Init(void);void adc_init(void);void adc3_init(void);
#endif
相关文章:
基于STM32F407ZET6的环境温湿度监控系统(粤嵌GEC-M4)
注意使用事项: 开发板如下 由于外部晶振是8M,需要修改setup和stm32f4头文件的晶振值。 操作如下: system_stm32f4xx.c的254行 #define PLL_M 8stm32f4xx.h的127行 #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the Ex…...
2023年五一杯数学建模A题无人机定点投放问题求解全过程论文及程序
2023年五一杯数学建模 A题 无人机定点投放问题 原题再现: 随着科学技术的不断发展,无人机在许多领域都有着广泛的应用。对于空中执行定点投放任务的无人机,其投放精度不仅依赖于无人机的操作技术,而且还与无人机执行任务时所处状…...
Redis 7 第九讲 微服务集成Redis 应用篇
Jedis 理论 Jedis是redis的java版本的客户端实现,使用Jedis提供的Java API对Redis进行操作,是Redis官方推崇的方式;并且,使用Jedis提供的对Redis的支持也最为灵活、全面;不足之处,就是编码复杂度较高。 …...
c++day7
仿照vector手动实现自己的myVector,最主要实现二倍扩容功能 #include <iostream>using namespace std; template <typename T> class Myvector { private:T *start;//起始指针T *end;//数组末尾指针T *last;//数组有效长度的尾指针 public://定义无参构…...
C++学习概述
1.c 为啥需要头文件 如果您刚开始使用 C,您可能想知道为什么C需要 #include 头文件,以及为什么一个程序要拥有多个 .cpp 文件。 原因很简单: a) 减少编译时间 随着程序的增长,您的代码也会增长,如果所有内容都在一个…...
关系型数据库和非关系型数据库
关系型数据库和非关系型数据库 关系型数据库非关系型数据库 非关系型数据库和关系型数据库是两种不同类型的数据库管理系统,它们用于存储和管理数据,但在数据组织和处理方式上有一些重要的区别。 关系型数据库 1.结构化数据存储:关系型数据库…...
基于SSM的快餐店点餐服务系统设计与实现
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用JSP技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…...
使用vcpkg配置CGAL+visual studio 2022
先安装vcpkg C:\dev> git clone https://github.com/microsoft/vcpkg C:\dev> cd vcpkg C:\dev\vcpkg> .\bootstrap-vcpkg.bat 运行后,先执行 C:\dev\vcpkg> .\vcpkg.exe install yasm-tool:x86-windows 这是因为gmp库中有个bug,只能这样…...
【Spring面试】三、Bean的配置、线程安全、自动装配
文章目录 Q1、什么是Spring Bean?和对象有什么区别Q2、配置Bean有哪几种方式?Q3、Spring支持的Bean有哪几种作用域?Q4、单例Bean的优势是什么?Q5、Spring的Bean是线程安全的吗?Q6、Spring如何处理线程并发问题…...
flink连接kafka报:org.apache.kafka.common.errors.TimeoutException
测试flink1.12.7 连接kafka: package org.test.flink;import org.apache.flink.api.common.serialization.SimpleStringSchema; import org.apache.flink.streaming.api.datastream.DataStream; import org.apache.flink.streaming.api.environment.StreamExecutio…...
sql order by 排序 null值放最后,怎么写
在 SQL 中,可以使用 ORDER BY 子句对结果进行排序。如果要将 NULL 值放在最后,可以在排序列中使用 CASE 表达式来处理。 下面是一个示例查询,将 NULL 值放在最后进行排序: SELECT column1, column2 FROM your_table ORDER BY CAS…...
HDMI字符显示实验
FPGA教程学习 第十五章 HDMI字符显示实验 文章目录 FPGA教程学习前言实验原理程序设计像素点坐标模块字符叠加模块 实验结果知识点总结 前言 在HDMI输出彩条的基础上输出osd叠加信息。 实验原理 实验通过字符转换工具将字符转换为 16 进制 coe 文件存放到单端口的 ROM IP 核…...
Spring Cloud 框架搭建
Spring Cloud 框架搭建之一基础框架 创建父项目创建子项目 创建父项目 第一步:新建项目,填写基础信息 第二步:这里不需要其他组件直接点next即可。 第三步:pom文件添加下述代码,将父项目设置为pom文件形式打包&#…...
20个非常有用的单行Python代码片段
1. 写在前面 继上篇,继续在本文分享 20 个 Python 单行代码,可以在 30 秒或更短时间内轻松学会。这些单行代码不仅可以提高效率,同时使代码看起来更整洁、更易读。:) 个人博客: https://jianpengzhang.git…...
【LangChain系列 9】Prompt模版——MessagePromptTemplate
原文地址:【LangChain系列 9】Prompt模版——MessagePromptTemplate 本文速读: MessagePromptTemplate MessagesPlaceholder 在对话模型(chat model) 中, prompt主要是封装在Message中,LangChain提供了一些MessagePromptTemplat…...
ROS2的学习路径
学习ROS2的建议学习路径: 理解基础知识: 熟悉机器人操作系统(ROS)的概念及其架构。了解ROS2相对于ROS1的优势以及其提供的关键功能。 安装和配置: 在你选择的操作系统上安装ROS2(如Ubuntu、Windows、macOS…...
Maintaining leader role through timed lease mechanism
Continuous understanding of distributed systems design On the one hand 基于定时的租约机制来保持leader角色 基于定时的租约机制来保持leader角色的设计思想是一种在分布式系统中确保高可用性和系统一致性的解决方法。 在分布式系统中,通常会有一个角色被选举…...
Mysql InnoDB引擎 的hash索引
Mysql InnoDB引擎不支持hash索引,但是在内存结构中有一个自适应hash索引,来提高查询性能 当设置hash索引时会自动转换成btree索引 查一下mysql官方文档:https://dev.mysql.com/doc/refman/5.7/en/create-index.html innodb_adaptive_hash_i…...
23年PMP考试如何备考?
接下来我要分享的备考建议分为三个部分,考试相关、备考期间注意和刷题建议。 1、PMP考试相关 PMP考试时间一定不能忘记,要密切关注,或许会出现延期的情况。考试教材现在是第七版教材,建议买一本或者用pdf电子版打印出来…...
mysql数据库增量备份方案、备份计划(InsCode AI 创作助手)
一、备份计划 以下是MySQL数据库增量备份的一般计划: 创建完整备份:在自动备份计划开始前,先创建一次完整备份。这个备份将包含所有数据和表结构。保存增量备份:在每次备份计划完成后,保存增量备份。这个备份将包含从…...
【Flink】FlinkCDC获取mysql数据时间类型差8小时时区解决方案
1、背景: 在我们使用FlinkCDC采集mysql数据的时候,日期类型是我们很常见的类型,但是FlinkCDC读取出来会和数据库的日期时间不一致,情况如下 FlinkCDC获取的数据中create_time字段1694597238000转换为时间戳2023-09-13 17:27:18 而数据库中原始数据如下,并没有到下午5点…...
Javas | DecimalFormat类、BigDecimal类、Random类
目录: 1.DecimalFormat类2.BigDecimal类3.Random类4.需求:编写程序,生成5个不重复的随机数 1.DecimalFormat类 DecimalFormat 是 NumberFormat 的一个具体子类,用于格式十进制数字。 /*** 关于数字的格式化*/ public class Decima…...
机器学习 实战系列 总目录
1、机器学习实战-系列教程1:线性回归入门教程(项目实战、原理解读、源码解读) 机器学习实战-系列教程1:线性回归入门教程(项目实战、原理解读、源码解读) 2、机器学习实战-系列教程2:手撕线性回…...
机器学习——贝叶斯(三种分布)/鸢尾花分类分界图/文本分类应用
0、前言: 机器学习中的贝叶斯的理论基础是数学当中的贝叶斯公式。这篇博客强调使用方法,至于理论未作深究。机器学习中三种类型的贝叶斯公式:高斯分布(多分类)、多项式分布(文本分类)、伯努利分…...
SOLIDWORKS Composer位置关键帧的使用
SOLIDWORKS Composer是专业的SOLIDWORKS及3D文件处理的动画制作软件,作为SOLIDWORKS 产品线下的一个明星存在。 SOLIDWORKS Composer几乎可以处理任何SOLIDWORKS的模型文件并将之转化成可以动作的机械动画,可以引用在企业的网站、产品说明书以及工作指导…...
PostgreSQL 流复制搭建与维护
文章目录 前言1. 配置环境1.1 环境介绍1.2 主库白名单1.3 主库参数配置 2. 流复制搭建2.1 备份恢复2.2 创建复制用户2.3 参数修改2.4 启动并检查2.5 同步流复制2.6 同步复制级别 3. 流复制监控3.1 角色判断3.2 主库查看流复制3.3 延迟监控3.4 备库查询复制信息 前言 PostgreSQ…...
【Redis】关于过期数据清除的一些策略
这里要讨论的为过期的数据是如何被清除的,也就是网上常常讨论的过期清除策略。 需要注意的是,redis除了会对过期的数据进行淘汰,也可以通过对内存大小进行限制,并对超出内存限制后进行数据淘汰。此时淘汰的数据未必是过期的&…...
动态SQL
Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。 1、if if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签…...
uniapp:OCR识别身份证上传原图失败,问题解决
1、上传普通图片成功 2、上传>4M | >5M图片失败检查:1、uni.uploadFile自身没有文件大小限制。然而,这仍然取决于你的应用程序所在的平台和存储空间容量。 2、上传照片后不在fail,在sucess 提交照片-3 {"data": "<h…...
shell循环和函数
目录 1.for循环2.while循环3.until循环4.函数 1.for循环 for循环是固定循环,也就是在循环时就已经知道需要进行几次的循环,有事也把for循环成为计数循环。for的语法如下两种: 语法一 for 变量 in 值1 值2 值3 …(可以是一个文件等)do程序do…...
做家政有什么网站做推广好/深圳seo网络优化公司
Python函数装饰器 装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。大多数初学者不知道在哪儿使用它们,所以我将要…...
文本资料分享网站 建设/qq群推广网站免费
S 2012 参数化报表 -- 利用拼接字符串来取代查询参数以上介绍过了如何在SQL Server中使用参数化查询,但是,如果遇到一些不支持参数化查询的数据库又该怎么办呢?此时,最终极的招数就是整个查询语句都通过参数化查询以拼接字符串的方…...
html5网站抓取/平原县网站seo优化排名
本文介绍了Kafka的相关概念,适合初学者学习相关概念。持续分享互联网开发技术,关注Java、架构等,欢迎关注我。发布与订阅消息系统在正式讨论Apache Kafka (以下简称Kafka)之前,先来了解发布与订阅消息系统的概念, 并认…...
住建城乡建设网站/快速优化网站排名的方法
本文实例讲述了Python表示矩阵的方法。分享给大家供大家参考,具体如下:在c语言中,表示个“整型3行4列”的矩阵,可以这样声明:int a[3][4];在python中一不能声明变量int,二不能列出维数。可以利用列表中夹带…...
wordpress 列表样式/腾讯企业邮箱登录入口
异常:nested exception is org.apache.ibatis.binding.BindingException: Parameter testypid not found. Available parameters are [ztpsXmjcxx, pageable, param1, param2]分析:以为是xml文件中没有对应的字段,一细看了几遍是有这个字段的…...
药业做网站的网站目标分析/百度收录规则
1. 为什么选择奇数台机器部署zookeeper集群: 关于ZooKeeper,需要明确一个很重要的特性:集群中只要有过半的机器是正常工作的,那么整个集群对外就是可用的,即过半存活即可用。 部署奇数台机器可以充分利用集群中的每个节…...