基于STM32的工程环境监控系统

 毕业设计(论文)- 接辅导,欢迎私信交流,看主页

课题名称   建筑工程环境监控系统设计  

学    院   电子信息                  

专    业    物联网工程               

摘要:随着信息技术的高速发展,很多传统行业正在发生改变,尤其是建筑行业。近年来,我国建筑业安全监督管理体系不断完善,安全监督管理不断深入和细化,智能物联网作为一种新兴的快速发展的技术,在建筑行业中已得到应用。

本文利用建筑工程物联网基本架构,以STM32单片机为主控,点灯科技手机APP物联网平台,设计了一个建筑工程物联网环境监测系统。该系统具备实时信息采集与数据分析管理功能,主要由三个部分构成:第一部分是感知层,主要完成ZigBee通信网络的组建与数据采集、传输工作;第二部分是传输层,主要是数据的处理和以太网的驱动工作;第三部分是应用层,负责存储和分析处理终端采集的数据。 感知层使用ZigBee无线传感器网络,由无线网络协调器、路由器和终端数据采集器等ZigBee无线节点构成,实现建筑工程现场实时数据采集;ZigBee无线节点使用微处理器STM32作为主控制器,采用嵌入式操作系统,并完成数据的初步处理与分析。应用层包括嵌入式系统端和远程参数显示端:嵌入式系统端包括用户按键,用户界面User Interface,即UI使用者界面,实现人机交互;远程云端,在手机APP上显示环境监控的参数,通过开放标准的物联网协议 MQTT、MQTT over WebSocket、CoAP/LwM2M 将物联网设备可靠地连接到 EMQX Cloud,实现智能互联。

关键词:建筑工程,物联网,STM32,实时信息采集,ZigBee,MQTT

目录

1 绪论 3

    1. 课题背景及意义 4
    2. 国内外发展状况 4
    3. 课题主要工作 8

2 方案选择 10

2.1控制器总体方案设计 11

2.2方案论证对比 12

3 系统硬件设计 12

3.1 主控模块硬件电路设计 13

3.2 电源稳压模块电路设计 18

3.3 雨滴传感器模块电路硬件设计 20

3.4 无线传输模块电路设计 25

3.5 风速传感器电路设计 26

4 系统软件设计 29

4.1 系统主程序设计 30

4.2 用户界面设计 33

4.3 无线传输模块数据采集驱动程序设计 35

4.4 风速传感器程序设计 36

4.5 雨滴传感器程序设计 36

5 系统整体功能测试 39

致谢 40

参考文献 41

附录程序 42

1 绪论

    1. 课题背景及意义

1.2.1国外发展状况

现在,随着社会的飞速发展,我们已经进入了一个信息化的时代,很多行业都有了机械代替人类,有了人工智能,可以帮助我们进行预测和预警。建筑行业的稳定发展显示,中国的经济正在逐步从衰退的冲击中复苏。与此同时,数字经济的转轨也给建筑行业带来了新的发展机会。在新基建计划下,5 G技术,物联网,人工智能,数据中心等新的基站将是一个具有挑战性的新市场。随着新技术的不断发展和应用,建筑产业的增值不断增加,建筑产业已成为中国经济发展的基石。在国际上,中国承建的许多国际基建工程已获得“一带一路”的批准。比如,在2019年12月,一个中国的合同公司已经在巴西签订了一份关于建设和运行巴西第二大大桥的合同,中国的承包商已经开始为非洲及东南亚国家建设“一带一路”的港口和桥梁。

随着人民生活水平的不断提高,人们的环保意识越来越强,对环境监测工作的需求也越来越大。环境监测是环境保护工程建设的重要依据,也是环境保护工作的重要依据。工业物联网解决方案能够帮助制造企业通过各种设备、实时数据分析、监测等手段,提高企业的敏捷性、通用性和控制力,从而达到更高的智能化运营水平。更快速的提供新的特性,与连接的产品。有了远程监控,管理和分析的能力,你就可以知道客户在什么时候和什么时候使用你的产品。

另外,我们还可以学习到怎样出售更多的服务,创造新的产品增值服务,根据实际用途设计合约,并通过更高的服务级别协定(SLAs),提供优质服务。利用工业物联网(IIoT)解决方案,利用预测模式的分析能力,实现预期的维修,从而降低故障的发生。利用 IIoT技术的企业工业物联网平台,用户可以通过传感器对连接的产品进行访问和分析,并利用该模型对产品的维护进行预测。

在一个专门为用户提供的服务中,可以增加用户的生命周期和第一个电话修理率。物联网,也就是万物互联的因特网,是指通过一种信息传感装置,按照约定的协议,把任意对象与网络连接起来,并在此基础上实现信息的交流、交流,实现智能化的识别、定位、跟踪、监控等功能。物联网着重于改变人们的生活和商业模式,以及创造大量的数据。为了满足海量存储的需要和研究,需要开发出海量的数据平台,充分发挥出物联网的所有优点。这是一种全新的、未来的大规模物联网发展趋势。

1.2.2 国内研究现状

在我国,对物联网技术的研究与应用还处于起步阶段。而物联网作为五大新兴产业之一,在国内的发展中,也受到了极大的关注。随着政府顶层设计的逐步明朗,以及资本市场对其的重视,越来越多的学者开始投身于物联网的研究,为其在工业上的应用做出自己的贡献。

张金刚和孟祥茹(2008)就物联网的相关理论进行了探讨,认为物联网的本质是 RFID传感器技术和它的应用。简而言之,无线通信技术、网络技术、计算机技术等技术的结合,通过主动标识管理对象,实现对对象的智能探测和遥控。董大浸、冯凯梁等人在《物联网技术在建筑安全管理中的应用》中,提出了一种在建筑行业中使用 RFID技术的设想,在建筑工程项目中,有可能出现安全隐患的区域,如果终端传感器采集到目标特征,并与数据中心进行比对,就可以向施工人员和安全监理人员发出相应的安全预警级别和预警等级,在建筑工程现场事故发生之前就进行大数据分析和预测,最终降低安全事故发生的概率。

1.3 课题主要工作

本文结合办公场所的实际条件,结合自己所掌握的专业知识,开发出一套适用于办公室的新的空调控制系统。其主要工作有:

(1)通过对国内外发展现状的比较,结合人民群众的日常需要,给出了整个系统的整体设计和功能模块的选取。主要介绍了控制模块的选择,显示模块的选择,数据采集模块的选择。

