这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【Let'sdo第1期-功率检测与控制系统DIY】-【过程贴】-3.INA219

共6条 1/1 1 跳转至

【Let'sdo第1期-功率检测与控制系统DIY】-【过程贴】-3.INA219过流保护,电流阈值写入flash

菜鸟
2025-06-01 16:21:19     打赏

        本次DIY要实现的是INA219过流保护的应用,分别是打嗝模式和自锁模式。我使用的方案是定时器每半秒检测一次主循环标志位,如果过流状态发生标志位置1反之置0。这个方案可以避免电机启动电流过大,一直触发过流的情况。

我定义的标志位:

image.png

接线图:

687e1d052451aa06653bdf3d0af5df8.jpg

继电器控制电机开关,继电器和片上的LED共用同一个GPIO口便于观察继电器状态。按钮可以控制这个io口就当开关了

ps:制作了GIF图结果发现不知道为什么传不上来,只能放图片凑活看了

打嗝模式


打嗝模式需要实现的需求是:当检测到处于过流状态时电机停机,等待3s电机重新开机,当检测到过流状态继续停机,反之开机正常运行。

1748764909348949.png

主循环:

1748765012303504.png

中断:

1748765208226235.png


自锁模式

自锁模式需要实现的需求是:当检测到处于过流状态时电机停机,外部开机按键不能在停机状态使用,在排除故障后由串口发送恢复指令电机重新开机。

1748764950782475.png

主循环:

1748765061463373.png

中断:

1748765352233278.png


电流阈值写入片内Flash

F411的flash有整整512k有7个扇区容量可以说是非常充足了。

1748764734372219.png

下面是串口修改flash的过程。

2025-06-01T08_11_20.190Z-507851.png

2025-06-01T08_11_45.334Z-589337.png

2025-06-01T08_12_02.458Z-289855.png


下面是代码部分:

#include "stm32f4xx.h"  // Device header
#include "stm32f4xx_conf.h"
#include "string.h"
#include "gpio.h"
#include "oled.h"
#include "ina219.h"
#include "Timer.h"
#include "delay.h"
#include "Serial.h"
#include "Store.h"
#include "MyFLASH.h"

//extern uint8_t Serial_RxFlag;

int Current_Limiting;    //!!电流限制变量临时存储后续写到flash里!!
int Current_Limiting_temp;

unsigned char time = 0;

unsigned char IO_Control = 0;    //IO控制位
unsigned char IO = 0;		//IO模式位
unsigned char IO_First = 0;    //IO首次变化

unsigned char MODE1_Burp;        //打嗝模式标志位
unsigned char MODE1_Stop_Burp;    //打嗝停止情况标志位:正常停止/打嗝停止

unsigned char MODE2_Recovery;    //过流模式标志位
unsigned char Stop_Recovery;    //过流停止模式标志位

unsigned char MODE_Flag;        //模式标志位

