单相计量芯片RN8209D使用经验分享

2019-12-09 13:47发布

本帖最后由 Baldwin 于 2018-10-16 08:24 编辑

之前用了三相计量芯片RN8302,RN8302计量芯片使用经验分享https://www.amobbs.com/thread-5697512-1-1.html
最近产品的另外一个系列需要单向计量,于是用了RN8209D,做下来效果还可以 ,能满足1级的精度,实际可以做到0.5S,总的来说这款芯片还是蛮不错的;老规矩,把相关资料分享给大家,少走弯路;
以下是实验时的误差记录
误差.png (5.95 KB, 下载次数: 0) 下载附件 2018-10-15 11:13 上传

HFConst,功率转换系数,启动功率寄存器值换算方法
HFConst换算.png (26.85 KB, 下载次数: 0) 下载附件 2018-10-15 11:16 上传


1---------------------------------------硬件部分-----------------------------------------------------------------------------------
RN8209D电路.png (92.71 KB, 下载次数: 0) 下载附件 2018-10-15 10:21 上传
电压和电流都采用互感器,电压采样采用泽明1:1电压互感器,电流采样采用5A:2.5mA互感器;RN8209D采用模拟SPI与单片机进行通信;电路相对比较简单;

2---------------------------------------RN8209D通信部分,采用模拟SPI-------------------------------------------------------------------------
  1. void RN8209D_ReadRegNoCheck(uint8_t addr,uint8_t *regbuf,uint8_t regbuflen)
  2. {
  3.     uint8_t ucI,ucK;

  4.     RN8209D_CS_CLR();
  5.     delay_us(10);
  6.     addr |= 0x00;            //发送读数据命令(bit.7=0)
  7.     for(ucI=0;ucI<8;ucI++)        //发送读数据命令,下降沿接收数据,高位在前,低位在后
  8.     {
  9.         if( addr & 0x80 )
  10.             RN8209D_MOSI_SET();
  11.         else
  12.             RN8209D_MOSI_CLR();
  13.         RN8209D_SCK_SET();
  14.         delay_us(RN_CLOCKWIDTH);
  15.         RN8209D_SCK_CLR();      //在时钟的下降沿写数据
  16.         addr<<=1;
  17.         delay_us(RN_CLOCKWIDTH);
  18.     }
  19.     RN8209D_MOSI_CLR();
  20.     RN8209D_SCK_CLR();
  21.     delay_us(50);
  22.     for(ucK=0;ucK<regbuflen;ucK++)
  23.     {
  24.         regbuf[ucK]=0x00;
  25.         for(ucI=0;ucI<8;ucI++)
  26.         {
  27.             RN8209D_SCK_SET();
  28.             delay_us(RN_CLOCKWIDTH);
  29.             regbuf[ucK]<<=1;
  30.             RN8209D_SCK_CLR();      //在时钟的下降沿读数据
  31.             delay_us(RN_CLOCKWIDTH/2);
  32.             if(RN8209D_Read_MISO())
  33.                 regbuf[ucK]=regbuf[ucK]|0x01;
  34.             delay_us(RN_CLOCKWIDTH/2);
  35.         }
  36.     }
  37.     RN8209D_CS_SET();
  38.     delay_us(10);
  39.     RN8209D_SCK_CLR();
  40.     delay_us(10);
  41. }

  42. uint8_t RN8209D_ReadReg(uint8_t addr,uint8_t *regbuf,uint8_t regbuflen)
  43. {
  44.     uint8_t buf[4];

  45.     RN8209D_ReadRegNoCheck(addr,regbuf,regbuflen);
  46.     m_memset(buf,0x01,4);
  47.     RN8209D_ReadRegNoCheck(Reg_RData,buf,4);

  48.     if(regbuflen == 3){
  49.         if(m_memcmp(regbuf,buf+1,regbuflen) == 0)
  50.             return 0;
  51.         else
  52.             return 1;
  53.     }
  54.     else if(regbuflen == 4){
  55.         if(m_memcmp(regbuf,buf,regbuflen) == 0)
  56.             return 0;
  57.         else
  58.             return 1;
  59.     }
  60.     else if(regbuflen == 2){
  61.         if(m_memcmp(regbuf,buf+2,regbuflen) == 0)
  62.             return 0;
  63.         else
  64.             return 1;
  65.     }
  66.     else{
  67.         return 1;
  68.     }

  69. }

  70. void RN8209D_WriteRegNoCheck(uint8_t addr,uint8_t *regbuf,uint8_t regbuflen)
  71. {
  72.     uint8_t ucI,ucK;

  73.     RN8209D_CS_CLR();
  74.     delay_us(100);
  75.     addr |= 0x80;   //发送写数据命令(bit.7=1)
  76.     for(ucI=0;ucI<8;ucI++)
  77.     {
  78.         if( addr & 0x80 )
  79.             RN8209D_MOSI_SET();
  80.         else
  81.             RN8209D_MOSI_CLR(); ;
  82.         RN8209D_SCK_SET();
  83.         delay_us(RN_CLOCKWIDTH);
  84.         RN8209D_SCK_CLR();          //在时钟的下降沿写数据
  85.         addr<<=1;
  86.         delay_us(RN_CLOCKWIDTH);
  87.     }
  88.     RN8209D_MOSI_CLR();
  89.     RN8209D_SCK_CLR();
  90.     delay_us(500);
  91.     for(ucK=0;ucK<regbuflen;ucK++)
  92.     {
  93.         for(ucI=0;ucI<8;ucI++)
  94.         {
  95.             if(regbuf[ucK] & 0x80 )
  96.                 RN8209D_MOSI_SET();
  97.             else
  98.                 RN8209D_MOSI_CLR();
  99.             RN8209D_SCK_SET();
  100.             delay_us(RN_CLOCKWIDTH);
  101.             RN8209D_SCK_CLR();      //在时钟的下降沿写数据
  102.             regbuf[ucK]<<=1;
  103.             delay_us(RN_CLOCKWIDTH);
  104.         }
  105.     }
  106.     RN8209D_MOSI_CLR();
  107.     delay_us(100);
  108.     RN8209D_CS_SET();
  109.     delay_us(100);
  110.     RN8209D_SCK_CLR();
  111.     delay_us(100);
  112. }

  113. uint8_t RN8209D_WriteReg(uint8_t addr,uint8_t *regbuf,uint8_t regbuflen)
  114. {
  115.     uint8_t buf[4];

  116.     RN8209D_WriteRegNoCheck(addr,regbuf,regbuflen);
  117.     m_memset(buf,0,4);
  118.     RN8209D_WriteRegNoCheck(Reg_WData,buf,regbuflen);

  119.     if(regbuflen == 3){
  120.         if(m_memcmp(regbuf,buf+1,regbuflen) == 0)
  121.             return 0;
  122.         else
  123.             return 1;
  124.     }
  125.     else if(regbuflen == 4){
  126.         if(m_memcmp(regbuf,buf,regbuflen) == 0)
  127.             return 0;
  128.         else
  129.             return 1;
  130.     }
  131.     else if(regbuflen == 2){
  132.         if(m_memcmp(regbuf,buf+2,regbuflen) == 0)
  133.             return 0;
  134.         else
  135.             return 1;
  136.     }
  137.     else{
  138.         return 1;
  139.     }
  140. }
