• 回复
  • 收藏
  • 点赞
  • 分享
  • 发新帖

【原创】新手自学单片机分享之基于51单片机的功率计设计(欢迎大家来指点)

从开始自学单片机到现在断断续续已有一个多月,为了巩固所学,学以致用,想着利用所学做些东西出来,由于我现在工作是做电源的,所以计划使用51单片机做一款功率计出来,可以测量电源输出的直流电压电流和功率,实用性和性能暂时就不要求自己了,能实现功能就好,目标是能把所学东西在里面全都实践一番,利用手上一块51开发板,计划逐步实现以下功能:

    第一步:AD检测电压电流,利用分压电阻采集电压,在电路中串联检测电阻采样电流值,并经AD转换后使用LCD显示出来电压电流和功率。

                这部分练习AD转换和1602LCD显示的操作,AD使用pcf8591,可以学习IIC协议的使用。

    第二步:增加使用LED数码管即时显示温度和时钟。不进行测量时LED不显示,换LCD显示温度和时钟。

    第三步:可手动设置测量电压电流量程,也可自动选择测量量程,可以手动设置电压电流温度异常值,检测到有异常时自动报警。

    第四步:将测量值通过按键记录在EEPROM中,按键可查看最近记录的电压电流和温度值。

    第五步:通过串口将测量参数显示在电脑上,也可通过电脑控制实现以上功能(最近看到有个叫labvie的东西,可能能用到)。

    ... ...

目前能想到的就这么多,可能做的过程中会有些改动,也可能会增加一些其他功能来练习所学,欢迎大家多多指导。

后续会逐步将进度贴上来供大家指正。

全部回复(12)
正序查看
倒序查看
Deaby
LV.3
2
2014-06-10 23:39

第一步已实现:

代码如下:

/*********************************************/

#include

#define uint unsigned int

#define uchar unsigned char

/********************************************/

uchar code DATE1[]="WELCOM TO BOE";    //LCD显示相关参数定义

uchar code DATE2[]="VIP TEST SYSTEM!";

uchar code DATE3[]="U=000.00V _P(W) ";

uchar code DATE4[]="I=00.000A _000.0";

uchar code DATE5[]={            //1602 LCD 0~9编码

0X30,0X31,0X32,0X33,0X34,

0X35,0X36,0X37,0X38,0X39};

sbit LCDRS=P2^4;

sbit LCDRW=P2^5;

sbit LCDEN=P2^6;

unsigned long U,I,PW,TTU,TTI,TTP;

double Tu,Ti,Tp;

uint a,b,c,d,e,f,g,h,k,m,n,o,q,r;

/**********************************************/

sbit sda=P2^0;                      //IIC端口定义

sbit scl=P2^1;

/**********************************************/

void delay(uint z)                  //延时1ms函数

{

uint x,y;

for(x=z;x>0;x--)

    for(y=110;y>0;y--);

}

/////////////////////////////////////////////以下LCD显示

/**********************************************/

void write_com(uint com)    //写指令函数                   

{

LCDRS=0;  //选择对指令操作

P0=com;

LCDEN=1; //开使能

delay(5);

LCDEN=0;

}

/***********************************************/

void write_date(uint date)    //写数据函数

{

LCDRS=1;

P0=date;

LCDEN=1;

delay(5);

LCDEN=0;

}

/***********************************************/

void clear()                 //清屏

{

write_com(0x01);

}

/***********************************************/

void initlcd()              //初始化函数

{

clear();

P0=0;

LCDEN=0;

LCDRW=0; //始终选择写操作

clear();

write_com(0x38); //两行8位5*7点阵

write_com(0x06); //写操作后画面不动,AC自动增一

write_com(0x0c); //开显示,不显示光标

}

/***********************************************/

void logo()                 //开机logo

{

uchar i;

write_com(0x80+0X01);

for(i=0;i<13;i++)

{

write_date(DATE1[i]);

delay(20);

}

write_com(0x80+0x40);

for(i=0;i<16;i++)

{

write_date(DATE2[i]);

delay(20);

}

delay(2000);

/***********************************************/

clear();              //固定显示部分

write_com(0x80);

for(i=0;i<16;i++)

{

write_date(DATE3[i]);

delay(1);

}

write_com(0x80+0X40);

for(i=0;i<16;i++)

{

write_date(DATE4[i]);

delay(1);

}

}

