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

智能推荐

什么是内部类?成员内部类、静态内部类、局部内部类和匿名内部类的区别及作用?_成员内部类和局部内部类的区别-程序员宅基地

文章浏览阅读3.4k次,点赞8次,收藏42次。一、什么是内部类?or 内部类的概念内部类是定义在另一个类中的类;下面类TestB是类TestA的内部类。即内部类对象引用了实例化该内部对象的外围类对象。public class TestA{ class TestB {}}二、 为什么需要内部类?or 内部类有什么作用?1、 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。2、内部类可以对同一个包中的其他类隐藏起来。3、 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。三、 内部类的分类成员内部_成员内部类和局部内部类的区别

分布式系统_分布式系统运维工具-程序员宅基地

文章浏览阅读118次。分布式系统要求拆分分布式思想的实质搭配要求分布式系统要求按照某些特定的规则将项目进行拆分。如果将一个项目的所有模板功能都写到一起,当某个模块出现问题时将直接导致整个服务器出现问题。拆分按照业务拆分为不同的服务器,有效的降低系统架构的耦合性在业务拆分的基础上可按照代码层级进行拆分(view、controller、service、pojo)分布式思想的实质分布式思想的实质是为了系统的..._分布式系统运维工具

用Exce分析l数据极简入门_exce l趋势分析数据量-程序员宅基地

文章浏览阅读174次。1.数据源准备2.数据处理step1:数据表处理应用函数:①VLOOKUP函数; ② CONCATENATE函数终表:step2:数据透视表统计分析(1) 透视表汇总不同渠道用户数, 金额(2)透视表汇总不同日期购买用户数,金额(3)透视表汇总不同用户购买订单数,金额step3:讲第二步结果可视化, 比如, 柱形图(1)不同渠道用户数, 金额(2)不同日期..._exce l趋势分析数据量

宁盾堡垒机双因素认证方案_horizon宁盾双因素配置-程序员宅基地

文章浏览阅读3.3k次。堡垒机可以为企业实现服务器、网络设备、数据库、安全设备等的集中管控和安全可靠运行,帮助IT运维人员提高工作效率。通俗来说,就是用来控制哪些人可以登录哪些资产(事先防范和事中控制),以及录像记录登录资产后做了什么事情(事后溯源)。由于堡垒机内部保存着企业所有的设备资产和权限关系,是企业内部信息安全的重要一环。但目前出现的以下问题产生了很大安全隐患:密码设置过于简单,容易被暴力破解;为方便记忆,设置统一的密码,一旦单点被破,极易引发全面危机。在单一的静态密码验证机制下,登录密码是堡垒机安全的唯一_horizon宁盾双因素配置

谷歌浏览器安装(Win、Linux、离线安装)_chrome linux debian离线安装依赖-程序员宅基地

文章浏览阅读7.7k次,点赞4次,收藏16次。Chrome作为一款挺不错的浏览器,其有着诸多的优良特性,并且支持跨平台。其支持(Windows、Linux、Mac OS X、BSD、Android),在绝大多数情况下,其的安装都很简单,但有时会由于网络原因,无法安装,所以在这里总结下Chrome的安装。Windows下的安装:在线安装:离线安装:Linux下的安装:在线安装:离线安装:..._chrome linux debian离线安装依赖

烤仔TVの尚书房 | 逃离北上广?不如押宝越南“北上广”-程序员宅基地

文章浏览阅读153次。中国发达城市榜单每天都在刷新,但无非是北上广轮流坐庄。北京拥有最顶尖的文化资源,上海是“摩登”的国际化大都市,广州是活力四射的千年商都。GDP和发展潜力是衡量城市的数字指...

随便推点

java spark的使用和配置_使用java调用spark注册进去的程序-程序员宅基地

文章浏览阅读3.3k次。前言spark在java使用比较少,多是scala的用法,我这里介绍一下我在项目中使用的代码配置详细算法的使用请点击我主页列表查看版本jar版本说明spark3.0.1scala2.12这个版本注意和spark版本对应,只是为了引jar包springboot版本2.3.2.RELEASEmaven<!-- spark --> <dependency> <gro_使用java调用spark注册进去的程序

汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用_uds协议栈 源代码-程序员宅基地

文章浏览阅读4.8k次。汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用,代码精简高效,大厂出品有量产保证。:139800617636213023darcy169_uds协议栈 源代码

AUTOSAR基础篇之OS(下)_autosar 定义了 5 种多核支持类型-程序员宅基地

文章浏览阅读4.6k次,点赞20次,收藏148次。AUTOSAR基础篇之OS(下)前言首先,请问大家几个小小的问题,你清楚:你知道多核OS在什么场景下使用吗?多核系统OS又是如何协同启动或者关闭的呢?AUTOSAR OS存在哪些功能安全等方面的要求呢?多核OS之间的启动关闭与单核相比又存在哪些异同呢?。。。。。。今天,我们来一起探索并回答这些问题。为了便于大家理解,以下是本文的主题大纲:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JCXrdI0k-1636287756923)(https://gite_autosar 定义了 5 种多核支持类型

VS报错无法打开自己写的头文件_vs2013打不开自己定义的头文件-程序员宅基地

文章浏览阅读2.2k次,点赞6次,收藏14次。原因:自己写的头文件没有被加入到方案的包含目录中去,无法被检索到,也就无法打开。将自己写的头文件都放入header files。然后在VS界面上,右键方案名,点击属性。将自己头文件夹的目录添加进去。_vs2013打不开自己定义的头文件

【Redis】Redis基础命令集详解_redis命令-程序员宅基地

文章浏览阅读3.3w次,点赞80次,收藏342次。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。当数据量很大时,count 的数量的指定可能会不起作用,Redis 会自动调整每次的遍历数目。_redis命令

URP渲染管线简介-程序员宅基地

文章浏览阅读449次,点赞3次,收藏3次。URP的设计目标是在保持高性能的同时,提供更多的渲染功能和自定义选项。与普通项目相比,会多出Presets文件夹,里面包含着一些设置,包括本色,声音,法线,贴图等设置。全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,主光源和附加光源在一次Pass中可以一起着色。URP:全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,一次Pass可以计算多个光源。可编程渲染管线:渲染策略是可以供程序员定制的,可以定制的有:光照计算和光源,深度测试,摄像机光照烘焙,后期处理策略等等。_urp渲染管线

推荐文章

热门文章

相关标签