找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2014|回复: 11
收起左侧

请问I2C从机单片机接收程序怎么写?

[复制链接]
ID:1043477 发表于 2022-9-1 09:22 | 显示全部楼层 |阅读模式
如题
回复

使用道具 举报

ID:123289 发表于 2022-9-1 17:41 | 显示全部楼层
仔细再读I2C通讯原理,芯片手册。
回复

使用道具 举报

ID:624769 发表于 2022-9-1 22:00 | 显示全部楼层
从机通常是被动触发型, 大多情况下,你从机是不可能啥是都不干,就用一个 while(SDA); 一直等主机发起始信号过来吧? 通常总要用到系统中断来等待被触发吧???
你连个单片机型号都没有,鬼知道应该用哪个中断方式来判定主机发送起始信号?
回复

使用道具 举报

ID:1043477 发表于 2022-9-2 10:40 | 显示全部楼层
188610329 发表于 2022-9-1 22:00
从机通常是被动触发型, 大多情况下,你从机是不可能啥是都不干,就用一个 while(SDA); 一直等主机发起始信 ...

这个单片机是已51为基础开发的型号,名字叫RX8F103 系列是通用型 1T 8051 Core MCU。在同样的系统时钟下,指令代码完全兼容传统 8051;
回复

使用道具 举报

ID:1043477 发表于 2022-9-2 10:46 | 显示全部楼层
yzwzfyz 发表于 2022-9-1 17:41
仔细再读I2C通讯原理,芯片手册。

感觉都看麻了
回复

使用道具 举报

ID:1043477 发表于 2022-9-2 10:47 | 显示全部楼层
188610329 发表于 2022-9-1 22:00
从机通常是被动触发型, 大多情况下,你从机是不可能啥是都不干,就用一个 while(SDA); 一直等主机发起始信 ...

我现在写的程序就是用whlie(),来判断是否开始
回复

使用道具 举报

ID:1043608 发表于 2022-9-2 11:58 | 显示全部楼层
仔细再读I2C通讯原理,芯片手册,根据单片机型号来编写程序
回复

使用道具 举报

ID:155507 发表于 2022-9-2 12:38 | 显示全部楼层

RX8F103系列
RX8F103-BlockDiag.jpg

RX8F103-Pins.jpg


给你个思路吧 从机想要接收 就需要知道主机的时钟线 把时钟线接到外部中断 进入中断后读取数据线 最后把数组组成一个字节
时钟线时跳变的,最好有个片选CS,将CS脚接到中断可能更好

网上找来的,可能会有所帮助吧


  1. /****************************************************************/
  2. bit iic_start_decide()    //IIC 开始判断
  3. {
  4.         while(SCL==0);                   //开始不满足条件
  5.         while((SCL==1)&&(SDA==1));       //开始条件
  6.         if((SCL==1)&&(SDA==0))           //开始
  7.         {
  8.                 while(SCL==1);               //等待到时钟开始低跳变
  9.                 return 1;
  10.         }
  11.         else
  12.         return 0;
  13. }

  14. /****************************************************************/
  15. bit iic_stop_decide()            //IIC 结束判断
  16. {
  17.         while(SCL==0);               //结束不满足条件
  18.         if((SCL==1)&&(0==SDA))       //结束
  19.         {
  20.                 while(SDA==0);           //等待到数据开始高跳变
  21.                 return 1;
  22.         }
  23.         else
  24.         {
  25.                 return 0;
  26.         }
  27. }
  28. /****************************************************************/
  29. uchar iic_receive()
  30. {
  31.         uchar i;
  32.         uchar rdata='0';

  33.         SDA=1;
  34.         for(i=0;i<8;i++)
  35.         {
  36.                 rdata<<=1;
  37.                 while(SCL==0);        //当时钟为低时,数据无效,等待
  38.                 if(SDA==1)
  39.                 rdata++;
  40.                 while(SCL==1);        //防止在一个高电平时读8次
  41.         }
  42.         return (rdata);
  43. }
  44. /****************************************************************/
  45. bit iic_ack_decide()
  46. {
  47.         bit ack_flag;         //局部变量
  48.         SDA=0;                ////8位发送完毕,释放数据线SDA,准备接收应答位
  49.         while(SCL==0);        //等待SCL变高电平
  50.         //ack_flag=0;
  51.         while(SCL==1);        //等待SCL变高电平
  52.         SDA=1;
  53.         ack_flag=1;
  54.         return(ack_flag);
  55. }