复制代码

3---------------------------------------RN8209 寄存器-------------------------------------------------------------------------
寄存器主要分2块,校表参数寄存器和计量参数寄存器
RN8209校表寄存器.png (137.38 KB, 下载次数: 0) 下载附件 2018-10-15 10:28 上传
RN8209计量参数寄存器.png (138.01 KB, 下载次数: 0) 下载附件 2018-10-15 10:28 上传

4---------------------------------------RN8209 特殊命令------------------------------------------------------------------------
RN8209部分寄存器进行写操作时,需要先发送写使能,才可以对寄存器操作,这点需要注意;同时,对RN8209芯片操作时,需要先发送复位命令哦;
RN8209特殊命令.png (131.62 KB, 下载次数: 0) 下载附件 2018-10-15 10:40 上传

5---------------------------------------RN8209 初始化(非校表初始化)------------------------------------------------------------------------
RN8209参数设置.png (21.54 KB, 下载次数: 0) 下载附件 2018-10-15 10:55 上传
这是RN8209需要用的变量,我把它放到结构体里,方便观察
  1. typedef struct{
  2.     uint16_t Cst_HFConst;
  3.     uint16_t Cst_PStart;  //有功启动功率
  4.     uint16_t Cst_DStart;
  5.     uint16_t Cst_GPQA;    //A通道功率增益校正
  6.     uint16_t Cst_GPQB;    //B通道功率增益校正
  7.     uint8_t  Cst_PhsA;    //A通道相位校正
  8.     uint8_t  Cst_PhsB;    //B通道相位校正
  9.     uint16_t Cst_QPhsCal; //无功相位校正
  10.     uint16_t Cst_APOSA;   //A通道有功功率offset校正
  11.     uint16_t Cst_APOSB;   //B通道有功功率offset校正
  12.     uint16_t Cst_RPOSA;   //A通道无功功率offset校正
  13.     uint16_t Cst_RPOSB;   //B通道无功功率offset校正
  14.     uint16_t Cst_IARMSOS; //A通道电流有效值offset校正
  15.     uint16_t Cst_IBRMSOS; //B通道电流有效值offset校正
  16.     uint16_t Cst_IBGain;  //B通道电流增益

  17.     uint16_t Cst_Ku;
  18.     uint32_t Cst_Kia;
  19.     uint32_t Cst_Kib;

  20.     uint16_t cheskSum;

  21. }StDef_RN8209DPara;