(2)硬件电路的设计已完成。该系统主要由 CPU外围电路、显示电路、驱动电路、各传感器接口电路组成。

(3)完成了系统的软件和接口的设计.主要介绍了主程序设计,各子程序设计,并对上位机的程序处理算法进行了研究。

(4)完成了所设计的控制系统的综合试验。通过对实验数据的分析和测试,得出了该项目设计的空气净化器能够满足使用的需要。

如图系统架构:

2 方案选择

选择合适的单片机控制器对本系统的各传感器进行联调至关重要,并能改善系统的稳定性。

2.1控制器总体方案设计

方案一:可编程逻辑器件 CPLD,它的输入和输出都是平行的。该方法具有快速的系统处理能力,但是规模大、结构复杂,而且不需要复杂的逻辑函数,对数据的处理速度也没有很高的要求。

方案二:以 FPGA为控制单元。FPGA具有较大的规模和较高的密度,能够完成多种复杂的逻辑功能。然而,由于它的昂贵,使得系统的运行费用大大提高,使得其在高速运算中的优越性没有得到充分发挥。

方案三:单片机STM32F401CCU6为核心。STM32F401CCU6是一款功能强大、效率高的微处理器。开发环境的便捷和高效,使得系统运行起来更加容易,并且具有其他类型的单片机所不能及的,具有很高的集成性和相对简单的编程能力。STM32具有很强的计时能力,它的主要用途是 PWM方式, PWM方式只能在计时器4个信道中产生相同的工作频率,但是占空比不同,这是因为要控制马达、舵机和红外线对管的工作,所以采用计时器的 PWM方式。为了满足相应的高速计算需求,本系统选用STM32F401CCU6单片机作为其核心部件。

3 系统硬件设计

3.1 主控模块硬件电路设计

STM32F411xC/E主要采用32比特、多层 AHB总线矩阵(Cortex®-M4)、 FPU内核 I、 D、 S总线等。

–DMA1内存总线

–DMA2内存总线

–DMA2外围总线

–内部闪存ICode总线

–内部闪存DCode总线

–主内部SRAM

–AHB1外围设备,包括AHB至APB桥接器和APB外围设备,–AHB2外围设备.

总线阵列可以从主机到从机,支持并行存取,在多台外设同时工作的情况下仍能有效地执行。该体系结构见图1示:

图1 AHB总线矩阵

1、下载端口:124: SWDIO;137: SWCLK.选择 SW的下载方式,仅用3条线即可, DIO, GND, CLK。

2、开始选择选项58:BOOT1;166:BOOT0;一般情况下BOOT0接地,BOOT1处于半空状态。

3、时钟29:OSC_IN;30:OSC_OUT.在接有源晶振的情况下,直接接OSC_IN插针,OSC_OUT插针悬在空中即可。

4、 VREF:V_ref+与V_dda相连,1 uF、10 nF的电容并联在 VDDA/VREF+和 VSSA/VFRE-之间。

V_ref+和V_dda不相连,要求将1 uF和10 nF的电容并联在 VREF+和 VREF+之间。VDDA与 VSSA间的电容器必须同时连接1 uF与10 nF。

5、设置调节器BYPASS_REG为低,启动调节器,通过2.2 uF的电容将VCAP_1和VCAP_2接地。

参照设计:当BYPASS_REG接地时,VCAP_1、VCAP_2用2.2 uF的电容器进行接地。

6、电源 VDD与 VSS间有一个100 nF的解耦电容。

7、电源监视器将PDR_ON (171)维持在高电平,并使能功率监视器。参考设计:3V3接驳PDR_ON (如有)

8、 VSSA与 VDDA、 VSSA、 VDDA之间用100 nF、10 uF的电容器相连。

9、备用电池 VBAT直接与3.3 V连接.VBAT:提供备用电源,保持 RTC/BKP寄存器等数据的断电,通常用钮扣式电池,不用的话可以用电源。如图2中的总示意图:

图2总原理图

如图三尺寸图:

图3尺寸图

如图四供电电压表格,根据数据手册的说明,这几个引脚的供电电压最大不能超过3.6V。

图4供电电压表格

如图五复位电路

图5复位电路

系统时钟一般是加外部晶振电路,相当于给单片机一个心跳。

如图六系统时钟

图6系统时钟

如图七烧录口

图7烧录口

图八Boot0和Boot1是用来选择STM32单片机的启动方式的。

图8 Boot0和Boot1

一旦选择了引导引脚,应用软件就可以修改内存。可在代码区访问(通过这种方式,代码可以通过ICode总线在系统总线的位置)。SYSCFG控制器中的SYSCFG内存重映射寄存器(SYSCFG_MEMRMP)。因此,可以重新映射以下存储器:

•主闪存

•系统内存

•嵌入式SRAM1

如图九闪存读取操作:

图9闪存读取操作

•闪存编程/擦除操作

•读/写保护

•预取I代码

•I代码上的64条128位缓存线

•D代码上的8条128位缓存线

如图十RDP级别转到另一个RDP级别

图10RDP级别转到另一个RDP级别

3.2 电源稳压模块电路设计

电源稳压模块电路设计

LM317是目前最常用的一种功率集成电路,它既是最简单的三端稳压器,也是最容易实现输出电压调节的器件。另外,它的特点是电压调节范围宽,稳压性能好,噪声低,纹波抑制率高。Lm317是一种可调三端正电压稳压器,它可以在1.2-37 V的电压范围内提供1.5安培以上的电流。输出电压可调节至1.2伏。输出电压为1.5 A。典型的线性调节系数为0.01%.标准负荷调节速率为0.1%。80分贝的脉动抑制率。保护输出端的短路。

过流保护,过热保护。调节管道的安全防护。标准三极管包装.电压范围:1.25~37 V,输出电流:5 mA~1.5 A;芯片内部有过热、过流、短路保护电路;最大输入-输出差值:40 V直流;最小输入-输出差值:3 V直流;工作环境:-10~+85℃。贮存环境:-65--150摄氏度.它的性能和7805相差无几,唯一的共同点就是电压范围更大,输出电流超过1 A。

下面是一个实用的可调电压稳压器的电路图:

图片中各个电容的大小如下图所示:

LM317是一种具有三端电压变化的整合式稳压块,使用方便,应用广泛。317系列产品有多种型号,有LM317HVH、W317L等.电控们常使用317稳压器来制造具有可变输出电压的稳压电源。

可以采用以下公式来计算稳压电源的输出电压: Vo=1.25 (1+R2/R1)。R1和R2的阻值,仅从公式本身就可以任意设置。但是,在稳压电源中,R1、R2的电阻不能任意设置,这是一个很好的方法。首先,317稳压器的输出电压在 Vo=1.25 V~37 V (例如LM317HVA、LM317HVK等高输出电压的317稳压器,其输出电压在 Vo=1.25 V~45 V)范围内,R2/R1的比率仅为0~28.6。

其次,317型稳压器均具有最低稳态操作电流,有些资料称最小稳态电流,有些资料称最小放电电流。最小的稳态操作电流通常是1.5毫安。不同厂家、不同型号的317稳压器,其最小稳压器工作电流值均不超过5 mA。317型稳压块在输出电压低于其最小稳定工作电流时,将无法正常工作。在317稳压器的输出电流比其最小稳态工作电流大的情况下,稳压器就能输出稳压电源。如果使用317稳压器(如所示)来制造稳压电源,而忽略了317稳压器的最低稳定操作电流,则您生产的稳压电源会产生以下异常:稳压电源的输出电压与无负载电压相差很大。

为了解决317稳压块最小稳态工作电流的问题,可以通过设置R1、R2的幅度,使得317稳压块在无负载状态下的最小稳态工作电流达到或等于317稳压块的最小稳定工作电流。这时,317稳压器在无负载状态下,只要保持其 Vo/(R1+R2)大于1.5 mA,即可确保其工作平稳。在上述公式中,1.5毫安是317稳压器的最低稳定操作电流。当然, Vo/(R1+R2)的数值可以设置成大于1.5 mA的任何数值,前提是可以确保317稳压器在无负载状态下工作。

经计算,R1的最大值是R1≈0.83 K (由于输出端总比调节端的电位1.25 V高,因此,为了保证输出电流达到1.5毫安、1.25/1.5×1000、调节端不存在电流、R1、R2串联、输出电压表示)。R2/R1的最大值为28.6,这就是一个很好的例证。所以R2的最大值为R2=23.74 K。在317型稳压块的输出电压计算中,为了保证317稳压块在空载状态下仍然能够工作,必须满足R1<0.83 K、R2>23.74 K的要求。

当然,在317稳压器的输出上并联泄流电阻器 R (如所示),能够将最小的稳定化操作电流提供给317稳压器。然而,当317稳压器的输出电压为37 V时,其输出电流比其最小稳压器的最小稳态运行电流要高,因此,若要使317稳压器的输出电压达到37 V,不但会造成电能的浪费,还会给系统带来更大的负荷,因此不适合采用这种方法。

3.3 无线传输模块电路硬件设计

SIM900A模块使用 UART (UART)通讯,并且SIM900A开发板均包含 TTL (V3.7也包含RS232级接口)。SIM900A模块采用 AT标准指令,完成通话、发送短信等功能。通过你的控制器,包括单片机,计算机等,与 TTL或者RS232接口相连接。当硬件连接完成之后, AT指令可以通过串口传输。

用计算机进行SIM900A的调试,建议先用计算机进行控制,再用 MCU进行控制。2.1硬件接口:当你用计算机调试我们的模块时,必须使用一台将SIM900和计算机相连的设备,通常使用USB--TTL和USB--232口线。在现实中, USB设备都是要被驱动的,每个系统的驱动都不一样。如图设计原理图:

设计原理图

3.3 雨滴采集模块电路设计

LM393是一种具有双重电压的比较电路.此输出负荷电阻可与允许的电源电压范围内的任何电压相连接,而不会受到 Vcc端电压的影响.此输出可以作为一个简单的接地 SPS开路(如果不采用负载电阻),则由驱动和器件的β值来约束输出部件的陷流.当电流达到16 mA (16 mA)时,输出晶体管将断开,输出电压将快速上升。

LM393是一种高增益宽波段的器件,其输出端与输入端间有一个寄生电容时,会产生振荡。只有当比较器改变时,才会出现这样的情况,而电源和旁通滤波器不能很好地解决这个问题,所以使用标准 PC板来降低寄生电容耦合。降低输入电阻低于10 K会降低反馈信号,甚至很小的正反向馈电(延时1.0至10 mV)都会引起快速的转换,因此除了使用延迟外,没有由于寄生电容引起的振动,将会在很短的转换周期内振荡。LM393偏压网络建立的静态电流不依赖于2.0~30 V的供电电压。一般情况下,电源无需加旁路电容器。

差分输入的电压可以比 Vcc高,而不会对设备造成损伤,并且保护部件要能够防止输入电压在负的端子上超过-0.3 V。

LM393的输出端为集电极断开,其发射端为 NPN输出晶体管,其输出端为多个集电极的输出端,或 OR (OR)功能。该输出可以用作一个简单的接地 SPS (在没有使用负载电阻器的情况下),由于可能产生的驱动和装置的β值,所以输出部件的陷波电流会受到限制。在达到16 mA的极限电流时,该输出晶体管会退出,并且输出电压会迅速升高.通过输出晶体管的伽马 SAT (γ SAT)来限定输出饱和电压。

输出晶体管的低失调电压(大约1.0 mV),在负载电流非常小的情况下,可以使输出钳位为零电平。

雨滴模块原理图

3.3 风速采集模块电路设计

使用优质 ABS 材质、硬度高、柔韧度好、抗压、抗腐蚀、使用寿命长。

风速模块

传感器安装尺寸图如下所示:

尺寸图

传感器与处理器接线图如下图所示,风速传感器正极(棕色线)接处理器的 ADC 接口,负极(蓝色线)接处理器的 GND。

接线图

电压信号与风速

关系图

风速传感器输出电压信号与风速的计算公式如下: F = 0.027´V 式中风速 F 单位为(m/s),电压 V 单位为(mV) 。

4 系统软件设计

本系统的软件设计部分包括终协调器程序设计、端节点程序设计、系统的移植的设计。

4.1 系统主程序设计

#include "main.h"

#include "i2c.h"

#include "usart.h"

#include "gpio.h"

void SystemClock_Config(void);

/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

int main(void)

