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

接线图:

继电器控制电机开关,继电器和片上的LED共用同一个GPIO口便于观察继电器状态。按钮可以控制这个io口就当开关了
ps:制作了GIF图结果发现不知道为什么传不上来,只能放图片凑活看了
打嗝模式
打嗝模式需要实现的需求是:当检测到处于过流状态时电机停机,等待3s电机重新开机,当检测到过流状态继续停机,反之开机正常运行。

主循环:

中断:

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

主循环:

中断:

电流阈值写入片内Flash
F411的flash有整整512k有7个扇区容量可以说是非常充足了。

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



下面是代码部分:
#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;
}
}
}
}
我要赚赏金
