基于STM32设计的智能灌溉控制系统

发布者:NatureLover最新更新时间:2024-09-26 来源: elecfans关键字:STM32  控制系统 手机看文章 扫描二维码
随时随地手机看文章

一、项目介绍

随着现代农业的发展,人们对于水资源的合理利用越来越重视。而传统的灌溉方式往往存在着浪费水资源、劳动力投入大、效率低等问题。因此,设计一款智能灌溉控制系统,可以实现对灌溉水量的精准控制,增加水资源利用率,提高农业生产效率,具有广泛的应用前景。

当前文章介绍一款高性能的智能灌溉控制系统的开发过程,可自动采集电压、电流、累计用水量,并根据用户需要实现自动灌溉、定时灌溉、周期灌溉和手动灌溉等多种模式,同时具备中控室控制、手机短信、现场遥控及现场手动等多种方式控制功能。该系统可以对现场温湿度限值进行设置和修改,并通过控制器或后台监控系统完成灌溉起始时间、停止时间、喷灌时间等参数设置。系统显示功能包括液晶屏以中文菜单方式显示现场采集数据以及后台监控系统配大屏幕显示器,图形、表格等多种形式动态显示整个灌溉区运行情况。同时,在电压、电流或者流量出现异常时,系统可以及时报警。该系统供电为220VAC,流量计量误差精度为2级,使用二维码或卡实现预付费功能,通讯使用4G与云平台连接。

image-20230427151119821

二、设计功能

本系统采用STM32作为主控芯片,并通过AD模块采集电压、电流和流量等数据。同时,通过继电器控制灌溉设备的启停,使用PWM控制阀门的开合程度,从而实现精确控制灌溉水量。通信模块则采用4G模块与云平台连接,实现远程监控及控制功能。预付费模块则使用二维码或卡实现预付费功能,用户需在充值后才能使用该系统进行灌溉操作。

系统软件设计包括采集程序、控制程序、前端程序和后台程序。其中,采集程序主要负责采集电压、电流、流量等数据,并将采集到的数据上传到云平台;控制程序主要负责控制灌溉设备的启停和阀门的开合程度,从而实现灌溉控制;前端程序主要负责实现中文菜单方式显示现场采集数据,并提供灌溉模式选择、参数设置等功能;后台程序主要负责实现大屏幕显示器、图形、表格等多种形式动态显示整个灌溉区运行情况。

【1】硬件部分

  1. MCU:本系统采用STM32作为主控芯片,其具有高性能、低功耗等优点,可满足该系统的高要求。

  2. 数据采集模块:本系统通过AD模块采集电压、电流和流量等数据,然后使用MCU进行处理,并将采集到的数据存储到Flash中。

  3. 控制模块:本系统通过继电器控制灌溉设备的启停,同时使用PWM控制阀门的开合程度,从而实现精确控制灌溉水量。

  4. 通信模块:本系统采用4G模块与云平台连接,实现远程监控及控制功能。

  5. 预付费模块:本系统使用二维码或卡实现预付费功能,用户需在充值后才能使用该系统进行灌溉操作。

【2】软件部分

  1. 采集程序:本系统的采集程序主要负责采集电压、电流、流量等数据,并将采集到的数据上传到云平台。

  2. 控制程序:本系统的控制程序主要负责控制灌溉设备的启停和阀门的开合程度,从而实现灌溉控制。

  3. 前端程序:本系统的前端程序主要负责实现中文菜单方式显示现场采集数据,并提供灌溉模式选择、参数设置等功能。

  4. 后台程序:本系统的后台程序主要负责实现大屏幕显示器、图形、表格等多种形式动态显示整个灌溉区运行情况。

三、系统实现

具体实现过程如下:

(1)采集程序

采集程序主要由AD模块和STM32芯片完成。AD模块采集电压、电流和流量等数据,经过滤波和放大处理后,传输到STM32芯片上。STM32芯片通过串口将采集到的数据上传到云平台,并存储在Flash中。

(2)控制程序