{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU

  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */

  SystemClock_Config();

   /* Initialize all configured peripherals */

  MX_GPIO_Init();

  MX_I2C1_Init();

  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */

void SystemClock_Config(void)

{

  RCC_OscInitTypeDef RCC_OscInitStruct = {0};

  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage

  */

  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

  /** Initializes the RCC Oscillators according to the specified parameters

  * in the RCC_OscInitTypeDef structure.

  */

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

  RCC_OscInitStruct.HSEState = RCC_HSE_ON;

  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;

  RCC_OscInitStruct.PLL.PLLQ = 4;

  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

  {

    Error_Handler();

  }

  /** Initializes the CPU, AHB and APB buses clocks

  */

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK

                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;

  

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)

  {

    Error_Handler();

  }

  /** Enables the Clock Security System

  */

  HAL_RCC_EnableCSS();

}

/**

  * @brief  This function is executed in case of error occurrence.

  * @retval None

  */

void Error_Handler(void)

{

  /* USER CODE BEGIN Error_Handler_Debug */

  /* User can add his own implementation to report the HAL error return state */

  __disable_irq();

  while (1)

  {

  }

  /* USER CODE END Error_Handler_Debug */

}

void assert_failed(uint8_t *file, uint32_t line)

{

  /* USER CODE BEGIN 6 */

  /* User can add his own implementation to report the file name and line number,

     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* USER CODE END 6 */

}

#endif /* USE_FULL_ASSERT */

4.2 用户界面设计

OLED屏幕的分辨率是128×64, OLED屏幕的尺寸是128×64,但因为 OLED不能同时控制一个阵列,所以它只能控制8个,所以垂直方向的坐标可以是0到7,8×64,或者从0到127。

正如说明书中对I2C地址的说明一样,地址是,0111100和0111101,这取决于 DC管脚的电平,一般情况下,我们把 DC管脚设为地,因此I2C从机的7个比特地址是0111100;另外,我们在与驱动 IC进行交流时,都是由主机向 IC发出指令或资料,也就是说,只有写入,没有读取,因此,从机的地址是0x78。

IIC界面模块:

IIC 接口模块

汉字取模

界面定义

GND:电力供应

VCC:3.3-5 V供电

SCL: IIC通讯中的时钟引脚D0脚

D1脚,用于 IIC通讯中的数据引脚

0.96英寸发光二极管驱动集成电路

0.96′ OLED (4 Pin)模组,以SSD1306为驱动,模组内装有稳压器,可实现软体 IIC通信与软体 IIC通信,开机后可自动重置,功耗低,可自发光。

SSD1306有三种寻址模式:页面寻址模式、水平寻址模式、垂直寻址模式。地址确定了如何写数据。SSD1306在接收到数据后,会把 SDA的信号线路调低,并发出一条响应信号,由 MCU检测出SSD1306接收到的数据。

如图应答时序图

应答时序图

OLED显示寻址图:

OLED显示寻址图

程序如下:

#include "oled.h"

#include "i2c.h"

#include "oledfont.h"          //头文件  

uint8_t CMD_Data[]={

0xAE, 0x00, 0x10, 0x40, 0xB0, 0x81, 0xFF, 0xA1, 0xA6, 0xA8, 0x3F,

0xC8, 0xD3, 0x00, 0xD5, 0x80, 0xD8, 0x05, 0xD9, 0xF1, 0xDA, 0x12,

0xD8, 0x30, 0x8D, 0x14, 0xAF};      //初始化命令

void WriteCmd(void)

{

uint8_t i = 0;

for(i=0; i<27; i++)

{

HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,CMD_Data+i,1,0x100);

}

}

//向设备写控制命令

void OLED_WR_CMD(uint8_t cmd)

{

HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,&cmd,1,0x100);

}

//向设备写数据

void OLED_WR_DATA(uint8_t data)

{

HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x40,I2C_MEMADD_SIZE_8BIT,&data,1,0x100);

}

//初始化oled屏幕

void OLED_Init(void)

{

HAL_Delay(200);

WriteCmd();

}

//清屏

void OLED_Clear(void)

{

uint8_t i,n;     

for(i=0;i<8;i++)  

{  

OLED_WR_CMD(0xb0+i);

OLED_WR_CMD (0x00);

OLED_WR_CMD (0x10);

for(n=0;n<128;n++)

OLED_WR_DATA(0);

}

}

//开启OLED显示    

void OLED_Display_On(void)

{

OLED_WR_CMD(0X8D);  //SET DCDC命令

OLED_WR_CMD(0X14);  //DCDC ON

OLED_WR_CMD(0XAF);  //DISPLAY ON

}

//关闭OLED显示     

void OLED_Display_Off(void)

{

OLED_WR_CMD(0X8D);  //SET DCDC命令

OLED_WR_CMD(0X10);  //DCDC OFF

OLED_WR_CMD(0XAE);  //DISPLAY OFF

}      

void OLED_Set_Pos(uint8_t x, uint8_t y)

{

OLED_WR_CMD(0xb0+y);

OLED_WR_CMD(((x&0xf0)>>4)|0x10);

OLED_WR_CMD(x&0x0f);

}

unsigned int oled_pow(uint8_t m,uint8_t n)

{

unsigned int result=1;  

while(n--)result*=m;    

return result;

}

//显示2个数字

//x,y :起点坐标  

//数字的位数/len

//尺寸:字体尺寸

/模型:图案0、填充图案;1、重叠图案

(0~4294967295);

汉字的显示

//hzk从模型获取的阵列

void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no)

{           

uint8_t t,adder=0;

OLED_Set_Pos(x,y);

    for(t=0;t<16;t++)

{

OLED_WR_DATA(Hzk[2*no][t]);

adder+=1;

     }

OLED_Set_Pos(x,y+1);

    for(t=0;t<16;t++)

{

OLED_WR_DATA(Hzk[2*no+1][t]);

adder+=1;

      }

}

/*

函数功能:显示无符号float数字

参数:xy坐标,num显示数字,precise显示数字的精度,size数字大小模式

返回值:无

*/

void OLED_ShowUnFloat(uint8_t x, uint8_t y, double num, uint8_t precisenum, uint8_t precisefloat, uint8_t size)