/***********************************************/

void display(double x,double y)

{

Tu=x;             //测量值和显示函数转换

Ti=y;

Tp=Tu*Ti;

TTU=Tu*100;

TTI=Ti*1000;

TTP=Tp*10;

/***********************************************/

U=TTU;                  //电压显示

a=U/10000;

b=U%10000/1000;

c=U%1000/100;

d=U%100/10; 

e=U%10/1;

write_com(0x80+0x02);

write_date(DATE5[a]);

write_date(DATE5[b]);

write_date(DATE5[c]);

write_date('.');

write_date(DATE5[d]);

write_date(DATE5[e]);

/***********************************************/

I=TTI;                   //电流显示       

f=I/10000;

g=I%10000/1000;

h=I%1000/100;

k=I%100/10; 

m=I%10/1;

write_com(0x80+0x40+0x02);

write_date(DATE5[f]);

write_date(DATE5[g]);

write_date('.');

write_date(DATE5[h]);

write_date(DATE5[k]);

write_date(DATE5[m]);

/***********************************************/

PW=TTP;                         //功率显示

n=PW/1000;

o=PW%1000/100;

q=PW%100/10;

r=PW%10/1;

 write_com(0x80+0x40+0x0b);

write_date(DATE5[n]);

write_date(DATE5[o]);

write_date(DATE5[q]);

write_date('.');

write_date(DATE5[r]);

}

//////////////////////////////////////////////////////////////////以下AD

/***********************************************/

void initad()                             //IIC初始化

{

scl=1;

delay(1);

sda=1;

delay(1);

}

/***********************************************/

void start()                              //IIC起始

{

sda=1;

delay(1);

scl=1;

delay(1);

sda=0;

delay(1);

}

/***********************************************/

void stop()                               //IIC终止

{

sda=0;

delay(1);

scl=1;

delay(1);

sda=1;

delay(1);

}

/***********************************************/

void respons()                        //从机应答

{

scl=1;

delay(1);

while(sda==1);

delay(1);

scl=0;

delay(1);

}

/***********************************************/

void write(uchar date)                 //写一个字节

{

uchar i,temp;

scl=0;

temp=date;

for(i=0;i<8;i++)

{

temp=temp<<1;

sda=CY;

delay(1);

scl=1;

delay(1);

scl=0;

delay(1);

}

}

/***********************************************/

uchar read()                       //读一个字节

{

uchar i,k;

scl=0;

delay(1);

sda=1;

for(i=0;i<8;i++)

{

scl=1;

k=(k<<1)|sda;

delay(1);

scl=0;

delay(1);

}

return k;

}

/***********************************************/

void main()

{

double UT,IT;

uint uset;

double iset;

uset=120;

iset=1.5;

initlcd();

initad();

logo();

start();

write(0x90);     //在1001000地址写

respons();

// write(0x40);     //设置AD为四通道不自动增加通道模式               0100 0000

// write(0x44);     //设置AD为四通道自动增加通道模式,AD3-U AD1-I     0100 0100

write(0x45);     //设置AD为四通道自动增加通道模式,AD0-U AD2-I     0100 0101

// write(0x46);     //设置AD为四通道自动增加通道模式,AD1-U AD3-I     0100 0110

// write(0x47);     //设置AD为四通道自动增加通道模式,AD2-U AD0-I     0100 0111

respons();

/************************************************/

while(1)

{

start();

write(0x91);

respons();

UT=read();

stop();

UT=UT*uset/255;

start();

write(0x91);

respons();

IT=read();

stop();

IT=IT*iset/255;

display(UT,IT);

}

}

