打印

基于STC12C5A60S2单片机测量工频交流电压问题

[复制链接]
2875|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gzh4510|  楼主 | 2015-2-6 18:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 gzh4510 于 2015-2-6 18:53 编辑


信号源是工频220V交流 LMV932MA 7脚输出,直接进入单片机AD。单片机为STC12C5A60S2 AD采样交流电压2个周期,时间间隔为312微妙,采样点数为128点。VCC为+5V。
+
单片机采集到的数据通过串口发送到PC端,在EXCEL里通过采集到的数据绘制的波形,基本等于正弦波,可以断定采集到的数据基本正确。
以下是程序
#include<STC12C5A60S2.h>
#include <intrins.h>
#include <math.h>
#include <string.h>
#include "LCD1602_1.h"
typedef unsigned char BYTE;
typedef unsigned int WORD;
#define FOSC 22118400L      //System frequency
#define BAUD 9600           //UART baudrate
/********************************************************************
                               ADC数据转换函数
*********************************************************************/
#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 个时钟周期转换一次
/********************************************************************
                              ADC转换数据数组
*********************************************************************/
double xdata ADC_DH_Temp[128];   //AD采样高8位缓冲区
unsigned int xdata ADC_DL_Temp[128];  //AD采样低2位缓冲区
unsigned int xdata ADC_Data[128];  
unsigned char ADC_Count;   //采样计数
unsigned char Disp_Tab[]={'0','1','2','3','4','5','6','7','8','9'};
bit ADC_Flag;   //采样完成标志位
/****************************************************************/
/****************************************************************/
unsigned char code mcustudio[] //={"      A D C     "};   //Photosensitive box
                                 ={"STC12C5A60S2  AD"};
/******************************************
          均方根值函数
******************************************/
double Calc (double *pData,int nNum)
{
double fsum=0;
unsigned char i;
//求平方和
for( i=0;i<nNum;++i)
{
  fsum+=pData*pData;
}
//平均 开方
return sqrt(fsum/nNum);
}
/******************************************
          AD初始化函数
******************************************/
void InitADC()
{
P1ASF=0XFF;   //P1所有I/O口作为模拟功能A/D使用
ADC_RES=0;   //AD数据高8位清空
ADC_RESL=0;  //AD数据低2位清空
ADC_CONTR=ADC_POWER|ADC_SPEEDHH;   //打开AD电源 转换周期90微妙
_nop_();
_nop_();
_nop_();  //保证电源打开
_nop_();
EADC=1;   //开AD中断
IPH=0X20;
IP=0X20;  //AD中断优先级最高
}
void InitTimer0(void)   //定时器0 312微妙定时
{
   AUXR |= 0x80;  //定时器时钟1T 模式
  TMOD = 0xA1;  //设置定时器模式
  TL0 = 0x0B;  //初值
  TH0 = 0xE5;
  TF0 = 0;  //清中断标志位
  ET0=1;     //开定时器0中思
  EA=1;     //开总中断
  TR0 = 1;  //启动定时器0
}
//******************************************//
//           测式用程序
//            串口发送
//******************************************//
/*----------------------------
Initial UART
----------------------------*/
void InitUart()
{
  PCON |= 0x80;  //
SCON = 0x50;  //
AUXR |= 0x40;  //定时器时钟选为Fosc,即1T
AUXR &= 0xFE;  //串口1选为定时器1为波特率发生器
TMOD &= 0x0F;  //清除定时器1模式
TMOD |= 0x20;  //为8位自动装载
TL1 = 0x70;  //初值
TH1 = 0x70;  //
ET1 = 0;  //关定时器1中断
TR1 = 1;  //启动定时器1中断
}
/*----------------------------
Send a string to UART
Input: s (address of string)
Output:None
----------------------------*/
void SendString(unsigned int *pData,int nNum)  //发送字符串函数
{
unsigned char i;
for(i=0;i<nNum;i++)
{
    SBUF=pData;
  while(TI==0);
  TI=0;
  
}
}
//******************************************//
//           测式用函数结束
//******************************************//