复制代码
  1. uint8_t RN8209D_Init(void)
  2. {
  3.     uint8_t regbuf[4];
  4.     uint8_t status = 1;

  5.     RN8209D_GPIOConfig();

  6.     RN8209D_RST_CLR();
  7.     delay_ms(100);
  8.     RN8209D_RST_SET();
  9.     delay_ms(100);

  10.     //读取RN8209 DeviceID
  11.     if(RN8209D_ReadReg(Reg_DeviceID,regbuf,3) == 0)
  12.     {
  13.         if((regbuf[0]==0x82)&&(regbuf[1]==0x09)&&(regbuf[2]==0x00)){
  14.             status = 0;
  15.         }
  16.         else{
  17.             status = 1;
  18.         }
  19.     }

  20.     //默认换算系数
  21.     //StDef_RN8209DPara_Reg.Cst_Kia = 41938;
  22.     //StDef_RN8209DPara_Reg.Cst_Kib = 44529;
  23.     //StDef_RN8209DPara_Reg.Cst_Ku  = 8711;

  24.     if(status == 0)
  25.     {
  26.         //写使能
  27.         regbuf[0] = 0xE5;
  28.         RN8209D_WriteReg(WREN,regbuf,1);
  29.         //复位
  30.         regbuf[0] = 0xFA;
  31.         RN8209D_WriteReg(WREN,regbuf,1);
  32.         delay_ms(20);
  33.         //写使能
  34.         regbuf[0] = 0xE5;
  35.         RN8209D_WriteReg(WREN,regbuf,1);
  36.         //系统控制寄存器
  37.         regbuf[0] = 0x00;
  38.         regbuf[1] = 0x51;  //开启通道B,A、B通道增益2
  39.         RN8209D_WriteReg(Reg_SYSCON,regbuf,2);
  40.         m_memset(regbuf,0,2);
  41.         RN8209D_ReadReg(Reg_SYSCON,regbuf,2);
  42.         //写HFCONST
  43.         regbuf[0] = 0x35;
  44.         regbuf[1] = 0x7B;
  45.         RN8209D_WriteReg(Reg_HFCONST,regbuf,2);
  46.         m_memset(regbuf,0,2);
  47.         RN8209D_ReadReg(Reg_HFCONST,regbuf,2);
  48.         //启动功率
  49.         regbuf[0] = 0x01;
  50.         regbuf[1] = 0x2D;
  51.         RN8209D_WriteReg(Reg_PStart,regbuf,2);
  52.         regbuf[0] = 0x01;
  53.         regbuf[1] = 0x2D;
  54.         RN8209D_WriteReg(Reg_DStart,regbuf,2);
  55.         //计量控制
  56.         regbuf[0] = 0x80;  //电能读后清零
  57.         regbuf[1] = 0x03;
  58.         RN8209D_WriteReg(Reg_EMUCON,regbuf,2);
  59.         //计量控制2
  60.         regbuf[0] = 0x00;
  61.         regbuf[1] = 0xB0;
  62.         RN8209D_WriteReg(Reg_EMUCON2,regbuf,2);
  63.         //A通道有功功率增益
  64.         //StDef_RN8209DPara_Reg.Cst_GPQA = 0;
  65.         regbuf[0] = StDef_RN8209DPara_Reg.Cst_GPQA/256;
  66.         regbuf[1] = StDef_RN8209DPara_Reg.Cst_GPQA%256;
  67.         RN8209D_WriteReg(Reg_GPQA,regbuf,2);
  68.         //B通道有功功率增益
  69.         //StDef_RN8209DPara_Reg.Cst_GPQB = 0;
  70.         regbuf[0] = StDef_RN8209DPara_Reg.Cst_GPQB/256;
  71.         regbuf[1] = StDef_RN8209DPara_Reg.Cst_GPQB%256;
  72.         RN8209D_WriteReg(Reg_GPQB,regbuf,2);
  73.         //A通道相位校正
  74.         //StDef_RN8209DPara_Reg.Cst_PhsA = 0;
  75.         regbuf[0] = StDef_RN8209DPara_Reg.Cst_PhsA;
  76.         RN8209D_WriteReg(Reg_PhsA,regbuf,1);
  77.         //B通道相位校正
  78.         //StDef_RN8209DPara_Reg.Cst_PhsB = 0;
  79.         regbuf[0] = StDef_RN8209DPara_Reg.Cst_PhsB;
  80.         RN8209D_WriteReg(Reg_PhsB,regbuf,1);
  81.         //A通道有功功率offset
  82.         //StDef_RN8209DPara_Reg.Cst_APOSA = 0;
  83.         regbuf[0] = StDef_RN8209DPara_Reg.Cst_APOSA/256;
  84.         regbuf[1] = StDef_RN8209DPara_Reg.Cst_APOSA%256;
  85.         RN8209D_WriteReg(Reg_APOSA,regbuf,2);
  86.         //B通道有功功率offset
  87.         //StDef_RN8209DPara_Reg.Cst_APOSB = 0;
  88.         regbuf[0] = StDef_RN8209DPara_Reg.Cst_APOSB/256;
  89.         regbuf[1] = StDef_RN8209DPara_Reg.Cst_APOSB%256;
  90.         RN8209D_WriteReg(Reg_APOSB,regbuf,2);
  91.         //A通道无功功率offset
  92.         StDef_RN8209DPara_Reg.Cst_RPOSA = 0;
  93.         regbuf[0] = StDef_RN8209DPara_Reg.Cst_RPOSA/256;
  94.         regbuf[1] = StDef_RN8209DPara_Reg.Cst_RPOSA%256;
  95.         RN8209D_WriteReg(Reg_RPOSA,regbuf,2);
  96.         //B通道无功功率offset
  97.         StDef_RN8209DPara_Reg.Cst_RPOSB = 0;
  98.         regbuf[0] = StDef_RN8209DPara_Reg.Cst_RPOSB/256;
  99.         regbuf[1] = StDef_RN8209DPara_Reg.Cst_RPOSB%256;
  100.         RN8209D_WriteReg(Reg_RPOSB,regbuf,2);
  101.         //A通道电流offset
  102.         //StDef_RN8209DPara_Reg.Cst_IARMSOS = 0;
  103.         regbuf[0] = StDef_RN8209DPara_Reg.Cst_IARMSOS/256;
  104.         regbuf[1] = StDef_RN8209DPara_Reg.Cst_IARMSOS%256;
  105.         RN8209D_WriteReg(Reg_IARMSOS,regbuf,2);
  106.         //B通道电流offset
  107.         //StDef_RN8209DPara_Reg.Cst_IBRMSOS = 0;
  108.         regbuf[0] = StDef_RN8209DPara_Reg.Cst_IBRMSOS/256;
  109.         regbuf[1] = StDef_RN8209DPara_Reg.Cst_IBRMSOS%256;
  110.         RN8209D_WriteReg(Reg_IBRMSOS,regbuf,2);
  111.         //B通道电流增益
  112.         StDef_RN8209DPara_Reg.Cst_IBGain = 0;
  113.         regbuf[0] = StDef_RN8209DPara_Reg.Cst_IBGain/256;
  114.         regbuf[1] = StDef_RN8209DPara_Reg.Cst_IBGain%256;
  115.         RN8209D_WriteReg(Reg_IBGain,regbuf,2);
  116.         //直流通道
  117.         regbuf[0]=0;regbuf[1]=0;
  118.         RN8209D_WriteReg(Reg_D2FPL,regbuf,2);
  119.         regbuf[0]=0;regbuf[1]=0;
  120.         RN8209D_WriteReg(Reg_D2FPH,regbuf,2);
  121.         regbuf[0]=0;regbuf[1]=0;
  122.         RN8209D_WriteReg(Reg_DCIAH,regbuf,2);
  123.         regbuf[0]=0;regbuf[1]=0;
  124.         RN8209D_WriteReg(Reg_DCIBH,regbuf,2);
  125.         regbuf[0]=0;regbuf[1]=0;
  126.         RN8209D_WriteReg(Reg_DCUH,regbuf,2);
  127.         regbuf[0]=0;regbuf[1]=0;
  128.         RN8209D_WriteReg(Reg_DCL,regbuf,2);
  129.         //写保护
  130.         regbuf[0] = 0xDC;
  131.         RN8209D_WriteReg(WREN,regbuf,1);
  132.         //获取校表寄存器校验值
  133.         RN8209D_GetCheckSum();
  134.     }

  135.     return status;
  136. }
