本帖最后由 一路向北lm 于 2019-3-31 17:47 编辑
本次DIY视频链接如下:
https://v.youku.com/v_show/id_XNDExOTg1NjgwOA==.html?spm=a2hzp.8253869.0.0
本次设计的所有资料(代码工程 、引脚分配 工具 调试助手 )打包分享给大家!

先来个段子:
学妹:学长,最近闲吗?有个事情想麻烦你一下?
我:还好吧,不是很忙,学妹有什么需要帮忙的吗?
学妹:我不会单片机,我们老师让我做一个有关单片机的毕业设计,这个该如何是好?我:交给我吧,没有你学长做不到的。(在女生面前吹牛,大家可以原谅!)
学妹:好啊!嗖嗖嗖,一堆文件飞了过来!
我:什么? stm32? 还联网? 还要远程控制? 还要监控? 厉害了我的学妹!
学妹:我就选的是这个题目,感觉不难吧?
我:还可以吧,是需要费些时日。
学妹:伟大的学长,你就是我的左手右脚,我一步也离不开你。
我:我评估了下,这个东西得做二十年了。
学妹:什么?你要纠缠我20年啊!
我:如果注定你是我的,还在乎这20年,一个指令就可以收了你!
学妹:你要干嘛?
我:我先送你的礼物,两颗心,选一个?
学妹:哇!!好厉害,我都要了!
我:没出息的样子!哈哈哈!
学妹:哼,别扯这么多没用的,开始做吧!
我:好的,正式开始DIY之旅!!!

