找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4992|回复: 19
收起左侧

请大佬赐教一下关于MCP3421芯片的问题

[复制链接]
ID:214223 发表于 2019-12-12 17:21 | 显示全部楼层 |阅读模式
简单描述一下我遇到的问题:了解到MCP3421是一块精度很高的AD,而且利用I2C通信。所以想用32做一个简单表头。

搭建AD部分电路,我用的是官方应用电路:
1.png (这里VDD用的是5V电源,stm32用的是3.3V,电源是分开的)
然后接入到stm32f103c8的PB6,PB7。也就是I2C1接口。但是程序是模拟I2C(因为网上例程基本上都用模拟I2C),也就是我并没有用到硬件I2C。
烧写程序过后,无论仿真查看变量值还是实际显示,都为0。读不到电压值。想问问大佬问题出在哪呢,是I2C接口吗,还是另有原因?
附上我的程序:

"mcp.h"

  1. #ifndef __MCP_H
  2. #define __MCP_H

  3. #include "sys.h"

  4. #define IIC_SCL_PORT              GPIOB
  5. #define IIC_SCL_CLK               RCC_APB2Periph_GPIOB  
  6. #define IIC_SCL_PIN               GPIO_Pin_6

  7. #define IIC_SDA_PORT              GPIOB
  8. #define IIC_SDA_CLK               RCC_APB2Periph_GPIOB  
  9. #define IIC_SDA_PIN               GPIO_Pin_7

  10. #define MCP3421_12AD 0x80       
  11. #define MCP3421_14AD 0x84
  12. #define MCP3421_16AD 0x88
  13. #define MCP3421_18AD 0x8c
  14.                     
  15. //IO方向设置
  16. #define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=8<<8;}
  17. #define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=3<<8;}


  18. //IO操作函数         
  19. #define Set_IIC_SCL  {GPIO_SetBits(IIC_SCL_PORT,IIC_SCL_PIN);}
  20. #define Clr_IIC_SCL  {GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_PIN);}
  21. #define Set_IIC_SDA  {GPIO_SetBits(IIC_SDA_PORT,IIC_SDA_PIN);}
  22. #define Clr_IIC_SDA  {GPIO_ResetBits(IIC_SDA_PORT,IIC_SDA_PIN);}
  23. #define READ_SDA    (GPIO_ReadInputDataBit(IIC_SDA_PORT, IIC_SDA_PIN))



  24. //IIC所有操作函数
  25. void IIC_Init(void);                //初始化IIC的IO口                                 
  26. void IIC_Start(void);                                //发送IIC开始信号
  27. void IIC_Stop(void);                                  //发送IIC停止信号
  28. void IIC_Send_Byte(u8 txd);                        //IIC发送一个字节
  29. u8 IIC_Read_Byte(void);//IIC读取一个字节
  30. u8 IIC_Wait_Ack(void);                                 //IIC等待ACK信号
  31. void IIC_Ack(void);                                        //IIC发送ACK信号
  32. void IIC_NAck(void);                                //IIC不发送ACK信号
  33. float READ_MCP3421(void);
  34. void WRITE_MCP3421(unsigned char wr_data);
  35. u32 Read_Mcp3421_Data(void);
  36. void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
  37. u8 IIC_Read_One_Byte(u8 daddr,u8 addr);       
  38. u32 Get_Adc(void);

  39. extern unsigned long int elech;
  40. extern unsigned long int elecl;
  41. extern unsigned long int elecm;
  42. extern unsigned long int mcp_busy;  

  43. void IIC_Delay(void);
  44. void IIC_Start_Test(void);


  45. #endif