复制代码

6---------------------------------------RN8209 校表初始化)------------------------------------------------------------------------
  1. void RN8209D_CalibrateInit(void)
  2. {
  3.     uint8_t regbuf[4];
  4.     uint8_t status = 1;

  5.     //读取RN8209 DeviceID
  6.     if(RN8209D_ReadReg(Reg_DeviceID,regbuf,3) == 0){
  7.         if((regbuf[0]==0x82)&&(regbuf[1]==0x09)&&(regbuf[2]==0x00)){
  8.             status = 0;
  9.         }
  10.         else{
  11.             status = 1;
  12.         }
  13.     }

  14.     //默认换算系数
  15.     //StDef_RN8209DPara_Reg.Cst_Kia = 41938;
  16.     //StDef_RN8209DPara_Reg.Cst_Kib = 44529;
  17.     //StDef_RN8209DPara_Reg.Cst_Ku = 8711;
  18.     if(status == 0){
  19.         //写使能
  20.         regbuf[0] = 0xE5;
  21.         RN8209D_WriteReg(WREN,regbuf,1);
  22.         //复位
  23.         regbuf[0] = 0xFA;
  24.         RN8209D_WriteReg(WREN,regbuf,1);
  25.         delay_ms(20);
  26.         //写使能
  27.         regbuf[0] = 0xE5;
  28.         RN8209D_WriteReg(WREN,regbuf,1);
  29.         //系统控制寄存器
  30.         regbuf[0] = 0x00;
  31.         regbuf[1] = 0x51;  //开启通道B
  32.         RN8209D_WriteReg(Reg_SYSCON,regbuf,2);
  33.         m_memset(regbuf,0,2);
  34.         RN8209D_ReadReg(Reg_SYSCON,regbuf,2);
  35.         //写HFCONST
  36.         regbuf[0] = 0x35;
  37.         regbuf[1] = 0x7B;
  38.         RN8209D_WriteReg(Reg_HFCONST,regbuf,2);
  39.         m_memset(regbuf,0,2);
  40.         RN8209D_ReadReg(Reg_HFCONST,regbuf,2);
  41.         //启动功率
  42.         regbuf[0] = 0x01;
  43.         regbuf[1] = 0x2D;
  44.         RN8209D_WriteReg(Reg_PStart,regbuf,2);
  45.         regbuf[0] = 0x01;
  46.         regbuf[1] = 0x2D;
  47.         RN8209D_WriteReg(Reg_DStart,regbuf,2);
  48.         //计量控制
  49.         regbuf[0] = 0x80;  //电能读后清零
  50.         regbuf[1] = 0x03;
  51.         RN8209D_WriteReg(Reg_EMUCON,regbuf,2);
  52.         //计量控制2
  53.         regbuf[0] = 0x00;
  54.         regbuf[1] = 0xB0;  //自定义电能寄存器为B通道
  55.         RN8209D_WriteReg(Reg_EMUCON2,regbuf,2);
  56.         //B通道电流增益
  57.         regbuf[0] = 0;
  58.         regbuf[1] = 0;
  59.         RN8209D_WriteReg(Reg_IBGain,regbuf,2);
  60.         //A通道有功功率增益
  61.         regbuf[0] = 0;
  62.         regbuf[1] = 0;
  63.         RN8209D_WriteReg(Reg_GPQA,regbuf,2);
  64.         //B通道有功功率增益
  65.         regbuf[0] = 0;
  66.         regbuf[1] = 0;
  67.         RN8209D_WriteReg(Reg_GPQB,regbuf,2);
  68.         //A通道相位校正
  69.         regbuf[0] = 0;
  70.         RN8209D_WriteReg(Reg_PhsA,regbuf,1);
  71.         //B通道相位校正
  72.         regbuf[0] = 0;
  73.         RN8209D_WriteReg(Reg_PhsB,regbuf,1);
  74.         //A通道有功功率offset
  75.         regbuf[0] = 0;
  76.         regbuf[1] = 0;
  77.         RN8209D_WriteReg(Reg_APOSA,regbuf,2);
  78.         //B通道有功功率offset
  79.         regbuf[0] = 0;
  80.         regbuf[1] = 0;
  81.         RN8209D_WriteReg(Reg_APOSB,regbuf,2);
  82.         //A通道无功功率offset
  83.         regbuf[0] = 0;
  84.         regbuf[1] = 0;
  85.         RN8209D_WriteReg(Reg_RPOSA,regbuf,2);
  86.         //B通道无功功率offset
  87.         regbuf[0] = 0;
  88.         regbuf[1] = 0;
  89.         RN8209D_WriteReg(Reg_RPOSB,regbuf,2);
  90.         //A通道电流offset
  91.         regbuf[0] = 0;
  92.         regbuf[1] = 0;
  93.         RN8209D_WriteReg(Reg_IARMSOS,regbuf,2);
  94.         //B通道电流offset
  95.         regbuf[0] = 0;
  96.         regbuf[1] = 0;
  97.         RN8209D_WriteReg(Reg_IBRMSOS,regbuf,2);
  98.         //校表时不要写保护
  99.     }
  100. }