{

uint8_t i = 0;

uint16_t integer;

double decimal;

integer = (int)num;//整数部分

decimal = (double)(num - integer);//小数部分

OLED_ShowNum(x,y,integer,precisenum,size);//显示整数部分

OLED_ShowChar(x+(size/2)*(precisenum+1),y,'.',size);//显示小数点

x = x+(size/2)*(precisenum+2);

while (precisefloat)//显示几位小数

{

decimal = decimal * 10;

integer = (int)decimal;//取出一位小数

decimal = (double)(decimal - integer);

OLED_ShowChar(x+(size/2)*i, y, integer + '0', size);//循环显示每位数字字符,从高位显示

i++;

precisefloat--;

}

}

4.3 系统远端操控界面设计

BlinkerButton

按键组件在App中可以设置 按键/开关/自定义 三种模式:按键 模式下支持 点按/长按/释放(tap/press/pressup) 三个动作开关 模式下支持 打开/关闭(on/off)两个动作自定义,模式下支持自定义指令 发送函数 :

attach()BlinkerButton.

attach()注册按键的回调函数, 当收到指令时会调用该回调函数

icon()

BlinkerButton.icon()

设置按键中显示的图标(icon), 图标列表及对应图标名称见

color()

BlinkerButton.color()

设置按键中显示图标的颜色, HTML颜色表

text()

BlinkerButton.text()

设置按键中显示的名字或者描述

BlinkerButton.text(text1)

一段描述文字

BlinkerButton.text(text1, text2)

两段描述文字

print()

BlinkerButton.print()

发送按键当前的状态(多用于开关模式下反馈开关状态), 并将以上设置一并发送APP

手机APP端页面

初始化, 创建对象:

setup() 中注册回调函数:

用于处理 RGB 收到数据的回调函数:

4.4 风速传感器数据采集驱动程序设计

// ADC1转换的电压值通过MDA方式传到SRAM

extern __IO uint16_t ADC_ConvertedValue[4];

// 用于保存转换计算后的电压值

float ADC_ConvertedValueLocal[4];  

void GPIO_Configuration(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

//GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE); //屏蔽所有作为JTAG口的GPIO口

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //屏蔽PB口上IO口JTAG功能

}

void WS_Value_Conversion()  //采集电压后根据手册提供函数关系计算PH值

{

WS_Value=100*ADC_ConvertedValueLocal[0];

dissbuff[1] = (int)(WS_Value)/100+'0';

dissbuff[2] = (int)(WS_Value)%100/10+'0';

dissbuff[3] = (int)(WS_Value)%10+'0';

WS_Buff[0] = dissbuff[1];

WS_Buff[1] = dissbuff[2];

WS_Buff[2] = dissbuff[3];

}

void Display_Data()

{

OLED_ShowStr(32,0,WS_Buff,2);//测试6*8字符

}

/**

  * @brief  主函数

  * @param  无

  * @retval 无

  */

int main(void)

{

GPIO_Configuration();

    /* 配置USART1 */

    USART1_Config();

    /* 初始化系统定时器 */

    SysTick_Init();

// ADC 初始化

I2C_Configuration();

 OLED_Init();

 ADCx_Init();  

dissbuff[0] = '#';     //串口发送字符串的标志

delay_ms(2000);  //延时2S

    OLED_CLS();//清屏

OLED_ShowStr(0,0,"WS:",2);

  while(1){

ADC_ConvertedValueLocal[0]=(float)ADC_ConvertedValue[0]/4096*3.3;

WS_Value_Conversion();

    Display_Data();

delay_ms(500);

printf("%s",dissbuff);//调用串口发送字符串}

连接图

4.5 雨滴传感器数据采集驱动程序设计

雨滴感应器是一种表面镀有一条线状的镍的板。这是建立在抗拒原则之上的。雨量感应器模块可以用模拟输出管脚来测量湿度,并能在超过湿度阈值时提供数字输出。

此模块是以LM393的运放为基础的。该系统由一个电子组件和一个印制的电路板来“收集”雨水。在电路板上累积的雨水,会形成一条由运算放大器测量的并联电阻路。

该传感器是一种电阻偶极,在潮湿时,其电阻值较低,在干燥时,其电阻值则较高。在没有雨点的情况下,它会增大阻力,所以我们就用 V= IR得到一个高压。

由于水是导电的,所以当有雨点的时候,由于有了水,就会使镍丝并联,从而减少了电阻,减少了两端的压降。

雨滴感应器

unsigned char date;

#define uchar unsigned char

#define uint unsigned int

sbit key1=P0^1;

void delay(uint z);

void Initial_com(void);

void delay(uint z)

{    

    uint i,j;

    for(i=z;i>0;i--)

        for(j=110;j>0;j--);

}

main()

{

 Initial_com();

 while(1)

 {

   if(key1==0)

{

delay();   

if(key1==0)    {

 SBUF=0X01;

 delay(200);

}

   

}

  if(RI)

  {

date=SBUF;    

RI=0;

  }

  }

}

4.6 无线传输模块驱动程序设计

串口通信程序流程图如图所示。

#include "GSM_usart2.h"

void USART2_Init(u32 bound)

{

GPIO_InitTypeDef GPIO_InitStructer;

USART_InitTypeDef USART_InitStructer;

NVIC_InitTypeDef NVIC_InitStructure;

USART_InitStructer.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //关闭硬件控制模式

USART_InitStructer.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //使能

USART_Init(USART2,&USART_InitStructer);

    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断

USART_Cmd(USART2, ENABLE);

}

void USART2_Send_data(char *str)//用于发送字符串(GSM模块需要接受的命令)

{

while(*str != '\0')

{

while(USART_GetFlagStatus(USART2,USART_FLAG_TC) == RESET);

USART_SendData(USART2,*str);

str++;

}

}

void USART2_Send_data_value(u8 dat)//用于发送十六进制数

{

while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==0);

USART_SendData(USART2,dat);

}

u8 Rec;

void USART2_IRQHandler(void)

{

if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)

{

Rec = USART_ReceiveData(USART2); //读取接收到的数据

    }

}

5 系统整体功能测试

该系统能够实现对建筑工程中的各种传感器数据进行实时的分析和管理,并对其进行及时的检测和检测。该系统可以有效地改善监测系统的稳定性和可靠性,保证系统的安全性和运行流畅,可以应用于各种施工现场的环境监测。

致谢

时间一晃而过,四年的大学生涯,终于要结束了。四年来,我受到了很多老师、同学、朋友的关心和帮助。在我的毕业论文快要写完的时候,我想对那些在这段时间里给予我支持、帮助和鼓励的人们表达我最真诚的感谢。