int main()
{
	gpio_init();
	OLED_Init();
	INA_Init();
	OLED_MAP();
	Timer_Init();
	Serial_Init();
	Store_Init();
	Serial_SendString(" Reset\r\n");
	
//	Store_Data[1] = 100;		//过流阈值强制修改接口
//	Store_Save();
	
	unsigned char MODE_First_Flag = 0;
	unsigned char i = 0;

	while(1)
	{
		Current_Limiting = *((__IO uint32_t *)(0x08060002));
		
		if(MODE_Flag == 0)	//模式0,电流测量无特殊模式
		{
			if(MODE_First_Flag == 1)
			{
				OLED_Clear();
				OLED_MAP();
				Serial_SendString(" MODE0_Measurement\r\n");
				MODE_First_Flag = 0;
			}
			show_v();
			show_w();
			show_i();
		}
		
		if(MODE_Flag == 1)	//打嗝模式
		{
			if(MODE_First_Flag == 1)
			{
				OLED_Clear();
				OLED_MAP();
				Serial_SendString(" MODE1_Burp\r\n");
				MODE_First_Flag = 0;
			}
			
			show_v();
			show_w();
			show_i();
			
			if((INA_GET_Current_MA())>=Current_Limiting)
			{
				MODE1_Burp = 1;
			}
			else
			{
				MODE1_Burp = 0;
			}
			
		}
		if(MODE_Flag == 2)	//过流保护模式
		{
			if(MODE_First_Flag == 1)
			{
				OLED_Clear();
				OLED_MAP();
				Serial_SendString(" MODE2_Recovery\r\n");
				MODE_First_Flag = 0;
			}
			
			show_v();
			show_w();
			show_i();
			
			if((INA_GET_Current_MA())>=Current_Limiting)
			{
				MODE2_Recovery = 1;
			}
			else if(Stop_Recovery == 0)
			{
				MODE2_Recovery = 0;
			}
			
		}
		if(MODE_Flag == 3)			//显示片内flash存储电流值
		{
			if(MODE_First_Flag == 1)
			{
				OLED_Clear();
				OLED_MAP2();
				MODE_First_Flag = 0;
			}
			//OLED_ShowNum(3,1,Current_Limiting,10);
			OLED_ShowNum(2,10,Current_Limiting,4);
			
			if((INA_GET_Current_MA())>=Current_Limiting)
			{
				MODE2_Recovery = 1;
			}
			else if(Stop_Recovery == 0)
			{
				MODE2_Recovery = 0;
			}
			
			if(MODE2_Recovery||MODE1_Burp)
			{
				OLED_ShowChiness(1,11,23);
				OLED_ShowChiness(1,13,24);
			}
			else
			{
				OLED_ShowChiness(1,11,22);
				OLED_ShowChiness(1,13,24);
			}
			
		}
		
		if(Serial_RxFlag == 1)	//接收到一个数据包到Serial_RxPacket数组里以'/0'结尾
		{
			Serial_RxFlag = 0;				//先清空标志位
			MODE_First_Flag = 1;			//首次循环标志位
			if (strcmp(Serial_RxPacket, "CurrentMode0") == 0)	//MODE0电流测量无特殊模式
			{
				MODE_Flag = 0;
			}
			else if (strcmp(Serial_RxPacket, "CurrentMode1") == 0)	//MODE1	//打嗝模式
			{
				MODE_Flag = 1;
			}
			else if (strcmp(Serial_RxPacket, "CurrentMode2") == 0)	//MODE2	//自锁模式
			{
				MODE_Flag = 2;
			}
			else if (strcmp(Serial_RxPacket, "CurrentMode3") == 0)	//MODE3	//显示片内flash存储电流值
			{
				MODE_Flag = 3;
			}
			else if (strcmp(Serial_RxPacket, "IO") == 0)	//IO反转
			{
				IO_Control = 1;
				MODE_First_Flag = 0;		//非模式控制清空首次循环标志
			}
			else if (strncmp(Serial_RxPacket, "CurrentThreshold:",17) == 0)	//修改电流阈值
			{
				MODE_First_Flag = 0;		//非模式控制清空首次循环标志
				Current_Limiting_temp = 0;
				i = 0;
				//Serial_RxPacket[100];
				while(1)
				{
					if(Serial_RxPacket[17+i]>'9')
					{break;}
					Current_Limiting_temp = Current_Limiting_temp*10 + (Serial_RxPacket[17+i]-'0');
					i++;
				}
				Store_Data[1] = Current_Limiting_temp;		//过流阈值强制修改接口
				Store_Save();
				
			}
			else if (strcmp(Serial_RxPacket, "RecoveryControl") == 0)	//IO反转
			{
				if(MODE2_Recovery)		//在过流保护时生效
				{
					MODE2_Recovery = 0;
					IO_Control = 1;
					Stop_Recovery = 0;
				}
				MODE_First_Flag = 0;		//非模式控制清空首次循环标志
			}
			else if (strcmp(Serial_RxPacket, "CanRun") == 0)	//IO 1
			{
				IO = 1;
				IO_First = 1;
				MODE_First_Flag = 0;		//非模式控制清空首次循环标志
			}
			else if (strcmp(Serial_RxPacket, "StopRun") == 0)	//IO 0
			{
				IO = 0;
				IO_First = 1;
				MODE_First_Flag = 0;		//非模式控制清空首次循环标志
			}
			else	//非控制数据包
			{
				Serial_SendString(" ERROR\r\n");
				MODE_First_Flag = 0;		//非模式控制清空首次循环标志
			}
			
		}
		
		
		if(((0==GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13))||IO_Control)&&(!MODE2_Recovery))	//继电器控制
		{
			GPIO_ToggleBits(GPIOA,GPIO_Pin_5);
			IO_Control = 0;
			if(MODE1_Stop_Burp)
			{
				time = 2;
			}
			while(0==GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13))
			{
				delay_ms(20);
			}
		}
		
		if((IO_First)&&(!MODE2_Recovery))		//继电器单次控制
		{
			IO_First = 0;
			GPIO_WriteBit(GPIOA,GPIO_Pin_5, IO);
		}
		
		
		
		
	}
}

	void TIM3_IRQHandler(void)
	{
		if(TIM_GetITStatus(TIM3,TIM_IT_Update) == SET)
		{
			TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
			time++;
			time = time%6;
			
			if(MODE_Flag == 0)	//模式0,电流测量无特殊模式
			{
				//发送电流电压数据
			}
			
			if(MODE_Flag == 1)	//模式1
			{
				if(MODE1_Burp)
				{
					IO_Control = 1;			//打嗝模式
					MODE1_Stop_Burp = 1;	//打嗝停止
				}
				else if(((INA_GET_Current_MA())<=1)&&(MODE1_Stop_Burp)&&(time==0))
				{
					IO_Control = 1;
					MODE1_Stop_Burp = 0;
				}
				else
				{
					IO_Control = 0;
				}
				
			}
			
			if(MODE_Flag == 2)	//模式2,电流过流保护模式
			{
				if(MODE2_Recovery)
				{
					GPIO_WriteBit(GPIOA,GPIO_Pin_5, 0);
					Stop_Recovery = 1;
				}
			}
			
		}
	}
	






关键词: 功率     检测     控制系统     过流     保护     flash    

院士
2025-06-01 20:25:36     打赏
2楼

不错,不错。

电流处理,尤其是过流和短路电流的区分,还是十分有必要区分对待


专家
2025-06-02 11:43:23     打赏
3楼

感谢分享


专家
2025-06-02 11:46:03     打赏
4楼

感谢分享


专家
2025-06-02 11:49:29     打赏
5楼

感谢分享


专家
2025-06-03 10:33:25     打赏
6楼

谢谢楼主分享


共6条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]