功能介绍:
0.本系统采用STC89C52作为单片机
1.采用LCD1602液晶循环显示当前检测的用电量
2.设计了eeprom可存储各个用户用电量
3.利用8个电位器模拟用户用电情况,便于演示
4.利用CD4051多路开光与一片ADC芯片配合实现了多路信号采集
原理图:
PCB:
主程序:
#include "main.h"
bit refreshFlag = 1;
bit isNewFlag; //是否为新芯片
float xdata Power[8] = 0;
unsigned char setIndex = 0;
unsigned char i = 0;
unsigned char ADC_Value;
char dis0[16]; //定义显示区域临时存储数组
void main(void)
{
bit ack = 0;
Timer0_Init();
EEPROM_Init();
LCD_Init(); //初始化液晶
DelayMs(200); //延时有助于稳定
LCD_Clear(); //清屏
ReadEEPROM();
if (isNewFlag != 0) //新芯片
{
EEPROM_WriteByte(ISNEW_ADDRESS, 0);
//给出初始值
for (i = 0; i <= 7; i++)
{
Power[i] = 0;
}
WriteEEPROM();
}
while (1) //主循环
{
if (refreshFlag == 1) //1s刷新一次数据
{
static unsigned char cnt = 0;
refreshFlag = 0;
TR0 = 0;
for (i=0; i<=7; i++)
{
CD4051_SelChannel(i); //配置采集通道
ADC_Value = ReadADC(AIN0_GND); //ADC采集
DelayMs(10);
if (ADC_Value > 5) //当采集值大于5时, 开始计算用电量, 为了滤除噪声取5为界限
{
Power[i] = Power[i] + (220 * (float)ADC_Value * 5 / 255) / 3.6; //换算千瓦时
EEPROM_WriteByte(BASE_ADDRESS+2*i, (((unsigned int)Power[i] & 0xFF00) >> 8));
EEPROM_WriteByte(BASE_ADDRESS+2*i+1, ((unsigned int)Power[i] & 0x00FF));
ADC_Value = 0;
}
}
DispNormal(cnt);
cnt++;
if (cnt > 7)
cnt = 0;
TR0 = 1;
}
CheckKey();
}
}
void WriteEEPROM(void) //写入用电量
{
for (i=0; i<=7; i++)
{
EEPROM_WriteByte(BASE_ADDRESS+2*i, (((unsigned int)Power[i] & 0xFF00) >> 8));
EEPROM_WriteByte(BASE_ADDRESS+2*i+1, ((unsigned int)Power[i] & 0x00FF));
}
}
void ReadEEPROM(void) //读取用电量
{
isNewFlag = EEPROM_ReadByte(ISNEW_ADDRESS);
for (i=0; i<=7; i++)
{
Power[i] = EEPROM_ReadByte(BASE_ADDRESS + 2*i);
Power[i] = ((unsigned int)Power[i] << 8) | EEPROM_ReadByte(BASE_ADDRESS + 2*i + 1);
}
}
void DispNormal(unsigned char channel)
{
sprintf(dis0, " Consumption %02d ", (unsigned int)channel); //打印通道值
LCD_DispStr(0, 0, dis0);
sprintf(dis0, " %10.4fkWh ", Power[channel]/1000000); //打印用电量
LCD_DispStr(0, 1, dis0); //显示第二行
}
void CheckKey(void)
{
if (!KEY_CLEAR) //清零按键按下
{
DelayMs(10);
if (!KEY_CLEAR)
{
for (i=0; i<=7; i++)
{
Power[i] = 0;
}
WriteEEPROM();
}
while (!KEY_CLEAR);
}
}
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void Timer0_Init(void)
{
TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TL0 = 0x00; //设置定时初值50ms
TH0 = 0x4C; //设置定时初值
EA = 1; //总中断打开
ET0 = 1; //定时器中断打开
TR0 = 1; //定时器开关打开
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void Timer0_Interrupt(void) interrupt 1
{
static unsigned char time50ms = 0;
TL0 = 0x00; //设置定时初值50ms
TH0 = 0x4C; //设置定时初值
time50ms++;
if (time50ms >= 20) // 1s
{
time50ms = 0;
refreshFlag = 1;
}
}