0
回复
2014-06-11 09:05
@Deaby
第一步已实现:[图片][图片][图片]代码如下:/*********************************************/#include#defineuintunsignedint#defineucharunsignedchar/********************************************/ucharcodeDATE1[]="WELCOMTOBOE";  //LCD显示相关参数定义ucharcodeDATE2[]="VIPTESTSYSTEM!";ucharcodeDATE3[]="U=000.00V_P(W)";ucharcodeDATE4[]="I=00.000A_000.0";ucharcodeDATE5[]={      //1602LCD0~9编码0X30,0X31,0X32,0X33,0X34,0X35,0X36,0X37,0X38,0X39};sbitLCDRS=P2^4;sbitLCDRW=P2^5;sbitLCDEN=P2^6;unsignedlongU,I,PW,TTU,TTI,TTP;doubleTu,Ti,Tp;uinta,b,c,d,e,f,g,h,k,m,n,o,q,r;/**********************************************/sbitsda=P2^0;           //IIC端口定义sbitscl=P2^1;/**********************************************/voiddelay(uintz)         //延时1ms函数{uintx,y;for(x=z;x>0;x--)    for(y=110;y>0;y--);}/////////////////////////////////////////////以下LCD显示/**********************************************/voidwrite_com(uintcom)  //写指令函数          {LCDRS=0; //选择对指令操作P0=com;LCDEN=1;//开使能delay(5);LCDEN=0;}/***********************************************/voidwrite_date(uintdate)  //写数据函数{LCDRS=1;P0=date;LCDEN=1;delay(5);LCDEN=0;}/***********************************************/voidclear()        //清屏{write_com(0x01);}/***********************************************/voidinitlcd()       //初始化函数{clear();P0=0;LCDEN=0;LCDRW=0;//始终选择写操作clear();write_com(0x38);//两行8位5*7点阵write_com(0x06);//写操作后画面不动,AC自动增一write_com(0x0c);//开显示,不显示光标}/***********************************************/voidlogo()        //开机logo{uchari;write_com(0x80+0X01);for(i=0;i
此贴已被例如本届原创帖大赛参赛作品,楼主加油,期待更多内容~!嘎嘎
0
回复
飞翔2004
LV.10
4
2014-06-11 21:39
@Deaby
第一步已实现:[图片][图片][图片]代码如下:/*********************************************/#include#defineuintunsignedint#defineucharunsignedchar/********************************************/ucharcodeDATE1[]="WELCOMTOBOE";  //LCD显示相关参数定义ucharcodeDATE2[]="VIPTESTSYSTEM!";ucharcodeDATE3[]="U=000.00V_P(W)";ucharcodeDATE4[]="I=00.000A_000.0";ucharcodeDATE5[]={      //1602LCD0~9编码0X30,0X31,0X32,0X33,0X34,0X35,0X36,0X37,0X38,0X39};sbitLCDRS=P2^4;sbitLCDRW=P2^5;sbitLCDEN=P2^6;unsignedlongU,I,PW,TTU,TTI,TTP;doubleTu,Ti,Tp;uinta,b,c,d,e,f,g,h,k,m,n,o,q,r;/**********************************************/sbitsda=P2^0;           //IIC端口定义sbitscl=P2^1;/**********************************************/voiddelay(uintz)         //延时1ms函数{uintx,y;for(x=z;x>0;x--)    for(y=110;y>0;y--);}/////////////////////////////////////////////以下LCD显示/**********************************************/voidwrite_com(uintcom)  //写指令函数          {LCDRS=0; //选择对指令操作P0=com;LCDEN=1;//开使能delay(5);LCDEN=0;}/***********************************************/voidwrite_date(uintdate)  //写数据函数{LCDRS=1;P0=date;LCDEN=1;delay(5);LCDEN=0;}/***********************************************/voidclear()        //清屏{write_com(0x01);}/***********************************************/voidinitlcd()       //初始化函数{clear();P0=0;LCDEN=0;LCDRW=0;//始终选择写操作clear();write_com(0x38);//两行8位5*7点阵write_com(0x06);//写操作后画面不动,AC自动增一write_com(0x0c);//开显示,不显示光标}/***********************************************/voidlogo()        //开机logo{uchari;write_com(0x80+0X01);for(i=0;i
支持一下楼主,为何楼主不采用单片机内部的AD转换?此案中单片机的精度不够?
0
回复
Deaby
LV.3
5
2014-06-11 21:50
@飞翔2004
支持一下楼主,为何楼主不采用单片机内部的AD转换?此案中单片机的精度不够?
我是利用手头一块开发板边学边做的,这块板子上只有stc的51单片机,不带AD的,上面使用的是NXP的PCF8591.就先用这个做了,目前不要求精度和性能,能实现功能就很满意了,等了解差不多了准备入手写高级点的单片机
0
回复
飞翔2004
LV.10
6
2014-06-11 21:56
@Deaby
我是利用手头一块开发板边学边做的,这块板子上只有stc的51单片机,不带AD的,上面使用的是NXP的PCF8591.就先用这个做了,目前不要求精度和性能,能实现功能就很满意了,等了解差不多了准备入手写高级点的单片机
我刚还在想怎么不用单片机自带的AD转换,那样更简洁,STC没用过,我觉得现在的单片机很多都有吧,我大多用AVR的都有自带AD转换。。。祝你成功,加油发帖哦,时间不多了。
0
回复
Deaby
LV.3
7
2014-06-11 22:03
@飞翔2004
我刚还在想怎么不用单片机自带的AD转换,那样更简洁,STC没用过,我觉得现在的单片机很多都有吧,我大多用AVR的都有自带AD转换。。。祝你成功,加油发帖哦,时间不多了。
谢谢,还需前辈多指教呢,计划两个月内能把计划中的事做完就可以了,我刚刚学还不熟,慢慢来了~~
0
回复
jenny01
LV.2
8
2014-06-12 11:08
@Deaby
谢谢,还需前辈多指教呢,计划两个月内能把计划中的事做完就可以了,我刚刚学还不熟,慢慢来了~~
不错啊,推荐给刚学单片机的弟弟
0
回复
Deaby
LV.3
9
2014-06-12 12:31
@jenny01
不错啊,推荐给刚学单片机的弟弟
谢谢捧场!
0
回复
挑战者
LV.5
10
2014-06-16 15:48
@Deaby
[图片]谢谢捧场!
不错啊
0
回复
Deaby
LV.3
11
2014-06-16 17:08
@挑战者
不错啊
谢谢鼓励~~
0
回复
小毛猴
LV.3
12
2014-06-17 14:21
@Deaby
谢谢,还需前辈多指教呢,计划两个月内能把计划中的事做完就可以了,我刚刚学还不熟,慢慢来了~~
楼主 期待更新啊,看完了 没的看了~~
0
回复
wangshujun
LV.8
13
2014-07-07 17:43
@Deaby
第一步已实现:[图片][图片][图片]代码如下:/*********************************************/#include#defineuintunsignedint#defineucharunsignedchar/********************************************/ucharcodeDATE1[]="WELCOMTOBOE";  //LCD显示相关参数定义ucharcodeDATE2[]="VIPTESTSYSTEM!";ucharcodeDATE3[]="U=000.00V_P(W)";ucharcodeDATE4[]="I=00.000A_000.0";ucharcodeDATE5[]={      //1602LCD0~9编码0X30,0X31,0X32,0X33,0X34,0X35,0X36,0X37,0X38,0X39};sbitLCDRS=P2^4;sbitLCDRW=P2^5;sbitLCDEN=P2^6;unsignedlongU,I,PW,TTU,TTI,TTP;doubleTu,Ti,Tp;uinta,b,c,d,e,f,g,h,k,m,n,o,q,r;/**********************************************/sbitsda=P2^0;           //IIC端口定义sbitscl=P2^1;/**********************************************/voiddelay(uintz)         //延时1ms函数{uintx,y;for(x=z;x>0;x--)    for(y=110;y>0;y--);}/////////////////////////////////////////////以下LCD显示/**********************************************/voidwrite_com(uintcom)  //写指令函数          {LCDRS=0; //选择对指令操作P0=com;LCDEN=1;//开使能delay(5);LCDEN=0;}/***********************************************/voidwrite_date(uintdate)  //写数据函数{LCDRS=1;P0=date;LCDEN=1;delay(5);LCDEN=0;}/***********************************************/voidclear()        //清屏{write_com(0x01);}/***********************************************/voidinitlcd()       //初始化函数{clear();P0=0;LCDEN=0;LCDRW=0;//始终选择写操作clear();write_com(0x38);//两行8位5*7点阵write_com(0x06);//写操作后画面不动,AC自动增一write_com(0x0c);//开显示,不显示光标}/***********************************************/voidlogo()        //开机logo{uchari;write_com(0x80+0X01);for(i=0;i
这个ad才8位呀,精度有点低了,反正串行的片子个位数比较高的吧
0
回复