通过这次毕业设计,我深刻认识到,做软件并不是一件容易的事,它要求设计师具备综合的专业知识、缜密的思维、严谨的工作态度、分析问题的能力和解决问题的能力。最后,我要对老师在我的设计工作中的大力支持表示由衷的感谢,让我能够按时、顺利地完成本次毕业设计。同时,我还要向各位老师、同学以及实习公司表示衷心的感谢,感谢他们在整个系统的设计过程中对我的支持与协助。

    首先,我想对导师的教诲表示衷心的感谢。从选题、构思、撰写到最后的结题,教师给予了我细心的辅导,并给予了我很大的帮助。教师对工作的认真负责,对学术的研究,认真的学术态度,认真的学术态度,都是我一生的宝贵财富。其次,我要向学校的所有领导和教师表示衷心的感谢,在他们的精心指导下,我获得了专业的经济知识和专业技术。同时,我也对论文的修改和改进表示了感谢,并对论文进行了改进。

在撰写这篇文章之前,我查阅了许多有关的信息,让我逐渐认识到了 MCU和 USB的技术特性,并且为下一步的发展指明了方向。后来,我遇到了不少麻烦,但我还是克服了,学习和思考能力都有了长足的进步。

在这段时间里,我的家人一直以来对我的包容、关爱和鼓励,还有我的同学和朋友们,都是他们的帮助和关心,让我能够在学习中保持良好的心态和良好的心态。

毕业在即,在未来的工作与人生中,我将牢记老师的教导,并将继续不懈的努力与追求,以回报曾经给予我帮助和帮助的人!

我要再一次向母校表示衷心的感谢。谢谢那些在毕业设计过程中与我密切配合的同学,以及在各个领域给予了我很大的支持。多亏了您的协助,我不但学习到了与此相关的新知识,而且也体会到了超越知识的力量,即团结的力量。最后,我要向那些曾经在毕业设计上给予我很大帮助的人表示衷心的感谢。希望自己可以坚持自己的青春梦想,永远不要放弃。

参考文献

参考文献

[1]沈凤梅、许文靖、陈凡、张想。

[2]张洋、刘建粉.以STM32为核心的新型智能防盗门.

[3]胡可狄、于亚利、李帅、李志峰、王昆。

[4]张晓霞,以STM32为核心的精密定位卷帘机控制系统的研制和研制.电子学出版社,2022,30,第1期.

[5]谈曾巧、陆正亮、张翔.以STM32为核心的三维卫星姿态控制系统的设计.现代电子技术,2022,45,第1期

[6]王晓甜、毛永毅.火箭弹爆破声程差数据采集系统的研制,电子与设计,2022,30,第1期.

[7]田杰、胡秋霞、赵镇.STM32公交话音报站系统的设计与实现.

[8]李惠娜.以STM32为基础的公有云技术在蛋孵化中的应用. Electronics,2022,第30,第2期

[9]黄@@COP1_B、翁发禄、韦辉、侯磊磊.四旋翼无人驾驶系统中基于STM32的智能控制方法的研究.科学技术与创新,2022,2.

[10]毕德、刘志君、杨成龙.基于STM32的车辆牌照识别技术.辽宁技术学院学报,2002年时,1.

[11]王馨慧.高校学生管理系统在物联网中的应用.电子世界,2020,1.

[12]吴旭东.变电所的电气设备安装技术要点与技术分析.电力工业,2020,1.

[13]沈文娟、黄芬、李任青.单片机技术在 Proteus模拟平台上的应用.电子世界,2020,1.

[14] 唐思源,白金牛,杨敏.计算机专业课考核方式的分析与探讨 ——以《医学图像处理》课程为例.电子世界,2020,第1期

[15]张土建、赖宇威、黄鹏峰.高转换、高功率因数三相三相光伏并网系统的研究与开发.电子世界,2020,1.

[16]周昰彤、鞠振河.太阳电池技术研究进展与前景.电子领域,2020,1.

[17]张旭东、孙暄、李孟阳.电力系统中适合公共网的自动接入控制系统的研究.电子学,2020,1

[18]梁富铭、王晓刚、陈新兵.电动汽车的设计与制造.电子领域,2020,1.

[19]张颢.云中数据安全问题及保护策略的探讨.电子世界,2020,1.

[20]朱明荣.基于视频的面部识别与追踪研究.电子学杂志,2020,1.

[21]张勇、周跃华、赵蕊.高速公路不停车停车收费系统的节能分析.交通节能与环境科学,2011 (3):38-43.

[22]李斐、郭金旭、戴焯、韦政.武汉科技大学学报:资讯科技出版社,2004,26 (5):103-106.

[23]任传成、巩建闽、王海涛.智慧小区停车场管理系统中 IC卡技术的应用.聊城大学学报.2003.

[24]赵红英、郑国强、鲍建军.车辆型号分类的模糊模式识别方法[J].农用车辆与拖拉机,2005 (2):27-29.

[25]赵红英、郑国强、鲍建军.无停车收费制度的研究.浙江工学院学报,2005,6 (3):39-42.

[26]董加敏.停车场管理体系的设计和优化.河南师范大学教育出版社,2007,35 (1):190-193.

[27]王瑛、张辉宜、金仁才.高速公路不停车计费制度的探讨.中国广播出版社,2009 (6):24-27.

[28]冯明发、卢锦川.汽车用无接触 IC卡自动读卡机的研制.中国新技术与新产品,2010 (18):25-26.

[29] 樊梅香,相晨萌,齐飞,刘树行.便携式移动收费系统研究[J].河北工业科技,2011,28(4):275-277.

[30] 贾岩岩,何宁.基于无线射频传输的地下车位管理系统[J].桂林电子科技大学学报,2013,33(5):353-357.

附录程序

/* Includes ------------------------------------------------------------------*/

#include "gpio.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/*----------------------------------------------------------------------------*/

/* Configure GPIO                                                             */

/*----------------------------------------------------------------------------*/

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/** Configure pins as

        * Analog

        * Input

        * Output

        * EVENT_OUT

        * EXTI

*/

#include "get_adc.h"

#include "oled.h"

#include "Pid.h"

#include "Interrupt.h"

AD Left,Right;

uint32_t ADC_Value[6];

void ADC_DMA_Iint(void)