控制程序主要由继电器和PWM模块完成。继电器用于控制灌溉设备的启停,PWM模块则用于控制阀门的开合程度,从而实现精确控制灌溉水量。控制程序通过读取Flash中存储的参数,确定灌溉起始时间、停止时间、喷灌时间等操作流程,并根据实时采集到的数据进行动态调整,保证灌溉操作的准确性和稳定性。

(3)前端程序

前端程序主要是通过液晶屏以中文菜单方式显示现场采集数据,并提供灌溉模式选择、参数设置等功能。用户可以通过按键或触摸屏来进行操作,并实时查看灌溉操作的运行情况。此外,用户还可以通过手机短信、现场遥控或现场手动等方式对灌溉操作进行控制。

(4)后台程序

后台程序主要负责实现大屏幕显示器、图形、表格等多种形式动态显示整个灌溉区运行情况,同时还能够将采集到的数据进行分析和统计,为灌溉管理提供决策参考。


四、核心代码

【1】电机控制代码

以下是STM32F103ZET6通过PWM控制直流电机转速的代码,并封装成子函数调用的示例:


首先,需要在STM32CubeMX中配置TIM定时器和GPIO引脚,以及将PWM模式设置为嵌套边沿对齐模式,然后生成代码,并在main.c文件中添加以下代码:


#include 'main.h'

#include 'stm32f1xx_hal.h'

/* TIM handle structure */

TIM_HandleTypeDef htim;

/* Function prototypes */

void PWM_Init(TIM_HandleTypeDef *htim, uint32_t channel);

void Set_Motor_Speed(TIM_HandleTypeDef *htim, uint32_t channel, uint16_t speed);

int main(void)

{

 /* Initialize the HAL Library */

 HAL_Init();

 /* Initialize TIM2 PWM with a frequency of 10 kHz */

 PWM_Init(&htim2, TIM_CHANNEL_1);

 /* Set the motor speed to 50% */

 Set_Motor_Speed(&htim2, TIM_CHANNEL_1, 5000);

 while (1)

  {

  /* Infinite loop */

  }

}

/**

 * @brief  Initializes PWM output on specified TIM channel.

 * @param  htim: TIM handle structure.

 * @param  channel: TIM channel to be used for PWM output.

 * @retval None

 */

void PWM_Init(TIM_HandleTypeDef *htim, uint32_t channel)

{

 TIM_OC_InitTypeDef sConfigOC = {0};

 /* Configure PWM output on specified TIM channel */

 sConfigOC.OCMode    = TIM_OCMODE_PWM1;

 sConfigOC.Pulse    = 0;

 sConfigOC.OCPolarity  = TIM_OCPOLARITY_HIGH;

 sConfigOC.OCFastMode  = TIM_OCFAST_DISABLE;

 HAL_TIM_PWM_ConfigChannel(htim, &sConfigOC, channel);

 /* Start PWM output */

 HAL_TIM_PWM_Start(htim, channel);

}

/**

 * @brief  Sets the motor speed on specified TIM channel.

 * @param  htim: TIM handle structure.

 * @param  channel: TIM channel to be used for PWM output.

 * @param  speed: Motor speed in units of 1/10,000th of the maximum speed.

 *         For example, a speed of 5000 would set the motor speed to 50%.

 * @retval None

 */

void Set_Motor_Speed(TIM_HandleTypeDef *htim, uint32_t channel, uint16_t speed)

{

 uint16_t max_speed = htim->Init.Period;

 /* Ensure that speed is within range */

 if (speed > max_speed)

  speed = max_speed;

 /* Update PWM duty cycle */

 __HAL_TIM_SET_COMPARE(htim, channel, speed);

}

在以上代码中,定义了两个函数:PWM_Init和Set_Motor_Speed。PWM_Init用于初始化TIM定时器的PWM输出,并设置指定通道的PWM模式和默认占空比为0。Set_Motor_Speed用于设置电机的转速,其接收三个参数:TIM句柄结构体,指定的通道,以及电机的转速(单位为1/10,000最大速度)。该函数会将电机的转速转换为PWM占空比,并通过__HAL_TIM_SET_COMPARE函数更新PWM占空比。


最后,可以按照以下步骤将代码封装成子函数调用:


将以上代码复制到单独的.c文件中,并包含必要的头文件。

