【STM32CubeMX】位置式PID调节控制输出电压(超详解) |
您所在的位置:网站首页 › 如何调节程序 › 【STM32CubeMX】位置式PID调节控制输出电压(超详解) |
本文将借助STM32CubeMX来配置ADC、DMA、DAC、USART,并利用PID位置式算法实现对输出电压进行AD采集通过PID算法调节DAC,获取到我们想要的电压值。 讲解的主要知识: 何为PID以及为何需要PIDSTM32CubeMX创建STM32源代码 1、何为PID以及为何需要PID以下是PID控制的整体框图,过程描述为:设定一个输出目标,反馈系统传回输出值,如与目标不一致,则存在一个误差,PID根据此误差调整输入值,直至输出达到设定值。 疑问:那我们为什么需要PID呢?比如我想要利用DAC输出一个1.65V电压,直接输出不就可以了吗? 这里必须要先说下我们的目标,因为我们所有的控制无非就是想输出能够达到我们的设定,即如果我们设定了一个目标电压值,那么我们想要一个什么样的电压值变化呢? 比如设定目标电压值为1.65V,目标无非是希望其能够快速而且没有抖动的达到1.65V。 那这样大家应该就明白,如果只是使用DAC输出一个数字信号,外界出现的误差(例如导线、噪声等原因)都可能影响到最终输出的数值,因此我们需要利用PID调节最终读取到我们想要的值。
2.1 所用工具: 芯片:STM32F103RCT6IDE:MDK-Keil软件STM32F1xxHAL库2.2 知识概括: STM32CubeMX创建ADC、DMA、DAC、USART例程Keil软件程序编写2.3 工程创建 1、芯片选择 芯片:STM32F103RCT6(根据自己的板子来进行选择) 4、ADC利用DMA传输 设置DMA传输模式:循环传输(有数据就传输),同时设置高优先级 7、配置时钟 F1系列芯片系统时钟为72MHzs 9、输出文件 ②处:复制所用文件的.c和.h③处:每个功能生产独立的.c和.h文件![]() 10、创建工程文件 点击GENERATE CODE 创建工程 11、配置下载工具 这里我们需要勾选上下载后直接运行 首先编写pid.c与pid.h文件代码,这里编写的是pid位置式算法。 (1)pid.h #ifndef __PID_H__ #define __PID_H__ #include "main.h" typedef struct { float SetVoltage; //定义设定值 float ActualVoltage; //定义实际值 float err; //定义偏差值 float err_last; //定义上一个偏差值 float Kp,Ki,Kd; //定义比例、积分、微分系数 float result; //pid计算结果 float voltage; //定义电压值(控制执行器的变量)0-5v右转 5-10v左转 float integral; //定义积分值 }pid_p; void PID_init( void); float PID_realize( float v, float v_r); #endif(2)pid.c #include "pid.h" #include "stdio.h" pid_p pid; //pid位置式 void PID_init() { printf("PID_init begin \n"); pid.SetVoltage= 0.0; // 设定的预期电压值 pid.ActualVoltage= 0.0; // adc实际电压值 pid.err= 0.0; // 当前次实际与理想的偏差 pid.err_last=0.0; // 上一次的偏差 pid.voltage= 0.0; // 控制电压值 pid.integral= 0.0; // 积分值 pid.Kp= 0.2; // 比例系数 pid.Ki= 0.15; // 积分系数 pid.Kd= 0.2; // 微分系数 printf("PID_init end \n"); } float PID_realize( float v, float v_r) { pid.SetVoltage = v; // 固定电压值传入 pid.ActualVoltage = v_r; // 实际电压传入 = ADC_Value * 3.3f/ 4096 pid.err = pid.SetVoltage - pid.ActualVoltage; //计算偏差 pid.integral += pid.err; //积分求和 pid.result = pid.Kp * pid.err + pid.Ki * pid.integral + pid.Kd * ( pid.err - pid.err_last);//位置式公式 pid.err_last = pid.err; //留住上一次误差 return pid.result; }(3)在main.c加上: /* USER CODE BEGIN Includes */ #include "stdio.h" #include "pid.h" /* USER CODE END Includes */ /* USER CODE BEGIN PD */ #define ADC_Channel_MAX 2 /* USER CODE END PD */ /* USER CODE BEGIN PV */ uint16_t ADC_DMA_Value[ADC_Channel_MAX]; // DMA得到ADC的值 uint16_t ADC_Value = 0; uint16_t DAC_Value = 100; /* USER CODE END PV */ /* USER CODE BEGIN 0 */ /** * 函数功能: 重定向c库函数printf到DEBUG_USARTx * 输入参数: 无 * 返 回 值: 无 * 说 明:无 */ int fputc(int ch, FILE *f) { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff); return ch; } /** * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx * 输入参数: 无 * 返 回 值: 无 * 说 明:无 */ int fgetc(FILE *f) { uint8_t ch = 0; HAL_UART_Receive(&huart1, &ch, 1, 0xffff); return ch; } /* USER CODE END 0 */(4)在ADC初始化之后加上AD校准函数: /* USER CODE BEGIN 2 */ HAL_ADCEx_Calibration_Start(&hadc1); // f1系列需要ADC校准,f4不需要 HAL_ADC_Start_DMA(&hadc1,(uint32_t *)&ADC_DMA_Value,ADC_Channel_MAX); // 启动ADC的DMA转换 PID_init(); /* USER CODE END 2 */(5)while中加上: HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, DAC_Value); // 设置DAC数值 HAL_DAC_Start(&hdac,DAC_CHANNEL_1); // 开启DAC输出 ADC_Value = ADC_DMA_Value[0]; printf("%0.2f\r\n", ADC_Value*3.3/4096); // 这里设置输出1.65V DAC_Value = DAC_Value + PID_realize(2048, ADC_Value); HAL_Delay(100);(6)用一根杜邦线连接PA0(ADC1_IN0)与PA4(DAC),然后串口连接电脑(我这里利用USB转TLL连接电脑,RX接PA9(USART1_TX),TX接PA10(USART1_RX)) (7)之后就可以完成正常读取,刚打开串口时: 以上就是利用PID调节控制获取我想要设定的电压值。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |