stm32+bl0939驱动、应用程序(完整)_bl0939单片机例程-程序员宅基地

技术标签: stm32  计量芯片驱动程序  

BL0939.h

#ifndef __IBL0903_H__
#define __IBL0903_H__

//只读寄存器  名称   地址          功能                     默认值
#define IA_FAST_RMS 0x00 //A 通道快速有效值,无符号        0x000000
#define IA_WAVE     0x01 //A 通道电流波形寄存器,有符号      0x000000
#define IB_WAVE     0x02//B 通道电流波形寄存器,有符号       0x000000
#define V_WAVE      0x03//电压波形寄存器,有符号           0x000000
#define IA_RMS      0x04//A 通道电流有效值寄存器,无符号      0x000000
#define IB_RMS      0x05//B 通道电流有效值寄存器,无符号      0x000000
#define V_RMS       0x06//电压有效值寄存器,无符号          0x000000
#define IB_FAST_RMS 0x07//B 通道快速有效值,无符号         0x000000
#define A_WATT      0x08//A 通道有功功率寄存器,有符号       0x000000
#define B_WATT      0x09//B 通道有功功率寄存器,有符号       0x000000
#define CFA_CNT     0x0A//A 通道有功电能脉冲计数,无符号      0x000000
#define CFB_CNT     0x0B//B 通道有功电能脉冲计数,无符号      0x000000
#define A_CORNER    0x0C//A 通道电流电压波形相角寄存器       0x0000      
#define B_CORNER    0x0D//B 通道电流电压波形相角寄存器       0x0000
#define TPS1        0x0E//B 通道电流电压波形相角寄存器       0x000
#define TPS2        0x0F//外部温度检测寄存器,无符号         0x000
//读写寄存器
#define A_F_RMS_CTL 0x10//A 通道快速有效值控制寄存器        0xFFFF
#define IA_RMSOS    0x13//电流 A 通道有效值小信号校正寄存器    0x00
#define IB_RMSOS    0x14//电流 B 通道有效值小信号校正寄存器    0x00
#define A_WATTOS    0x15//A 通道有功功率小信号校正寄存器      0x00
#define B_WATTOS    0x16//B 通道有功功率小信号校正寄存器      0x00
#define WA_CREEP    0x17//有功功率防潜寄存器                 0x0B
#define MODE        0x18//用户模式选择寄存器                 0x0000
#define SOFT_RESET  0x19//写入 0x5A5A5A时用户区寄存器复位      0x000000
#define USR_WRPROT  0x1A//写入 0x55后用户操作寄存器可以写入;  0x00
#define TPS_CTRL    0x1B//温度模式控制寄存器                 0x07FF
#define TPS2_A      0x1C//外部温度传感器增益系数校正寄存器      0x0000
#define TPS2_B      0x1D//外部温度传感器偏移系数校正寄存器      0x0000
#define B_F_RMS_CTL 0x1E//B 通道快速有效值控制寄存器        0xFFFF

#define RN_SENDMAX      10
#define RN_RECEMAX      10

typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;

typedef enum
{
    
    RET_POW_SUC = 0,
    RET_POW_FAL
} Error_code_t;

typedef struct//发送数据结构体
{
    
  u16 Len;//数据长度
  u8 Data[RN_SENDMAX];//发送数据缓存数组
  u16 HaveSenLen;//记录已经发送的字节数
}RN_SEND;

typedef struct//接收数据结构体
{
    
  u16 Len;
  u8 Data[RN_RECEMAX];
  u16 HaveReceLen;
}RN_RECE;

typedef struct
{
    
    uint64_t base_energy_pow;//通道电量基数
    u32 last_energy_pow;//上次读到的电量基数
}BL0939_Para_t;

  BL0939_Para_t m_para[CHECK_CHANNELS];
  void delay_nms(u32 n);
  void BL_Config(void);//硬件配置
  void BL_GPIOconfig(void);
  void BL_Send(void);//串口发送
  BOOL BL_Write(u8 wreg, u8 *pbuf, u16 uclen,u8 ch);
  BOOL BL_Read(u8 wreg,u8 ch);
  BOOL Block_Rece(void);//阻塞接收+超时处理
  BOOL Block_Send(void);//阻塞发送+超时处理
  Error_code_t WriteData(u8 wreg, u8 *data, u8 len, u8 ch);
  Error_code_t ReadData(u8 wreg, u8 *data, u8 len, u8 ch);
  BOOL BLCheckSum(u8 reg, u8 *data, u8 ch);
  Error_code_t read_ch_pow(float* POW, u8 ch);
  Error_code_t read_ch_cur(u16* Cur, u8 ch);
  Error_code_t read_ch_vol(u16* Vol, u8 ch);
  Error_code_t get_device_id(const u32 m_ch);
  Error_code_t read_ch_energy_pow(u32* Energy_Pow, u8 ch);
  Error_code_t write_ch_oilvl(u16 Over_Cur, u8 ch);
  Error_code_t soft_reset(u8 ch);
  Error_code_t Init(u8 ch);
  Error_code_t set_powercheck_ic( const u32 m_ch);
  u32 calculate_energy(u8 ch, u32 ele);
#endif

BL0939.c

#include "IBL0903.h"

static u8 BUS_ADDR[5] = {
    0x01,0x02,0x03,0x04,0x05};//5片bl0939的地址

RN_SEND RnSend = {
    0}; //发送结构体对象
RN_RECE RnRece = {
    0}; //接收结构体对象
volatile u8 SendFinsh = 0;
volatile u8 ReceFinsh = 0;

typedef struct
{
    
    u8 addr;
    u8 data[3];
}BL0903_req_t;

static BL0903_req_t config_req[] ={
    
  {
    MODE,{
    0x00,0x10,0x00}},//报警功能开启50hz 400ms/
  {
    TPS_CTRL,{
    0xff,0xff,0x00}},//开启A通道过流,漏电报警
  {
    A_F_RMS_CTL,{
    0xE6,0xF4,0x00}},//短路40A:0x3A77  80A:0x74E6
  {
    B_F_RMS_CTL,{
    0x62,0x84,0x00}},//漏电30mA
};


void main()
{
    
    BL_Config();//通信串口配置

    for(u8 i=1;i<11;i++)
    {
    //挨个配置芯片
        if(i%2)
            continue;//每个芯片双通道,只需要配置一次
        if(Init(i) == RET_POW_FAL)//芯片初始化
        {
    
            Dprintf(EN_LOG, TAG, "芯片 %d 初始化**失败**\r\n", i);
        }
        else
        {
    
            if(set_powercheck_ic(i) == RET_POW_FAL)
            {
    
                Dprintf(EN_LOG, TAG, "芯片 %d 配置**失败**\r\n", i);
            }
        }
    }

    //测试读取1通道的数据
    //读取电流
    u16 cur;
    read_ch_cur(&cur, 1);

    //读取电压
    u16 vol;
    read_ch_vol(&vol, 1)

    //读取功率
    float pow
    read_ch_pow(&pow, 1);
   
   //读取电量
   u32 ele;
   read_ch_energy_pow(&ele, 1);
}

/*******************************************************************************
 函 数 名: delay_nms
 功能描述: 延时nms
 入口参数: n:ms数
 出口参数: 无
********************************************************************************/
void delay_nms(u32 n)
{
    
    u32 t = 14000;
	while (n--)
	{
    
        while (t--);
    }		
}

//串口配置
void BL_Config(void)
{
    
    USART_DeInit(USART2);//复位串口
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    //时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);  //GPIOD时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);//使能USART2
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//使能重映射
    GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);//IO映射

    //USART2_TX  GPIOD.5
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;         //PD.5
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //频率50M
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   //复用推挽输出
    GPIO_Init(GPIOD, &GPIO_InitStructure);            //初始化GPIOA.2
    GPIO_SetBits(GPIOD, GPIO_Pin_5);
    //USART2_RX  GPIOD.6
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;             //PD6
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
    GPIO_Init(GPIOD, &GPIO_InitStructure);                //初始化GPIOA.3
    //USART2初始化配置
    USART_InitStructure.USART_BaudRate = 4800;                                      //波特率4800
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;                     //数据8位
    USART_InitStructure.USART_StopBits = USART_StopBits_1_5;                          //1.5位停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;                           //无校验
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                 //收发模式
    USART_Init(USART2, &USART_InitStructure);                                       //初始化UART2

    //USART2 NVIC初始化
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);
    USART_ClearFlag(USART2, USART_FLAG_TC);
    USART_ClearFlag(USART2, USART_FLAG_IDLE);
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //开启接收中断,RXNE读寄存器非空
    USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); //使能接收一帧数据中断
    USART_ITConfig(USART2, USART_IT_TC, ENABLE);   //开启发送中断,TC发送完成    
    USART_Cmd(USART2, ENABLE);                     //使能串口2
}

//过载中断配置
void BL_GPIOconfig(void)
{
    //中断配置
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,ENABLE);
    GPIOMode_TypeDef m_gpiotypedef = USE_HW_BL0939CH4 ? GPIO_Mode_IPD : GPIO_Mode_IPU;
    EXTITrigger_TypeDef m_extitypedef = USE_HW_BL0939CH4 ? EXTI_Trigger_Rising : EXTI_Trigger_Falling;
    //CF A通道过载 空闲高电平,过载低电平 PC1
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = m_gpiotypedef; //上拉输入
    GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化GPIOC1
    //B_LEAK B通道过载 空闲高电平,过载低电平 PD9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_Init(GPIOD, &GPIO_InitStructure); //初始化GPIOD9
    //ZX 过零 PC2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化GPIOC2
    
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //使能复用功能时钟
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = m_extitypedef;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource1);
    EXTI_InitStructure.EXTI_Line = EXTI_Line1;
    EXTI_Init(&EXTI_InitStructure);
    
    //ZX 过零 PC2
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource2);
    EXTI_InitStructure.EXTI_Line = EXTI_Line2;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//过零设为双边沿
    EXTI_Init(&EXTI_InitStructure);
    
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
    NVIC_Init(&NVIC_InitStructure);
    EXTI->IMR &= ~ (EXTI_Line2);//禁能过零中断
    
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //响应优先级
    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
    NVIC_Init(&NVIC_InitStructure);   
    
    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
    NVIC_Init(&NVIC_InitStructure);
}

//命令复位
Error_code_t soft_reset(u8 ch)
{
    //ch [0-9]
    static u8 reset_count = 0;
    u8 t_data[3] = {
    0x55,0x00,0x00};
    u8 reset[3] = {
    0x5A,0x5A,0x5A};
    BL_Write(USR_WRPROT, t_data, 3, ch+1);//写使能
    BL_Write(SOFT_RESET, reset, 3, ch+1);//写数据
    delay_nms(3);
    u8 r_data[3] ={
    0};
    if((ReadData(MODE, r_data, 3, ch+1) == RET_POW_SUC) && r_data[1]==0)
    {
    
        Dprintf(EN_LOG, TAG, "通道 %d 复位**成功**\r\n", ch+1);
    }
    else
    {
    
        if(++reset_count>3)
        {
    
            reset_count = 0;
            return RET_POW_FAL;
        }
        else
            return soft_reset(ch);
    }
    delay_nms(5);
    reset_count = 0;
    return RET_POW_SUC;
}

//芯片初始化
Error_code_t Init(u8 ch)
{
        
    return ((get_device_id(m_ch) == RET_POW_SUC)?RET_POW_SUC:RET_POW_FAL);//读取id检验通信是否成功
}

//读取芯片id
Error_code_t get_device_id(const u32 ch)
{
    
    static u8 fail_count = 0;
    u8 id = 0;
    if((ReadData(WA_CREEP, &id, 1, ch) == RET_POW_SUC) && (id == 0x0B))
    {
    
        fail_count = 0;
        delay_nms(5);
    }
    else
    {
    //读取失败,重复读取
        if(++fail_count >= 3)
        {
    
            fail_count = 0;
            return RET_POW_FAL;
        }
        return get_device_id(ch);
    }
    return RET_POW_SUC;
}

//配置芯片寄存器
Error_code_t set_powercheck_ic( const u32 ch)
{
    
    u8 temp_addr = 0;    
    Dprintf(EN_LOG, TAG, "通道 %d 检测芯片初始化**成功**\r\n", ch);
    soft_reset(ch);
    for (u8 i = 0; i < (sizeof(config_req) / sizeof(BL0903_req_t)); i++)
    {
    
        temp_addr = config_req[i].addr;
        if(WriteData(temp_addr,config_req[i].data,3,ch) == RET_POW_FAL)
        {
    
            Dprintf(EN_LOG, TAG, "通道 %d 检测芯片初始化**失败**\r\n", ch);
            return RET_POW_FAL;
        }
        delay_nms(1);
    }
    BL_GPIOconfig();//中断配置
    return RET_POW_SUC;
}

//设置过载电流
Error_code_t write_ch_oilvl(u16 Over_Cur, u8 ch)
{
    
    u8 addr = (ch%2)?A_F_RMS_CTL:B_F_RMS_CTL;
    Over_Cur |= 0x8000;//周波刷新
    u8 data[2] = {
    Over_Cur&0xff,(Over_Cur>>8)};
    if(WriteData(addr, data, 2, ch) == RET_POW_FAL)
    {
    
        Dprintf(EN_LOG, TAG, "通道 %d 过流设置**失败**\r\n", ch);
        return RET_POW_FAL;
    }
    return RET_POW_SUC;
}

//往芯片写数据
Error_code_t WriteData(u8 wreg, u8 *data, u8 len, u8 ch)
{
    
    static u8 time_count = 0;
    u8 t_data[3] = {
    0x55,0x00,0x00};
    BL_Write(USR_WRPROT, t_data, 3, ch);//写使能
    BL_Write(wreg, data, len, ch);//写数据
    t_data[0] = 0;
    BL_Write(USR_WRPROT, t_data, 3, ch);//写禁能
    u8 r_data[3] ={
    0};
    ReadData(wreg, r_data, 3, ch);
    if(memcmp(data, r_data, len)!=0)
    {
    
        if(time_count++ >=3)
        {
    
            time_count = 0;
            return RET_POW_FAL;
        }
        return WriteData(wreg, data, len, ch);
    }
    time_count = 0;
    return RET_POW_SUC;
}

//从芯片读数据
Error_code_t ReadData(u8 wreg, u8 *data, u8 len, u8 ch)
{
    
    u8 temp_buf[4] = {
    0};
    if(BL_Read(wreg, ch) == TRUE)
    {
    //读指令发送成功
        if(Block_Rece() == TRUE)
        {
    //数据读取成功
            memcpy(temp_buf, RnRece.Data, 4);
            ReceFinsh = 0;
            RnRece.HaveReceLen = 0;            
            if(BLCheckSum(wreg, temp_buf, ch) == TRUE)
            {
    
                memcpy(data, temp_buf, len);
                return RET_POW_SUC;
            }
        }
    }
    ReceFinsh = 0;
    return RET_POW_FAL;
}

//串口写数据
BOOL BL_Write(u8 wReg, u8 *pBuf, u16 ucLen, u8 ch)
{
    
    memset(RnSend.Data, 0, sizeof(RnSend.Data)); //清空发送缓存数组
    u8 chksum = 0,num =0;
    u8 addr = BUS_ADDR[(ch-1)/2] | 0xA0;//写命令+从机地址
    chksum += addr;
    RnSend.Data[num++] = addr;
    chksum += wReg;
    RnSend.Data[num++] = wReg;
    for(u8 i=0; i<ucLen; i++)
    {
    
        RnSend.Data[num++] = pBuf[i];
        chksum += pBuf[i];
    }
    chksum = ~chksum;
    RnSend.Data[5] = chksum;
    RnSend.Len = 6;//从机地址 寄存器 三字节数据 校验
    RnSend.HaveSenLen = 1;
    BL_Send();
    return Block_Send();
}