在该文件中定义一个名为Motor_Control的函数,该函数接收三个参数:TIM句柄结构体,指定的通道,以及电机的转速。

在Motor_Control函数中调用PWM_Init和Set_Motor_Speed函数,并传递相应的参数。

在main函数中调用Motor_Control函数,传递相应的参数。

以下是Motor_Control函数的示例代码:


#include 'motor_control.h'

void Motor_Control(TIM_HandleTypeDef *htim, uint32_t channel, uint16_t speed)

{

 /* Initialize PWM output on specified TIM channel */

 PWM_Init(htim, channel);

 /* Set the motor speed */

 Set_Motor_Speed(htim, channel, speed);

}

在以上示例中,将PWM的初始化和设置电机转速的函数封装成了一个名为Motor_Control的函数。可以在需要控制电机转速的其他地方调用Motor_Control函数即可。


注意,在调用Motor_Control函数之前,需要先定义并初始化TIM句柄结构体,并确保GPIO引脚已经正确配置为TIM模式。此外,如果需要控制多个电机,可以在Motor_Control函数中增加参数以区分不同的电机通道。


以下是motor_control.h头文件的示例代码:


cCopy Code#ifndef __MOTOR_CONTROL_H__

#define __MOTOR_CONTROL_H__

#include 'stm32f1xx_hal.h'

/* Function prototypes */

void PWM_Init(TIM_HandleTypeDef *htim, uint32_t channel);

void Set_Motor_Speed(TIM_HandleTypeDef *htim, uint32_t channel, uint16_t speed);

void Motor_Control(TIM_HandleTypeDef *htim, uint32_t channel, uint16_t speed);

#endif /* __MOTOR_CONTROL_H__ */

在以上头文件中,声明了三个函数:PWM_Init,Set_Motor_Speed和Motor_Control,并包含必要的头文件。


【2】电压、电流采集

为了采集220V抽水电机的用电量和当前电压,当前使用STM32F103ZET6的ADC(模数转换器)来测量电压和电流,并通过乘法器计算电功率和电能。


下面是实现方案和实现代码:


选择合适的传感器: 为了测量电压,可以使用AC-AC变压器将220V交流电压降至低电平,再使用电阻分压器将电压信号调整在ADC的输入范围内。 为了测量电流,可以使用霍尔传感器或者电阻式传感器,将电流信号转换成电压信号,然后通过电阻分压器调整信号范围。

配置ADC: 使用STM32CubeMX软件选择相应的引脚和配置ADC模块,设置采样频率、参考电压等参数。需要注意的是,ADC模块只能同时转换一路模拟信号,因此需要轮流采样电压和电流信号。

计算电流、电压、功率和能量: 将电压和电流信号转换成数字值后,可以使用下面的公式计算电流、电压、功率和能量:

Copy Code电流 = AD值 / 灵敏度

电压 = AD值 / 分压比

功率 = 电压 * 电流

能量 = 功率 * 时间

其中,灵敏度是传感器的转换系数,分压比是电阻分压器的比值,时间可以通过定时器计算。


输出数据: 将测量的电流、电压、功率和能量输出到串口或者LCD显示屏上。可以设置一个定时器,在一定时间间隔内输出一次数据。

实现代码:


#include 'stm32f1xx_hal.h'

ADC_HandleTypeDef hadc1;

TIM_HandleTypeDef htim2;

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_ADC1_Init(void);

static void MX_TIM2_Init(void);

uint16_t ad_val_ch1, ad_val_ch2;

float voltage, current, power, energy;

int main(void)

{

 HAL_Init();

 SystemClock_Config();

 MX_GPIO_Init();

 MX_ADC1_Init();

 MX_TIM2_Init();

 while (1)

  {

  // ADC采样电压信号

  HAL_ADC_Start(&hadc1);

  HAL_ADC_PollForConversion(&hadc1, 100);

  ad_val_ch1 = HAL_ADC_GetValue(&hadc1);

  voltage = ad_val_ch1 * 3.3 / 4096 * 10; // 假设分压比为10

  // ADC采样电流信号

  HAL_TIM_Base_Start(&htim2);

  HAL_ADC_Start(&hadc1);

  HAL_ADC_PollForConversion(&hadc1, 100);

  ad_val_ch2 = HAL_ADC_GetValue(&hadc1);

  current = ad_val_ch2 * 3.3 / 4096 * 50; // 假设灵敏度为50mV/A

  // 计算功率和能量

  power = voltage * current;

  energy += power * 0.1; // 假设定时器时间间隔为100ms

  // 输出测量结果

  printf('Voltage: %.2f Vrn', voltage);

  printf('Current: %.2f Arn', current);

  printf('Power: %.2f Wrn', power);

  printf('Energy: %.2f Jrn', energy);

  HAL_Delay(1000); // 假设数据输出间隔为1s

  }

}

