OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 10493|回复: 8

STM8L152通过模拟IIC读取INA226电压电流问题,求解各位

[复制链接]

5

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
111
金钱
111
注册时间
2017-2-21
在线时间
17 小时
发表于 2017-2-23 16:16:55 | 显示全部楼层 |阅读模式
2金钱
大家好,这个问题搞了几天了,头大,不知道问题在哪里,单片机跟INA226就是通过IIC通讯,没别的连接了,通过软件模拟IIC的方式,我想是不是我的读取代码有问题,特意贴出来,请求大家帮我看看,谢谢!
#define SCL_H()   (GPIO_SetBits(GPIOC,GPIO_Pin_1))
#define SCL_L()   (GPIO_ResetBits(GPIOC,GPIO_Pin_1))

#define SDA_H()   (GPIO_SetBits(GPIOC,GPIO_Pin_0))
#define SDA_L()   (GPIO_ResetBits(GPIOC,GPIO_Pin_0))

#define SDA_out() (GPIO_Init(GPIOC,GPIO_Pin_0,GPIO_Mode_Out_PP_High_Slow))
#define SDA_in()  (GPIO_Init(GPIOC,GPIO_Pin_0,GPIO_Mode_In_PU_No_IT))
#define Read_SDA()  (GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_0))


#define INA226_ADDRESS    0x80

#define                CFG_REG                 0x00
#define                SV_REG                         0x01
#define                BV_REG                 0x02
#define                PWR_REG                 0x03
#define                CUR_REG                 0x04
#define          CAL_REG                 0x05
#define                ONFF_REG                 0x06
#define                AL_REG                         0x07
#define           INA226_GETALADDR        0x14


void delay_nus(u16 i)
{
    while(i --);
}


//------------------------------------------------------------------------------
//子程序IIC_Start
//------------------------------------------------------------------------------
void IIC_Start(void)
{
        SDA_out();
        delay_nus(2);// 1us
        SDA_H();
        SCL_H();
        delay_nus(8); // 4us
        SDA_L();
        delay_nus(8); // 4us
        SCL_L();
        delay_nus(8);    // 4us
}

//------------------------------------------------------------------------------
//子程序IIC_Stop(void)
//------------------------------------------------------------------------------
void IIC_Stop(void)
{
        SDA_out();
        SCL_L();                              //
        delay_nus(8); // 4us
        SDA_L();                               
        delay_nus(8); // 4us
        SCL_H();
        delay_nus(8);// 4us
        SDA_H();
        delay_nus(8);// 4us
}

u8 IIC_WaitAck(void)
{           
        u8 ucErrTime=0;
        SDA_in();   
        SDA_H();delay_nus(2);// 1us           
        SCL_H();delay_nus(2);         // 1us
        while(Read_SDA())
        {
                ucErrTime++;
                if(ucErrTime>250)
                {
                        IIC_Stop();
                        return 1;
                }
        }
        SCL_L();
        return 0;            
}

void IIC_Ack(void)
{      
        SDA_out();
        SCL_L();
        delay_nus(4); // 2us
        SDA_L();
        delay_nus(4);// 2us
        SCL_H();
        delay_nus(4);// 2us
        SCL_L();
        delay_nus(4);// 2us
}

void IIC_NoAck(void)
{      
        SDA_out();
        SCL_L();
        delay_nus(4);// 2us
        SDA_H();
        delay_nus(4);// 2us
        SCL_H();
        delay_nus(4);// 2us
        SCL_L();
        delay_nus(4);// 2us
}

void IIC_WriteByte(u8 byte)
{             
        u8 i = 0;
        SDA_out();
        for(i = 0; i < 8; i++)
        {
                SCL_L();
                delay_nus(4);// 2us
                if(byte & 0x80)
                {
                        SDA_H();
                }
                else
                {
                        SDA_L();
                }
                delay_nus(4);
                SCL_H();
                delay_nus(4);
                byte<<=1;
        }
        SCL_L();
        delay_nus(4);
}

