基于51单片机的电表电量采集系统程序.docx
《基于51单片机的电表电量采集系统程序.docx》由会员分享,可在线阅读,更多相关《基于51单片机的电表电量采集系统程序.docx(14页珍藏版)》请在冰豆网上搜索。
![基于51单片机的电表电量采集系统程序.docx](https://file1.bdocx.com/fileroot1/2022-11/16/de507e96-cc59-41f2-8fa8-36ae1a5c3d6b/de507e96-cc59-41f2-8fa8-36ae1a5c3d6b1.gif)
基于51单片机的电表电量采集系统程序
#include//AD7135直接与单片机相连采用查询的方法多路
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
#defineulongunsignedlong
#defineADP2P2
#defineADP0P0
#defineCD4051P1
#definefosc12//晶振频率
#definetime02000//定时2000us
#definejishu1000//假设AD输入电压与对应瞬时功率的基数
//1V对应1000w
uintidatajisuandu;//临时变量,用于计算电度数
uintidatatime0_0;//临时变量,用于计算定时
sbitSTAT7135=P1^7;//7135的启动端
sbitbusy=P2^6;//7135的忙端
sbitst=P2^5;//7135的选通端
sbitCS7221=P1^5;//7221的片选
sbitDIN7221=P1^4;//7221的数据端
sbitCLK7221=P1^6;//7221的时钟端
sbitSDA=P3^1;//2416的数据端
sbitSCL=P3^0;//2416的时钟端
//sbiten_24c16=P3^4;
ucharDISPBUF[8]={0,1,2,3,4,5,6,7};//显示缓冲区
ucharADBUF[40]=0;//AD缓冲区(万千百十个)*8
ucharTIME[2]=0;//用于定时
ucharBUF[5]=0;//数据处理缓冲区
voiddelay(uintn);//延时子程序
voidInitial7221(void);//MAX7221初始化
voidWR7221(ucharaddr,ucharData);//MAX7221写程序
voidMax7221Display(uchar*buffer);//MAX7221显示程序
voidtime2ms(void);//定时器0初始化程序
voidtime0_int(void);//定时器0中断服务程序
voidICL7135(void);//ICL71358路信号AD转换程序
voidSAVE(void);//电量存储转电度程序
voidstart_bit(void);//IIC开始条件
voidstop_bit(void);//IIC停止条件
voidmast_ack(void);//IIC应答
bitwrite_8bit(ucharch);//IIC写8位数据
ucharread24c16(uintaddress,uchar*shu);//IIC读字节数据
ucharwrite24c16(uintaddress,ucharddata);//IIC写字节数据
ucharpage_wr(uintfirstw_ad,uintcounter,uchar*firstr_ad);//IIC页写
ucharpage_rd(uintfirstrd_ad,uintcount,uchar*firstwr_ad);//IIC页读
main()
{//while(page_wr(0,120,0)==0);//初次使用时清电量数
Initial7221();//初始化7221
Max7221Display(&DISPBUF[0]);//开机默认显示0~7
delay(40);//延时
time2ms();//启动定时器
while
(1)
{
if(TIME[1]%10==0)//5秒时间到
{ICL7135();//启动8路AD转换
SAVE();//存储电能
}
}
}
voidWR7221(ucharaddr,ucharData)//MAX7221的写子程序
{
uchari;
CS7221=0;//片选有效
for(i=0;i<8;i++)//写8位地址
{
CLK7221=0;//时钟低
DIN7221=(addr&(0x80>>i))?
1:
0;//先发高位依次到低位
_nop_();
_nop_();
CLK7221=1;//时钟高上升沿锁数据
_nop_();
_nop_();
}
for(i=0;i<8;i++)//写8位数据
{
CLK7221=0;//时钟低
DIN7221=(Data&(0x80>>i))?
1:
0;//先发高位依次到低位
_nop_();
_nop_();
CLK7221=1;//时钟高上升沿锁数据
_nop_();
_nop_();
}
CS7221=1;//片选无效
}
voidInitial7221(void)//MAX7221初始化
{
WR7221(0x0A,0x0A);//亮度地址0AH,0x00~0x0F,0x0F最亮
WR7221(0x0B,0x07);//扫描LED个数地址0BH,0x00~0x07,最多扫描8个数码管
WR7221(0x0C,0x01);//工作模式地址0x0C.0x00:
关断;0x01:
正常
WR7221(0x09,0xFF);//编码模式地址0x09.0x00~0xFF:
哪一位为1,哪一位就支持编码
}
voidMax7221Display(uchar*buffer)//MAX7221显示子程序
{
uchari;
for(i=0;i<8;i++)//MAX7221的8个数码管显示
{
WR7221(i+1,*(buffer+i));//调MAX7221的写子程序
}
}
voiddelay(uintn)//延时程序
{
uinti,j;
for(i=0;ifor(j=0;j<1140;j++);
}
voidtime2ms(void)//T0定时器初始化
{
TMOD=0x01;//T0工作方式1
/*2ms定时设置*/
time0_0=65536-time0*fosc/12;//计算初值
TH0=(time0_0/256);//装定时器0初值
TL0=(time0_0%256);
TR0=1;//启动定时器0
ET0=1;//打开定时器0中断
EA=1;//打开总中断
}
/*定时器0中断服务子程序,定时用于AD转换
1s约转换3次,8路信号约3s时间
为了时间充裕5s采集一次电能信号*/
voidtime0_int(void)interrupt1
{
TH0=(time0_0/256);//重装定时器0初值
TL0=(time0_0%256);
TIME[0]++;
if(TIME[0]==250)//250*2ms=500ms=0.5s时间到
{
TIME[0]=0;//到0.5s时TIME[0]清0
TIME[1]++;//TIME[1]加1内存的0.5秒的整数倍
}
}
voidICL7135(void)//启动8路AD转换
{
uchari,j;
STAT7135=1;//7135启动端使能启动AD转换
CD4051=CD4051&0xf0;//设置CD4051的第一路信号输入AD
for(j=0;j<=7;j++)//8路循环测量
{
i=CD4051&0xf0;//读P1口的状态保护高位
CD4051=j|i;//通过j调节多路开关的转换
STAT7135=1;//7135启动端使能启动AD转换
i=busy;//读7135的正在转换忙端
do{i=busy;}while(busy==0);//忙端为0时等待直到开始转换
do{i=busy;}while(busy==1);//忙端为1时正在转换等待
STAT7135=0;//7135禁止AD转换
do{i=ADP2;}while((ADP2&0x010)!
=0x010);//读7135的D5,直到D5为1
if((ADP2&0x010)==0x010)//D5为1开始读AD转换结果
{
//STAT7135=0;
ADBUF[j*5]=ADP0&0x0f;//读7135的万位
do{i=ADP2;}while((ADP2&0x08)!
=0x08);//读7135的D4,直到D4为1
ADBUF[1+j*5]=ADP0&0x0f;//读7135的千位
do{i=ADP2;}while((ADP2&0x04)!
=0x04);//读7135的D3,直到D3为1
ADBUF[2+j*5]=ADP0&0x0f;//读7135的百位
do{i=ADP2;}while((ADP2&0x02)!
=0x02);//读7135的D2,直到D2为1
ADBUF[3+j*5]=ADP0&0x0f;//读7135的十位
do{i=ADP2;}while((ADP2&0x01)!
=0x01);//读7135的D1,直到D1为1
ADBUF[4+j*5]=ADP0&0x0f;//读7135的个位
//ADBUF[0]=j+1;//路号
//Max7221Display(&ADBUF[j*5]);//当频率慢时可以显示AD转换的结果
}
}
}
voidSAVE(void)//电能处理保存
{
uchark,i;
ulongkk,kk1,kk2;
if(TIME[1]<120)//小于1分钟时120*0.5=60s简单加
{
for(k=0;k<=7;k++)//8路电能循环存储
{
while(page_rd(k*5,5,&BUF[0])==0);//读原来的电能各路5位数字
for(i=0;i<=4;i++)
{
BUF[i]=BUF[i]+ADBUF[i+k*5];//本次的电能和原来的电能求和
}
while(page_wr(k*5,5,&BUF[0])==0);//存新的总电能
}