//串口读数据
BOOL BL_Read(u8 wReg, u8 ch)
{
    
    memset(RnSend.Data, 0, sizeof(RnSend.Data)); //清空发送缓存数组
    memset(RnRece.Data, 0, sizeof(RnRece.Data)); //清空接收缓存数组
    RnSend.Data[0] = BUS_ADDR[(ch-1)/2] | 0x50;//读命令+从机地址
    RnSend.Data[1] = wReg;
    RnSend.Len = 2;
    RnSend.HaveSenLen = 1;
    BL_Send();
    return Block_Send();
}

//校验数据是否正确
BOOL BLCheckSum(u8 reg, u8 *data, u8 ch)
{
    
    u8 checksum = 0;
    u8 addr = 0x50 | BUS_ADDR[(ch-1)/2];
    checksum += addr;
    checksum += reg;
    for(u8 i=0; i<3; i++)
        checksum += data[i];
    checksum = ~checksum;
    return (checksum == data[3])?TRUE:FALSE;
}

//等待发送完成
BOOL Block_Send(void)
{
    
    u32 t = 0;
    while (!SendFinsh)
    {
    
        if (++t > 1400 * 1000) //14000 == 1ms
        {
    
            GPIO_SetBits(GPIOD, GPIO_Pin_5);
            return FALSE; //读取超时,说明芯片不正常
        }
    }    
    return TRUE;
}

//等待接收完成
BOOL Block_Rece(void)
{
    
    u32 t = 0;
    while (!ReceFinsh)
    {
    
        if (++t > 1400 * 1000) //14000 == 1ms
        {
    
            return FALSE; //读取超时,说明芯片不正常
        }
    }
    return TRUE;
}

//串口发送
void BL_Send()
{
    
    USART_ClearFlag(USART2, USART_FLAG_TC); //清除传输完成标志位,否则可能会丢失第1个字节的数据
                                            //此处第一次发送触发发送中断,后面字节都在中断服务程序发送,注意地址++避免首字节重复发送
    SendFinsh = 0;
    USART2->DR = RnSend.Data[0];
}

//读取电流值
//下面具体参数需按实际电路中的参数
Error_code_t read_ch_cur(u16 *Cur, u8 ch)
{
    
    u8 read_reg;
    read_reg = (ch%2)?IA_RMS:IB_RMS;
    u8 temp_cur[3] = {
    0};
    u8 RL = 2;
    float R5 = 10.2;
    u32 Rt = 2000;
    float ptf_cur = 0.0;
    if(ReadData(read_reg, temp_cur, 3, ch) == RET_POW_SUC)
    {
    
        ptf_cur = (float)(*(u32*)temp_cur * 1.218)/(324004*RL);
        Dprintf(EN_LOG,TAG,"通道 %d cur : %.3f \r\n",ch,ptf_cur);
        *Cur = (u16)ptf_cur;
        return RET_POW_SUC;
    }
    return RET_POW_FAL;
}

//读取功率
//下面参数需按照实际电路
Error_code_t read_ch_pow(float *Pow, u8 ch)
{
    
    u8 read_reg;    
    read_reg = (ch%2)?A_WATT:B_WATT;
    u8 temp_pow[3] = {
    0};
    u8 RL = 2;
    float R5 = 10.2;
    float R17 = 0.0239;
    u32 Rt = 2000;
    if(ReadData(read_reg, temp_pow, 3, ch) == RET_POW_SUC)
    {
    
        u32 t_pow = *(u32*)temp_pow;
        if(t_pow & 0x00800000)
        {
    //负数处理
            t_pow = ((~t_pow)&0x00FFFFFF)+1;
        }
        double divisor, dividend;
        divisor = 4046*RL*0.24*1000.0;
        dividend = t_pow * 1.483524 * 1000.24;
        *Pow = (float)(dividend/divisor);
        Dprintf(EN_LOG,TAG,"通道 %d pow : %.3f \r\n",ch,*Pow);
        return RET_POW_SUC;
    }
    return RET_POW_FAL;
}