复制代码

7---------------------------------------RN8209 校表步骤------------------------------------------------------------------------
详细流程参考手册
RN8209校表流程.png (22.33 KB, 下载次数: 0) 下载附件 2018-10-15 11:04 上传

将校表台电压设置220V,5A
(1)电压、电流系数校准
  1. /********************************************************
  2. 功能描述:   计算电压、电流显示转换系数
  3. 参数说明:
  4. 返回说明:
  5. 调用方式:
  6. 全局变量:
  7. 读写时间:
  8. 注意事项:
  9. 日期    :
  10. ********************************************************/
  11. void RN8209D_CalibrateKx(uint8_t phase)
  12. {
  13.     uint8_t regbuf[3];
  14.     //uint32_t tempValue;
  15.     uint32_t regtemp[12],regtotal=0;
  16.     uint8_t i = 0;

  17.     if(phase == phase_A){
  18.         for(i=0;i<12;i++)
  19.         {
  20.             if(RN8209D_ReadReg(Reg_URMS,regbuf,3)==0){
  21.                 regtemp[i] = (regbuf[0]<<16)+(regbuf[1]<<8)+(regbuf[2]);
  22.             }
  23.             delay_ms(350);
  24.         }
  25.         //第一个数据不要
  26.         for(i=1;i<12;i++){
  27.             regtotal += regtemp[i];
  28.         }
  29.         regtotal /= 11;
  30.         StDef_RN8209DPara_Reg.Cst_Ku = regtotal / 220;

  31.         regtotal = 0;

  32.         for(i=0;i<12;i++)
  33.         {
  34.             if(RN8209D_ReadReg(Reg_IARMS,regbuf,3)==0){
  35.                 regtemp[i] = (regbuf[0]<<16)+(regbuf[1]<<8)+(regbuf[2]);
  36.             }
  37.             delay_ms(350);
  38.         }
  39.         //第一个数据不要
  40.         for(i=1;i<12;i++){
  41.             regtotal += regtemp[i];
  42.         }
  43.         regtotal /= 11;
  44.         StDef_RN8209DPara_Reg.Cst_Kia = regtotal / 5;
  45.     }
  46.     else if(phase == phase_B){
  47.         for(i=0;i<12;i++)
  48.         {
  49.             if(RN8209D_ReadReg(Reg_URMS,regbuf,3)==0){
  50.                 regtemp[i] = (regbuf[0]<<16)+(regbuf[1]<<8)+(regbuf[2]);
  51.             }
  52.             delay_ms(350);
  53.         }
  54.         //第一个数据不要
  55.         for(i=1;i<12;i++){
  56.             regtotal += regtemp[i];
  57.         }
  58.         regtotal /= 11;
  59.         StDef_RN8209DPara_Reg.Cst_Ku = regtotal / 220;

  60.         regtotal = 0;

  61.         for(i=0;i<12;i++)
  62.         {
  63.             if(RN8209D_ReadReg(Reg_IBRMS,regbuf,3)==0){
  64.                 regtemp[i] = (regbuf[0]<<16)+(regbuf[1]<<8)+(regbuf[2]);
  65.             }
  66.             delay_ms(350);
  67.         }
  68.         //第一个数据不要
  69.         for(i=1;i<12;i++){
  70.             regtotal += regtemp[i];
  71.         }
  72.         regtotal /= 11;
  73.         StDef_RN8209DPara_Reg.Cst_Kib = regtotal / 5;
  74.     }
  75. }
复制代码