u8 IIC_ReadByte(u8 ack)
{
        u8 i,ReadByte;
        SDA_out();      
        SDA_H();
        SDA_in();
        for(i = 0; i < 8; i++)
        {       
                ReadByte <<= 1;
                SCL_L();
                delay_nus(4);// 2us
                SCL_H();
                delay_nus(4);// 2us
                if(Read_SDA())
                {
                        ReadByte |= 0x01;
                }
                else
                {
                        ReadByte &= ~(0x01);       
                }
                delay_nus(6);// 3us
                SCL_L();
                delay_nus(6);// 3us
        }       
        if (!ack)
        IIC_NoAck();
        else
        IIC_Ack();
        SDA_out();
        return ReadByte;
}

//------------------------------------------------------------------------------
//子程序config_INA226
//------------------------------------------------------------------------------
void config_INA226()
{
    IIC_Start();
    IIC_WriteByte(0x80); //写命令。从器件地址为1000,0000(最后一位为R/W),A1 A0:GND GND
    IIC_WriteByte(0x00); //写地址。配置寄存器地址。
    IIC_WriteByte(0x43); //配置寄存器。0100'010,1'01,11'0,111(16个平均数,总线2.116ms,分流4.156,共100.352ms)
    IIC_WriteByte(0xff);
    IIC_Stop();
}

//------------------------------------------------------------------------------
//子程序cal_INA226
//------------------------------------------------------------------------------
void cal_INA226()
{
    IIC_Start();
    IIC_WriteByte(0x80); //写命令。从器件地址为1000,0000(最后一位为R/W),A1 A0:GND GND
    IIC_WriteByte(0x05); //写地址。校准寄存器地址。
    IIC_WriteByte(0x04); //最大电流取6A,Current_LSB=6/(2^15)=0.00018,取0.0002A,R_shut=0.025,CAL=1024(0x0400)
    IIC_WriteByte(0x00);
    IIC_Stop();
}

u16 INA226_ReadData(u8 addr)
{
        u16 temp=0;
        IIC_Start();
        IIC_WriteByte(addr);
        IIC_Stop();
       
        IIC_Start();
        IIC_WriteByte(addr+1);
        IIC_WaitAck();
        temp = IIC_ReadByte(1);
        temp<<=8;       
        temp |= IIC_ReadByte(0);
        IIC_Stop();
        return temp;
}

void INA226_SetRegPointer(u8 addr,u8 reg)
{
        //IIC_Start();
        //IIC_WriteByte(addr);
        //IIC_WriteByte(reg);
        //IIC_Stop();

        IIC_Start();
        IIC_WriteByte(addr);
        IIC_WaitAck();
        IIC_WriteByte(reg);
        IIC_WaitAck();
        IIC_Stop();       
}

u16 INA226_GetCurrent(u8 addr)
{
        u32 temp1=0;

        INA226_SetRegPointer(addr,SV_REG);
        temp1 = INA226_ReadData(addr);
        if(temp1&0x8000)
        {
                temp1 = ~(temp1 - 1);       
                temp1 = (temp1*25 + 5) / 10 / 5;               
        }
        else
        {
                INA226_SetRegPointer(addr,CUR_REG);
                temp1 = INA226_ReadData(addr);
                temp1 = temp1&0x7fff;
        }
        return temp1;
}

// 1.25mV/bit
u16 INA226_GetVoltage(u8 addr)
{
        u32 temp=0;
        INA226_SetRegPointer(addr,BV_REG);
        temp = INA226_ReadData(addr);
        temp = (temp*125 + 50)/100;
        return (u16)temp;       
}

// 2.5uV/bit
u16 INA226_GetShuntVoltage(u8 addr)
{
        u32 temp1=0;
        INA226_SetRegPointer(addr,SV_REG);
        temp1 = INA226_ReadData(addr);
        if(temp1&0x8000)        temp1 = ~(temp1 - 1);       
        temp1 = (temp1*25 + 5) / 10;
        return (u16)temp1;       
}


u16 getcurrent,getvol,getshutvol;

void INA226_Test(void)
{
        getcurrent = INA226_GetCurrent(INA226_ADDRESS);
        getvol = INA226_GetVoltage(INA226_ADDRESS);
        getshutvol = INA226_GetShuntVoltage(INA226_ADDRESS);
}

然后对下面几个变量进行在线观察,结果如下:
getcurrent 一直为:0x3852
getvol一直为:0x3fff
getshutvol一直为:0x199C

不知道为什么,是我的代码有问题吗,请大家帮我看看,谢谢!

最佳答案

