功能:
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; //标志位清零
}
}