{

/*此句不可放在循环里,会紊乱通道采集*/

HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 6);

  

}

/* ===================================================================

 备注:电感AD采集归一化计算

1、可以方便自己对数据的感知,在普通元素和特殊元素间;

2、在赛道更换后,测新的赛道的最大值,改变max的值即可,有较强的适应性;

3、方便数据处理。

** ===================================================================*/

void Ad_Value(void){  

   char i;

   uint32_t Max=3400;     //采集最大值

   uint32_t Min=300;      //采集最小值   根据实际场地采集最大最小值

 uint32_t Left_firet[20],Left_second[20],Left_third[20];

 uint32_t Right_firet[20],Right_second[20],Right_third[20];

 float Sum[6];

 float AD_average[6];

 /* 求最大最小值*/

 for (int i = 0; i < 6; i++) {

Max = Max < ADC_Value[i] ? ADC_Value[i] : Max;

Min = Min > ADC_Value[i] ? ADC_Value[i] : Min;

 }

 for(i=0;i<20;i++)

   {   

        Left_firet[i]=ADC_Value[0];   

        Sum[0]+=Left_firet[i];

Left_second[i]=ADC_Value[1];   

        Sum[1]+=Left_second[i];

  Left_third[i]=ADC_Value[2];   

        Sum[2]+=Left_third[i];

Right_third[i]=ADC_Value[3];   

        Sum[3]+=Right_third[i];

Right_second[i]=ADC_Value[4];   

        Sum[4]+=Right_second[i];

  Right_firet[i]=ADC_Value[5];   

        Sum[5]+=Right_firet[i];

        

   }

 //不能直接两层for循环,因为就不是同一时间的采集值了

 for (i = 0; i < 6; i++)

 {

AD_average[i] = Sum[i]/20;  //计算20次的平均值

  Sum[i] = 0;

 }

 Left.firet = 1000*(AD_average[0]-Min)/(Max-Min);        //归一化到0-1000          

 Left.second = 1000*(AD_average[1]-Min)/(Max-Min);

 Left.third = 1000*(AD_average[2]-Min)/(Max-Min);  

 Right.third = 1000*(AD_average[3]-Min)/(Max-Min);  

 Right.second = 1000*(AD_average[4]-Min)/(Max-Min);  

 Right.firet = 1000*(AD_average[5]-Min)/(Max-Min);  

 if(Abs(Right.firet-Left.firet) >= 390 ){//|| Abs(Right.second-Left.second) >= 200

HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_SET);

PID_direction.Kp = 4;//6,弯道为6...7.5

PID_direction.Kd = 0.6;

Incremental_encoder(encoder1,18, 1); //闭环

Incremental_encoder(encoder2,18, 2);

 }

 else{

PID_direction.Kp = 2.5;//3,直道为2.5...3

PID_direction.Kd = 0.5;

Incremental_encoder(encoder1,30, 1); //闭环

Incremental_encoder(encoder2,30, 2);

HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_RESET);

 }

}

#include "Pid.h"

/*放.c文件中*/

PID PID_speed,PID_direction;

/*函数功能:增量PI控制器

入口参数:编码器测量值,目标速度

返回  值:电机PWM

根据增量式离散PID公式

pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]*/

void PID_Init(void){

PID_speed.Kp = 4;

PID_speed.Ki = 0.1;

PID_speed.Kp2 = 4.2;

PID_speed.Ki2 = 0.12;

PID_direction.Kp = 3;//6,弯道为6

PID_direction.Ki = 0;

PID_direction.Kd = 0.5;

}

/*

控制器是编码器,mode选择左右编码器,闭环

*/

void Incremental_encoder(int Encoder,int Target, char mode){

if (mode == 1){

 PID_speed.err=Target-Encoder;                                  

 PID_speed.Pwm+=PID_speed.Kp*(PID_speed.err-PID_speed.err_last)   +

 PID_speed.Ki*PID_speed.err;  

 PID_speed.err_last=PID_speed.err;

 TIM3->CCR1 = Xianfu_Pwm(500 + PID_speed.Pwm);

 TIM3->CCR2 = Xianfu_Pwm(500 - PID_speed.Pwm);

}

if (mode == 2){

 PID_speed.err2=Target-Encoder;                                  

 PID_speed.Pwm2+=PID_speed.Kp2*(PID_speed.err2-PID_speed.err_last2)+

 PID_speed.Ki2*PID_speed.err2;  

 PID_speed.err_last2=PID_speed.err2;

 TIM3->CCR3 = Xianfu_Pwm(500 + PID_speed.Pwm2);

 TIM3->CCR4 = Xianfu_Pwm(500 - PID_speed.Pwm2);

}

}

void Direction_track(void)

{

static float A = 0.9, B = 1.2, C = 0.9, P = 9;   //0.5 1 1.1

static float up, down;

/*差比和*/

up = A*(Left.second - Right.second) + B*(Left.firet - Right.firet);

down = A*(Left.second + Right.second) + C*Abs(Left.firet - Right.firet);

PID_direction.err = (up / down) * P;

/*PD控制*/

PID_direction.Pwm = PID_direction.Kp * PID_direction.err +

PID_direction.Kd * (PID_direction.err - PID_direction.err_last);

//OLED_ShowNum(65,4,Right.firet,5,12);

PID_direction.err_last = PID_direction.err;

TIM4 -> CCR1 = 125 + PID_direction.Pwm;

//printf("%d", PID_direction.Pwm);打印波形

}

uint16_t Xianfu_Pwm(uint16_t pwm){

if (pwm <= 50){

return 50;

}

else if(pwm >= 950){

return 950;

}

else {

return pwm;

}

}

float Abs(float a){

if (a <= 0){

return -a;

}

else{

return a;

}

}

//target = target > 70?70 : (target<-70?(-70):target);//速度限幅

#ifndef  __PID_H

#define  __PID_H

#include "stm32f4xx_hal.h"

#include "main.h"

#include "get_adc.h"

#include "oled.h"

typedef struct

{

float Kp,Ki,Kd,Kp2,Ki2,Kd2;

float integral,integral2;

float err,err2;

  float err_last,err_last2;

int Pwm,Pwm2;

} PID;

void PID_Init(void);

void Incremental_encoder(int Encoder,int Target, char mode);

void Direction_track(void);

uint16_t Xianfu_Pwm(uint16_t pwm);

float Abs(float a);

