基于51单片机的4路交流电机电流监测系统Protues仿真

本项目介绍了一款采用STC89C52单片机的电流监测系统,能够实时监测四路电流并实现过流保护。系统支持通过串口发送命令控制继电器状态,并允许用户设置电流阈值。

功能:
0.本项目采用STC89C52作为单片机系统的控制MCU
1.系统实时显示当前监测的4路电流,当检测的电流超过阈值时,蜂鸣器报警,并串口上报过流通道电流信息,
用户可通过串口发送命令的方式控制对应通道的继电器,同时关闭报警
2.按键可更改电流阈值,电流阈值掉电不丢失
控制命令:*Cx# 闭合继电器(x对应1/2/3/4/A) *Bx# 断开继电器(x对应1/2/3/4/A) A代表全部
3.采用DC002作为电源接口可直接输入5V给整个系统供电

仿真图:
在这里插入图片描述

主程序:

#include "main.h"
#include "math.h"

bit refreshFlag = 1;
bit isNewFlag = 1;

enum _MODE_DF_ dispMode;
xdata float f_cur[4]; //单位A
float f_curVolt = 0.0; //单位V
int curMax[4]; //过流阈值单位mA

unsigned char setIndex = 0; //设定位置
unsigned char setChannel = 0; //设定通道
unsigned char cnt = 0;
unsigned char channel = 0;
unsigned char sendDelay = 0; //串口发送数据延时

xdata char dis0[16]; //定义显示区域临时存储数组

void main(void)
{

    EEPROM_Init();
    ReadData();
    // isNewFlag = 1;
    if (isNewFlag != 0) //新芯片
    {
        EEPROM_WriteByte(ISNEW_ADDRESS, 0);
        //给出初始值
        curMax[0] = 1000;
        curMax[1] = 1100;
        curMax[2] = 1200;
        curMax[3] = 1300;
        WriteData();
    }

    LCD_Init();   //初始化液晶
    DelayMs(200); //延时有助于稳定
    UART_Init(); //初始化串口
    LCD_DispStr(0, 0, "    Welcome!    ");
    DelayS(1);

    DelayS(1);
    
    Timer0_Init();
    
    RELAY1 = CLOSE;
    RELAY2 = CLOSE;
    RELAY3 = CLOSE;
    RELAY4 = CLOSE;
    BUZZER = OFF;
    
    while (1) //主循环
    {
        
        if (refreshFlag == 1) //500ms获取数据并发送
        {
            refreshFlag = 0;
            
            CD5051_SelChannel(channel);

            for (cnt = 0; cnt < 50; cnt++) //采集50次数据
            {
                f_curVolt = f_curVolt + 5 * (ReadADC(AIN0_GND)-1) / 255; //转换电流 ReadADC(AIN0_GND)-1仿真需要减1,因protues中最小输出code值为1
                DelayUs10x(10);
            }
            
            f_cur[channel] = f_curVolt / 50 * 2000 / 150; //求平均后计算电流,电阻150欧姆 I = U * 2000 / R (A)
            f_curVolt = 0;

            if ((f_cur[channel]*1000) > curMax[channel]) //电流超过阈值范围
            {
                BUZZER =  ON;
                SendData(channel); //发送错误通道电流及阈值电流
            }

            //液晶显示
            if (dispMode == NORMAL)
            {
                DispNormal();
            }
            channel++;
            if (channel > 3)
            {
                channel = 0;
            }
        }

        KeyProcess();
    }
}

/************************* 正常显示 *************************/
void DispNormal()
{
    sprintf(dis0, "1:%4.1fA  2:%4.1fA", (float)f_cur[0], (float)f_cur[1]);
    LCD_DispStr(0, 0, dis0);
    sprintf(dis0, "3:%4.1fA  4:%4.1fA", (float)f_cur[2], (float)f_cur[3]);
    LCD_DispStr(0, 1, dis0);
}

/************************* 显示电流阈值 *************************/
void DispSetCurrentLimit(unsigned char channel, unsigned char setIndex)
{
    sprintf(dis0, "  Max Current %1d ", (int)channel+1); //打印
    LCD_DispStr(0, 0, dis0);

    sprintf(dis0, "      %4.1f A    ", (float)curMax[channel]/1000); //打印
    LCD_DispStr(0, 1, dis0);

    switch (setIndex)
    {
        case 1: LCD_SetCursor(9, 1, 1); break;
        default:;
    }
}

/************************* 串口发送数据 *************************/
void SendData(unsigned char channel)
{
    sprintf(dis0, "Current %1d:%4.1fA\r\n", (int)channel+1, f_cur[channel]); //串口发送
    UART_SendStr(dis0, 16); //发送数据
    DelayMs(10);
    sprintf(dis0, "Max %1d: %4.1fA\r\n", (int)channel+1, (float)curMax[channel] / 1000); //串口发送
    UART_SendStr(dis0, 13); //发送数据
    DelayMs(10);
}