复制代码




回复

使用道具 举报

ID:401564 发表于 2022-9-2 16:16 | 显示全部楼层
感觉这没什么意义呀,还不如果用Modbus
如果你只是你自己用的,两个单片机之间的通讯,直接用串口就行了
回复

使用道具 举报

ID:624769 发表于 2022-9-2 19:31 | 显示全部楼层
从8楼贴出的资料看, 你这片单片机是支持 硬件 I2C 从机模式的, 因此,不建议你用 软件来实现, 建议参看该单片机手册 I2C 从机这个篇章,用硬件来实现, 除了 几个寄存器需要设置一下,其他都和 串口一主多从的从机侧的发送/接收 差不多的流程。也是被触发后,查验地址,和自己是否吻合,吻合的话 分析指令,主机是读,还是写,写的话简单,收取所有主机发出的数据,然后统一处理,是读的话,把需要给主机的数据准备好,扔一个字节到 I2Cbuf, 等主机读走后,中断再次触发,再扔下一个字节到 I2Cbuf,周而复始。
回复

使用道具 举报

ID:155507 发表于 2022-9-3 08:31 | 显示全部楼层
给你个STC8G作为参考。


  1. //STC8G---I2C硬件模式
  2. //从机中断模式
  3. #include "reg51.h"
  4. #include "intrins.h"

  5. sfr     P_SW2   =   0xba;

  6. #define I2CCFG      (*(unsigned char volatile xdata *)0xfe80)
  7. #define I2CMSCR     (*(unsigned char volatile xdata *)0xfe81)
  8. #define I2CMSST     (*(unsigned char volatile xdata *)0xfe82)
  9. #define I2CSLCR     (*(unsigned char volatile xdata *)0xfe83)
  10. #define I2CSLST     (*(unsigned char volatile xdata *)0xfe84)
  11. #define I2CSLADR    (*(unsigned char volatile xdata *)0xfe85)
  12. #define I2CTXD      (*(unsigned char volatile xdata *)0xfe86)
  13. #define I2CRXD      (*(unsigned char volatile xdata *)0xfe87)

  14. sfr     P1M1    =   0x91;
  15. sfr     P1M0    =   0x92;
  16. sfr     P0M1    =   0x93;
  17. sfr     P0M0    =   0x94;
  18. sfr     P2M1    =   0x95;
  19. sfr     P2M0    =   0x96;
  20. sfr     P3M1    =   0xb1;
  21. sfr     P3M0    =   0xb2;
  22. sfr     P4M1    =   0xb3;
  23. sfr     P4M0    =   0xb4;
  24. sfr     P5M1    =   0xc9;
  25. sfr     P5M0    =   0xca;

  26. sbit    SDA     =   P1^4;
  27. sbit    SCL     =   P1^5;

  28. bit isda;                                       //设备地址标志
  29. bit isma;                                       //存储地址标志
  30. unsigned char addr;
  31. unsigned char pdata buffer[256];

  32. void I2C_Isr() interrupt 24
  33. {
  34.     _push_(P_SW2);
  35.     P_SW2 |= 0x80;

  36.     if (I2CSLST & 0x40)
  37.     {
  38.         I2CSLST &= ~0x40;                       //处理START事件
  39.     }
  40.     else if (I2CSLST & 0x20)
  41.     {
  42.         I2CSLST &= ~0x20;                       //处理RECV事件
  43.         if (isda)
  44.         {
  45.             isda = 0;                           //处理RECV事件(RECV DEVICE ADDR)
  46.         }
  47.         else if (isma)
  48.         {
  49.             isma = 0;                           //处理RECV事件(RECV MEMORY ADDR)
  50.             addr = I2CRXD;
  51.             I2CTXD = buffer[addr];
  52.         }
  53.         else
  54.         {
  55.             buffer[addr++] = I2CRXD;            //处理RECV事件(RECV DATA)
  56.         }
  57.     }
  58.     else if (I2CSLST & 0x10)
  59.     {
  60.         I2CSLST &= ~0x10;                       //处理SEND事件
  61.         if (I2CSLST & 0x02)
  62.         {
  63.             I2CTXD = 0xff;                      //接收到NAK则停止读取数据
  64.         }
  65.         else
  66.         {
  67.             I2CTXD = buffer[++addr];            //接收到ACK则继续读取数据
  68.         }
  69.     }
  70.     else if (I2CSLST & 0x08)
  71.     {
  72.         I2CSLST &= ~0x08;                       //处理STOP事件
  73.         isda = 1;
  74.         isma = 1;
  75.     }

  76.     _pop_(P_SW2);
  77. }

  78. void main()
  79. {
  80.     P0M0 = 0x00;
  81.     P0M1 = 0x00;
  82.     P1M0 = 0x00;
  83.     P1M1 = 0x00;
  84.     P2M0 = 0x00;
  85.     P2M1 = 0x00;
  86.     P3M0 = 0x00;
  87.     P3M1 = 0x00;
  88.     P4M0 = 0x00;
  89.     P4M1 = 0x00;
  90.     P5M0 = 0x00;
  91.     P5M1 = 0x00;

  92.     P_SW2 = 0x80;

  93.     I2CCFG = 0x81;                              //使能I2C从机模式
  94.     I2CSLADR = 0x5a;                            //设置从机设备地址寄存器I2CSLADR=0101_1010B
  95.                                                 //即I2CSLADR[7:1]=010_1101B,MA=0B。
  96.                                                 //由于MA为0,主机发送的的设备地址必须与
  97.                                                 //I2CSLADR[7:1]相同才能访问此I2C从机设备。
  98.                                                 //主机若需要写数据则要发送5AH(0101_1010B)
  99.                                                 //主机若需要读数据则要发送5BH(0101_1011B)
  100.     I2CSLST = 0x00;
  101.     I2CSLCR = 0x78;                             //使能从机模式中断
  102.     EA = 1;

  103.     isda = 1;                                   //用户变量初始化
  104.     isma = 1;
  105.     addr = 0;
  106.     I2CTXD = buffer[addr];

  107.     while (1);
  108. }


  109. //从机模式 查询方式
  110. #include "reg51.h"
  111. #include "intrins.h"

  112. sfr     P_SW2   =   0xba;

  113. #define I2CCFG      (*(unsigned char volatile xdata *)0xfe80)
  114. #define I2CMSCR     (*(unsigned char volatile xdata *)0xfe81)
  115. #define I2CMSST     (*(unsigned char volatile xdata *)0xfe82)
  116. #define I2CSLCR     (*(unsigned char volatile xdata *)0xfe83)
  117. #define I2CSLST     (*(unsigned char volatile xdata *)0xfe84)
  118. #define I2CSLADR    (*(unsigned char volatile xdata *)0xfe85)
  119. #define I2CTXD      (*(unsigned char volatile xdata *)0xfe86)
  120. #define I2CRXD      (*(unsigned char volatile xdata *)0xfe87)

  121. sfr     P1M1    =   0x91;
  122. sfr     P1M0    =   0x92;
  123. sfr     P0M1    =   0x93;
  124. sfr     P0M0    =   0x94;
  125. sfr     P2M1    =   0x95;
  126. sfr     P2M0    =   0x96;
  127. sfr     P3M1    =   0xb1;
  128. sfr     P3M0    =   0xb2;
  129. sfr     P4M1    =   0xb3;
  130. sfr     P4M0    =   0xb4;
  131. sfr     P5M1    =   0xc9;
  132. sfr     P5M0    =   0xca;

  133. sbit    SDA     =   P1^4;
  134. sbit    SCL     =   P1^5;

  135. bit isda;                                       //设备地址标志
  136. bit isma;                                       //存储地址标志
  137. unsigned char addr;
  138. unsigned char pdata buffer[256];

  139. void main()
  140. {
  141.     P0M0 = 0x00;
  142.     P0M1 = 0x00;
  143.     P1M0 = 0x00;
  144.     P1M1 = 0x00;
  145.     P2M0 = 0x00;
  146.     P2M1 = 0x00;
  147.     P3M0 = 0x00;
  148.     P3M1 = 0x00;
  149.     P4M0 = 0x00;
  150.     P4M1 = 0x00;
  151.     P5M0 = 0x00;
  152.     P5M1 = 0x00;

  153.     P_SW2 = 0x80;

  154.     I2CCFG = 0x81;                              //使能I2C从机模式
  155.     I2CSLADR = 0x5a;                            //设置从机设备地址寄存器I2CSLADR=0101_1010B
  156.                                                 //即I2CSLADR[7:1]=010_1101B,MA=0B。
  157.                                                 //由于MA为0,主机发送的的设备地址必须与
  158.                                                 //I2CSLADR[7:1]相同才能访问此I2C从机设备。
  159.                                                 //主机若需要写数据则要发送5AH(0101_1010B)
  160.                                                 //主机若需要读数据则要发送5BH(0101_1011B)
  161.     I2CSLST = 0x00;
  162.     I2CSLCR = 0x00;                             //禁止从机模式中断

  163.     isda = 1;                                   //用户变量初始化
  164.     isma = 1;
  165.     addr = 0;
  166.     I2CTXD = buffer[addr];

  167.     while (1)
  168.     {
  169.         if (I2CSLST & 0x40)
  170.         {
  171.             I2CSLST &= ~0x40;                   //处理START事件
  172.         }
  173.         else if (I2CSLST & 0x20)
  174.         {
  175.             I2CSLST &= ~0x20;                   //处理RECV事件
  176.             if (isda)
  177.             {
  178.                 isda = 0;                       //处理RECV事件(RECV DEVICE ADDR)
  179.             }
  180.             else if (isma)
  181.             {
  182.                 isma = 0;                       //处理RECV事件(RECV MEMORY ADDR)
  183.                 addr = I2CRXD;
  184.                 I2CTXD = buffer[addr];
  185.             }
  186.             else
  187.             {
  188.                 buffer[addr++] = I2CRXD;        //处理RECV事件(RECV DATA)
  189.             }
  190.         }
  191.         else if (I2CSLST & 0x10)
  192.         {
  193.             I2CSLST &= ~0x10;                   //处理SEND事件
  194.             if (I2CSLST & 0x02)
  195.             {
  196.                 I2CTXD = 0xff;                  //接收到NAK则停止读取数据
  197.             }
  198.             else
  199.             {
  200.                 I2CTXD = buffer[++addr];        //接收到ACK则继续读取数据
  201.             }
  202.         }
  203.         else if (I2CSLST & 0x08)
  204.         {
  205.             I2CSLST &= ~0x08;                   //处理STOP事件
  206.             isda = 1;
  207.             isma = 1;
  208.         }
  209.     }
  210. }

  211. //测试I2C从机模式代码的主机代码
  212. #include "reg51.h"
  213. #include "intrins.h"

  214. sfr     P_SW2   =   0xba;

  215. #define I2CCFG      (*(unsigned char volatile xdata *)0xfe80)
  216. #define I2CMSCR     (*(unsigned char volatile xdata *)0xfe81)
  217. #define I2CMSST     (*(unsigned char volatile xdata *)0xfe82)
  218. #define I2CSLCR     (*(unsigned char volatile xdata *)0xfe83)
  219. #define I2CSLST     (*(unsigned char volatile xdata *)0xfe84)
  220. #define I2CSLADR    (*(unsigned char volatile xdata *)0xfe85)
  221. #define I2CTXD      (*(unsigned char volatile xdata *)0xfe86)
  222. #define I2CRXD      (*(unsigned char volatile xdata *)0xfe87)

  223. sfr     P1M1    =   0x91;
  224. sfr     P1M0    =   0x92;
  225. sfr     P0M1    =   0x93;
  226. sfr     P0M0    =   0x94;
  227. sfr     P2M1    =   0x95;
  228. sfr     P2M0    =   0x96;
  229. sfr     P3M1    =   0xb1;
  230. sfr     P3M0    =   0xb2;
  231. sfr     P4M1    =   0xb3;
  232. sfr     P4M0    =   0xb4;
  233. sfr     P5M1    =   0xc9;
  234. sfr     P5M0    =   0xca;

  235. sbit    SDA     =   P1^4;
  236. sbit    SCL     =   P1^5;

  237. void Wait()
  238. {
  239.     while (!(I2CMSST & 0x40));
  240.     I2CMSST &= ~0x40;
  241. }

  242. void Start()
  243. {
  244.     I2CMSCR = 0x01;                             //发送START命令
  245.     Wait();
  246. }

  247. void SendData(char dat)
  248. {
  249.     I2CTXD = dat;                               //写数据到数据缓冲区
  250.     I2CMSCR = 0x02;                             //发送SEND命令
  251.     Wait();
  252. }

  253. void RecvACK()
  254. {
  255.     I2CMSCR = 0x03;                             //发送读ACK命令
  256.     Wait();
  257. }

  258. char RecvData()
  259. {
  260.     I2CMSCR = 0x04;                             //发送RECV命令
  261.     Wait();
  262.     return I2CRXD;
  263. }

  264. void SendACK()
  265. {
  266.     I2CMSST = 0x00;                             //设置ACK信号
  267.     I2CMSCR = 0x05;                             //发送ACK命令
  268.     Wait();
  269. }

  270. void SendNAK()
  271. {
  272.     I2CMSST = 0x01;                             //设置NAK信号
  273.     I2CMSCR = 0x05;                             //发送ACK命令
  274.     Wait();
  275. }

  276. void Stop()
  277. {
  278.     I2CMSCR = 0x06;                             //发送STOP命令
  279.     Wait();
  280. }

  281. void Delay()
  282. {
  283.     int i;

  284.     for (i=0; i<3000; i++)
  285.     {
  286.         _nop_();
  287.         _nop_();
  288.         _nop_();
  289.         _nop_();
  290.     }
  291. }

  292. void main()
  293. {
  294.     P0M0 = 0x00;
  295.     P0M1 = 0x00;
  296.     P1M0 = 0x00;
  297.     P1M1 = 0x00;
  298.     P2M0 = 0x00;
  299.     P2M1 = 0x00;
  300.     P3M0 = 0x00;
  301.     P3M1 = 0x00;
  302.     P4M0 = 0x00;
  303.     P4M1 = 0x00;
  304.     P5M0 = 0x00;
  305.     P5M1 = 0x00;

  306.     P_SW2 = 0x80;

  307.     I2CCFG = 0xe0;                              //使能I2C主机模式
  308.     I2CMSST = 0x00;

  309.     Start();                                    //发送起始命令
  310.     SendData(0x5a);                             //发送设备地址(010_1101B)+写命令(0B)
  311.     RecvACK();
  312.     SendData(0x00);                             //发送存储地址
  313.     RecvACK();
  314.     SendData(0x12);                             //写测试数据1
  315.     RecvACK();
  316.     SendData(0x78);                             //写测试数据2
  317.     RecvACK();
  318.     Stop();                                     //发送停止命令

  319.     Start();                                    //发送起始命令
  320.     SendData(0x5a);                             //发送设备地址(010_1101B)+写命令(0B)
  321.     RecvACK();
  322.     SendData(0x00);                             //发送存储地址高字节
  323.     RecvACK();
  324.     Start();                                    //发送起始命令
  325.     SendData(0x5b);                             //发送设备地址(010_1101B)+读命令(1B)
  326.     RecvACK();
  327.     P0 = RecvData();                            //读取数据1
  328.     SendACK();
  329.     P2 = RecvData();                            //读取数据2
  330.     SendNAK();
  331.     Stop();                                     //发送停止命令

  332.     P_SW2 = 0x00;

  333.     while (1);
  334. }


复制代码



回复

使用道具 举报

ID:961114 发表于 2022-9-3 11:16 | 显示全部楼层
本帖最后由 STC庄伟 于 2022-9-5 13:29 编辑

111.jpg
STC-ISP软件V6.90I版
2.jpg
http://www.stcmcudata.com/STC8F-DATASHEET/STC32G.pdf
回复

使用道具 举报

13#
无效楼层,该帖已经被删除
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

Powered by 单片机教程网

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