查看完整内容[请看2#楼]

void I2C_Start(void) { // I2C_SDAOut(); SDA_out(); SDA_H(); SCL_H(); delay_nus(28); SDA_L(); delay_nus(2); SCL_L(); delay_nus(15); } void I2C_Stop(void) { // I2C_SDAOut(); SDA_out(); SCL_L(); SDA_L(); delay_nus(2); SCL_H(); delay_nus(2); SDA_H(); delay_nus(8); } void I2C_Ack(void) { // I2C_SDAOut(); SCL_L(); SDA_out(); SDA_H( ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

5

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
111
金钱
111
注册时间
2017-2-21
在线时间
17 小时
 楼主| 发表于 2017-2-23 16:16:56 | 显示全部楼层

void I2C_Start(void)
{
//        I2C_SDAOut();
        SDA_out();      
        SDA_H();
        SCL_H();
        delay_nus(28);
        SDA_L();
        delay_nus(2);
        SCL_L();
        delay_nus(15);
}

void I2C_Stop(void)
{
//        I2C_SDAOut();
        SDA_out();      
        SCL_L();
        SDA_L();
        delay_nus(2);
        SCL_H();
        delay_nus(2);
        SDA_H();
        delay_nus(8);
}

void I2C_Ack(void)
{
//        I2C_SDAOut();
        SCL_L();
        SDA_out();             
        SDA_H();
        delay_nus(17);
        SCL_H();
        delay_nus(4);
        SCL_L();
       
}

void I2C_NoAck(void)
{
//        I2C_SDAOut();
        SCL_L();
        SDA_out();
        SDA_H();
        delay_nus(17);
        SDA_L();
        delay_nus(2);
        SCL_H();
        delay_nus(4);
        SCL_L();
       
}

u8 I2C_WaitACK(void)
{
        u8 errtime = 0;
//        I2C_SDAIn();
        SDA_in();
        //SDA_H();
        delay_nus(2);
        SCL_L();
        delay_nus(2);                 
        while(Read_SDA())
        {
                errtime++;
                if(errtime>250)
                {
                        delay_ms(65530);
                        I2C_Stop();
                        return 1;
                }
        }
        SCL_H();
        delay_nus(4);
        SCL_L();       
        //SDA_out();
        //SDA_H();
        //delay_nus(24);
        return 0;
}

void I2C_WRData(u8 data)
{
        u8 i;
        SDA_out();
//        I2C_SDAOut();
        //SCL_L();
        //SDA_L();
        //delay_nus(15);
        SDA_H();
        delay_nus(6);
        for(i=0;i<8;i++)
        {       
                //I2C_SDA = (data&0x80)>>7;
                if((data&0x80)>>7)
                {
                        SDA_H();
                }
                else
                {
                        SDA_L();
                }

                data<<=1;
                delay_nus(4);// 2.4us
                SCL_H();
                delay_nus(2);
                SCL_L();
                delay_nus(4);
        }       
}

u8 I2C_RDData(u8 ack)
{
        u8 i,data=0;
//        I2C_SDAIn();
        SDA_in();
        for(i=0;i<8;i++)
        {
                SCL_L();
        delay_nus(4);
                SCL_H();
        data<<=1;
        if(Read_SDA()) data++;   
                delay_nus(4);
        }
        if(ack) I2C_Ack();
        else I2C_NoAck();               
        return data;
}

void I2C_SDAOut(void)
{
        GPIO_Init(GPIOC , GPIO_Pin_0 , GPIO_Mode_Out_PP_High_Slow);  
}

void I2C_SDAIn(void)
{
        GPIO_Init(GPIOC , GPIO_Pin_0 , GPIO_Mode_In_PU_No_IT);  
}


void INA226_SendData(u8 addr,u8 reg,u16 data)
{
        u8 temp=0;
        I2C_Start();

        I2C_WRData(addr);
        I2C_WaitACK();

        I2C_WRData(reg);
        I2C_WaitACK();
       
        temp = (u8)(data>>8);
        I2C_WRData(temp);
        I2C_WaitACK();

        temp = (u8)(data&0x00FF);
        I2C_WRData(temp);
        I2C_WaitACK();
       
        I2C_Stop();
}

void INA226_Init(void)
{       
        GPIO_Init(GPIOC , GPIO_Pin_0 , GPIO_Mode_Out_PP_High_Slow);  
        GPIO_Init(GPIOC , GPIO_Pin_1 , GPIO_Mode_Out_PP_High_Slow);  
       
        INA226_SendData(INA226_ADDR1,CFG_REG,0x43FF);
        INA226_SendData(INA226_ADDR1,CAL_REG,1024);
}
void INA226_SetRegPointer(u8 addr,u8 reg)
{
        I2C_Start();

        I2C_WRData(addr);
        I2C_WaitACK();
       SDA_H();
        SCL_L();
        delay_nus(16);
        I2C_WRData(reg);
        I2C_WaitACK();
        SDA_H();
        SCL_L();
      delay_nus(16);
        I2C_Stop();
}


u16 INA226_ReadData(u8 addr)
{
        u16 temp=0;
        I2C_Start();

        I2C_WRData(addr+1);
        I2C_WaitACK();
       
        temp = I2C_RDData(0);
        temp<<=8;       
        temp |= I2C_RDData(0);
       
        I2C_Stop();
        return temp;
}

u8 INA226_AlertAddr(void)
{
        u8 temp;
        I2C_Start();

        I2C_WRData(INA226_GETALADDR);
        I2C_WaitACK();
       
        temp = I2C_RDData(1);
       
        I2C_Stop();
        return temp;
}

// 1mA/bit
u16 INA226_GetCurrent(u8 addr)
{
        u16 temp=0;       
        INA226_SetRegPointer(addr,SV_REG);
        temp = INA226_ReadData(addr);
        if(temp&0x8000)
        {
                temp = ~(temp - 1);       
                temp = (temp*25 + 5) / 10 / 5;               
        }
        else
        {
                INA226_SetRegPointer(addr,CUR_REG);
                temp = INA226_ReadData(addr);
                temp = temp&0x7fff;
        }
        return temp;
}

//  1 .25mV/bit
u16 INA226_GetVoltage(u8 addr)
{
        u32 temp=0;
        INA226_SetRegPointer(addr,BV_REG);
        temp = INA226_ReadData(addr);
        temp = (temp*125 + 50)/100;
        return (u16)temp;       
}

// .5uV/bit
u16 INA226_GetShuntVoltage(u8 addr)
{
        u32 temp=0;
        INA226_SetRegPointer(addr,SV_REG);
        temp = INA226_ReadData(addr);
        if(temp&0x8000)        temp = ~(temp - 1);       
        temp = (temp*25 + 5) / 10;
        return (u16)temp;       
}

u16 getcurrent,getvol,getshutvol;

void INA226_Test(void)
{
        getcurrent = INA226_GetCurrent(INA226_ADDRESS);
        delay_nus(200); // 668us
        getvol = INA226_GetVoltage(INA226_ADDRESS);
        delay_nus(200); // 668us
        getshutvol = INA226_GetShuntVoltage(INA226_ADDRESS);
        delay_nus(200); // 668us
}
u16 GetCurrent_INA226(void)
{
        return getcurrent;
}

回复

使用道具 举报

5

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
111
金钱
111
注册时间
2017-2-21
在线时间
17 小时
 楼主| 发表于 2017-2-23 16:17:48 | 显示全部楼层
延迟delay_nus用示波器实测,一次为0.5us。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2017-2-23 20:14:10 | 显示全部楼层
帮顶
回复

使用道具 举报

5

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
111
金钱
111
注册时间
2017-2-21
在线时间
17 小时
 楼主| 发表于 2017-2-24 00:05:53 | 显示全部楼层
顶起来,大家伙,帮我看看分析分析,感谢感谢!
回复

使用道具 举报

5

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
111
金钱
111
注册时间
2017-2-21
在线时间
17 小时
 楼主| 发表于 2017-2-28 20:51:38 | 显示全部楼层
已解决,是CLK和SDA中间的时序问题导致的。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2017-2-28 21:59:31 | 显示全部楼层
帮顶
回复

使用道具 举报

5

主题

29

帖子

0

精华

初级会员

Rank: 2

积分
127
金钱
127
注册时间
2018-5-8
在线时间
32 小时
发表于 2018-5-25 09:03:39 | 显示全部楼层
兄弟能不能分享一下例程
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
6
金钱
6
注册时间
2020-3-12
在线时间
1 小时
发表于 2021-9-26 17:06:33 | 显示全部楼层
楼主能分享下CLK和SDA中间的时序是什么问题
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 13:00

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表