//读取电压值
//计算公式按实际电路
Error_code_t read_ch_vol(u16 *Vol, u8 ch)
{
       
    u8 temp_vol[3] = {
    0};
    u32 temp_reg = 0;
    if(ReadData(V_RMS, temp_vol, 3, ch) == RET_POW_SUC)
    {
    
        temp_reg = *(u32*)(temp_vol);
        *Vol = (u16)(((double)temp_reg * 1.218 * (float)(200*5+0.24))/(79931*240));
        Dprintf(EN_LOG,TAG,"通道 %d vol : %d \r\n",ch,*Vol);
        return RET_POW_SUC;
    }
    return RET_POW_FAL;
}

//读取用电量
Error_code_t read_ch_energy_pow(u32* Energy_Pow, u8 ch)
{
    
    u8 read_addr;
    read_addr = (ch%2)?CFA_CNT:CFB_CNT;
    u8 temp_energy[3] = {
    0};
    if(ReadData(read_addr, temp_energy, 3, ch) == RET_POW_SUC)
    {
    
        u32 t_energy = *(u32*)temp_energy;
        if(t_energy & 0x00800000)
        {
    //负数处理
            t_energy = ((~t_energy)&0x00FFFFFF)+1;
        }        
        m_para[ch-1].base_energy_pow += ((t_energy>m_para[ch-1].last_energy_pow)?(t_energy-m_para[ch-1].last_energy_pow):0);
        Dprintf(YELLOW,"","通道 %d 本次:%d 上次:%d 累计:%d\r\n",ch,t_energy,m_para[ch-1].last_energy_pow,m_para[ch-1].base_energy_pow);
        m_para[ch-1].last_energy_pow = t_energy;
        *Energy_Pow = t_energy;        
        return RET_POW_SUC;
    }
    return RET_POW_FAL;
}

//计算用电量
u32 IBL0903::calculate_energy(u8 ch, u32 ele)
{
    
    u8 RL = 2;
	float R5 = 10.2;
    float R17 = 0.0239;    
    u32 Rt = 2000;
    double energy;
	u32 rtn;
    energy = (double)(1638.4*256*1.218*1.218*1000.24)/(double)((uint64_t)3600000*4046*0.24*RL);//每个脉冲多少毫度
    rtn = (u32)(ele * energy);
    Dprintf(GREEN,"","通道%d 脉冲%d 毫度%d\r\n",ch,ele,rtn);
    return rtn;
}


/*************************************************************
**函数原型  USART2_IRQHandler
**功能描述  串口2中断处理函数
**入口参数  无
**出口参数  无
*************************************************************/
extern "C"
{
    
    void USART2_IRQHandler()
    {
    
        while (1)
        {
    
            if (USART2->SR & (1 << 5)) //接收一字节中断
            {
    
                USART2->SR &= ~(1 << 5);
                RnRece.Data[RnRece.HaveReceLen++] = USART2->DR;
            }
            else if (USART_GetITStatus(USART2, USART_IT_IDLE) != RESET) //接收一帧中断
            {
    
                USART_ReceiveData(USART2); //清除IDLE空闲标志位
                USART_ClearFlag(USART2, USART_FLAG_IDLE);
                ReceFinsh = 1;
            }
            else if (USART2->SR & (1 << 6)) //发送中断
            {
    
                USART2->SR &= ~(1 << 6);
                //if()判断发送的长度是否发送结束
                if (RnSend.HaveSenLen < RnSend.Len)
                {
    
                    USART2->DR = RnSend.Data[RnSend.HaveSenLen++];
                }
                else
                {
    
                    RnSend.HaveSenLen = 1;
                    SendFinsh = 1;
                }
            }
            else
            {
    
                break;
            }
        }
    }
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_33315912/article/details/130224894

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签