(2)1.0功率校准
  1. /********************************************************
  2. 功能描述:   误差法校准功率增益
  3. 参数说明:
  4. 返回说明:
  5. 调用方式:
  6. 全局变量:
  7. 读写时间:
  8. 注意事项:
  9. 日期    :
  10. ********************************************************/
  11. void RN8209D_CalibrateGPQxErr(uint8_t phase,int16_t err)
  12. {
  13.     const uint16_t regGPx[]={Reg_GPQA,Reg_GPQB};
  14.     const uint16_t regArry[]={Reg_PowerPA,Reg_PowerPB};
  15.     uint8_t regbuf[5];
  16.     float k = 0;
  17.     uint16_t GPQx;
  18.     uint16_t tempValue;

  19.     //判断是否是负数
  20.     if(err & 0x8000){
  21.         err &= 0x7fff;
  22.         err = -err;
  23.     }

  24.     k = (-err/10000.0)/(1+err/10000.0);
  25.     if(k > 0){
  26.         GPQx = (uint16_t)(k*32768);
  27.         //写使能
  28.         regbuf[0] = 0xE5;
  29.         RN8209D_WriteReg(WREN,regbuf,1);
  30.         regbuf[0] = GPQx/256;
  31.         regbuf[1] = GPQx%256;
  32.         RN8209D_WriteReg(regGPx[phase],regbuf,2);
  33.     }
  34.     else{
  35.         GPQx = (uint16_t)(k*32768+65536);
  36.         //写使能
  37.         regbuf[0] = 0xE5;
  38.         RN8209D_WriteReg(WREN,regbuf,1);
  39.         //写寄存器
  40.         regbuf[0] = GPQx/256;
  41.         regbuf[1] = GPQx%256;
  42.         RN8209D_WriteReg(regGPx[phase],regbuf,2);
  43.         m_memset(regbuf,0x00,2);
  44.         RN8209D_ReadReg(regGPx[phase],regbuf,2);
  45.     }
  46.     if(phase == phase_A){
  47.         StDef_RN8209DPara_Reg.Cst_GPQA = GPQx;
  48.         if(RN8209D_ReadReg(regArry[phase],regbuf,2)==0){
  49.             tempValue = regbuf[0]*256+regbuf[1];
  50.             //StDef_RN8209DPara_Reg.Cst_Kpa = tempValue / 1100;
  51.         }
  52.     }
  53.     else if(phase == phase_B){
  54.         StDef_RN8209DPara_Reg.Cst_GPQB = GPQx;
  55.         if(RN8209D_ReadReg(regArry[phase],regbuf,2)==0){
  56.             tempValue = regbuf[0]*256+regbuf[1];
  57.             //StDef_RN8209DPara_Reg.Cst_Kpb = tempValue / 1100;
  58.         }
  59.     }
  60. }
复制代码

(3)0.5L相位校正
将校表台电压设置220V,5A,0.5L
  1. /********************************************************
  2. 功能描述:   误差法校准相位
  3. 参数说明:
  4. 返回说明:
  5. 调用方式:
  6. 全局变量:
  7. 读写时间:
  8. 注意事项:
  9. 日期    :
  10. ********************************************************/
  11. void RN8209D_CalibratePhsXErr(uint8_t phase,int16_t err)
  12. {
  13.     double k = 0;
  14.     uint8_t phsValue = 0;
  15.     const uint16_t regGPx[]={Reg_PhsA,Reg_PhsB};
  16.     uint8_t regbuf[5];

  17.     k = asin(-err/10000.0/1.732)*180/3.142;
  18.     if(k > 0){
  19.         phsValue = (uint8_t)(k/0.02);
  20.     }
  21.     else{
  22.         phsValue = (uint8_t)(k/0.02+512);
  23.     }
  24.     //写使能
  25.     regbuf[0] = 0xE5;
  26.     RN8209D_WriteReg(WREN,regbuf,1);
  27.     //写寄存器
  28.     regbuf[0] = phsValue;
  29.     RN8209D_WriteReg(regGPx[phase],regbuf,1);
  30.     if(phase == phase_A){
  31.         StDef_RN8209DPara_Reg.Cst_PhsA = phsValue;
  32.     }
  33.     else if(phase == phase_B){
  34.         StDef_RN8209DPara_Reg.Cst_PhsB = phsValue;
  35.     }
  36. }
复制代码

(4)5% Ib 功率Offset校正
将校表台电压设置220V,0.25A,1.0
  1. void RN8209D_CalibrateAPOSx(uint8_t phase)
  2. {
  3.     uint8_t regbuf[5];
  4.     uint32_t regtemp[12],regtotal=0;
  5.     const uint16_t regArry[]={Reg_PowerPA,Reg_PowerPB};
  6.     const uint16_t reg_APOSArry[]={Reg_APOSA,Reg_APOSB};
  7.     const uint16_t reg_GPQxArry[]={Reg_GPQA,Reg_GPQB};
  8.     uint8_t i = 0;
  9.     uint16_t temp;
  10.     float gGPQx = 0;
  11.     double k = 0;

  12.     for(i=0;i<12;i++){
  13.         if(RN8209D_ReadReg(regArry[phase],regbuf,4)==0){
  14.             regtemp[i] = (regbuf[0]<<24)+(regbuf[1]<<16)+(regbuf[2]<<8)+(regbuf[3]);
  15.             //求补码
  16.             if(regtemp[i]&0x80000000){
  17.                regtemp[i] = ~regtemp[i];
  18.                regtemp[i] += 1;
  19.             }
  20.         }
  21.         delay_ms(350);
  22.     }
  23.     //第一个数据不要
  24.     for(i=1;i<12;i++){
  25.         regtotal += regtemp[i];
  26.     }
  27.     regtotal /= 11;

  28.     RN8209D_ReadReg(reg_GPQxArry[phase],regbuf,2);
  29.     temp = regbuf[0]*256+regbuf[1];
  30.     if(temp&0x8000)
  31.     {
  32.         gGPQx = (temp-65536)/32768.0;
  33.     }
  34.     else{
  35.         gGPQx = temp/32768.0;
  36.     }

  37.     k = (602299-regtotal)/(1+gGPQx);
  38.     if(k > 0){
  39.         temp = (uint16_t)k;
  40.     }
  41.     else{
  42.         temp = (uint16_t)(k+65536);
  43.     }
  44.     //写使能
  45.     regbuf[0] = 0xE5;
  46.     RN8209D_WriteReg(WREN,regbuf,1);
  47.     //写寄存器
  48.     regbuf[0] = temp/256;regbuf[1] = temp%256;
  49.     RN8209D_WriteReg(reg_APOSArry[phase],regbuf,2);
  50.     if(phase == phase_A){
  51.         StDef_RN8209DPara_Reg.Cst_APOSA = temp;
  52.     }
  53.     else if(phase == phase_B){
  54.         StDef_RN8209DPara_Reg.Cst_APOSB = temp;
  55.     }

  56. }
