STM32读取多个ADM1191电流电压,实现电源监控器 最近在通过STM32从多个ADM1191芯片中回读电压电流,踩坑不少,故做此简单记录。 一:芯片简介 1.主控芯片型号:STM32F405RGTX 高性能MCU,主频168MHZ,Cortex4-M4内核 2.ADM1191是一款集成电流检测放大器,可通过I2C接口传送的片内,12位模数转换器(ADC)提供数字电流和电压监控。内部电流检测放大器通过VCC引脚和感测引脚在电源路径中的感测电阻上的电压感测电压。 12位ADC可以测量检测电阻中看到的电流,以及VCC引脚上的电源电压。 行业标准I2C接口允许控制器从ADC读取电流和电压数据。测量可以由I2C命令或通过转换(CONV)引脚启动。 CONC引脚特别适用于同步多个ADM1191设备上的读取。或者,ADC可以连续运行,并且用户可以在需要时读取最新的转换数据。最多可以创建16个唯一的I2C地址,具体取决于A0引脚和A1引脚的方式连接。 器件I2C地址如下表: 二、电压电源回读 本实验用STM32与三个ADM1191采用I2C总线进行数据交换。 I2C协议常用信号这里不做记录。下面是读写ADM1191的读写控制时序: 发命令格式: 各位命令的含义: 这里是低七位,最高位控制其是发命令(MSB:0)还是向寄存器写入(MSB:1) 下面直接上程序: 1.采样控制引脚初始化:
void CONV_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(CONV_GPIO_CLK,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Pin =CONV_GPIO_PIN;
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
GPIO_Init(CONV_GPIO_PORT,&GPIO_InitStructure);
GPIO_ResetBits(CONV_GPIO_PORT,CONV_GPIO_PIN);
}```c
void CONV_EN()
{
GPIO_SetBits(CONV_GPIO_PORT,CONV_GPIO_PIN);
}
void CONV_DISABLE()
{
GPIO_ResetBits(CONV_GPIO_PORT,CONV_GPIO_PIN);
}
2.过流过压引脚初始化:当发送过流过压现象是该引脚被置低
void ALERT_Pin_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(ALERT_ARM_GPIO_CLK|ALERT_OPTICAL_GPIO_CLK|ALERT_SAMPLE_GPIO_CLK,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Pin =ALERT_ARM_GPIO_PIN |ALERT_OPTICAL_GPIO_PIN | ALERT_SAMPLE_GPIO_PIN;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
3.配置ADM1191及回读电压电流:
uint8_t adm1191_convert_con(uint8_t addr)
{
i2c_Start();
i2c_SendByte(addr|ADM1191_I2C_WR);
if(i2c_WaitAck() != 0)
{
goto cmd_fail;
}
i2c_SendByte(0x05);
if(i2c_WaitAck() != 0)
{
goto cmd_fail;
}
i2c_Stop();
return 1;
cmd_fail:
i2c_Stop();
return 0;
}
uint8_t adm1191_convert_once(uint8_t addr)
{
i2c_Start();
i2c_SendByte(addr|ADM1191_I2C_WR);
if(i2c_WaitAck() != 0)
{
goto cmd_fail;
}
i2c_SendByte(0x05);
if(i2c_WaitAck() != 0)
{
goto cmd_fail;
}
i2c_Stop();
return 1;
cmd_fail:
i2c_Stop();
return 0;
}
uint8_t adm1191_rd_VI(uint8_t *_pReadBuf,uint8_t addr)
{
CONV_EN();
delay_us(300);
i2c_Start();
i2c_SendByte(addr | ADM1191_I2C_RD);
if (i2c_WaitAck() != 0)
{
goto cmd_fail;
}
for(uint8_t i=0;i<3;i++)
{
_pReadBuf[i] = i2c_ReadByte();
if(i == 2)
{
i2c_NAck();
}
else
i2c_Ack();
}
i2c_Stop();
CONV_DISABLE();
return 1;
cmd_fail:
i2c_Stop();
return 0;
}
uint8_t Get_vi_from_1191(uint8_t addr,uint8_t *_pReadBuf,float *V,float * I)
{
int vcode,icode;
uint8_t temp;
if(Check_I2cdev_Ok(addr))
{
if(adm1191_convert_once(addr))
{
if(adm1191_rd_VI(_pReadBuf,addr))
{
temp=_pReadBuf[2];
vcode=(_pReadBuf[0]<<4) | (_pReadBuf[2] >> 4);
icode=(_pReadBuf[1]<<4) | (temp & 0x0F);
*V=(26.52/4096)*vcode;
*I=(105.84/4096)*icode/1000/0.01;
return 1;
}
else
{
__485print_str("read VI failed\r\n");
return 0;
}
}
else
{
__485print_str("config adm1191 failed\r\n");
return 0;
}
}
else
{
__485print_str("no find i2c device");
return 0;
}
}
使用定时器采样,2s采样一次,我使用的是基本定时器TIM6,定时器初始化过程略过,下面是定时器中断处理函数:
void TIM6_DAC_IRQHandler(void)
{
if ( TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET )
{
if(Get_vi_from_1191(ADDRESS_ADM1191_ARM,V_ARM,&arm_v,&arm_i))
{
__485print_str("ARM供电电压 : ");
__485_print_float(arm_v);
__485print_str("\r\n");
__485print_str("ARM供电电流 : ");
__485_print_float(arm_i);
__485print_str("\r\n");
}
else
{
__485print_str("get arm_v failed\r\n");
}
if(Get_vi_from_1191(ADDRESS_ADM1191_OPTICAL,V_OPTICAL,&opt_v,&opt_i))
{
__485print_str("光源供电电压 : ");
__485_print_float(opt_v);
__485print_str("\r\n");
__485print_str("光源供电电流 : ");
__485_print_float(opt_i);
__485print_str("\r\n");
}
else
{
__485print_str("get optical_v failed\r\n");
}
if(Get_vi_from_1191(ADDRESS_ADM1191_SAMPLE,V_SAMPLE,&sam_v,&sam_i))
{
__485print_str("数采板供电电压 : ");
__485_print_float(sam_v);
__485print_str("\r\n");
__485print_str("数采板供电电流 : ");
__485_print_float(sam_i);
__485print_str("\r\n");
}
else
{
__485print_str("get sample_v failed\r\n");
}
TIM_ClearITPendingBit(BASIC_TIM , TIM_IT_Update);
}
}
主函数:
float arm_v,sam_v,opt_v;
float arm_i,sam_i,opt_i;
float temp4,temp5;
u16 temp4_adc,temp5_adc;
extern __IO uint16_t adc_value[2];
int main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
LED_GPIO_Config();
init_control_power_pin();
CONV_GPIO_Config();
ALERT_Pin_Config();
EXTI_Config();
TIMx_Configuration();
delay_init(168);
_485_init(115200);
while(1)
{
LED_TOGGLE;
delay_ms(1000);
}
}
三、烧写测试 到此完结,第一次创作,不喜勿喷~~~~~~~~~~
|