打印
[技术问答]

【新唐003】+ 交流信号有效值的测量

[复制链接]
2740|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gugogol|  楼主 | 2018-3-27 21:13 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 gugogol 于 2018-3-28 18:41 编辑

过年前偶尔发现新唐的N76E003很火,我也买了个测试板回来试了一下,发现果然不错,现分享一下我用它来做交流电有效值的测量的测试程序。由于我是第一次使用C写代码(以前一直用汇编),大家不要见笑!代码我是直接在新唐的ADC例程上改过来的,测试正弦波的有效值用的是均方根测量法 ,采用半波测量,5V的交流信号通过二个10K的电阻分压后接入ADC端口。在测试时发现这芯片有一个美中不足的地方,ADC的参考源固定为电源电压,不像AVR单片机那样可选VDD/片内1.1V参考源/外部Vref参考源,这样使单片机的ADC在小信号测量的应用上欠缺精度调整的灵活性,当然对精度要求不高的,12位也足够了。
                                                                             

//  File Function: N76E003  ADC demo code
//*********************************************************************************************************

**
#include "N76E003.h"
#include "SFR_Macro.h"
#include "Function_define.h"
#include "Common.h"
#include "Delay.h"
#include "math.h"

uint16_t ADCData;
uint16_t xdata ADCDatas[370];
uint8_t VOLT[6];
uint8_t FREQ[5];
uint16_t VOL ;
uint16_t i ;
uint8_t FREQData=206;
uint32_t SINData=0;
double VData=0;
uint32_t ADCDatat;

/*******************************************************************************
**void ADC_Data_Read(unsigned int *AD_Value)
**完成一次ADC转换
**入口参数:unsigned int *AD_Value
            *AD_Value ->读取ADC采样数据指针
**输出:无
*******************************************************************************/
void ADC_Data_Read(uint16_t *AD_Value)
{
                        clr_ADCF;
                        set_ADCS;                                                                        //

ADC start trig signal
      while(ADCF == 0);
      *AD_Value = ADC1_GetConversionValue();  //读取转换数据
}
/*******************************************************************************
**函数名称:void Uart_SendString(u8 *data , u8 strlen)
**功能:向串口发送多个字符
**输入参数:u8 *data   ,  u8 strlen
**输出:无
*******************************************************************************/
void Uart_SendString(uint8_t *datas , uint8_t strlen)
{
  unsigned char datalen;
        InitialUART0_Timer1(115200);
  for(datalen = 0 ; datalen < strlen ; datalen++)
  {
    Send_Data_To_UART0(datas[datalen]);
  }
}
/**********************************
***功能:延时
************************************/
void Delay_short()
{
        long int i;
        for (i = 0; i < 5; i++) ;    //5:30uS
}

/*******************************************************************************
**函数名称:void FREQ_Test(unsigned int *FREQ_T)
**功能:测量信号频率
**入口参数:unsigned int *FREQ_T
            *FREQ_T ->读取频率数据指针
**输出:无
*******************************************************************************/
void FREQ_TEST(uint8_t *FREQ_T)
{
     ADC_Data_Read(&ADCData);
          Delay_short();
  while(ADCData<20)       //等待高电平
  {
     ADC_Data_Read(&ADCData);
          Delay_short();
  }
    while(ADCData>1)       //等待低电平
  {
     ADC_Data_Read(&ADCData);
          Delay_short();
  }
    while(ADCData<20)       //等待高电平
  {
     ADC_Data_Read(&ADCData);
          Delay_short();
  }
    i=0;   
  while(ADCData > 20)      //对高电平转换次数计数,用作判定频率
  {
      ADC_Data_Read(&ADCData);    //ADC转换一次用时48uS
          Delay_short();
      i++;
   }
  if (i>191)
  { i=206;}     //如果计数大于185则认为是50Hz,采样次数为206
      else
         {i=172;} //如果计数小于185则认为是60Hz,采样次数为172
     *FREQ_T = i ;
}