复制代码

(5)电流Offset校正
将校表台电压设置220V,0A,1.0,只提供电压
  1. /********************************************************
  2. 功能描述:   计算电流通道offset
  3. 参数说明:
  4. 返回说明:
  5. 调用方式:
  6. 全局变量:
  7. 读写时间:
  8. 注意事项:
  9. 日期    :
  10. ********************************************************/
  11. void RN8209D_CalibrateCurrentOffset(uint8_t phase)
  12. {
  13.     uint8_t regbuf[5];
  14.     uint32_t regtemp[12],regtotal=0;
  15.     const uint16_t regArry[]={Reg_IARMS,Reg_IBRMS};
  16.     const uint16_t regIx_OS[]={Reg_IARMSOS,Reg_IBRMSOS};
  17.     uint8_t i = 0;
  18.     uint16_t temp;

  19.     for(i=0;i<12;i++)
  20.     {
  21.         if(RN8209D_ReadReg(regArry[phase],regbuf,3)==0){
  22.             regtemp[i] = (regbuf[0]<<16)+(regbuf[1]<<8)+(regbuf[2]);
  23.         }      
  24.         delay_ms(350);
  25.     }
  26.     //第一个数据不要
  27.     for(i=1;i<12;i++){
  28.         regtotal += regtemp[i];
  29.     }
  30.     regtotal /= 11;
  31.     regtotal = regtotal * regtotal;
  32.     //求反码
  33.     regtotal = ~regtotal;
  34.     temp = (regtotal>>8);
  35.     //符号位
  36.     if(regtotal & 0x80000000)
  37.         temp |= 0x8000;
  38.     //写使能
  39.     regbuf[0] = 0xE5;
  40.     RN8209D_WriteReg(WREN,regbuf,1);
  41.     //写寄存器
  42.     regbuf[0] = temp/256;regbuf[1] = temp%256;
  43.     RN8209D_WriteReg(regIx_OS[phase],regbuf,2);
  44.     if(phase == phase_A){
  45.         StDef_RN8209DPara_Reg.Cst_IARMSOS = temp;
  46.     }
  47.     else if(phase == phase_B){
  48.         StDef_RN8209DPara_Reg.Cst_IBRMSOS = temp;
  49.     }
  50. }
复制代码

8---------------------------------------RN8209计量参数读取------------------------------------------------------------------------
(1)电压
  1. /********************************************************
  2. 功能描述:
  3. 参数说明:
  4. 返回说明: 扩大10倍
  5. 调用方式:
  6. 全局变量:
  7. 读写时间:
  8. 注意事项:
  9. 日期    :
  10. ********************************************************/
  11. uint8_t RN8209D_ReadVoltage(uint16_t *vol)
  12. {
  13.     uint8_t  regbuf[3];
  14.     uint32_t tempValue;

  15.     if(RN8209D_ReadReg(Reg_URMS,regbuf,3)==0){
  16.         tempValue = (regbuf[0]<<16)+(regbuf[1]<<8)+(regbuf[2]);
  17.         if(tempValue & 0x800000){
  18.             tempValue = 0;
  19.         }
  20.         else{
  21.             *vol = (uint16_t)(tempValue*10.0/StDef_RN8209DPara_Reg.Cst_Ku);
  22.         }
  23.         return 0;
  24.     }
  25.    
  26.     return 1;
  27.    
  28. }
复制代码

(2)电流
  1. /********************************************************
  2. 功能描述:
  3. 参数说明:
  4. 返回说明: 扩大1000倍
  5. 调用方式:
  6. 全局变量:
  7. 读写时间:
  8. 注意事项:
  9. 日期    :
  10. ********************************************************/
  11. uint8_t RN8209D_ReadCurrent(uint8_t phase,uint16_t *current)
  12. {
  13.     uint8_t  regbuf[3];
  14.     uint32_t tempValue;

  15.     if(phase == phase_A){
  16.         if(RN8209D_ReadReg(Reg_IARMS,regbuf,3)==0){
  17.             tempValue = (regbuf[0]<<16)+(regbuf[1]<<8)+(regbuf[2]);
  18.             if(tempValue & 0x800000){
  19.                 tempValue = 0;
  20.             }
  21.             else{
  22.                 *current = (uint16_t)(tempValue*1000.0/StDef_RN8209DPara_Reg.Cst_Kia);
  23.             }
  24.             return 0;
  25.         }
  26.     }
  27.     else if(phase == phase_B){
  28.         if(RN8209D_ReadReg(Reg_IBRMS,regbuf,3)==0){
  29.             tempValue = (regbuf[0]<<16)+(regbuf[1]<<8)+(regbuf[2]);
  30.             if(tempValue & 0x800000){
  31.                 tempValue = 0;
  32.             }
  33.             else{
  34.                 *current = (uint16_t)(tempValue*1000.0/StDef_RN8209DPara_Reg.Cst_Kib);
  35.             }
  36.             return 0;
  37.         }
  38.     }
  39.     return 1;
  40. }