/******************************************
                  主函数
******************************************/
void main(void)
{
// double ADC_1;
unsigned int ADC_2;
unsigned char LedOut[4];
InitADC();   //AD初始化
LCMInit();  //1602初始化
InitTimer0(); //定时器0初始化
InitUart();   //串口初始化
DisplayListChar(0, 0, mcustudio);   //LCD1602显示
  //SendString(1,16);
while(1)
{
  
  if(ADC_Flag==1)   //AD转换完成置位
  {
      ADC_Flag=0;   
   
   ADC_2=(int)(Calc(ADC_DH_Temp,128)*130);   //计算有效值
   
   //ADC_Merge(ADC_DH_Temp,ADC_DL_Temp);
   //SendString(ADC_Data,64);
   //SendString(ADC_DH_Temp,128);   //发送高8位数据
  // SendString(ADC_DL_Temp,64);   //发送低2位数据
   //   1602显示
      LedOut[0]=Disp_Tab[ADC_2%100000/10000];
   LedOut[1]=Disp_Tab[ADC_2%10000/1000];
   LedOut[2]=Disp_Tab[ADC_2%1000/100];
      LedOut[3]=Disp_Tab[ADC_2%100/10];
      LedOut[4]=Disp_Tab[ADC_2%10];
   DisplayOneChar(1, 1, LedOut[0]);
   DisplayOneChar(2, 1, LedOut[1]);
    DisplayOneChar(3, 1, LedOut[2]);
    DisplayOneChar(4, 1, '.');
    DisplayOneChar(5, 1, LedOut[3]);
    DisplayOneChar(6, 1, LedOut[4]);
    DisplayOneChar(7, 1,'V');
   ET0 = 1;   //开定时器0中断
   EADC=1;  //开AD中断
   
  }
}
}
void Timer0Interrupt(void) interrupt 1   //定时器0中断函数 312微秒时间
{
    TL0 = 0x0B;  //初值
   TH0 = 0xE5;
   ET0=0;   //关定时器0中断
   ADC_CONTR=ADC_POWER|ADC_SPEEDHH|ADC_START|0x20; //开始转换 P1.0输入 90个周期
   _nop_();
   _nop_();
   _nop_();   //保证电源打开
   _nop_();
   P20=~P20;  //测式用LED灯
}
void ADC_ISR() interrupt 5 using 1
{
EADC=0;  //关AD中断
ADC_CONTR&=~ADC_FLAG;   //关闭AD转换
ADC_DH_Temp[ADC_Count]=(ADC_RES)*10*49.999/255;  //取高8位数据存入数组
ADC_DL_Temp[ADC_Count]=ADC_RESL;   // ADC_RESL&0X03;            //取低2位数据存入数组
ADC_Count++;   //采样计数
if(ADC_Count>=128)
{
  ADC_Count=0;
  ADC_Flag=1;
}
else
{
  ET0 = 1;   //开定时器0中断
  EADC=1;  //开AD中断
  }
}
现在的问题是,取8位AD数据是正确的,如果取10AD数据该如何取?
我最开始定义一个INT的变量,然后左移两位,在加上低2位的数据,但上传上来的数据不对。
还有问题就是,这个信号中包含直流2.5V的直流,应该怎么计算采进来的数据呢?
电路图最后一级为I/V转换电路,那么转换出来的电压如何计算呢?


那位好心的师傅帮帮我,谢谢了,弄这个我以经弄了两个多月了,我并非电子出身,我是学强电的,就是对单片机非常的感兴趣,所以都是自己学的。谢谢好心人的帮助!



1.png (60.33 KB )

1.png

2.png (50.38 KB )

2.png

3.png (41.51 KB )

3.png

4.png (42.14 KB )

4.png

5.png (69.99 KB )

5.png

相关帖子

沙发
dirtwillfly| | 2015-2-6 20:44 | 只看该作者
ADC转换结果存储寄存器有个调整控制位,没设置错吧?

使用特权

评论回复
板凳
gzh4510|  楼主 | 2015-2-7 14:05 | 只看该作者
dirtwillfly 发表于 2015-2-6 20:44
ADC转换结果存储寄存器有个调整控制位,没设置错吧?

默认的

使用特权

评论回复
地板
xyz549040622| | 2015-2-8 21:14 | 只看该作者
现在的问题是,取8位AD数据是正确的,如果取10AD数据该如何取?我最开始定义一个INT的变量,然后左移两位,在加上低2位的数据,但上传上来的数据不对。
答:有两个寄存器,一个是AD转换结果寄存器,一个是AD转换结果寄存器低。AUXR1寄存器的ADRJ位是数据格式调正位。具体的计算公式如下:

使用特权

评论回复
5
HGQ21102| | 2015-2-8 22:02 | 只看该作者
本帖最后由 HGQ21102 于 2015-2-8 22:04 编辑

好像高手都不浮下,
俺共享下了(俺也是网上找的)
adc10模块与adc8模块给楼主参考下吧,还有常用的滤波算法~:lol
adc8.rar (1.7 KB)

adc10.rar (1.94 KB)

使用特权

评论回复
6
m564522634| | 2015-2-9 13:54 | 只看该作者
AD的转换结果是放到专门的寄存器中的,8位和10的区别的读取寄存器的值不一样。 还有怎么测量电压不用专门的计量芯片吗,直接用这种可靠吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

2

帖子

0

粉丝