void SystemClock_Config(void)

{

 RCC_OscInitTypeDef RCC_OscInitStruct = {0};

 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

 __HAL_RCC_PWR_CLK_ENABLE();

 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

 RCC_OscInitStruct.OscillatorType = RCCRCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;

RCC_OscInitStruct.HSIState = RCC_HSI_ON;

RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;

RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;

if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

{

Error_Handler();

}

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;

RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;

RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;

RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

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

{

Error_Handler();

}

}

static void MX_ADC1_Init(void)

{

ADC_ChannelConfTypeDef sConfig = {0};

__HAL_RCC_ADC1_CLK_ENABLE();

hadc1.Instance = ADC1;

hadc1.Init.ScanConvMode = DISABLE;

hadc1.Init.ContinuousConvMode = ENABLE;

hadc1.Init.DiscontinuousConvMode = DISABLE;

hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;

hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

hadc1.Init.NbrOfConversion = 1;

if (HAL_ADC_Init(&hadc1) != HAL_OK)

{

Error_Handler();

}

sConfig.Channel = ADC_CHANNEL_0; // 假设测量电压的ADC通道为0

sConfig.Rank = ADC_REGULAR_RANK_1;

sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5;

if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)

{

Error_Handler();

}

sConfig.Channel = ADC_CHANNEL_1; // 假设测量电流的ADC通道为1

if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)

{

Error_Handler();

}

}

static void MX_TIM2_Init(void)

{

__HAL_RCC_TIM2_CLK_ENABLE();

htim2.Instance = TIM2;

htim2.Init.Prescaler = 7200 - 1;

htim2.Init.CounterMode = TIM_COUNTERMODE_UP;

htim2.Init.Period = 10000 - 1; // 假设定时器时间间隔为100ms

if (HAL_TIM_Base_Init(&htim2) != HAL_OK)

{

Error_Handler();

}

}

void Error_Handler(void)

{

while (1)

{

}

}

#ifdef USE_FULL_ASSERT

void assert_failed(char *file, uint32_t line)

{

}

#endif


关键字:STM32  控制系统 引用地址:基于STM32设计的智能灌溉控制系统

上一篇:STM32单片机GPIO的配置模式
下一篇:STM32的DMA数据传输实例

推荐阅读最新更新时间:2024-11-11 11:40