复制代码

(3)有功功率
  1. /********************************************************
  2. 功能描述:   读取有功功率
  3. 参数说明:
  4. 返回说明:   扩大1000倍
  5. 调用方式:
  6. 全局变量:
  7. 读写时间:
  8. 注意事项:
  9. 日期    :
  10. ********************************************************/
  11. uint8_t RN8209D_ReadPower(uint8_t phase,uint32_t *p)
  12. {
  13.     uint8_t  regbuf[4];
  14.     uint32_t tempValue;

  15.     if(phase == phase_A){
  16.         if(RN8209D_ReadReg(Reg_PowerPA,regbuf,4)==0){
  17.             tempValue = (regbuf[0]<<24)+(regbuf[1]<<16)+(regbuf[2]<<8)+(regbuf[3]);
  18.             if(tempValue&0x80000000){
  19.               tempValue = ~tempValue;
  20.               tempValue += 1;
  21.             }
  22. //            if(tempValue>=21903393){
  23. //                *p = (uint32_t)(tempValue*0.0000457);
  24. //            }
  25. //            else if(tempValue<21903393 && tempValue>=2190339){
  26. //                *p = (uint32_t)(tempValue*10*0.0000457);
  27. //            }
  28. //            else if(tempValue<2190339 && tempValue>=219033){
  29. //                *p = (uint32_t)(tempValue*100*0.0000457);
  30. //            }
  31. //            else if(tempValue<219033){
  32. //                *p = (uint32_t)(tempValue*1000*0.0000457);
  33. //            }

  34.             *p = (uint32_t)(tempValue*0.000457);
  35.             return 0;
  36.         }
  37.     }
  38.     else if(phase == phase_B){
  39.         if(RN8209D_ReadReg(Reg_PowerPB,regbuf,4)==0){
  40.             tempValue = (regbuf[0]<<24)+(regbuf[1]<<16)+(regbuf[2]<<8)+(regbuf[3]);
  41.             if(tempValue&0x80000000){
  42.               tempValue = ~tempValue;
  43.               tempValue += 1;
  44.             }
  45.             *p = (uint32_t)(tempValue*0.0000457);
  46.             return 0;
  47.         }
  48.     }
  49.     return 1;
  50. }
复制代码

(4)有功电能
  1. /********************************************************
  2. 功能描述:   读取累计电量
  3. 参数说明:
  4. 返回说明:   扩大100倍
  5. 调用方式:
  6. 全局变量:
  7. 读写时间:
  8. 注意事项:
  9. 日期    :
  10. ********************************************************/
  11. uint8_t RN8209D_ReadTotalE(uint8_t phase,uint32_t *p)
  12. {
  13.     uint8_t  regbuf[3];
  14.     uint32_t tempValue;

  15.     if(phase == phase_A){
  16.         if(RN8209D_ReadReg(Reg_EnergyP,regbuf,3)==0){
  17.             tempValue = (regbuf[0]<<16)+(regbuf[1]<<8)+(regbuf[2]);
  18.             //*p = (uint32_t)(tempValue*100.0/1200);
  19.             *p = tempValue;
  20.             return 0;
  21.         }
  22.     }
  23.     else if(phase == phase_B){
  24.         if(RN8209D_ReadReg(Reg_EnergyD,regbuf,3)==0){
  25.             tempValue = (regbuf[0]<<16)+(regbuf[1]<<8)+(regbuf[2]);
  26.             //*p = (uint32_t)(tempValue*100.0/1200);
  27.             *p = tempValue;
  28.             return 0;
  29.         }
  30.     }
  31.     return 1;
  32. }
复制代码

----------------------------------------------------------------
单相计量芯片RN8209C、RN8209D用户手册_v1_7.pdf (780.49 KB, 下载次数: 144) 2018-10-15 11:21 上传 点击文件名下载附件
锐能微第三代单相计量芯片应用笔记v1.3.pdf (702.31 KB, 下载次数: 165) 2018-10-15 11:21 上传 点击文件名下载附件

RN8209.C
rn8209.rar (5.08 KB, 下载次数: 127) 2018-10-16 08:24 上传 点击文件名下载附件
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
90条回答
Baldwin
2019-12-17 04:42
梨花 发表于 2019-3-31 22:27
请教下楼主,对于掉电的情况,怎么做到及时保存电量呢?是加掉电检测好呢?还是固定时间存储一次电量好呢? ...

有2种方式:
1、采用掉电存储,这种方式最可靠,平常只需要按照固定电量来存储,比如增加1度电就存储一次;等到掉电时再存储一次;
2、采用固定电量存储,存储就需要采用铁电储存器,这样可以做到0.01度电就存储一次;但是会存在电量计不满0.01度电时因为掉电导致数据丢失的情况;

另外,按照固定时间存储不可取,因为有的时间用电多,有的时间用电少;

我们是按照0.01度电储存一次+掉电储存来做的

一周热门 更多>