冯:
参考,别人的别人的,参考链接:参考链接
思:
这块简单易制作的0-30V,STC单片机数字电压表,被测电压经限流电阻接到AD检测端并由分流电阻分流,读出8位、2的8次方(256)的AD数据,由AD值计算出AD端电压,即分流点电压,由此电压计算出分流电流,再由此电流计算出输入电压。
如图:(参考链接中的)(链接中的图形,有个电容,可以起到很好的作用)
使用STC15F2K60s2AD单片机,P1段输出加限流电阻,AD为8位,计算方法:5/256=0.0195312V,分流电阻为实测阻值。AD值0.0195312v/对地分流电阻,算出分流电流,然后用分流电流分流电阻与限流电阻之和即为要显示的输入电压值,业余使用,精度已经够用了。
或者可以直接接分压电阻,但是如果是空载的话,就会有些问题。
如图:
当直接接电阻时:(我使用的是STC15F2K系列,是10位AD,但是只用到8位而已,即用高八位,低二位不用)
电压=(5/256=0.019532)*AD值
电流=……
原理图:(15大多系列可以不用晶振,也可以用晶振)
其中:
官方推荐电路:
主函数:
/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC15F4K60S4 系列 AD转换查询方式举例----------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966-------------------------*/
/* --- Web: www.STCMCU.com --------------------------------------------*/
/* --- Web: www.GXWMCU.com --------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序 */
/* 如果要在文章中应用此代码,请在文章中注明使用了STC的资料及程序 */
/*---------------------------------------------------------------------*/
//若无特别说明,工作频率一般为11.0592MHz
#include "reg51.h"
#include "intrins.h"
#define FOSC 11059200L//晶振大小
#define BAUD 115200//波特率
typedef unsigned char BYTE; //重命名 unsigned char 为 BYTE
typedef unsigned int WORD; //重命名 unsigned int 为 WORD
#define URMD 0 //0:使用定时器2作为波特率发生器
//WORD data dis[5]={0x00,0x00,0x00,0x00,0x00};
WORD ad_data;//记录AD值
float j=0.0;//计算电压值
int sum=0;//将浮点电压值装换成int型
//74HC595IO口定义
sbit SRCLK=P2^2;
sbit Rclk=P2^1;
sbit SER=P2^0;
//数码管IO口(使用的是共阴)
sbit SMG1=P2^3;
sbit SMG2=P2^4;
sbit SMG3=P2^5;
sbit SMG4=P2^6;
//数码管共阴码表
char code smgduan[17]=
{
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
};//显示0~F的值
char Data[4]={
0};//记录电压的4位数(Data【0】=高位依次)
sfr T2H = 0xd6; //定时器2高8位
sfr T2L = 0xd7; //定时器2低8位
sfr AUXR = 0x8e; //辅助寄存器
sfr ADC_CONTR = 0xBC; //ADC控制寄存器
sfr ADC_RES = 0xBD; //ADC高8位结果
sfr ADC_LOW2 = 0xBE; //ADC低2位结果
sfr P1ASF = 0x9D; //P1口第2功能控制寄存器
#define ADC_POWER 0x80 //ADC电源控制位
#define ADC_FLAG 0x10 //ADC完成标志
#define ADC_START 0x08 //ADC起始控制位
#define ADC_SPEEDLL 0x00 //540个时钟
#define ADC_SPEEDL 0x20 //360个时钟
#define ADC_SPEEDH 0x40 //180个时钟
#define ADC_SPEEDHH 0x60 //90个时钟
void InitUart();//串口初始化
void InitADC();//AD初始化
void SendData(BYTE dat);//串发送数据
BYTE GetADCResult(BYTE ch);//获取AD值
void Delay(WORD n);//延时
void ShowResult(BYTE ch);//使用AD中的某一个输入口可以是0~7
void Hc595SendByte(char dat);//
void DigDisplay()//显示数据
{
char i;
for(i=0; i<4; i++)
{
switch(i) //位选,选择点亮的数码管,
{
case 0://Data【0】
SMG1=0;
SMG2=1;
SMG3=1;
SMG4=1;
break;
case 1://Data【1】
SMG1=1;
SMG2=0;
SMG3=1;
SMG4=1;
break;
case 2://Data【2】
SMG1=1;
SMG2=1;
SMG3=0;
SMG4=1;
break;
case 3://Data【3】
SMG1=1;
SMG2=1;
SMG3=1;
SMG4=0;
break;
}
if(i==1)
{
Hc595SendByte(smgduan[Data[i]]|0x80);//第二个数码管加点(.)
}
else
{
Hc595SendByte(smgduan[Data[i]]);//发送段码
}
Delay(100);
Hc595SendByte(0x00);//消影
Delay(100);//这里的延时不要太久
}
}
void main()
{
SMG1=0;
SMG2=0;
SMG3=0;
SMG4=0;//初始化数码管四位都开启
InitUart(); //初始化串口
InitADC(); //初始化ADC
while (1)
{
char i=0;
Delay(100);
ShowResult(2); //显示通道3
DigDisplay();
}
}
/*----------------------------
发送ADC结果到PC
----------------------------*/
void ShowResult(BYTE ch)//数据处理
{
SendData(ch); //显示通道号
// SendData(GetADCResult(ch));
// Delay(10000);
// Delay(10000);
ad_data=GetADCResult(ch);
j=ad_data*19.5312;//由AD数据*19.5312(放大1000倍)=分流后的电压
j=j/9890; //j(电压)/接地电阻(实测)9890欧
j=j*60190;//j(电流)*(输入限流电阻(实测)60190欧+接地电阻(实测)9890欧) 计算出实际输入电压 如果使用高精度电阻,则直接输入电阻值
//SendData(j);
sum=j;
// Data[0]=sum/10000%10;//(这里是直接接负载电阻的测量电压方法)
// Data[1]=sum/1000%10;
// Data[2]=sum/100%10;
// Data[3]=sum/10%10;
Data[0]=sum/10000%10;//十位
Data[1]=sum/1000%10;//个位
Data[2]=sum/100%10;//十分位
Data[3]=sum/10%10;//百分位
}
/*----------------------------
读取ADC结果
----------------------------*/
BYTE GetADCResult(BYTE ch)
{
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
_nop_(); //等待4个NOP
_nop_();
_nop_();
_nop_();
while (!(ADC_CONTR & ADC_FLAG));//等待ADC转换完成
ADC_CONTR &= ~ADC_FLAG; //Close ADC
return ADC_RES; //返回ADC结果
}
/*----------------------------
初始化串口
----------------------------*/
void InitUart()
{
SCON = 0x5a; //设置串口为8位可变波特率
#if URMD == 0
T2L = (65536 - (FOSC/4/BAUD));
T2H = (65536 - (FOSC/4/BAUD)) >> 8;
AUXR = 0x14; //T2为1T模式, 并启动定时器2
AUXR |= 0x01; //选择定时器2为串口1的波特率发生器
#elif URMD == 1
AUXR = 0x40; //定时器1为1T模式
TMOD = 0x00; //定时器1为模式0(16位自动重载)
TL1 = (65536 - (FOSC/4/BAUD));
TH1 = (65536 - (FOSC/4/BAUD)) >> 8;
TR1 = 1; //定时器1开始启动
#else
TMOD = 0x20; //设置定时器1为8位自动重装载模式
AUXR = 0x40; //定时器1为1T模式
TH1 = TL1 = (256 - (FOSC/32/BAUD));
TR1 = 1;
#endif
}
/*----------------------------
初始化ADC
----------------------------*/
void InitADC()
{
P1ASF = 0xff; //设置P1口为AD口
ADC_RES = 0; //清除结果寄存器
ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
Delay(2); //ADC上电并延时
}
/*----------------------------
发送串口数据
----------------------------*/
void SendData(BYTE dat)
{
while (!TI); //等待前一个数据发送完成
TI = 0; //清除发送标志
SBUF = dat; //发送当前数据
}
/*----------------------------
软件延时
----------------------------*/
void Delay(WORD n)
{
WORD x;
while (n--)
{
x = 10;
while (x--);
}
}
void Hc595SendByte(char dat)
{
char a;
SRCLK = 1;
Rclk = 1;
for(a=0; a<8; a++) //发送8位数
{
SER = dat >> 7; //从最高位开始发送
dat <<= 1;
SRCLK = 0; //发送时序
_nop_();
_nop_();
SRCLK = 1;
}
Rclk = 0;
_nop_();
_nop_();
Rclk = 1;
}
其实AD的检测的程序是参考了官方的。配置在如下图中参考:
大致就是这样:最后是Keil的一张图:
结语:由于本人技术有限,难免会有错误的地方,如有错误,还望大家多多指教v.
感谢:怡
作者:杏林洁白