extern PID PID_speed,PID_direction;

#endif

void Motor_Init(void) {

    HAL_TIM_Base_Start(&htim3);

    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);

    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);

    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);

    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);

}

void speed_change(char val)   //未闭环时的速度选择

{

switch (val)

  {

   case 1:

TIM3->CCR1 = 320;//right  0.33

TIM3->CCR2 = 680;

TIM3->CCR3 = 680;//left

TIM3->CCR4 = 320;

   break;

   case 2:

TIM3->CCR1 = 280;//right   0.43

TIM3->CCR2 = 770;

TIM3->CCR3 = 770;//left

TIM3->CCR4 = 280;

   break;

case 3:

TIM3->CCR1 = 185;//right   0.63

TIM3->CCR2 = 815;

TIM3->CCR3 = 800;//left

TIM3->CCR4 = 205;

break;

case 4:

TIM3->CCR1 = 85;//right   0.83

TIM3->CCR2 = 915;

TIM3->CCR3 = 100;//left

TIM3->CCR4 = 900;

break;

   default:

   break;

  }

}

void Direction_Init(void){

HAL_TIM_Base_Start(&htim4);

HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);

TIM4 -> CCR1 = 125;   //125   60 ~ 185

}

void pid(a,b)

{

  read_dmp(&mpu_pose_msg);//读取mpu姿态

w_mpu_read_all_raw_data(&mpu_raw_msg); //读取原始数据

//前后

if (forword == 0&&back == 0) target = 0;  //未接收到命令,原地

if (forword == 1) {HAL_GPIO_WritePin(GPIOC , GPIO_PIN_13 ,1),target =  +8;}               //前进

if (back == 1)    {HAL_GPIO_WritePin(GPIOC , GPIO_PIN_13 ,1),target=-8;};               //后退

target = target > 70?70 : (target<-70?(-70):target);  //前进后退速度限幅

//左右

if (left == 0&&right == 0) turn_RL = 0;  //未接收到命令,原地

if (left == 1) {HAL_GPIO_WritePin(GPIOC , GPIO_PIN_13 ,1),turn_RL=-90;};               //左

if (right == 1)   {HAL_GPIO_WritePin(GPIOC , GPIO_PIN_13 ,1),turn_RL=+90;} ;               //右

turn_RL = turn_RL > 200?200 : (turn_RL<-200?(-200):turn_RL);  //前进后退速度限幅

  up_pwm = balance(mpu_pose_msg.pitch,mpu_raw_msg.mpu_gyro[1]); //直立环

//调遥控走了一些弯路,原来是速度环的参数没有调好。

v_pwm = velocity(target,a,b);   //速度环

Turn = turn(mpu_pose_msg.roll,turn_RL); //转向环

Balance_Pwm = up_pwm + v_pwm;

LAST_PWM1 = Balance_Pwm - Turn;

LAST_PWM2 = Balance_Pwm + Turn;

Xianfu_Pwm();   //pwm电机限幅

Turn_Off(mpu_pose_msg.pitch); //超过40度关闭电机

Set_Pwm(LAST_PWM1,LAST_PWM2);  //输入最终pwm给电机

}

int balance(float Angle,float Gyro)     //直立环

{  

   float Bias,kp=40,kd=0.15;//165,0.5。22,0.125//22.5,0.127

 int balance;

 Bias=Angle-ZHONGZHI;       //求出平衡的角度中值 和机械相关

 balance=kp*Bias+Gyro*kd;   //计算平衡控制的电机PWM  PD控制   kp是P系数 kd是D系数

 return balance;

}

float velocity(float target,int encoder_left,int encoder_right)  //速度环

{  

    static float Velocity,Encoder_Least,Encoder;

   

  float kp=25,ki=0.1;//18,0.05.  60, 0.3

Encoder_Least =(encoder_left+encoder_right)+target;                    //获取最新速度偏差,测量速度(左右编码器之和)-目标速度(此处为零)

Encoder *= 0.7;                                                 //一阶低通滤波器       

Encoder += Encoder_Least*0.3;                                     //一阶低通滤波器  

  

Encoder_Integral +=Encoder;                                       //积分出位移

   // Encoder_Integral=Encoder_Integral- target;                       //接收遥控器数据,控制前进后退

if(Encoder_Integral>10000)   Encoder_Integral=10000;             //积分限幅

if(Encoder_Integral<-10000) Encoder_Integral=-10000;              //积分限幅

Velocity=Encoder*kp+Encoder_Integral*ki;                          //速度控制

  return Velocity;

}

float turn(float gyro,int RC)  //转向环

{

float Tur,Kp=2;

Tur = -RC*Kp-gyro*Kd;                 //结合Z轴陀螺仪进行PD控制

return Tur;

}

void Xianfu_Pwm(void)          //pwm电机限幅

{

  int Amplitude=420;    //PWM满幅是720 限制在300

    if(LAST_PWM1<-Amplitude) LAST_PWM1=-Amplitude;

if(LAST_PWM1>Amplitude)  LAST_PWM1=Amplitude;

  if(LAST_PWM2<-Amplitude) LAST_PWM2=-Amplitude;

if(LAST_PWM2>Amplitude)  LAST_PWM2=Amplitude;

}

          

void Set_Pwm(int LAST_PWM1,int LAST_PWM2)          //输入最终pwm给电机

{

     if(LAST_PWM1>0)

{

HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,1);

HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,0);

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,1);

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,0);

}

else

{

HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,0);

HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,1);

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,0);

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,1);

}

if(LAST_PWM2>0)

{

HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,1);

HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,0);

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,1);

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,0);

}

else

{

HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,0);

HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,1);

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,0);

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,1);

}

  TIM3 ->CCR1 = myabs(LAST_PWM1);

  TIM3 ->CCR2 = myabs(LAST_PWM2);

}

int myabs(int a) //绝对值函数

{    

  int temp;

if(a<0)  temp=-a;  

  else temp=a;

  return temp;

}

void Turn_Off(float angle)

{

if(angle<-65||angle>65)//倾角大于40度关闭电机

{

HAL_GPIO_WritePin(GPIOB , GPIO_PIN_12 ,0); //STBY,关闭电机。

Encoder_Integral=0;

      }

else

{

HAL_GPIO_WritePin(GPIOB , GPIO_PIN_12 ,1); //STBY,开启电机。

}

     

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值