/************************* 读取数据 *************************/
void ReadData(void)
{
    unsigned char i;

    isNewFlag = EEPROM_ReadByte(ISNEW_ADDRESS);

    for (i = 0; i < 4; i++)
    {
        curMax[i] = EEPROM_ReadByte(BASE_ADDRESS + 2*i);
        curMax[i] = (curMax[i] << 8) | EEPROM_ReadByte(BASE_ADDRESS + 2*i + 1);
    }
}

/************************* 写入数据 *************************/
void WriteData(void)
{
    unsigned char i;

    for (i = 0; i < 4; i++)
    {
        EEPROM_WriteByte(BASE_ADDRESS + 2*i, ((curMax[i] & 0xFF00) >> 8));
        EEPROM_WriteByte(BASE_ADDRESS + 2*i + 1, (curMax[i] & 0x00FF));
    }
}

/*------------------------------------------------
                    定时器初始化子程序
------------------------------------------------*/
void Timer0_Init(void)
{
    TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
    TH0 = (65536 - 10000) / 256; //重新赋值 10ms
    TL0 = (65536 - 10000) % 256;
    EA = 1;  //总中断打开
    PT0 = 1;
    ET0 = 1; //定时器中断打开
    TR0 = 1; //定时器开关打开
}

/*------------------------------------------------
                定时器中断子程序
------------------------------------------------*/
void Timer0_Interrupt(void) interrupt 1
{
    static unsigned char time10ms = 0;
    
    TH0 = (65536 - 10000) / 256; //重新赋值 10ms
    TL0 = (65536 - 10000) % 256;

    time10ms++;
    if (time10ms > 50) // 0.5s
    {
        refreshFlag = 1;
        time10ms = 0; 
    }
    
}


/************************* 串口配置 *************************/
void UART_Init(void)
{
	SCON = 0x50;
	TH2 = 0xFF;
	TL2 = 0xFD;
	RCAP2H = 0xFF;  //(65536-(FOSC/32/BAUD))   BAUD = 115200 FOSC = 11059200
	RCAP2L = 0xFD;

	/*****************/
	TCLK = 1;
	RCLK = 1;
	C_T2 = 0;
	EXEN2 = 0;

	/*****************/
	TR2 = 1;
	ES   = 1; //关闭串口中断
	EA   = 1; //打开总中断

}

/************************* 串口发送字节 *************************/
void UART_SendByte(unsigned char dat) //串口发送单字节数据
{
	unsigned char time_out;
    
	time_out = 0;
	SBUF = dat;						  //将数据放入SBUF中
	while ((!TI) && (time_out < 100)) //检测是否发送出去
	{
		time_out++;
		DelayUs10x(2);
	}		//未发送出去 进行短暂延时
	TI = 0; //清除ti标志
}

/************************* 串口发送字符串 *************************/
void UART_SendStr(unsigned char *s, unsigned char length)
{
	unsigned char num;
	num = 0x00;
	while (num < length) //发送长度对比
	{
		UART_SendByte(*s); //放松单字节数据
		s++;			  //指针++
		num++;			  //下一个++
	}
}


/************************* 串口中断 *************************/
void UART_Interrupt(void) interrupt 4 //串行中断服务程序
{
    static unsigned char i = 0;
    static unsigned char firstBit = 0;
    static unsigned char R_buf[4];
    
    if (RI)//判断是接收中断产生
    {
        RI = 0; //标志位清零
        SBUF = SBUF;
        if (SBUF == '*')
        {
            firstBit = 1; //接收标志成功
            i = 0;
            R_buf[1] = 0;
            R_buf[2] = 0;
            R_buf[3] = 0;
        }
        if (firstBit == 1)
        {
            R_buf[i] = SBUF;
            
            i++;
            if (i >= 4)
            {
                i = 0;
                if (R_buf[0] == '*' && R_buf[3] == '#')
                {
                    if (R_buf[1] == 'C') //继电器闭合命令
                    {
                        switch (R_buf[2])
                        {
                            case '1': RELAY1 = CLOSE; break;
                            case '2': RELAY2 = CLOSE; break;
                            case '3': RELAY3 = CLOSE; break;
                            case '4': RELAY4 = CLOSE; break;
                            case 'A': RELAY1 = CLOSE; RELAY2 = CLOSE; RELAY3 = CLOSE; RELAY4 = CLOSE; break;
                            default:break;
                        }
                        BUZZER = OFF;
                    }
                    else if (R_buf[1] == 'B') //继电器断开命令
                    {
                        switch (R_buf[2])
                        {
                            case '1': RELAY1 = BREAK; break;
                            case '2': RELAY2 = BREAK; break;
                            case '3': RELAY3 = BREAK; break;
                            case '4': RELAY4 = BREAK; break;
                            case 'A': RELAY1 = BREAK; RELAY2 = BREAK; RELAY3 = BREAK; RELAY4 = BREAK; break;
                            default:break;
                        }
                        BUZZER = OFF;
                    }
                }
                firstBit = 0;
            }
        }
    }
    if (TI)//判断是中断产生
    {
        TI = 0; //标志位清零
    }
}

仿真演示视频:
https://www.bilibili.com/video/BV1c44y1Q7JX/

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值