/*******************************************************************************
**函数名称:void RMS_Test(double *RMS_T)
**功能:测量信号的均方根值
**入口参数:unsigned uint32_t *RMS_T
            *RMS_T ->读取采样有效值指针
**输出:无
*******************************************************************************/
void RMS_Test( double *RMS_T)
{
//等待信号波形开端         
  while(ADCData<20)       //等待高电平
  {
     ADC_Data_Read(&ADCData);
          Delay_short();
  }
    while(ADCData>10)       //等待低电平
  {
     ADC_Data_Read(&ADCData);
          Delay_short();
  }
    while(ADCData<20)       //等待高电平
  {
     ADC_Data_Read(&ADCData);
          Delay_short();
  }        
//波形进入高电平开端,开始半波采样        
            i=0;
      ADCDatas = ADCData  ;        
            i++;
                while(i < FREQData )
    {
      ADC_Data_Read(&ADCData);    //转换一次ADC用时13.5uS
      ADCDatas = ADCData  ;
                        Delay_short();             //延时30US
                        i++  ;
    }
        i=0;
  SINData=0;
  while(i<FREQData)
{
//计算均方根值(有效值) **********************
            ADCDatat = ADCDatas;
     SINData += ADCDatat * ADCDatat ;   //平方和
     i++;
  }
     SINData = SINData / FREQData ;   //平方和平均
     *RMS_T  = sqrt ( (double)(SINData) ); //开方
//           VData = VData / 21.33 ;        //比例调整
        
}
//**********************************************        
/******************************************************************************
The main C function.  Program execution starts
here after stack initialization.
******************************************************************************/
void main (void)
{
                InitialUART0_Timer1(115200);
                 Enable_ADC_AIN0;                                                // Enable AIN0 P1.7 as ADC

input, Find in "Function_define.h" - "ADC INIT"
while(1)
{
        FREQ_TEST(&FREQData);   //测试信号频率
//***************************************************************   
//**********************************************       
/******************************************************************************
The main C function.  Program execution starts
here after stack initialization.
******************************************************************************/
void main (void)
{
                  InitialUART0_Timer1(115200);
                  Enable_ADC_AIN0;                                                // Enable AIN0 P1.7 as ADC input, Find in "Function_define.h" - "ADC INIT"
            P14_PushPull_Mode ;      //设置模拟串口1的发送端口
            P15_PushPull_Mode ;      //设置模拟串口2的发送端口

  while(1)
  {
            FREQ_TEST(&FREQData);   //测试信号频率
            RMS_Test( & VData );           //测试信号有效值
                        VData = VData / 21.33 ;        //比例调整
      VOL = (uint32_t)(VData);       //数据类型强制转换
//**********************************************       
      FREQ[2] = FREQData % 10 + '0';      //ASCII转换
      FREQ[1] = FREQData % 100 / 10 + '0';
      FREQ[0] = FREQData / 100 % 10 + '0';
      FREQ[3] = 0x30;                  
      FREQ[4] = 0x30;
      Uart_SendString(FREQ , 5);
      Uart_SendString(" " , 1);  //
      VOLT[3] = VOL % 10 + '0';      //ASCII
      VOLT[2] = VOL % 100 / 10 + '0';
      VOLT[1] = VOL / 100 % 10 + '0';
      VOLT[0] = VOL / 1000 + '0';      
      VOLT[4] = 0x0d;                    //换行
      VOLT[5] = 0x0a;
      Uart_SendString(VOLT , 6);
                  Timer0_Delay1ms(1000) ;
   }
}


     

沙发
heisexingqisi| | 2018-3-28 09:33 | 只看该作者
注释全是乱码,差评

使用特权

评论回复
板凳
heisexingqisi| | 2018-3-28 09:33 | 只看该作者
文本格式选择utf8

使用特权

评论回复
地板
Kelan| | 2018-3-28 09:57 | 只看该作者
该MCU还是性价比很高的,虽然它的ADC的参考源固定为电源电压VDD,但通过等式运算,可以把内部的Vref(1.22左右,具体可以读到每个IC 的该值)当作“参考源”,最终获得的数据还是较准确的。

使用特权

评论回复
5
座机呀| | 2018-3-28 12:51 | 只看该作者
别忘记回帖

微信截图_20180328124941.png (45.83 KB )

微信截图_20180328124941.png

使用特权

评论回复
6
gugogol|  楼主 | 2018-3-28 18:29 | 只看该作者
heisexingqisi 发表于 2018-3-28 09:33
注释全是乱码,差评

我昨晚一直纳闷别人是怎么可以做到不乱码的呢?谢谢你!

使用特权

评论回复
7
cw6610| | 2018-3-29 11:33 | 只看该作者
你好,最近在接触新唐 N76E003 芯片,

原设计的电路是在输入IO前端使用电压比较器,比较器门限电压0.7V,  当采集的电压高于0.7V时比较器动作,IO高电平;当采集的电压低于0.7V时,IO低电平,但在0.7V左右时会出再震荡。所以又在比较器的输出端与同相端串一电阻,做成施密特比较器,但这样单片机外围电路较多。

现在想将单片机的一个IO设置成施密特触发输入,将采集的电压信号直接输入给单片机,  

咨询一下,当IO设置成施密特输入时,上下限两个触发门限电压是否可以设置呢??

谢谢!!

使用特权

评论回复
8
gugogol|  楼主 | 2018-3-29 23:12 | 只看该作者
cw6610 发表于 2018-3-29 11:33
你好,最近在接触新唐 N76E003 芯片,

原设计的电路是在输入IO前端使用电压比较器,比较器门限电压0.7V,  ...

不可调的,如果对速度要求不高的,可以用AD采样来做。

使用特权

评论回复
9
cw6610| | 2018-3-30 00:35 | 只看该作者
gugogol 发表于 2018-3-29 23:12
不可调的,如果对速度要求不高的,可以用AD采样来做。

谢谢,下午细看了手册,注意到了不能设置


使用特权

评论回复
10
wangjiahao88| | 2018-3-30 10:09 | 只看该作者
如果 需要做到精确的 ADC 测量的话 那么 外部VREF+ VREF- 需要做什么特别的处理吗?

使用特权

评论回复
11
gugogol|  楼主 | 2018-3-30 21:33 | 只看该作者
wangjiahao88 发表于 2018-3-30 10:09
如果 需要做到精确的 ADC 测量的话 那么 外部VREF+ VREF- 需要做什么特别的处理吗? ...

N76E003是不可以外接Vref的。

使用特权

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

本版积分规则

3

主题

29

帖子

1

粉丝