复制代码
"mcp.c"
  1. #include "mcp.h"


  2. void IIC_Delay(void)
  3. {
  4.         unsigned int i;
  5.         for(i=0;i<75;i++)
  6.         {
  7.                
  8.         }
  9. }


  10. void IIC_Init(void)
  11.         {                                             
  12.         GPIO_InitTypeDef GPIO_InitStructure;
  13.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);                                                 

  14.         GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN;
  15.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //推挽输出
  16.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  17.         GPIO_Init(IIC_SCL_PORT, &GPIO_InitStructure);

  18.         GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
  19.         GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);

  20.         Set_IIC_SCL;
  21.         Set_IIC_SDA;
  22.         }

  23. //产生IIC起始信号
  24. void IIC_Start(void)
  25. {
  26.         SDA_OUT();     //sda线输出
  27.         Set_IIC_SDA;                    
  28.         Set_IIC_SCL;
  29.         IIC_Delay();
  30.         Clr_IIC_SDA;//START:when CLK is high,DATA change form high to low
  31.         IIC_Delay();
  32.         Clr_IIC_SCL;//钳住I2C总线,准备发送或接收数据
  33. }         

  34. //产生IIC停止信号
  35. void IIC_Stop(void)
  36. {
  37.         SDA_OUT();//sda线输出
  38.         Clr_IIC_SCL;
  39.         Clr_IIC_SDA;//STOP:when CLK is high DATA change form low to high
  40.         IIC_Delay();
  41.         Set_IIC_SCL;
  42.         IIC_Delay();
  43.         Set_IIC_SDA;//发送I2C总线结束信号
  44.         IIC_Delay();                                                                  
  45. }

  46. //等待应答信号到来
  47. //返回值:1,接收应答失败
  48. //        0,接收应答成功
  49. u8 IIC_Wait_Ack(void)
  50. {
  51.   unsigned char i=2;
  52.   SDA_IN();      //SDA设置为输入
  53.         Set_IIC_SDA;
  54.         IIC_Delay();
  55.         Set_IIC_SCL;
  56.         IIC_Delay();

  57.   while(i--)
  58.                  {
  59.                         if(READ_SDA==1)
  60.                                         {
  61.                                         Clr_IIC_SCL;
  62.                                         IIC_Delay();
  63.                                          Set_IIC_SCL;
  64.                                         IIC_Delay();
  65.                                         }
  66.                         else
  67.                                 goto loop;
  68.                         }
  69. loop:
  70.   Clr_IIC_SCL;
  71.   IIC_Delay();
  72.   return 0;
  73. }

  74. //产生ACK应答
  75. void IIC_Ack(void)
  76. {
  77.         Clr_IIC_SCL;
  78.         SDA_OUT();
  79.         Clr_IIC_SDA;
  80.         IIC_Delay();
  81.         Set_IIC_SCL;
  82.         IIC_Delay();
  83.         Clr_IIC_SCL;
  84. }

  85. //不产生ACK应答                    
  86. void IIC_NAck(void)
  87. {
  88.         Clr_IIC_SCL;
  89.         SDA_OUT();
  90.         Set_IIC_SDA;
  91.         IIC_Delay();
  92.         Set_IIC_SCL;
  93.         IIC_Delay();
  94.         Clr_IIC_SCL;
  95. }       

  96. //IIC发送一个字节
  97. //返回从机有无应答
  98. //1,有应答
  99. //0,无应答                          
  100. void IIC_Send_Byte(u8 txd)
  101. {                        
  102.     u8 t;   
  103.         SDA_OUT();             
  104.     for(t=0;t<8;t++)
  105.     {              
  106.                 Clr_IIC_SCL;
  107.                 IIC_Delay();
  108.                 if (txd&0x80)         Set_IIC_SDA
  109.                 else Clr_IIC_SDA;
  110.         txd<<=1;           
  111.                 IIC_Delay();
  112.                 Set_IIC_SCL;
  113.                 IIC_Delay();
  114.        

  115.     }
  116.         Clr_IIC_SCL;         
  117. }

  118. //读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
  119. u8 IIC_Read_Byte(void)
  120. {
  121.         unsigned char i,receive=0;
  122.         SDA_IN();//SDA设置为输入
  123.     for(i=0;i<8;i++ )
  124.         {
  125.     receive<<=1;
  126.                 Clr_IIC_SCL;
  127.                 IIC_Delay();
  128.                 Set_IIC_SCL;
  129.                 IIC_Delay();
  130.         if(READ_SDA)
  131.                 {
  132.                         receive |= 0x01;
  133.         }
  134.                 else
  135.                 {
  136.                         receive &= 0xfe;
  137.                 }
  138.     }

  139.         Clr_IIC_SCL;                                          
  140.     return receive;
  141. }

  142. /*******************************************************************
  143. wr_data:MCP3421_12AD 采用12位AD       
  144. wr_data:MCP3421_14AD 采用14位AD
  145. wr_data:MCP3421_16AD 采用16位AD
  146. wr_data:MCP3421_18AD 采用18位AD
  147. ********************************************************************/
  148. void WRITE_MCP3421(unsigned char wr_data)
  149. {
  150.         IIC_Start();
  151.         IIC_Send_Byte(0xd0);//写
  152.         IIC_Wait_Ack();
  153.         IIC_Send_Byte(wr_data);
  154.         IIC_Wait_Ack();
  155.         IIC_Stop();
  156. }


  157. float READ_MCP3421(void)
  158. {
  159.         unsigned long int elech;
  160.         unsigned long int elecm;
  161.         unsigned long int elecl;
  162.         unsigned long int AD_B_Result;
  163.         float AD_F_Result=0.0;
  164.         IIC_Start();
  165.         IIC_Send_Byte(0xd1);//读
  166.         IIC_Wait_Ack();
  167.         elech=(long int)IIC_Read_Byte();
  168.         IIC_Ack();
  169.         elecm=(long int)IIC_Read_Byte();
  170.         IIC_Ack();
  171.         elecl=(long int)IIC_Read_Byte();
  172.         IIC_NAck();
  173.         IIC_Stop();
  174.         AD_B_Result=(elech<<16)|(elecm<<8)|(elecl);
  175.         AD_B_Result=AD_B_Result&0x01ffffff;
  176.         AD_F_Result=(float)((float)(2.048/131072)*((float)AD_B_Result));
  177.         return AD_F_Result;
  178. }
复制代码


最后在我的main函数里面
  1. int main(void)
  2. {
  3. float Vrm = 0.0;
  4. char DisBuf[200];
  5. IIC_Init();
  6. while(1)
  7. {
  8.          WRITE_MCP3421(MCP3421_18AD);
  9.             Vrm=READ_MCP3421();
  10.                    IIC_Delay();
  11.         printf(" | V:%4.2f | \r\n",Vrm);
  12.          sprintf(DisBuf,"% 4.2f",Vrm);
  13. LCD_ShowString(110,270, (u8*)DisBuf,DARKBLUE);
  14. }
  15. }
复制代码
这里用了printf函数,网上有资料说不用在I2C通信时使用这个函数,所以我注释了过后再运行查找变量,或者就是更改另一种显示方法,始终都是读不到电压值的。求大佬不吝赐教,感激不尽!



回复

使用道具 举报

ID:214223 发表于 2019-12-12 17:25 | 显示全部楼层
突然想起来这个初始化程序好像也是在51论坛里面看到的,他们也确实能用啊!
回复

使用道具 举报

ID:401564 发表于 2019-12-13 08:19 | 显示全部楼层
这个IC的IIC地址并不是固定的,是根据IC上丝印来决定的
每一批出厂的IC的IIC地址都是不一样的,所以,你用别人的代码就不一定行,要看你手头上IC的丝印来决定的 51hei截图20191213081607.jpg
回复

使用道具 举报

ID:214223 发表于 2019-12-13 10:40 | 显示全部楼层
Y_G_G 发表于 2019-12-13 08:19
这个IC的IIC地址并不是固定的,是根据IC上丝印来决定的
每一批出厂的IC的IIC地址都是不一样的,所以,你用 ...

噢噢噢噢,十分谢谢,我以为器件出厂默认都是000
回复

使用道具 举报

ID:214223 发表于 2019-12-13 10:45 | 显示全部楼层
Y_G_G 发表于 2019-12-13 08:19
这个IC的IIC地址并不是固定的,是根据IC上丝印来决定的
每一批出厂的IC的IIC地址都是不一样的,所以,你用 ...

我看了下我这个是默认丝印是000,那么问题应该不在这对吧?
回复

使用道具 举报

ID:401564 发表于 2019-12-13 11:57 | 显示全部楼层
Host 发表于 2019-12-13 10:45
我看了下我这个是默认丝印是000,那么问题应该不在这对吧?

那就不知道了,我是用汇编的,C语言是真心看不明白
回复

使用道具 举报

ID:662832 发表于 2019-12-13 12:37 | 显示全部楼层
每一批出厂的IC的IIC地址都是不一样,用别人的代码就不一定行,要看你的IC的丝印
回复

使用道具 举报

ID:214223 发表于 2019-12-13 15:46 | 显示全部楼层
Y_G_G 发表于 2019-12-13 11:57
那就不知道了,我是用汇编的,C语言是真心看不明白

噢噢噢噢,麻烦了,非常感谢
回复

使用道具 举报

ID:214223 发表于 2019-12-13 15:49 | 显示全部楼层
还有大佬赐教吗?小弟感激不尽
回复

使用道具 举报

ID:401564 发表于 2019-12-14 11:06 | 显示全部楼层
Host 发表于 2019-12-13 15:46
噢噢噢噢,麻烦了,非常感谢

其实这IC没有那么难操作的,就数据处理不太好处理,用C的话就不存在这个问题的
你可以先写一个专门验证的函数,功能也不要太多就,就写入和读取功能验证而已,只要能正常写入和读取,器件就会有应答信号,其它的再慢慢的修改
回复

使用道具 举报

ID:214223 发表于 2019-12-16 12:17 | 显示全部楼层
Y_G_G 发表于 2019-12-14 11:06
其实这IC没有那么难操作的,就数据处理不太好处理,用C的话就不存在这个问题的
你可以先写一个专门验证的 ...

好,那我先单独做试试,实在是非常感谢
回复

使用道具 举报

ID:684378 发表于 2020-1-9 21:50 | 显示全部楼层
代码就懒得看了,实话说MCP3421我正好做过,你首先确定你的I2C通了没有,上电有默认设置,你先读一个字节看对不对,读写地址别搞错了,D0  D1,
回复

使用道具 举报

ID:822748 发表于 2020-9-24 11:33 | 显示全部楼层
MCP3421不兼容3.3V呀,要把MCP3421电源换成3.3V
回复

使用道具 举报

ID:149642 发表于 2021-4-20 11:51 | 显示全部楼层
哎,只会汇编,咋办?
板凳,瓜子,啤酒。
回复

使用道具 举报

ID:417546 发表于 2022-4-1 21:09 | 显示全部楼层
微兔程序 发表于 2020-9-24 11:33
MCP3421不兼容3.3V呀,要把MCP3421电源换成3.3V
mcp3421.png
回复

使用道具 举报

ID:417546 发表于 2022-4-1 21:10 | 显示全部楼层
微兔程序 发表于 2020-9-24 11:33
MCP3421不兼容3.3V呀,要把MCP3421电源换成3.3V

支持的,官方手册是2.7-5.5V!
回复

使用道具 举报

ID:703081 发表于 2022-4-12 11:36 | 显示全部楼层
高手在民间
回复

使用道具 举报

ID:149642 发表于 2024-1-13 21:03 | 显示全部楼层
我是只读了第一个字节,后面就读不出了。。不知道什么原因,配置16位,18位,14位都是这样。。应答程序应该没问题,
回复

使用道具 举报

ID:401564 发表于 2024-1-15 12:44 | 显示全部楼层
lksbbs 发表于 2024-1-13 21:03
我是只读了第一个字节,后面就读不出了。。不知道什么原因,配置16位,18位,14位都是这样。。应答程序应该 ...

每读取完一个字节的数据,就要应答一次
读取完所有的数据,就要发送一个不应答信号和一个停止信号,不然数据容易乱
要严格按照时序图上的来操作
回复

使用道具 举报

ID:149642 发表于 2024-1-16 07:57 | 显示全部楼层
Y_G_G 发表于 2024-1-15 12:44
每读取完一个字节的数据,就要应答一次
读取完所有的数据,就要发送一个不应答信号和一个停止信号,不然数 ...

谢谢,不是应答的问题,已经解决了,是接收数据前需要先拉低数据位,或者说先清0
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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