题目:基于STM32单片机远程控制与监控系统
1.写在前面的话:本次DIY也是为了提高自己的动手能力,虽然自我感觉良好。在二姨家的这段岁月感觉自己也参加了几个类似的活动,期间收获很大,读研期间虽然老师布置的东西多,任务中,但我依然不负使命,积极参加二姨家的活动,学习大家的经验,这个比什么都重要,此贴也可以为感兴趣的初学者的一个参考!
2.初步规划: (模块选型)
从学妹的角度从发,我决定选择:STM32F103C8T6 作为主控芯片(大学期间学的都是F1系列,大家接触到的第一个都应该是F103ZET6吧),这里选择C8T6 可以节约成本,引脚数更少,不至于资源浪费。说到远程呢?必须要有一个WIFI模块,这样可以一键连接我们的Internet,说到一键入网,哈哈哈!我自己都会觉得很牛的!然后就是需要一些传感器了,这里我选择了两个传感器:1. DHT11温湿度传感器,可以实时监测当前环境的温湿度(主要是便宜,也可以满足要求!) 2. MQ-2 可燃气体监测,这个模块可以监测环境中是否有可燃气体存在,接口处有模拟量和数字量,为了方便这里我们直接用单片机的GPIO去检测该模块的数字量端口,发生电平突变时,就意味着存在可燃气体。 接下来就是输出端口的控制,本次DIY尽可能的满足生活需要,在一些宿舍和房间布置该diy装置,实时的查看效果,选择了带光耦隔离的继电器模块,这样可以消除交流市电带来的干扰,进一步保护单片机。选择三路继电器输出,可以外接三路家庭控制电路。
3.购买模块: 3.1 STM32F103C8T6最小系统,买回来就是这个样子,不是很贵,但是很多外设足够我们自己使用。焊接好排针如下图,这里预留了SWD下载调试接口,使用STlink 或者Jlink下载还是美滋滋的!
3.2这个是联网的wifi模块,采用ESP8266 MOD 可以支持多台APP同时连接控制,模块还加入了CH340下载芯片,可以轻松实现各种云端的SDK固件烧写。
4.焊接组装:
底板采用万用洞洞板+排针引出(可以拆拔),我们再需要最小系统的时候可以将从底板上取下,可以重复利用,人性化设计理念
整体焊接图如下:
可燃气体检测模块局部图:
温湿度传感器局部图:
继电器模块局部图:
串口打印信息口输出,可以连接至PC端输出信息。
5.电路原理图部分: STM32F103C8T6 最小原理图如下, 包括下载调试SWD接口 所有的IO 排针引出,BOOT选择电路, 电源滤波稳压电路,电源指示灯,调试指示灯电路 晶振电路 复位电路 RTC时钟电路等。附上PDF文件
6.调试部分:(注:调试代码仅供大家参考,可下载最终工程代码)
STM32F103c8t6的调试:
附上测试程序,通过ST-link 或者Jlink烧写到STM32 最小系统即可完成对PC13 引脚 LED指示灯闪烁。
- //头文件
- #include "stm32f10x.h"
- #include "GPIOLIKE51.h"
- //函数声明
- void GPIO_Configuration(void);
- //=============================================================================
- //文件名称:Delay
- //功能概要:延时
- //参数说明:nCount:延时长短
- //函数返回:无
- //=============================================================================
- void Delay(uint32_t nCount)
- {
- for(; nCount != 0; nCount--);
- }
- //=============================================================================
- //文件名称:main
- //功能概要:主函数
- //参数说明:无
- //函数返回:int
- //=============================================================================
- int main(void)
- {
- GPIO_Configuration();
- while (1)
- {
- PCout(13)=1;
- Delay(0xfffff);
- // Delay(0xfffff);
- // Delay(0xfffff);
- // Delay(0xfffff);
- PCout(13)=0;
- Delay(0xfffff);
- // Delay(0xfffff);
- // Delay(0xfffff);
- // Delay(0xfffff);
- }
- }
- //=============================================================================
- //文件名称:GPIO_Configuration
- //功能概要:GPIO初始化
- //参数说明:无
- //函数返回:无
- //=============================================================================
- void GPIO_Configuration(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
-
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC , ENABLE);
- //=============================================================================
- //LED -> PC13
- //=============================================================================
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(GPIOC, &GPIO_InitStructure);
- }
继电器驱动调试: 设计了三路继电器,在没有接入云端之间需要完成对继电器的硬件驱动,这里我们先以标准库为例,后面需要改为HAL库,这里只是为了完后对继电器的单独控制的调试工作。驱动代码如下,附上测试
- #include "led.h"
- void LED_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
- 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;
- GPIO_Init(GPIOC, &GPIO_InitStructure);
- }
- #ifndef __LED_H
- #define __LED_H
- #include "stm32f10x.h"
- #define K3_ON GPIO_ResetBits(GPIOC,GPIO_Pin_13)
- #define K3_OFF GPIO_SetBits(GPIOC,GPIO_Pin_13)
- #define K2_ON GPIO_ResetBits(GPIOC,GPIO_Pin_14)
- #define K2_OFF GPIO_SetBits(GPIOC,GPIO_Pin_14)
- #define K1_ON GPIO_ResetBits(GPIOC,GPIO_Pin_15)
- #define K1_OFF GPIO_SetBits(GPIOC,GPIO_Pin_15)
- void LED_Init(void);
- #endif
DHT11温湿度传感器调试:先使用标准库,通过串口助手实时打印DHT11 温湿度传感器的温度,这里使用了火哥的测试代码打包如下:- #ifndef __DHT11_H
- #define __DHT11_H
- #include "stm32f10x.h"
- #include "bsp_SysTick.h"
- #define HIGH 1
- #define LOW 0
- #define DHT11_CLK RCC_APB2Periph_GPIOB
- #define DHT11_PIN GPIO_Pin_11
- #define DHT11_PORT GPIOB
- //带参宏,可以像内联函数一样使用,输出高电平或低电平
- #define DHT11_DATA_OUT(a) if (a) \
- GPIO_SetBits(GPIOB,GPIO_Pin_10);\
- else \
- GPIO_ResetBits(GPIOB,GPIO_Pin_10)
- //读取引脚的电平
- #define DHT11_DATA_IN() GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)
- typedef struct
- {
- uint8_t humi_int; //湿度的整数部分
- uint8_t humi_deci; //湿度的小数部分
- uint8_t temp_int; //温度的整数部分
- uint8_t temp_deci; //温度的小数部分
- uint8_t check_sum; //校验和
-
- }DHT11_Data_TypeDef;
- void DHT11_GPIO_Config(void);
- static void DHT11_Mode_IPU(void);
- static void DHT11_Mode_Out_PP(void);
- uint8_t Read_DHT11(DHT11_Data_TypeDef *DHT11_Data);
- static uint8_t Read_Byte(void);
- #endif /* __DHT11_H */
- #include "bsp_dht11.h"
- /*
- * 函数名:DHT11_GPIO_Config
- * 描述 :配置DHT11用到的I/O口
- * 输入 :无
- * 输出 :无
- */
- void DHT11_GPIO_Config(void)
- {
- /*定义一个GPIO_InitTypeDef类型的结构体*/
- GPIO_InitTypeDef GPIO_InitStructure;
- /*开启DHT11_PORT的外设时钟*/
- RCC_APB2PeriphClockCmd(DHT11_CLK, ENABLE);
- /*选择要控制的DHT11_PORT引脚*/
- GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
- /*设置引脚模式为通用推挽输出*/
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- /*设置引脚速率为50MHz */
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- /*调用库函数,初始化DHT11_PORT*/
- GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
- /* 拉高GPIOB10 */
- GPIO_SetBits(DHT11_PORT, GPIO_Pin_10);
- }
- /*
- * 函数名:DHT11_Mode_IPU
- * 描述 :使DHT11-DATA引脚变为上拉输入模式
- * 输入 :无
- * 输出 :无
- */
- static void DHT11_Mode_IPU(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- /*选择要控制的DHT11_PORT引脚*/
- GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
- /*设置引脚模式为浮空输入模式*/
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
- /*调用库函数,初始化DHT11_PORT*/
- GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
- }
- /*
- * 函数名:DHT11_Mode_Out_PP
- * 描述 :使DHT11-DATA引脚变为推挽输出模式
- * 输入 :无
- * 输出 :无
- */
- static void DHT11_Mode_Out_PP(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- /*选择要控制的DHT11_PORT引脚*/
- GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
- /*设置引脚模式为通用推挽输出*/
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- /*设置引脚速率为50MHz */
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- /*调用库函数,初始化DHT11_PORT*/
- GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
- }
- /*
- * 从DHT11读取一个字节,MSB先行
- */
- static uint8_t Read_Byte(void)
- {
- uint8_t i, temp=0;
- for(i=0;i<8;i++)
- {
- /*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/
- while(DHT11_DATA_IN()==Bit_RESET);
- /*DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”,
- *通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时
- */
- Delay_us(40); //延时x us 这个延时需要大于数据0持续的时间即可
- if(DHT11_DATA_IN()==Bit_SET)/* x us后仍为高电平表示数据“1” */
- {
- /* 等待数据1的高电平结束 */
- while(DHT11_DATA_IN()==Bit_SET);
- temp|=(uint8_t)(0x01<<(7-i)); //把第7-i位置1,MSB先行
- }
- else // x us后为低电平表示数据“0”
- {
- temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行
- }
- }
- return temp;
- }
- /*
- * 一次完整的数据传输为40bit,高位先出
- * 8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和
- */
- uint8_t Read_DHT11(DHT11_Data_TypeDef *DHT11_Data)
- {
- /*输出模式*/
- DHT11_Mode_Out_PP();
- /*主机拉低*/
- DHT11_DATA_OUT(LOW);
- /*延时18ms*/
- Delay_ms(18);
- /*总线拉高 主机延时30us*/
- DHT11_DATA_OUT(HIGH);
- Delay_us(30); //延时30us
- /*主机设为输入 判断从机响应信号*/
- DHT11_Mode_IPU();
- /*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/
- if(DHT11_DATA_IN()==Bit_RESET)
- {
- /*轮询直到从机发出 的80us 低电平 响应信号结束*/
- while(DHT11_DATA_IN()==Bit_RESET);
- /*轮询直到从机发出的 80us 高电平 标置信号结束*/
- while(DHT11_DATA_IN()==Bit_SET);
- /*开始接收数据*/
- DHT11_Data->humi_int= Read_Byte();
- DHT11_Data->humi_deci= Read_Byte();
- DHT11_Data->temp_int= Read_Byte();
- DHT11_Data->temp_deci= Read_Byte();
- DHT11_Data->check_sum= Read_Byte();
- /*读取结束,引脚改为输出模式*/
- DHT11_Mode_Out_PP();
- /*主机拉高*/
- DHT11_DATA_OUT(HIGH);
- /*检查读取的数据是否正确*/
- if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)
- return SUCCESS;
- else
- return ERROR;
- }
- else
- {
- return ERROR;
- }
- }
-
- /*************************************END OF FILE******************************/
MQ-2 可燃气体模块调试:
这个模块操作很简单,类似于按键操作,只需要去检测相应的GPIO管脚的电平高低即可!这里和按键一起驱动,因为我们需要一个按键来连接网络,调 试的驱动代码如下。- static void MX_GPIO_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- /* GPIO Ports Clock Enable */
- __HAL_RCC_GPIOD_CLK_ENABLE();
- __HAL_RCC_GPIOA_CLK_ENABLE();
- __HAL_RCC_GPIOB_CLK_ENABLE();
- __HAL_RCC_GPIOC_CLK_ENABLE();
- /*Configure GPIO pin : KEY1_Pin */
- GPIO_InitStruct.Pin = KEY1_Pin;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);
- /*Configure GPIO pin : KEY2_Pin */
- GPIO_InitStruct.Pin = KEY2_Pin;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(KEY2_GPIO_Port, &GPIO_InitStruct);
-
- GPIO_InitStruct.Pin =K1_Pin;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_HIGH; //key1
- HAL_GPIO_Init(K1_GPIO_Port, &GPIO_InitStruct);
-
- GPIO_InitStruct.Pin =K2_Pin;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_HIGH; //key2
- HAL_GPIO_Init(K2_GPIO_Port, &GPIO_InitStruct);
-
- GPIO_InitStruct.Pin =K3_Pin;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_HIGH; // MQ
- HAL_GPIO_Init(K3_GPIO_Port, &GPIO_InitStruct);
-
-
- GPIO_InitStruct.Pin =MQ_Pin;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(MQ_GPIO_Port, &GPIO_InitStruct);
-
-
- HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13, GPIO_PIN_SET);
- HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14, GPIO_PIN_SET);
- HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15, GPIO_PIN_SET);
- }
|