精华内容
下载资源
问答
  • STM32毕业设计项目
    万次阅读
    2021-05-11 19:21:46

    STM32毕业设计项目

    1、基于STM32单片机大棚环境参数无线蓝牙检测设计

    2、基于STM32单片机智能RFID刷卡汽车位锁设计

    https://wusiyuan.blog.csdn.net/article/details/117019231

    更多相关内容
  • 设计选用STM32单片机作控制器,设计温度单反馈的控制系统,对电加热水器内水的温度进行控制。通过PT100温度传感器实现对水温信号的采集,并利用模拟量前向通道来对水温信号进行处理。利用STM32单片机进行控制输出PWM...
  • stm32毕业设计_基于stm32的视觉检测设计——(附源码和文档)
  • STM32毕业设计论文-STM32图像采集系统 (基于stm32的图像动态采集系统 论文)
  • 用安卓APP控制,附论文,驱动模块、文档等待 电机驱动模块、L298N 主控板、 蓝牙通信模块、FBT06_LPDB android控制端等 首先,给电源模块上12v的电源,然后打开电机驱动模块开关,同时将主控板的供电端连接到电源...
  • stm32毕业设计论文.pdf

    2020-10-23 07:44:18
    成都理工大学毕业设计论文 基于 STM32 定时器产生 PWM 的研究 作者姓名:222 专业班级:222 指导老师:222 摘要 随着科技水平的提高 ARM 的应用越来越广泛With the develop of technology, ARM is used in various ...
  • STM32毕业设计论文.doc

    2021-10-10 16:27:01
    STM32毕业设计论文.doc
  • 1、可通过密码、指纹、RFID、手机(NFC)、远程控制(点灯科技)、进行解锁,解锁成功,舵机会转到相应角度,模拟开门的效果。如果需要关门,需要触摸红外对管传感器,模拟门关了可以上锁。 2、可对指纹进行增删查改家庭...
  • 摘要 洛阳理工学院毕业设计论文 PAGE I PAGE I 基于STM32的图像动态采集系统 摘 要 随着科技水平的提高 ARM的应用越来越广泛本论文旨在对ARM的深入学习论文对?STM32驱动OV7670图像传感器以及图像在SSD1289驱动控制...
  • 基于STM32的热水器设计,可以自动加水,自动放水,自动加热,可以通过按键设计加热时间,水位过低,自动上水。
  • 基于stm32与lora模块物联网环境监测系统的设计.pdf
  • 毕业设计论文】适用于自动化 摘要:本论文设计了一款宠物自动喂食装置,该装置使用STM32作为主MCU,通过ESP8266模块连接TLINK物联网平台,通过TLINK平台的手机APP查看宠物喂食的状态,并可以听过手机发送指令控制...
  • 毕业设计用于:自动化专业 本文件中包含毕设所需所有内容:论文、代码、外文原文、外文翻译、手册、建模、答辩PPT、原理图等,物超所值! 摘要:随着我国社会经济水平的不断发展,进而使我国的宠物业得到了蓬勃的...
  • STM32单片机平衡小车毕业设计,包含PCB、原理图、配件清单、等等、 单片机采用:STM32F103VET6 陀螺仪:MPU6050 电机驱动:TB6612 蓝牙:HC05 等等
  • 采集节点,是本系统的关键部分,它以STM32F4Discovery为控制核心,通过温湿度传感器DHT11、气压传感器BMP085以及灰尘传感器GP2Y1010对相关信息进行采集。然后,通过气象预报算法对降雨情况进行大概的预报。最后,对...
  • 题目:基于STM32的OneNet物联网环境检测系统(毕业设计) 功能: 通过stm32单片机,实时采集温湿度、光照强度、烟雾浓度数据,并将数据实时上传至OneNe中国移动t物联网云平台。 资料包含: 程序源码 电路图 任务书...
  • wifi控制基于STM32与NFC的万能红外遥控器—毕业设计(2)  前面我们主要介绍了一下红外发射以及接收的代码,也是本此设计的核心。这一篇博客主要对手机app与该模块的一个通信方式,以及main函数的实现方法。 1、...
  • 毕业设计】适用于自动化专业 文件夹中包含:STM32的程序、OpenMV的程序、原理图 文章介绍可以查看:https://blog.csdn.net/JIE15164031299/article/details/119617832
  • 题目:基于STM32单片机智能电表无线WIFI插座APP交流电压电流检测设计(毕业设计) 设计框架: 本设计由STM32单片机核心板电路+交流电压电流检测模块电路+WIFI模块电路+指示灯电路组成。 功能: 1、通过电压互感器...
  • 文章目录1 背景2 系统设计方案2.1 实现功能2.1.1 硬件部分:2.1.2 软件部分:2.1.3 WIFI通信功能:2.2 系统架构2.2.1 WiFi 通信2.2.2 电机驱动2.2.3 摄像头2.2.4 舵机2.2.5 PWM舵机控制2.2.6 红外循迹模块3 软件设计...


    1 背景

    近几年,人们的生活正在逐渐向智能化转变, 嵌入式技术及一些新技术的快速发展, 使人们生活和工作变得越来越智能化 。智能小车可以在所处的环境中通过传感器自 行进行判断和分析,在无人操作的情况下自 主完成任务。

    设计的智能小车通过WIFI实现远程无线控制,同时具有避障及温度采集功能, 实现了小车的智能化, 可以作为研究智能汽车或者其他移动机器人的基础模型,具有较大的研究空间。

    2 系统设计方案

    2.1 实现功能

    学长设计的小车能够实现无线控制, 避障, 循迹等功能, 由硬件, 软件,无线传输三大部分组成,现对以上三部分功能进行具体的叙述 。

    2.1.1 硬件部分:

    输出 PWM 控制电机; 检测障碍物, 检测距离为 10cm;串口通信, 需要通过串口对智能小车进行调试, 串口波特率设置为 115200;对接收到的命令进行处理和判断;通过温度传感器检测环境温度; 连接WIFI 模块及控制 WIFI模块;通过uCOS-II实现多个任务同时执行。

    2.1.2 软件部分:

    操作界面功能;通过SOCKET编程实现联网,可以连接到 WIFI模块;接收STM32开发板传输的数据和发送指令数据;利用摄像头进行拍照, 在小车行驶过程中接收小车传输的图片信息并显示;实现小车的模式切换, 模式 1 为无线控制行驶模式,模式2为自动行驶模式。

    2.1.3 WIFI通信功能:

    与 PC 端进行联网连接;实现PC 与单片机之间的数据交换功能。

    2.2 系统架构

    小车采用 STM32F103 开发板,与 51 单片机相比, STM32可以搭载小型系统且速度更快,设计方案如下图所示。

    STM32开发板作为本设计的控制中心, 使用 PWM 输出波形驱动电机转动, 通过内部定时器达到控制方向的效果, 同时将接收到的数据及命令经过处理器判断和计算从IO口输出。

    • 利用温度传感器采集温度信息通过串口传输到 WIFI模块,在PC 端显示;
    • 利用红外传感器实现探测障碍和循迹功能。
    • WIFI模块是 PC 端和开发板进行数据交互的媒介, PC 端的操作指令由WIFI模块进行发送,开发板和 PC 端之间设置了相应的数据协议,由此判断接收到的是哪种类型的命令,小车根据命令执行相应的操作。

    在这里插入图片描述

    2.2.1 WiFi 通信

    WIFI通信模块作为 STM32和 PC 端通信的中介, 两端都通过 WIFI模块进行数据交互, 该模块选用 ESP8266芯片 [5] , 其特点就是如果断开连接, 再次连接, 模块会连接到最近一次连接过的热点。

    ESP8266支持三种模式, 分别为 STA 模式, AP模式, STA+AP 模式。

    这里学长使用 AP 模式, 使其他网 络能 够连接到ESP8266。 本设计使用 ESP8266的 AP模式,使其他网络能够连接到 ESP8266,与STM32的引脚连接如表所示。

    在这里插入图片描述

    在这里插入图片描述

    2.2.2 电机驱动

    在这里插入图片描述

    为了实现PC 端能够控制小车的速度以及满足直流电机的驱动 电 压, 本设计选用 L298N 电 机驱动 模块给直流 电 机供电 。

    电机状态与STM32输入如表2。 电机驱动共有两个电源输入接口,一个是5V,另一个是12V,在使用时12V的接口输入电压要大于7V,5V的接口就可以向单片机供电。

    在这里插入图片描述

    2.2.3 摄像头

    ov7670是OmniVision公司生产的一款感光整列,30W像素。

    在这里插入图片描述
    为什么要用带FIFO的模块呢?因为stm32速度比较慢,带FIFO可已将摄像头拍摄的数据暂时存在FIFO里,然后我们的stm32再慢慢的将拍摄的数据读出来,通过串口发送到串口上位机显示。

    FIFO,即first in first out的缩写。在这里,FIFO的速度很快,可以将摄像头的数据暂时存起了。以便我们慢速的CPU将获得的数据慢慢取出来并处理,达到一个类似水库的作用。

    2.2.4 舵机

    在这里插入图片描述
    舵机的输入线共有三条, 红色中间, 是电源线, 一边黑色的是地线, 这辆根线给舵机提供最基本的能源保证, 主要是电机的转动消耗。 电源有两种规格, 一是 4.8V, 一是 6.0V, 分别对应不同的转矩标准, 即输出力矩不同, 6.0V 对应的要大一些, 具体看应用条件; 另外一根线是控制信号线, Futaba 的一般为白色, JR 的一般为桔黄色。

    另外要注意一点, SANWA 的某些型号的舵机引线电源线在边上而不是中间, 需要辨认。但记住红色为电源, 黑色为地线, 一般不会有错。

    2.2.5 PWM舵机控制

    舵机的控制信号为周期是 20ms 的脉宽调制( PWM) 信号, 其中脉冲宽度从0.5ms-2.5ms, 相对应舵盘的位置为 0-180 度, 呈线性变化。 也就是说, 给它提供一定的脉宽, 它的输出轴就会保持在一个相对应的角度上, 无论外界转矩怎样改变, 直到给它提供一个另外宽度的脉冲信号, 它才会改变输出角度到新的对应的位置上。

    2.2.6 红外循迹模块

    采用TCRT5000红外反射传感器,一种集发射与接收于一体的光电传感器,它由一个红外发光二极管和一个NPN红外光电三极管组成。检测反射距离1mm-25mm适用,传感器特设M3固定安装孔,调节方向与固定方便易用,使用宽电压LM393比较器,信号干净,波形好,驱动能力强,超过15mA。可以应用于机器人避障、机器人进行白线或者黑线的跟踪,可以检测白底中的黑线,也可以检测黑底中的白线,是寻线机器人的必备传感器。流水线计件、电度表脉冲数据采样、传真机碎纸机纸张检测等众多场合。

    在这里插入图片描述

    3 软件设计

    小车控制是通过 stm32单片机控制驱动电路和给舵机送控制信号, 然而这些控制信号的命令又是电脑等终端设备通过无线路由器串口传送给单片机的, 所以在程序中我们需要设计到串口的使用、 定时器使用、 I/O 口的使用。

    系统主程序模块主要完成对系统中各模块电路的初始化等工作, 主要包括对定时器、 串口中断、 外部中断的初始化, 同时执行电脑等终端设备所发送的命令, 等待外部中断以及根据所需要的功能进行相应操作。 软件总体设计及程序流程如下图

    在这里插入图片描述

    4 测试效果

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    5 部分关键代码

    主程序

    #include "stm32f10x.h"
    #include "bsp_SysTick.h"
    #include "bsp_led.h"
    #include <string.h>
    #include <stdlib.h>
    #include "bsp_pwm_output.h" 
    #include "infrared.h" 
    #include "delay.h"
    //全局变量
    unsigned int Task_Delay[NumOfTask];
    
    /**
      * @brief  主函数
      * @param  无
      * @retval 无
      */
    int main(void)
    {	
    	
    	  //初始化systick
    	SysTick_Init();											//用于延时等操作
    	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;
    	TIMx_PWM_Init();			//PWM波初始化
      infrared_Initial();		//红外初始化
    	while(1)
    	{
    		if((infrared_Scan(infrared_5_GPIO_PORT,infrared_5_GPIO_PIN)==INFRARED_ON)&&\
    			(infrared_Scan(infrared_6_GPIO_PORT,infrared_6_GPIO_PIN)==INFRARED_ON))//前方有障碍,必须两边同时检测到才能触发,否则均认为是误触
    		{		
    			DelayS(3);		//延迟3秒
    			if((infrared_Scan(infrared_5_GPIO_PORT,infrared_5_GPIO_PIN)==INFRARED_ON)&&\
    			(infrared_Scan(infrared_6_GPIO_PORT,infrared_6_GPIO_PIN)==INFRARED_ON))//仍旧有障碍
    			{
    					TIMx_Mode_Config(500,0,0,500);//右转500ms
    		  		DelayMs(500);
    				
    			}
    			else
    			{
    			     TIMx_Mode_Config(500,0,0,500);//直行500ms
    					 DelayMs(500);
    			}
    			
    		}
    		else
    		{
    			if((infrared_Scan(infrared_3_GPIO_PORT,infrared_3_GPIO_PIN)==INFRARED_ON))//循迹,右侧内部传感器见到黑线,说明车身方向偏右
    			    TIMx_Mode_Config(0,0,600,0);//轻微左转
    			else if((infrared_Scan(infrared_2_GPIO_PORT,infrared_2_GPIO_PIN)==INFRARED_ON))//循迹,左侧内部传感器见到黑线,说明车身方向偏左
    			    TIMx_Mode_Config(600,0,0,0);//轻微右转
    			else if((infrared_Scan(infrared_4_GPIO_PORT,infrared_4_GPIO_PIN)==INFRARED_ON))//循迹,右侧外部传感器见到黑线,说明车身方向偏左
    			    TIMx_Mode_Config(0,0,900,0);//剧烈左转
    			else if((infrared_Scan(infrared_1_GPIO_PORT,infrared_1_GPIO_PIN)==INFRARED_ON))//循迹,左侧外部传感器见到黑线,说明车身方向偏左
    			    TIMx_Mode_Config(900,0,0,0);//剧烈右转
    			else
    				 TIMx_Mode_Config(500,0,500,0);//直行
    		}
    	}
    
    }
    
    

    PWM程序

    #include "bsp_pwm_output.h" 
    
     /**
      * @brief  配置TIM3复用输出PWM时用到的I/O
      * @param  无
      * @retval 无
      */
    static void TIMx_GPIO_Config(void) 
    {
      GPIO_InitTypeDef GPIO_InitStructure;
    
    	/* 设置TIM3CLK 为 72MHZ */
    //  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 
    	macTIM_APBxClock_FUN (macTIM_CLK, ENABLE);
    
      /* GPIOA and GPIOB clock enable */
      macTIM_GPIO_APBxClock_FUN (macTIM_GPIO_CLK, ENABLE); 
    
      /*GPIOA Configuration: TIM3 channel 1 as alternate function push-pull */
      GPIO_InitStructure.GPIO_Pin =  macTIM_CH1_PIN;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		    // 复用推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(macTIM_CH1_PORT, &GPIO_InitStructure);
    
      /*GPIOB Configuration: TIM3 channel 2 as alternate function push-pull */
      GPIO_InitStructure.GPIO_Pin =  macTIM_CH2_PIN;
      GPIO_Init(macTIM_CH2_PORT, &GPIO_InitStructure);
    
      /*GPIOB Configuration: TIM3 channel 3 as alternate function push-pull */
      GPIO_InitStructure.GPIO_Pin =  macTIM_CH3_PIN;
      GPIO_Init(macTIM_CH3_PORT, &GPIO_InitStructure);
    	
      /*GPIOB Configuration: TIM3 channel 4 as alternate function push-pull */
      GPIO_InitStructure.GPIO_Pin =  macTIM_CH4_PIN;
      GPIO_Init(macTIM_CH4_PORT, &GPIO_InitStructure);
    	
    }
    
    /**
      * @brief  配置TIM3输出的PWM信号的模式,如周期、极性、占空比
      * @param  无
      * @retval 无
      */
    /*
     * TIMxCLK/CK_PSC --> TIMxCNT --> TIMx_ARR --> TIMxCNT 重新计数
     *                    TIMx_CCR(电平发生变化)
     * 信号周期=(TIMx_ARR +1 ) * 时钟周期
     * 占空比=TIMx_CCR/(TIMx_ARR +1)
     */
    void TIMx_Mode_Config(u16 CCR1_Val,u16 CCR2_Val,u16 CCR3_Val, u16 CCR4_Val)
    {
    	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	TIM_OCInitTypeDef  TIM_OCInitStructure;
    
    
    /* ----------------------------------------------------------------------- 
        macTIMx Channel1 duty cycle = (macTIMx_CCR1/ macTIMx_ARR+1)* 100% = 50%
        macTIMx Channel2 duty cycle = (macTIMx_CCR2/ macTIMx_ARR+1)* 100% = 37.5%
        macTIMx Channel3 duty cycle = (macTIMx_CCR3/ macTIMx_ARR+1)* 100% = 25%
        macTIMx Channel4 duty cycle = (macTIMx_CCR4/ macTIMx_ARR+1)* 100% = 12.5%
      ----------------------------------------------------------------------- */
    
      /* Time base configuration */		 
      TIM_TimeBaseStructure.TIM_Period = 999;       //当定时器从0计数到999,即为1000次,为一个定时周期
      TIM_TimeBaseStructure.TIM_Prescaler = 0;	    //设置预分频:不预分频,即为72MHz
      TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ;	//设置时钟分频系数:不分频(这里用不到)
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式
      TIM_TimeBaseInit(macTIMx, &TIM_TimeBaseStructure);
    
      /* PWM1 Mode configuration: Channel1 */
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;	    //配置为PWM模式1
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	
      TIM_OCInitStructure.TIM_Pulse = CCR1_Val;	   //设置跳变值,当计数器计数到这个值时,电平发生跳变
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;  //当定时器计数值小于CCR1_Val时为高电平
      TIM_OC1Init(macTIMx, &TIM_OCInitStructure);	 //使能通道1
      TIM_OC1PreloadConfig(macTIMx, TIM_OCPreload_Enable);
    
      /* PWM1 Mode configuration: Channel2 */
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = CCR2_Val;	  //设置通道2的电平跳变值,输出另外一个占空比的PWM
      TIM_OC2Init(macTIMx, &TIM_OCInitStructure);	  //使能通道2
      TIM_OC2PreloadConfig(macTIMx, TIM_OCPreload_Enable);
    
      /* PWM1 Mode configuration: Channel3 */
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = CCR3_Val;	//设置通道3的电平跳变值,输出另外一个占空比的PWM
      TIM_OC3Init(macTIMx, &TIM_OCInitStructure);	 //使能通道3
      TIM_OC3PreloadConfig(macTIMx, TIM_OCPreload_Enable);
    
      /* PWM1 Mode configuration: Channel4 */
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = CCR4_Val;	//设置通道4的电平跳变值,输出另外一个占空比的PWM
      TIM_OC4Init(macTIMx, &TIM_OCInitStructure);	//使能通道4
      TIM_OC4PreloadConfig(macTIMx, TIM_OCPreload_Enable);
      TIM_ARRPreloadConfig(macTIMx, ENABLE);			 // 使能TIM3重载寄存器ARR
    
      /* TIM3 enable counter */
      TIM_Cmd(macTIMx, ENABLE);                   //使能定时器3	
    }
    
    /**
      * @brief  TIM3 输出PWM信号初始化,只要调用这个函数
      *         TIM3的四个通道就会有PWM信号输出
      * @param  无
      * @retval 无
      */
    void TIMx_PWM_Init(void)
    {
    	TIMx_GPIO_Config();
    	TIMx_Mode_Config(0,0,0,0);	
    }
    
    

    延时程序

    #include "stm32f10x.h"
    #include "delay.h"
    
    static u8  fac_us=0;//us延时倍乘数
    static u16 fac_ms=0;//ms延时倍乘数
    
    //初始化延迟函数
    //当使用ucos的时候,此函数会初始化ucos的时钟节拍
    //SYSTICK的时钟固定为HCLK时钟的1/8
    //SYSCLK:系统时钟
    void DelayInit()
    {
    	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);	//选择外部时钟  HCLK/8
    	fac_us=SystemCoreClock/8000000;	//为系统时钟的1/8  
    	fac_ms=(u16)fac_us*1000;//非ucos下,代表每个ms需要的systick时钟数   
    }
    
    //延时nus
    //nus为要延时的us数.		    								   
    void DelayUs(unsigned long 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 DelayMs(unsigned int 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;       //清空计数器
    }
    
    void DelayS(unsigned int ns)//延时秒
    {
    	unsigned char i;
    	for(i=0;i<ns;i++)
    	{
    		DelayMs(1000);
    	}
    }
    
    

    6 最后

    技术解答、毕设帮助、开题指导
    print("Q 746876041") 
    

    请添加图片描述

    展开全文
  • 基于stm32的毕设

    2018-06-08 09:48:31
    STM32使用C语言利用RVMDK开发软件进行软件设计; 距离数据采集需要使用测距传感器; 实时距离数据应用数码管显示或者液晶显示。
  • 基于ALIENTEK 探索者 STM32F407开发板,设计一款五子棋游戏。通过LCD液晶屏显示游戏画面,通过触摸屏幕进行游戏模式选择、落子、暂停游戏、重新开始游戏、悔棋等操作。通过LCD液晶屏显示游戏画面,通过触摸屏幕进行...
  • 毕业设计——基于STM32的家庭健康监测系统

    万次阅读 多人点赞 2021-08-15 14:57:05
    这是本科时的毕业设计,想着之后读研了,研究方向是机器学习了,可能不会这么再碰32或者51之类的板子了,就想趁着还没有忘记就来梳理一下,纪念陪伴了我两年的硬件朋友们,作为的一个足迹。 二、项目背景及资源分享 ...


    一、前言

    这是本科时的毕业设计,想着之后读研了,研究方向是机器学习了,可能不会这么再碰32或者51之类的板子了,就想趁着还没有忘记就来梳理一下,纪念陪伴了我两年的硬件朋友们,也作为一个足迹。

    二、项目背景及资源分享

    这次毕业设计的灵感来源于20年的电赛,当时因为考研时间紧张的原因,在做一个《无线传感器结点》题目的时候,当时是使用的无线传感器模块将数据传到电脑作为一个上位机的展示。但当时想做的是使用wifi模块来实现无线传输功能,传到一个自己写的web服务器,在页面上进行展示的,由于时间原因最终还是选择了前者。因此毕业设计就选择这个相近的题目,也算是弥补当时的遗憾。

    本次的课题是数据传送至onenet云平台上的,之前看到一个up主讲的stm32连接onenet的详细步骤,这里给大家分享一下:

    链接:https://www.bilibili.com/video/BV1y54y1q7uT?from=search&seid=4104843828856938758
    第一个可能失效了,这里重新找了一个:
    https://www.bilibili.com/video/BV1Yb411T7D1?from=search&seid=3711635156906757806&spm_id_from=333.337.0.0

    这是onenet平台的官方MQTT协议连接手册:
    链接:https://open.iot.10086.cn/doc/mqtt/

    相关资源的百度云链接:
    链接:https://pan.baidu.com/s/1RcM71gcsQ8O7dhGP0_b12w
    提取码:5613

    三、项目介绍

    1、项目名称

    基于STM32的家庭健康监测系统

    2、系统框架

    根据需求,该系统可以实时监测被测者的心率、体温以及周遭环境的温度,也同时可以通过姿态解算来判断被测者是否摔倒。该系统可以将被测者的心率、体温等数据既在本地显示,也可以通过WI-FI传输至云平台以实现远程显示。当被测者摔倒时会发出蜂鸣声,以便引起周围人向被测者施以援手;当被测者吸烟时则会发出警报直至香烟熄灭,可以让被测者远离不健康的生活习惯。

    3、功能简介

    该设计是主要功能如下:
    (1) 实时的采集心率、温度、烟雾浓度等信息;
    (2) 实时的显示心电图以及温度数值信息;
    (3) 实现跌倒的判断,并且在跌倒时发出报警;
    (4) 实现吸烟警告,在吸烟时发出报警;
    (5) 实现将温度、心率、姿态解算数据、烟雾浓度等发送至云平台;
    (6) 通过登录云平台查看心率、温度、烟雾浓度的折线图。
    在这里插入图片描述

    4、控制核心

    STM32C8T6(最小核心板),当然,用其他型号的32,如STM32ZET6也是可以的。
    在这里插入图片描述

    5、外围模块

    心率模块:ADS1292R
    在这里插入图片描述
    温度模块:LMT70
    在这里插入图片描述
    姿态解算模块:MPU6050
    在这里插入图片描述
    WIFi模块:ATK-ESP8266
    在这里插入图片描述
    液晶显示模块:OLED12864
    在这里插入图片描述

    6、上位机

    OneNET云平台
    在这里插入图片描述

    四、相关设计及框图

    1、系统总统设计

    基于本系统的需求,本设计提出了分层的设计思想,将系统分为:硬件采集层、网络传输层、数据展示层,提高了软硬件之间的耦合性,便于分工与维护。其中,硬件采集层负责收集心率、温度、烟雾浓度、姿态解算数据,网络传输层负责将前一层采集到的数据通过WI-FI传输到数据展示层,而数据展示层分为本地数据展示和云端数据展示。
    在这里插入图片描述

    2、数据采集层设计框图

    在这里插入图片描述

    3、数据传输层设计框图

    在这里插入图片描述

    4、数据展示层设计框图

    在这里插入图片描述

    五、各功能模块详细设计

    1、心率监测功能

    在检测的时候,会有许噪音对检测的结果带来干扰,比如人体自身以及电路的干扰都会对检测结果产生影响,当许多干扰信号和心电信号混在一起的时候就可能会使有用信号发生变形甚至被淹没,因此滤波是非常必要的,而滤波可以分为代码实现的软件滤波和芯片自带的硬件滤波,ADS1292R是一款医用级的前端芯片。该模块按照以下的工作时序与STM32进行全双工的SPI通讯。
    在这里插入图片描述
    该模块在系统中的工作流程图:
    在这里插入图片描述
    当ADS1292R上电后至少需要等待1s,当寄存器稳定后再进入ADS1292R的引脚初始化,其中包含了CS、START、RESET、DRYDY控制引脚,当引脚初始化超时则会重新初始化,其次是SPI通讯端口的初始化,然后继续对ADS1292R进行采集操作的一系列配置就可以获得心率的原始数据。

    该段是对ADS1292R初始化的配置函数

    /* 初始化ads1292r,超时时间为timeout*100ms,返回0表示初始化失败 */
    uint8_t ads1292r_init( uint8_t timeout)
    {
        uint8_t id ;
        
        /* gpio接口初始化,针对非hal库版本需要再此添加代码 */
        port_gpio_init() ;
        
        /* spi接口初始化 */
        port_spi_init() ;
        
        ADS1292_CS_SET() ;
        
        ADS1292_REST_RESET() ;
        ADS1292_START_RESET() ;
        port_delay_ms(1000) ;
        ADS1292_REST_SET() ;
        port_delay_ms(100) ;    /* 硬件复位 */
        
    	ads1292r_send_cmd(ADS1292R_COMMAND_SDATAC) ;    /* 软件复位,并停止连续读状态 */
        port_delay_ms(100) ;
        ads1292r_send_cmd(ADS1292R_COMMAND_RESET) ;
        port_delay_ms(1000) ;
        ads1292r_send_cmd(ADS1292R_COMMAND_SDATAC) ;
        port_delay_ms(100) ;
        
        while( ( id != ads1292r_reg.id) && ( timeout > 0))       /* 识别芯片型号,1292r为0x73 */
    	{        
            id = ads1292r_rw_reg(ADS1292R_COMMAND_RREG|ADS1292R_REG_ID, 0) ;
            
            timeout-- ;
            port_delay_ms(100) ;
    	}
        
        /* 500sps采样率 */
        ads1292r_reg.cfg1 = ADS1292R_SET_BITS(ads1292r_reg.cfg1, ADS1292R_DR, ADS1292R_OVERSAMPLING_500SPS) ;
        
        /* 导联脱落比较器开,内部2.42v参考电压 */
        ads1292r_reg.cfg2 = ADS1292R_SET_BITS(ads1292r_reg.cfg2, ADS1292R_PDB_LOFF_COMP, ADS1292R_PDB_LOFF_COMP_ON) ;  
        ads1292r_reg.cfg2 = ADS1292R_SET_BITS(ads1292r_reg.cfg2, ADS1292R_PDB_REFBUF, ADS1292R_PDB_REFBUF_ON) ;       
        ads1292r_reg.cfg2 = ADS1292R_SET_BITS(ads1292r_reg.cfg2, ADS1292R_VREF_4V, ADS1292R_VREF_2420MV) ;      
        
        /* 通道二导联脱落检测功能开 */
        ads1292r_reg.loff_sens = ADS1292R_SET_BITS(ads1292r_reg.loff_sens, ADS1292R_LOFF2N, ADS1292R_LOFF2N_ON) ;
        ads1292r_reg.loff_sens = ADS1292R_SET_BITS(ads1292r_reg.loff_sens, ADS1292R_LOFF2P, ADS1292R_LOFF2P_ON) ;
        
        /* pga斩波频率4分频,右腿驱动电源开,开启通道二的右腿驱动输出 */
        ads1292r_reg.rld_sens = ADS1292R_SET_BITS(ads1292r_reg.rld_sens, ADS1292R_CHOP, ADS1292R_CHOP_FREQ_DIV4) ;
        ads1292r_reg.rld_sens = ADS1292R_SET_BITS(ads1292r_reg.rld_sens, ADS1292R_PDB_RLD, ADS1292R_PDB_RLD_ON) ;
        ads1292r_reg.rld_sens = ADS1292R_SET_BITS(ads1292r_reg.rld_sens, ADS1292R_RLD2N, ADS1292R_RLD2N_ON) ;
        ads1292r_reg.rld_sens = ADS1292R_SET_BITS(ads1292r_reg.rld_sens, ADS1292R_RLD2P, ADS1292R_RLD2P_ON) ;
        
        /* 右腿驱动参考电压选择内部信号 */
        ads1292r_reg.resp2 = ADS1292R_SET_BITS(ads1292r_reg.resp2, ADS1292R_RLDREF_INT, ADS1292R_RLDREF_INT) ;
        
        return timeout ;
    }
    

    其他的关于芯片识别和采样频率设置、开启导联脱落比较器、开启二联导脱落检测功能、开启通道二右腿驱动输出并选择内部信号的代码这里就不放了,这些可以通过官方给的芯片资料是可以移植的。

    然后来说一下软件滤波的操作:
    初始化函数返回的timeout的是初始化失败次数,如果超过则会一直卡在这里不能继续往下。流程图的原始数据是仅仅只是硬件滤波后的ADC原始数据,为了能够得到符合正常范围的心电信号,还需要对数据进行软件滤波,处于过于偏大或者偏小的波形,最后才能将滤波后的心率值存到数组中。以下为软件滤波的部分代码:

     ads1292r_get_value(ad_b);
            ecg_data = i24toi32(ad_b+6);  /* 转换原始数据 */
            ecg_sum = 0;
            for(i = 0; i < 8; i++)
            {
                ecg_data_s[i] = ecg_data_s[i+1];
                ecg_sum += ecg_data_s[i];
            }
            ecg_data_s[8] = ecg_data;
            ecg = (ecg_sum + ecg_data) / 9;
    
            ecg_min = 5000000;
            ecg_max = -5000000;
            for(i=0; i < 29; i++)
            {
                ecg_buf[i]=ecg_buf[i+1];
                ecg_max = ecg_max < ecg_buf[i] ? ecg_buf[i] : ecg_max;
                ecg_min = ecg_min > ecg_buf[i] ? ecg_buf[i] : ecg_min;
            }
            ecg_buf[29]=ecg;
            ecg_max = ecg_max < ecg ? ecg : ecg_max;
            ecg_min = ecg_min > ecg ? ecg : ecg_min;
    
            if((ecg_max - ecg_min > 30000)&&(tim3_tick > 200))
            {
                if((60000/tim3_tick < 200) && (60000/tim3_tick > 40))
                {
                    Heart_buff[0] = Heart_buff[1];
                    Heart_buff[1] = Heart_buff[2];
                    Heart_buff[2] = Heart_buff[3];
                    Heart_buff[3] = Heart_buff[4];
                    Heart_buff[4] = Heart_buff[5];
                    Heart_buff[5] = Heart_buff[6];
                    Heart_buff[6] = Heart_buff[7];
                    Heart_buff[7] = Heart_buff[8];
                    Heart_buff[8] = Heart_buff[9];
                    Heart_buff[9] = 60000/tim3_tick;
    
                    Heart_rate=(Heart_buff[0]+Heart_buff[1]+Heart_buff[2]+Heart_buff[3]+Heart_buff[4]
                                +Heart_buff[5]+Heart_buff[6]+Heart_buff[7]+Heart_buff[8]+Heart_buff[9])/10;
                }
    
                tim3_tick = 0;
            }
    

    从流程图中可以看到在定时器中断的作用下,每隔100ms就会将获得滤波后的心电信号以串口的方式传输到主控的STM32芯片再对心率数据进行下一步的处理。

    2、温度采集功能

    LMT70是一款高精度的医用级温度传感器,其仅需3.3V的电压就可以驱动,且功耗极低,可以检测的温度范围是-55摄氏度到150摄氏度。温度模块与主控STM32采用的是IIC通信,其具体的引脚连接图如下:
    在这里插入图片描述
    以下为该模块在系统中的流程图:
    在这里插入图片描述
    由于在硬件电路中,ADS115和LMT70是合在一起的,共同算作温度模块,因此,在流程图中的ADS115初始化是指整个温度模块的初始化,以下为ADS115初始化函数:

    void ads1115_Init(void)
    {
      
    
      ads1115_I2C_INIT();  // ads1115_I2C init
    
      /* 增益 */
      m_gain = GAIN_ONE;
      
      
      /* config the config reg */
      if (ConfigeRegister(m_channel))
      {
        // deal error 
        printf("init configreg error\r\n");
      }
      
    }
    

    该初始化函数完成了IIC引脚的初始化以及寄存器的配置。通过对convert寄存器的处理,可以获得原始的ADC数据,最后再通过对该数据进行才得到最终温度数值,再把该数据通过IIC传给STM32进行进一步的处理。

    具体的式子如下:

    //采集ADC数 (温度)
            adcx=GetAds1115Values();//采集ADC数据
            temp=(float)adcx*0.125f;
            tem = (-0.0000084515f)*temp*temp+(-0.176928f)*temp+203.393f;
    

    3、跌倒监测功能(姿态解算)

    MPU6050是整合性六轴运动处理组件,其中组合了三轴陀螺仪和三轴加速器。加速度传感器是用来检查空集中的6个面(前后左右上下)中的哪些面受到了力的作用,陀螺仪是检测3个方向的欧拉角,以水平摊开的手掌为例,判断手掌上下摆动幅度的角度叫俯仰角用pitch表示,判断手掌左右水平移动的角度叫偏航角用yaw表示,判断手掌左右翻滚的角度叫滚转角用roll表示。本模块所需要实现简单的跌倒检测的功能,首先得知道什么算跌倒或者如何表示跌倒的状态。跌倒是指突发、不自主的、非故意的体位改变,倒在地上或更低的平面上[4]。人体在跌倒瞬间,身体的加速度和角速度在水平和垂直方向都会发生巨大的变化[5]。因此,通过判断三个方向的欧拉角以及三个方向的综合加速度综合考虑来判断是否摔倒。
    在这里插入图片描述
    MPU6050的初始化代码是可以根据官方资料移植的,所以这里就不贴初始化了,这里介绍一下跌倒监测的实现。
    首先知道DMP功能移植DMP是MPU6050内部的运动引擎,由Inven Sence公司自主提供,用于从内部传感器中直接解算出四元数,大幅降低运算复杂度。由于DMP可直接输出四元数,从而可以减轻外围微处理器的工作负担,且能避免繁琐的滤波和数据融合处理,能降低系统运算的复杂度。以为为四元组转换公式的转换公式,其中四元单位数的平方和为1。

    在这里插入图片描述
    然后通过四元组转化得到三个方向的欧拉角,代码实现如下:

    if(sensors&INV_WXYZ_QUAT) 
    	{
    		q0 = quat[0] / q30;	//q30格式转换为浮点数
    		q1 = quat[1] / q30;
    		q2 = quat[2] / q30;
    		q3 = quat[3] / q30; 
    		//计算得到俯仰角/横滚角/航向角
    		*pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3;	// pitch
    		*roll  = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3;	// roll
    		*yaw   = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3;	//yaw
    

    得到三个方向的欧拉角之后,再结合人体加速度向量幅值SVM来综合判断是否跌倒。
    其中SVM是三个方向的综合加速度值,式子如下:
    S V M = a = a x 2 + a y 2 + a z 2 \mathbf{SVM}=a=\sqrt{a_x^2+a_y^2+a_z^2} SVM=a=ax2+ay2+az2

    以下为跌倒监测的代码实现:

    void fall(){
    	
    			MPU_Get_Accelerometer(&aacx,&aacy,&aacz);	//得到加速度传感器数据		
    				SVM = sqrt(pow(aacx,2)+  pow(aacy,2) + pow(aacz,2));	
    				//printf("pitch:%0.1f   roll:%0.1f   yaw:%0.1f   SVM:%u\r\n",fabs(pitch),fabs(roll),fabs(yaw),SVM);
    				
    				//分析x、y、z角度的异常判断
    				if( fabs(pitch)>40 || fabs(roll)>40 || fabs(yaw)>40 )//倾斜角度的“绝对值”大于70°,SVM大于设定的阈值时,即认为摔倒
    					mpu_1_flag = 1;	
    				else 
    					mpu_1_flag = 0;
    				
    				//分析加速度SVM的异常判断
    				if( SVM>22000 || SVM<12000 ){i = 0;}
    				i++;
    				
    				if( i<=3 ){mpu_2_flag = 1;}
    				else 
    				{
    					i = 3;
    					mpu_2_flag = 0; 
    				}
    		
    				//综合欧拉角、SVM异常判断异常
    				if( mpu_2_flag || mpu_1_flag){mpu_flag = 1;}
    				else {mpu_flag = 0;}
    				
    				BEEP=0;		  
    				delay_ms(300);//延时300ms
    				if(mpu_flag==1)
    				{
    						BEEP=1; 
    						LED2=0;
    						LED1=1;
    					delay_ms(300);//延时300ms
    					
    				}	BEEP=0;	
    				delay_ms(300);
    				LED1=0;
    				LED2=1;
    
    }
    

    4、WI-FI模块

    该模块的工作流程如下:
    在这里插入图片描述
    系统上电后对首先是对WI-FI模块引脚进行初始化包括WI-FI模块的RESET引脚,在本设计中WI-FI模块通过USART3串口与主控STM32进行通信,因此还需要对USART3(串口3)进行初始化,串口初始化代码是基本功这里就也不贴代码啦。

    紧接着是 然后是对WI-FI模块的配置,首先是主控STM32通过串口3向ESP8266发送RST复位指令,然后清除ESP8266中的缓存,根据本设计的需求是要把硬件采集层所获取的所有数据传输到云平台,因此配置其工作模式为“STA”模式(WI-FI模式)。配置为STA模式后需要连接手机热点,通过串口3发送AT指令到ESP8266配置WIFI的名称和密码,命令格式为: AT+CWJAP=“名称”,“密码”,为了方便串口3发送命令,本设计将热点名称和密码做了宏定义,宏定义如下:

    #define ESP8266_WIFI_INFO		"AT+CWJAP=\"ONTNET\",\"lyycz1314\"\r\n"
    

    能上网之后接下来访问云平台公网IP,因为ESP8266模块内部自带了TCP/IP协议栈,因此通过AT命令连接到云平台,命令格式为:AT+CIPSTART= “TCP”,“IP”,“端口”,为了方便串口3发送命令,本设计将云平台的IP地址、端口做了宏定义,宏定义如下:

    #define ESP8266_ONENET_INFO		"AT+CIPSTART=\"TCP\",\"183.230.40.39\",6002\r\n"
    

    以上这两个每个人的都不一样,根据自己的具体情况配置,如果直接复制就会访问到别人的云平台创建的项目上,这样就尴尬啦。

    配置完成后就可以向云平台发送MQTT协议包,等待平台回应后就可以将各种数据打包发送至云平台了,以下为ESP8266初始化的具体代码:

    void ESP8266_Init(void)
    {
    	GPIO_InitTypeDef GPIO_Initure;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    	//ESP8266复位引脚
    	GPIO_Initure.GPIO_Mode = GPIO_Mode_Out_PP;
    	GPIO_Initure.GPIO_Pin = GPIO_Pin_1;					//GPIOB1-复位
    	GPIO_Initure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOB, &GPIO_Initure);
    	
    	GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_RESET);
    	delay_ms(250);
    	GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_SET);
    	delay_ms(500);
    	
    	ESP8266_Clear();
    
    	printf("AT\r\n");
    	while(ESP8266_SendCmd("AT\r\n\r", "OK", 100))
    		delay_ms(500);
    	
    	printf("CWMODE\r\n");
    	while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK", 100))
    		delay_ms(500);
    	
    	printf("AT+CWDHCP\r\n");
    	while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK", 200))
    		delay_ms(500);
    	
    	printf("CWJAP\r\n");
    	while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP", 200))
    		delay_ms(500);
    	
    	printf("CIPSTART\r\n");
    	while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT", 200))
    		delay_ms(500);
    	
    	printf("ESP8266 Init OK\r\n");
    }
    
    

    上段代码也是可以移植的,以下是ESP8266向云平台发送数据的具体代码:

    void OneNet_SendData(void)
    {
    	
    	MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};												//协议包
    	
    	char buf[128];
    	
    	short body_len = 0, i = 0;
    	
    //	printf("Tips:	OneNet_SendData-MQTT\r\n");
    	
    	memset(buf, 0, sizeof(buf));
    	
    	body_len = OneNet_FillBuf(buf);																	//获取当前需要发送的数据流的总长度
    	
    	if(body_len)
    	{
    		if(MQTT_PacketSaveData(DEVID, body_len, NULL, 5, &mqttPacket) == 0)							//封包
    		{
    			for(; i < body_len; i++)
    				mqttPacket._data[mqttPacket._len++] = buf[i];
    			
    			ESP8266_SendData(mqttPacket._data, mqttPacket._len);									//上传数据到平台
    //			printf("Send %d Bytes\r\n", mqttPacket._len);
    			
    			MQTT_DeleteBuffer(&mqttPacket);															//删包
    		}
    		else
    			printf("WARN:	EDP_NewBuffer Failed\r\n");
    	}
    	
    }
    

    这里是定义ONENET平台收数据的数据流的名称,上面的视频链接中如何配置云平台也会说到,并且更加详细。

    //上传数据流(名称及值)
    unsigned char OneNet_FillBuf(char *buf)
    {
    	char text[32];
    	
    	memset(text, 0, sizeof(text));
    	
    	strcpy(buf, ",;");
    		
    	memset(text, 0, sizeof(text));
    	sprintf(text, "Temperature,%.3lf;", tem+0.05f);
    	strcat(buf, text);
    	
    	memset(text, 0, sizeof(text));
    	sprintf(text, "Heart rate,%d;", Heart_rate);//(上传的数据流的名称)
    	strcat(buf, text);
    	
    	memset(text, 0, sizeof(text));
    	sprintf(text, "The Falls,%d;",mpu_flag);
    	strcat(buf, text);
    	
    		memset(text, 0, sizeof(text));
    	sprintf(text, "The Smoke,%lf;",temp2);
    	strcat(buf, text);
    	
    	return strlen(buf);
    }
    

    5、显示模块、烟雾报警模块

    由于这两个模块比较简单,尤其是OLED12864是最常见的模块,移植也直接用IIC协议,包括配置文件都是一起移植的,所以这里这两个模块间便不在赘述。

    六、实物测试及效果展示

    1、总体效果

    在这里插入图片描述

    2、网络测试

    通过串口调试助手,将WIFI模块与云平台连接情况打印出来,就可以清楚的知道问题出在哪一步。
    在这里插入图片描述

    3、开始界面:

    在这里插入图片描述

    4、心率、温度、烟雾浓度测试:

    在这里插入图片描述

    其中第一个数字表示的是心率值,第二个是当前室温,第三个是烟雾浓度值,第四个只有0\1,0表示没有跌倒,1表示跌倒。

    后是对跌倒检查功能的测试,首先默认水平是正常的状态,当把设计快速立放则会被视作摔了,液晶显示器的最后一位数字也会从0变成1,蜂鸣器会发出报警,以及下面的指示灯会变成红色,以下为测试结果:
    在这里插入图片描述
    在这里插入图片描述

    5、oneNET平台测试

    以下为平台接收到单片机传上来的各数据:
    在这里插入图片描述
    折线图显示:
    在这里插入图片描述

    七、总结

    终于写完啦,这个应该是我目前最长的一个帖子了哈,以上就是我的毕业设计了。当时本来还想加语音识别以及播报和北斗GPS定位的,测试了一下,加语音识别播报最小板引脚的勉强刚刚够,但如果加GPS的话由于硬件限制,stm32c8t6只有128k,不够存GPS数据,换zet6测试就可以,由于时间原因没有换核心板子(换了代码很多地方都要改,工作量有点大)后来还是没有用c8t6调出来,这也是遗憾的一点。有问题或者有兴趣进一步了解的同学,可以私聊,在能力范围内的会尽力帮助大家~~~

    那啥,都看到这儿了,点个关注在走呗~ 谢谢!(鞠躬)

    八、元器件清单

    显示模块:OLED128564
    心率模块:ADS1292R
    温度模块:LMT70
    姿态解算模块:MPU6050
    WIFi模块:ATK-ESP8266
    烟雾浓度检测模块:MQ-2
    降压稳压模块:LM2596S(可调降压带显示版)
    主控芯片:STM32F103C8T6(最小版)

    展开全文
  • 设计并实现了在STM32嵌入式平台上缺陷图像获取,缺陷边缘轮廓的提取算法,以及缺陷边缘轮廓图像的追踪算法与绘制。(该代码来源于本人本科毕业设计一部分)
  • 设计为基于stm32f103c8t6最小系统的万年历,在oled上显示年月日时分秒星期,具有闰年自动调整功能,实时温湿度测量显示等,内有工程代码,课程设计报告、接线原理图等,有不懂的请查看设计报告。ps:该设计是作者...
  • 项目是2020年TI杯电子设计大赛中的题目类似设计,用来巡线与速度调节都可以参考此教程源码 2020年TI杯电子设计大赛中的题目 1.任务 利用TI的MSP430/MSP432平台,设计制作一个四轮电动小车。要求小车能沿着指定路线在...

    2021年10月27-2022年1月1日 可承接单片机设计,有意可添加Q2809786963

    化作尘所有项目开源!!!

    视频代码资料文件包链接:https://download.csdn.net/download/mbs520/18273096

    百度网盘链接:https://pan.baidu.com/s/1iarHvWLLeAvFnJfxYEw9Rw
    提取码:e0fz

    一、项目描述

    项目是2020年TI杯电子设计大赛中的题目类似设计,用来巡线与速度调节都可以参考此教程源码

    2020年TI杯电子设计大赛中的题目

    1.任务
    利用TI的MSP430/MSP432平台,设计制作一个四轮电动小车。要求小车能沿着指定路线在坡道上自动循迹骑线行驶。小车必须独立运行,车外不能使用任何设备(包括电源)。小车(含电池)重量小于1.5kg,外形尺寸在地面投影不大于25cm×25cm。坡道用长、宽约1m的细木工板制作,允许板上有木质本色及自然木纹。木工板表面铺设画有1cm×1cm黑白间隔的纸条(以下简称为标记线)作为路线指示;标记线起始段为直线,平行于木板两边;标记线在坡顶转向90°,转弯半径20cm;标记线平行坡顶距离≥30cm,距坡顶距离≤20cm;标记线总长度为1m。停车标记为宽1cm长5cm的黑色线条,垂直于坡顶标记线。小车坡度角示意及行驶线路顶视图如图1所示。
    在这里插入图片描述

    2.要求
    (1)坡度角θ=0°,电动小车能够沿标记线自动骑线行驶,在停车点停车;小车上标记点到停车标记中心线的垂直距离误差≤2cm。停车时立即发出声音提示。小车行驶过程中,其地面投影不得脱离标记线。 (15分)
    (2)在完成(1)的基础上,电动小车能够设定行驶时间,自动控制小车匀速通过1米长的线路,在停车点停车。行驶时间可在10s~20s间设定。误差绝对值≤1s。行驶过程中不得碾压、脱离标记线。时间误差每超过1s扣1分。 (20分)
    (3)坡度角θ=10°,完成要求(2)的动作。 (20分)
    (4)可任意指定坡度角θ在11°~30°,完成要求(2)的动作。 (20分)
    (5)在完成(4)后,尽量增加坡度角θ,完成要求(2)动作。 (20分)
    (6)其他。 (5分)
    设计报告:

    项 目主要内容满分
    方案论证比较与选择,方案描述3
    理论分析与计算系统相关参数设计5
    电路与程序设计系统组成,原理框图与各部分的电路图,系统软件与流程图5
    测试方案与测试结果测试结果完整性,测试结果分析5
    设计报告结构及规范性摘要,正文结构规范,图表的完整与准确性。2
    总分20

    3.说明
    (1)本题目必须使用指定的MSP430/MSP432平台。并将该平台置于显著位置便于评测。不得另外使用其它CPU控制芯片。
    (2)不得采用履带小车及带刺轮胎。小车轮胎采用橡胶塑料等柔性材质,不得在其表面涂抹粘性物质等。行驶路面不得铺设除标记线外的任何材料。小车全程在木工板上行驶。
    (3)小车设定模式后自动行驶,中途不得人工介入控制。在要求(2)~(5)的测试中,小车应匀速行驶。停顿、打滑、碾压标记线每次扣除2分。
    (4)小车标记点:小车到达停车线的标记点自定,并在行驶前明确标记在车体上,以便测量。
    (5)所有测试中,行驶过程时间超过30s、小车投影脱离标记线或停车误差超过2cm,均视为失败。
    (6)要求(5)中最大角度的测试,θ由选手自己选定。
    (7)每项测试过程允许测试两次,取最好成绩。坡度角可以用安卓手机上的“指南针”APP软件测量。

    二、制作选材

    1、主控芯片stm32f103c8t6

    STM32F103C8T6是一款基于ARM Cortex-M 内核STM32系列的32位的微控制器,程序存储器容量是64KB
    STM32 F1系列为Cortex-M3基础型MCU 。其中增强型STM32F103- 72 MHz CPU,具有高达1MB的Flash、电机控制、USB和CAN。
    其FLASH(KB)大小为64
    RAM(KB)大小为20
    封装方式采用LQFP48
    通用I/O口个数为37
    工作电压为2~3.6V
    16位定时器个数4
    电机控制定时器个数1
    CAN个数1
    在这里插入图片描述
    2、编码电机
    型号MG513 p30 12v
    转动一圈390个脉冲
    减速比1比30

    然后通过获取每100毫秒的脉冲个数

    就可以计算出速度的大小

    在这里插入图片描述
    3、7针0.96寸oled显示屏
    在这里插入图片描述
    4、舵机
    看着挺高级的,马力大,不过控制代码与那种两块钱的一样,模拟控制,PWM控制,用来控制方向
    在这里插入图片描述
    4、红外传感器模块

    4个红外对管,一块模拟转数字模块
    在这里插入图片描述
    5、电源18650+电池座
    经济实惠
    在这里插入图片描述

    6、锂电池充电器
    一个模块加一个电池座,加起来不到2块钱
    商品链接我得整理一下。。。
    在这里插入图片描述

    7、旋转编码器,
    用来调节时间的,按下小车就可以跑了

    在这里插入图片描述

    7、小车底盘
    购买链接: https://m.tb.cn/h.4MEu0RC?sm=51a10c
    其实编码电机与舵机小车上面都有,直接买一个小车车身
    买来是散装的,装了好久装好:
    在这里插入图片描述

    三、原理图设计

    首先就是要进行硬件设计,连接好了硬件,软件就好办了

    原理图设计:(可能有点模糊,建议下载我的资料里面有原图)
    在这里插入图片描述

    然后开始连接硬件

    在这里插入图片描述

    在这里插入图片描述

    连接好了硬件,写程序就可以调试了…
    在这里插入图片描述
    硬件与程序调试用了两天时间总算搞定了接下来开始测量数据

    四、数据测量

    功耗测量:
    在这里插入图片描述

    设置全程1.5m走的时间:

    时间电流电压
    静态111mA11.5V
    10s242mA11.1v
    11s238mA11.1v
    12s228mA11.1v
    13s224mA11.2v
    14s204mA11.1v
    15s191mA11.2v
    16s189mA11.3v
    17s188mA11.3v
    18s187mA11.2v
    19s184mA11.3v
    20s185mA11.3v
    21s183mA11.2v
    22s181mA11.3v
    23s179mA11.3v
    24s177mA11.3v
    25s174mA11.4v
    26s171mA11.4v
    27s168mA11.4v

    2、OLED速度监测

    在这里插入图片描述

    显示屏数据说明:
    v1 v2左右轮实时速度
    pidout输出pwm值
    time 设定时间 speed通过设定时间计算得到的速度,因为路程固定
    running stop运行状态

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    可以看到PID算法起到了良好的效果,很好的把速度恒定在指定范围之内

    平地测量场景:
    在这里插入图片描述

    记录数据

    在这里插入图片描述

    五、程序设计

    1、主程序设计
    主函数它是执行了整个程序的入口点。
    首先初始设置定时器参数,设置TIM1 16位定时器递增计数,设置定时器时间10MS,主要用来在定时器中断测量小车速度与PID算法调用
    配置TIM4为PWM模式,设置周期为30ms,298能够反应过来,周期太大小车会有抖动,通过脉宽来调节小车速度,脉宽越大,小车运动越快,设置计数器为1000向上计数,也就是重装载值设置1000小车最快,设置重装载值0小车不运动
    配置TIM3为PWM模式,根据舵机的特性,配置周期为30MS,向上计数模式,计数器设置为3000,当脉宽长度为28MS时,舵机刚好再0度位置,所以初始化重装载寄存器为2800,上电默认向前方向
    配置红外传感器4个输入引脚为输入模式,来检测输入的电平情况
    配置旋钮编码器为3个引脚输入模式,用来检测是否旋转与按下
    配置LED引脚为推挽输出模式,来驱动LED闪烁
    配置串口与滴答定时器延时,串口主要用来调试,延时用来消耗某些时刻需要消耗的时间
    循环:
    循环检测旋钮状态,如果旋转了就根据旋转的方向与角度设定时间的大小,如果旋钮按键按下,那么前进状态变成1

    main.c

    //主函数
    int main(void)
    {
    	u8 state;
    	int ang,i;
    	
        uart_init(9600);//蓝牙串口初始化
    	delay_init(); //延时初始化
    	SteerinMotor_Init(); //舵机初始化
    	EncodeMotor_Init();//编码电机初始化
    	OLED_Init();//oled初始化
    	LED_Init();//led初始化
    	TIM1_Int_Init(100,7200);//定时器初始化10ms
    	Encodeing_Init();//旋钮编码器初始化
    	//测试
        printf(" this is Ramp patorl trolley  by HUAZUOCHEN! ^_^ \r\n");
        while (1) {
    		OLED_update();//更新OLED显示
    		encodeing_scan();//编码器扫描
    		//获取红外线传感器传回的数据
    		state = Get_Infrared_Sensor();
    		ang = 0;
    		switch (state)//循迹转弯设置
    		{
    			case 0x00:ang = 0;
    				break;
    			case 0x01:ang = -55;
    				break;
    			case 0x03:ang = -45;
    				break;
    			case 0x02:ang = -10;
    				break;
    			case 0x06:set_steerMotor_ang(0);//设置舵机角度 0
    				break;
    			case 0x04:ang = 10;
    				break;
    			case 0x0c:ang = 45;
    				break;
    			case 0x08:ang = 55;
    				break;
    			case 0x0f:  //识别到杂乱信号角度设置为0
    			case 0x09:
    			case 0x05:
    			case 0x0a:
    			case 0x0e:
    			case 0x0b:
    					run_flag = 0;//停止	
    				break;
    			default:ang = 0;
    				break;
    		}
    		if(ang != 0)
    		{
    			set_steerMotor_ang(ang);//设置舵机角度
    			delay_ms(100);
    		}
    		state = 0;
        }
    }
    
    

    定时器1中断,10ms调用一次,调用时计数10次调用,也就是100ms进行一次速度测量,V = X/t ,速度等于位移处以时间,位移等一编码个数乘以编码单位长度,小车轮的直径为6.4厘米,周长为20.12cm,得到一个脉冲计数,大约是0.258毫米,得出左轮速度V_left = pause_cnt_left2.58;右轮速度V_right = pause_cnt_right2.58;当按下旋转编码器的按键run_flag = 1;使得PID算法开始运行,小车开始按照计算好的速度与当前测量到的速度做比较,进行闭环PID调节。

    timer.c

    
    u16 time_cnt,run_cnt;
    //100ms计算一次速度
    void TIM1_UP_IRQHandler(void)
    {
    	if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
    	{
    		TIM_ClearITPendingBit(TIM1, TIM_IT_Update);  //清除TIMx的中断待处理位:TIM 中断源 
    		time_cnt ++;
    		if(time_cnt >= 10)
    		{
    			V_left = pause_cnt_left*2.58;
    			V_right = pause_cnt_right*2.58;
    			pause_cnt_left=0;
    			pause_cnt_right=0;
    			time_cnt =0;
    			LED = !LED;
    		}
    		
    		if(run_flag)
    		{
    			speed = 1200/time;  //总路程/时间
    			Set_Temp1 = Set_Temp = speed;
    			set_pid_speed();
    			run_cnt++;
    			if(run_cnt == time*200)
    			{
    				run_flag = 0;
    				run_cnt = 0;
    			}
    		}
    		else 
    		{
    			PID_OUT = 0;
    			PID_OUT1= 0;
    			//run_cnt = 0;
    			car_go_forward(0,0);//停止
    		}
    	}
    }
    

    霍尔编码器脉冲获取采用中断方式,中断设置上升沿下降沿都触发,
    电机传动轴与编码器相连,编码器感应论上有13个感应线条,从而使得编码器齿轮转动一圈,或编码器能识别到13个脉冲
    减速箱使得小车轮子转动一圈,电机轴转动30圈,使得编码器齿轮也转动30圈,得到,小车轮子转动一圈,编码器输出13×30,等于390个脉冲,又因为一个脉冲有一个上升,沿有一个下降沿,单片机通过检测上升沿和下降沿,可以得到有780个计数,

    encode_motor.c

    double V_left,V_right;//定时器计算
    u16 pause_cnt_left,pause_cnt_right;//脉冲计数
    
    //外部中断2服务程序
    void EXTI2_IRQHandler(void)
    {
    	pause_cnt_left++;
    	EXTI_ClearITPendingBit(EXTI_Line2);  //清除LINE2上的中断标志位  
    }
    //外部中断3服务程序
    void EXTI3_IRQHandler(void)
    {
    	
    	pause_cnt_right++;
    	EXTI_ClearITPendingBit(EXTI_Line3);  //清除LINE3上的中断标志位  
    }
    

    速度平衡算法,给定一个速度,听过与编码电机反馈的速度进行比对,然后输出一个算出来的PWM值返回给电机调速,达成闭环速度调节

    PID.c

    
    void PID_calc(float V_1, float V_2) //PID算法
    {
        /***********************左轮**************************/
        float Rate;//误差变化率
        float Rate1;//误差变化率
        Current_Error = Set_Temp - V_1;//当前误差
        Sum_Error += Current_Error; //误差积分
        Prev_Error = Last_Error;//存储误差积分
        Last_Error = Current_Error;//存储误差分析
        Rate = Current_Error - Last_Error; //变化速率计算
    
    
        if (Rate > 10) //不让ta大于5也不让ta小于5
            Rate = 10;
        if (Rate < -10)
            Rate = -10;
    
        P_OUT = P * Gain * Current_Error; //比列项
        I_OUT = I * Gain * Sum_Error; //积分项
    
        //积分限幅处理
        if (I_OUT > PID_I_MAX)  I_OUT = PID_I_MAX; //不能超过最大值不能低于最小值
        if (I_OUT < PID_I_MIN)  I_OUT = PID_I_MIN;
    
        //微分输出处理
        D_OUT = D * Gain * Rate;
        PID_OUT =  P_OUT  +  I_OUT  +  D_OUT ;
        if (PID_OUT >= V_DATA_MAX)  PID_OUT = V_DATA_MAX;
        if (PID_OUT <= V_DATA_MIN)  PID_OUT = V_DATA_MIN;
    
        /***********************右轮********************************/
    
        Current_Error1 = Set_Temp1 - V_2;//当前误差
        Sum_Error1 += Current_Error1; //误差积分
        Prev_Error1 = Last_Error1;//存储误差积分
        Last_Error1 = Current_Error1;//存储误差分析
        Rate1 = Current_Error1 - Last_Error1; //变化速率计算
    
    
        if (Rate1 > 10) //不让ta大于5也不让ta小于5
            Rate1 = 10;
        if (Rate1 < -10)
            Rate1 = -10;
    
        P_OUT1 = P * Gain1 * Current_Error1; //比列项
        I_OUT1 = I * Gain1 * Sum_Error1; //积分项
    
        //积分限幅处理
        if (I_OUT1 > PID_I_MAX1)  I_OUT1 = PID_I_MAX1; //不能超过最大值不能低于最小值
        if (I_OUT1 < PID_I_MIN1)  I_OUT1 = PID_I_MIN1;
    
        //微分输出处理
        D_OUT1 = D * Gain * Rate1;
        PID_OUT1 =  P_OUT1  +  I_OUT1  +  D_OUT1 ;
        if (PID_OUT1 >= V_DATA_MAX1)  PID_OUT1 = V_DATA_MAX1;
        if (PID_OUT1 <= V_DATA_MIN1)  PID_OUT1 = V_DATA_MIN1;
        /*******************************************************/
    }
    
    

    获取红外传感器值
    红外对管用一个发射管与一个接收管组成,红外发射管发射出去的红外线遇到白色物体会反射回红外接收管,使之导通,反之遇到黑色物体不反射,使之截止。接收到的红外线越强,导通电流越大,输出电压越大,输出的电压经过逻辑电路转换为数字信号传回到单片机进行识别处理。单片机引出4个引脚对应接收电平状态,4个引脚配置为输入模式,循环检测电平的变化,电平为1则对应红外对管识别到黑色,电平0对应红外对管识别到白色

    //获取传感器状态
    u8 Get_Infrared_Sensor(void)
    {
    	u8 state=0;
    	if(PBin(4) == 1)     
    		state |= 0x08;	//IN4
    	if(PBin(5) == 1)
    		state |= 0x04;	 //IN3
    	if(PBin(6) == 1)
    		state |= 0x02;	 //IN2
    	if(PBin(7) == 1)
    		state |= 0x01;	 //IN1
    	
    	return state;
    }
    
    

    化作尘其它开源项目:

    单片机项目:

    基于stm32c8t6的坡道行驶巡线小车(2020年TI杯大学生电子设计竞赛 C题)https://blog.csdn.net/mbs520/article/details/115438122

    基于STM32F4的音乐播放器
    https://blog.csdn.net/mbs520/article/details/111313042

    基于STM32F4的电子阅读器(首创)
    https://blog.csdn.net/mbs520/article/details/110817173

    基于51单片机WiFi视频小车(首创)
    https://blog.csdn.net/mbs520/article/details/109843972

    基于51单片机蓝牙小车
    https://blog.csdn.net/mbs520/article/details/109775964
    基于MSP430 坡道行驶电动小车(2020年TI杯大学生电子设计竞赛 C题)
    https://blog.csdn.net/mbs520/article/details/109090072

    基于stm32f4的智能门锁系统
    https://blog.csdn.net/mbs520/article/details/106987758

    基于51单片机超声波测距小车
    https://blog.csdn.net/mbs520/article/details/106599219

    基于51单片机定时宠物喂食系统
    https://blog.csdn.net/mbs520/article/details/108292187

    Linux项目:

    基于QT5 Linux平台 停车场管理系统
    https://blog.csdn.net/mbs520/article/details/113481824

    基于QT5 Linux平台 车载系统
    https://blog.csdn.net/mbs520/article/details/112873809

    基于Linux系统 媒体播放器
    https://blog.csdn.net/mbs520/article/details/107880118

    基于Linux系统 语音识别、人机对话
    https://blog.csdn.net/mbs520/article/details/113179224

    基于Linux系统小钢琴程序(暂无博客)
    https://download.csdn.net/download/mbs520/12798287

    基于Linux系统 QQ通讯录管理系统(暂无博客)

    展开全文
  • 摘要:本文通过OpenMV作为是识别模块去识别被测物体(以红色小球为例),当其识别到红色小球后,判断小球中心点所在的区域信息,并将其区域标志位通过串口发送给STM32,当STM32接收到位置信息后对x轴、y轴的两个舵机...
  • 毕业设计:基于STM32的指纹识别门禁系统设计。指纹解锁,手机蓝牙解锁等多种解锁方式。0.96寸oled显示,可显示万年历,汉字库显示。可设置时间,录入指纹,修改密码等操作。
  • stm32f103+wifi模块接入中国移动物联网云平台 包含温湿度检测,火焰检测,蜂鸣器报警,led灯闪烁等 资料包含: 程序源码 电路图 任务书 答辩技巧 开题报告 参考论文 系统框图 程序流程图 使用到的芯片资料 器件...
  • stm32嵌入式课程设计,包含keil5程序,proteus仿真,设计报告。芯片stm32f401. 使用了keil RTX2实时系统,以及emwin图形界面。可以显示时间日期,以及设置时间日期,详情请看设计报告

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,237
精华内容 1,294
关键字:

stm32毕业设计

友情链接: jy103.zip