STM32串口发送数据的标准函数
例子:1 void UART_Send_Message(u8 *Data,u8 lenth) { while(lenth--) { USART_SendData(USART2, *Data); while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); Data++; } } void main() { u8 Sendbuf ; Sendbuf =0xA0; Sendbuf =0xA0; Sendbuf =0xA0; UART_Send_Message(Sendbuf,3); } 例子2:
[单片机]
密歇根大学验证互联巡航控制系统 提升车辆节能表现
据外媒报道,密歇根大学(U-M)采用车间通信(V2V)技术,使自动驾驶车辆能及时响应其他道路使用者,帮助其节能并提升安全性,从而验证了互联巡航控制系统的高效性。 该团队在路测中展现了互联巡航控制的许多优点,该团队只启用了一辆自动驾驶汽车,将其与其他车辆进行类比测试。互联巡航控制可调节车速,这取决于其车间通信系统所获取的信息,周边车辆可利用无线网络,共享实时车速及定位数据。 相较于其他被广泛采用的自适应巡航系统,互联巡航控制系统可追踪多辆前方车辆,密歇根大学的路测演示了该系统及自动驾驶车辆与传统车辆间的车间通信是如何有助于规避“交通波(traffic wave)”。在该情境中,最前方的那辆汽车将引发其他车辆的“制动-再加速(bra
[汽车电子]
浅谈DCS控制系统中的通信技术
  从 DCS控制系统 的级成结构看可以分为三大部分:带I/O部件的控制器、通讯网络和人机接口(HSI)。控制器I/O部件直接与生产过程相连,接收现场设备送来的信号;人机接口是操作人员与 DCS 相互交换信息的设备;通讯网络将控制器和人机接口联系起来,形成一个有机的整体。早期的DCS系统的通讯网络都是专用的,DCS有 几级网络,完成不同模件之间的通讯。从目前的情况 来看,DCS的最多网络级有四级,它们分别是I/O总线、现场总线、控制总线和DCS网络。   I/O总线,它把多种I/O信号送到控制器,由控制器读取I/O信号。这称为I/O总线。I/O板相互之间并不交换数据。I/O总线的速率是不高的。从几十K到几兆不等。这与计算机技术的发展
[嵌入式]
STM32学习——USART收发数据
简介 1.串口通讯的双方若采用不同的电平标准,则需要利用电平转换芯片进行转换。 2.调试程序时可以把一些调试信息“打印”在电脑端的串口调试助手上。 3.硬件原理以后有空再研究,应该跟微机里学的挺类似的。。。 配置一个串口的步骤 1.使能USART时钟,以及RX和TX引脚的GPIO时钟 2.初始化GPIO,配置相关的引脚功能 3.配置USART的工作参数 4.配置中断控制器NVIC,使能串口中断 5.使能USART的接收中断 6.使能USART 7.编写中断服务函数 代码设计 通用代码参考的是野火的代码,自己写的太不规范了。。。 (1)串口初始化 void USART_Config(void) { GPIO_I
[单片机]
stm32之神州三号开发板 USB DFU 实现过程
1.官网下载usb源码包 2.神舟III号的MCU位f103ze 系列。打开压缩包,直接找到 Device_Firmware_Upgrade 文件包 MDK打开工程。 3.选择 stm3210E_EVAL这个选项 ,此时启动文件为 starup_stm32f10x_hd.s. (1)选择器件类型为STM32F103ZE;C/C++的Define修改为USE_STDPERIPH_DRIVER, STM32F10X_HD, USE_STM3210E_EVAL; include paths选择F103相关文件。 (2)工程文件右键修改Mange Project ,把不必要的文件删除,如下。 4.修改 usb 拉高管脚为PG1
[单片机]
<font color='red'>stm32</font>之神州三号开发板 USB DFU 实现过程
基于STM32物联网开发板--环境光采集BH1750
1 概述 BH1750FVl 是一种用于 RC 总线接口的数字环境光 传感器 LC。该 芯片 最适合于获取移动电话液晶显示器和按键背光功率的环境光数据。采集范围在(1~65535 l×)之间。 特征 I IC 总线接口 光强数字 转换器 16 位分辩率(1 ~65535) 直接数字输出, 省略复杂的计算, 省略标定 不区分环境光源, 接近于视觉灵敏度的分光特性 应用 手机 、 液晶电视、 笔记本 电脑 ; 便携式游戏机、 数码 相机、 数码摄像机; 汽车导航、 PDA、 液晶显示器; 硬件 接口 : 引脚 说明 B_SCL PB10 I2C 时钟 线 B_ SD A
[单片机]
基于<font color='red'>STM32</font>物联网开发板--环境光采集BH1750
解决STM32 SPI 半残废 NSS无法拉高
众所周知,STM32 SPI是个半残废,NSS无法自动拉高,所以使用SPI 从机会一直使能,当主机是一对多的时候,就会出现SPI从机互相干扰的问题。 我利用GPIO中断,代替NSS引脚,使用过程如下代码所示 1.初始化SPI 的IO口,其中NSS引脚先不管。 void GPIO_SPI12_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; //----- 第1步:打开SPI部件的时钟 --------------------------------------------------------------------------------------------
[单片机]
STM32如何确定执行哪个中断函数
如下面所示: NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //NRF24L01 中断响应 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级 0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级为1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能 NVIC_Init(&NVIC_InitStructure); 则对应的中断函数就是 STM3210x_
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved