当前位置:   article > 正文

AT89C52编写I2C总线通讯,附带源码_at89c52延时函数

at89c52延时函数

今天学习了一下AT89C52编写IIC总线通讯,通讯时序方面还可以接受,但是容易记混,重复了两遍过程,熟悉了很多,以后害的多看多学多记多用。使用的是AT24c02来模拟的I2C的通讯时序

原理讲解:

  1. /*====================================
  2. 函数 :At24c02Write(uchar ADDR, DAT)
  3. 参数 :ADDR 单元地址0-255,DAT 需要输入的数据0-255
  4. 返回值 :无
  5. 描述 :At24c02指定单元写入一个字节数据
  6. ====================================*/
  7. void AT24c02Write(uchar ADDR,DAT)//写进AT24c02
  8. {
  9. I2cStart(); //I2C起始信号
  10. I2cSendByte(AT24c02ADDR + I2cWrite);//IC发送一个字节**************************
  11. if(ReadACK()) //读从机应答
  12. AckFlag =1; //无应答
  13. else
  14. AckFlag =0; //应答
  15. I2cSendByte(ADDR);//发送储存单元地址字节**************************************
  16. if(ReadACK())
  17. AckFlag =1; //无应答
  18. else
  19. AckFlag =0; //应答
  20. I2cSendByte(DAT);//IC发送一个字节
  21. if(ReadACK())
  22. AckFlag =1; //无应答
  23. else
  24. AckFlag =0; //应答
  25. I2cStop(); //I2C停止信号
  26. }

  1. /*====================================
  2. 函数 :At24c02Read(uchar ADDR)
  3. 参数 :ADDR 单元地址 0-255
  4. 返回值 :返回指定单元的数据
  5. 描述 :读AT24C02指定单元内数据
  6. ====================================*/
  7. uchar AT24c02Read(uchar ADDR)
  8. {
  9. uchar DAT; //返回数据
  10. I2cStart();//I2C起始信号
  11. I2cSendByte(AT24c02ADDR +I2cWrite);//IC发送一个字节//发送器件地址加写方向位
  12. if(ReadACK()) //读从机应答
  13. AckFlag =1; //无应答
  14. else
  15. AckFlag =0; //应答
  16. I2cSendByte(ADDR);//IC发送一个字节
  17. ReadACK(); //读从机应答
  18. I2cStart(); //再次产生I2C起始信号
  19. I2cSendByte(AT24c02ADDR +I2cRead);//IC读取
  20. if(ReadACK()) //读从机应答
  21. AckFlag =1; //无应答
  22. else
  23. AckFlag =0; //应答
  24. DAT=I2cReadByte();//读取一个字节
  25. SendACK(1); //主机发送非应答
  26. I2cStop(); //I2C停止信号
  27. return(DAT); //返回读出数据
  28. }

  1. /*====================================
  2. 函数 :I2cStart()
  3. 参数 :无
  4. 返回值 :无
  5. 描述 :I2C总线起始信号
  6. ====================================*/
  7. void I2cStart()//起始信号的函数
  8. {
  9. SCL =1;
  10. SDA =1;
  11. delay5us();
  12. SDA =0;
  13. delay5us();
  14. }
  15. /*====================================
  16. 函数 :I2cStop()
  17. 参数 :无
  18. 返回值 :无
  19. 描述 :I2C总线停止信号
  20. ====================================*/
  21. void I2cStop()//停止信号的函数
  22. {
  23. SCL =0;
  24. SDA =0;
  25. SCL =1;
  26. delay5us();
  27. SDA =1;
  28. delay5us();
  29. }
  30. /*====================================
  31. 函数 :ReadACK()
  32. 返回值 :1非应答,0应答
  33. 描述 :I2C总线读从机应答信号
  34. ====================================*/
  35. bit ReadACK()//主机读从机应答
  36. {
  37. SCL =0; //拉低时钟总线,允许从机控制SDA
  38. SCL =1; //拉高,读SDA
  39. delay5us();
  40. if (SDA) //非应答
  41. {
  42. SCL =0;
  43. return(1);
  44. }
  45. else //应答
  46. {
  47. SCL =0;
  48. return(0);
  49. }
  50. }
  51. /*====================================
  52. 函数 :SendACK(bit i)
  53. 参数 :1主机发送非应答,0发送应答
  54. 返回值 :无
  55. 描述 :主机发送应答信号
  56. ====================================*/
  57. void SendACK(bit i)//主机发送应答
  58. {
  59. SCL =0; //拉低时钟总线,允许主机控制SDA
  60. if(i) //发送非应答 SDA=1
  61. SDA =1;
  62. else //发送应答 SDA=0
  63. SDA =0;
  64. SCL =1; //拉高总线 让从机读SDA
  65. delay5us(); //延时5us
  66. SCL =0;//拉低时钟总线,允许SDA释放
  67. SDA =1;//释放数据总线
  68. }

  1. /*IIC通信,AT24C02读写数据,数码管显示数据*/
  2. #include <REGX52.H>
  3. #include <intrins.h>
  4. #define uint unsigned int
  5. #define uchar unsigned char
  6. //宏定义
  7. #define AT24c02ADDR 0xA0 //AT24C02硬件地址
  8. #define I2cRead 1 //I2C读方向位
  9. #define I2cWrite 0 //I2C写方向位
  10. sbit DU =P2^6;//段选
  11. sbit WE =P2^7;//位选
  12. sbit SCL =P2^1;//时钟线
  13. sbit SDA =P2^0;//数据线
  14. uchar num;//数码管显示的值
  15. bit AckFlag;
  16. uchar ms_50,s; //记录50ms的个数 20个为1s
  17. //共阴极数码管0-9
  18. uchar code duanxuan[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};
  19. //位选前4个数码管
  20. uchar code weixuan[] ={0xfe,0xfd,0xfb,0xf7};
  21. void delay(uint x) //@12.000MHz 延迟函数1毫秒
  22. {
  23. unsigned char i, j;
  24. while(x--)
  25. {
  26. i = 2;
  27. j = 239;
  28. do
  29. {
  30. while (--j);
  31. } while (--i);
  32. }
  33. }
  34. void delay5us() //@12.000MHz
  35. {
  36. _nop_();
  37. }
  38. void display(uchar i) //数码管显示函数
  39. {
  40. static uchar wei;
  41. uchar qian,bai, shi, ge;
  42. qian =i/1000;
  43. bai = i / 100%10;
  44. shi = i /10%10;
  45. ge = i % 10;
  46. P0 = 0XFF;//清除断码
  47. WE = 1; //位选打开
  48. P0 = weixuan[wei];
  49. WE = 0; //关闭位选寄存器
  50. switch(wei)
  51. {
  52. case 0:DU = 1;P0 = duanxuan[qian];DU = 0;break;
  53. case 1:DU = 1;P0 = duanxuan[bai];DU = 0;break;
  54. case 2:DU = 1;P0 = duanxuan[shi];DU = 0;break;
  55. case 3:DU = 1;P0 = duanxuan[ge];DU = 0;break;
  56. }
  57. wei++;
  58. if(wei ==4)
  59. wei =0;
  60. }
  61. void timer0Init() //定时器0初始化
  62. {
  63. EA =1; //打开总中断
  64. ET0 =1; //打开定时器0中断
  65. TR0 =1; //启动定时器0
  66. //TCON中的打开定时器
  67. TMOD |=0x01; //TMOD不能位寻址 0000 00010 01表示定时器模式 16位定时
  68. TH0 =0xed; //(65535-46082)/256; //定时器 50ms 65536-50000/1.085/2568
  69. TL0 =0xff; //(65535-46082)%256; //8
  70. }
  71. /*******************************************************************
  72. //IIC通信代码
  73. *******************************************************************/
  74. /*====================================
  75. 函数 :I2cStart()
  76. 参数 :无
  77. 返回值 :无
  78. 描述 :I2C总线起始信号
  79. ====================================*/
  80. void I2cStart()//起始信号的函数
  81. {
  82. SCL =1;
  83. SDA =1;
  84. delay5us();
  85. SDA =0;
  86. delay5us();
  87. }
  88. /*====================================
  89. 函数 :I2cStop()
  90. 参数 :无
  91. 返回值 :无
  92. 描述 :I2C总线停止信号
  93. ====================================*/
  94. void I2cStop()//停止信号的函数
  95. {
  96. SCL =0;
  97. SDA =0;
  98. SCL =1;
  99. delay5us();
  100. SDA =1;
  101. delay5us();
  102. }
  103. /*====================================
  104. 函数 :ReadACK()
  105. 返回值 :1非应答,0应答
  106. 描述 :I2C总线读从机应答信号
  107. ====================================*/
  108. bit ReadACK()//主机读从机应答
  109. {
  110. SCL =0; //拉低时钟总线,允许从机控制SDA
  111. SCL =1; //拉高,读SDA
  112. delay5us();
  113. if (SDA) //非应答
  114. {
  115. SCL =0;
  116. return(1);
  117. }
  118. else //应答
  119. {
  120. SCL =0;
  121. return(0);
  122. }
  123. }
  124. /*====================================
  125. 函数 :SendACK(bit i)
  126. 参数 :1主机发送非应答,0发送应答
  127. 返回值 :无
  128. 描述 :主机发送应答信号
  129. ====================================*/
  130. void SendACK(bit i)//主机发送应答
  131. {
  132. SCL =0; //拉低时钟总线,允许主机控制SDA
  133. if(i) //发送非应答 SDA=1
  134. SDA =1;
  135. else //发送应答 SDA=0
  136. SDA =0;
  137. SCL =1; //拉高总线 让从机读SDA
  138. delay5us(); //延时5us
  139. SCL =0;//拉低时钟总线,允许SDA释放
  140. SDA =1;//释放数据总线
  141. }
  142. //发送一个字节8位,从最高位开始***********************************************发送1个字节
  143. /*====================================
  144. 函数 :I2cSendByte(uchar DAT)
  145. 参数 :DAT需要发送的数据
  146. 返回值 :无
  147. 描述 :I2C发送一个字节数据
  148. ====================================*/
  149. void I2cSendByte(uchar DAT)
  150. {
  151. uchar i;
  152. for(i=0;i<8;i++) //分别写8次,每次写1
  153. {
  154. SCL =0; //时钟线为0
  155. if(DAT & 0x80) //1011 0110&1000 0000 1为真所以发送1 否则为0则发送0
  156. SDA =1;
  157. else
  158. SDA =0;
  159. SCL =1;
  160. DAT =DAT<<1; //向左移位 每次移位1次 一共8
  161. }
  162. SCL =0; //拉低时钟
  163. SDA = 1; //释放数据总线
  164. }
  165. /*====================================
  166. 函数 :At24c02Write(uchar ADDR, DAT)
  167. 参数 :ADDR 单元地址0-255,DAT 需要输入的数据0-255
  168. 返回值 :无
  169. 描述 :At24c02指定单元写入一个字节数据
  170. ====================================*/
  171. void AT24c02Write(uchar ADDR,DAT)//写进AT24c02
  172. {
  173. I2cStart(); //I2C起始信号
  174. I2cSendByte(AT24c02ADDR + I2cWrite);//IC发送一个字节**************************
  175. if(ReadACK()) //读从机应答
  176. AckFlag =1; //无应答
  177. else
  178. AckFlag =0; //应答
  179. I2cSendByte(ADDR);//发送储存单元地址字节**************************************
  180. if(ReadACK())
  181. AckFlag =1; //无应答
  182. else
  183. AckFlag =0; //应答
  184. I2cSendByte(DAT);//IC发送一个字节
  185. if(ReadACK())
  186. AckFlag =1; //无应答
  187. else
  188. AckFlag =0; //应答
  189. I2cStop(); //I2C停止信号
  190. }
  191. /*====================================
  192. 函数 :I2cReadByte()
  193. 参数 :无
  194. 返回值 :返回读出的一字节数据
  195. 描述 :I2C总线读一字节数据
  196. ====================================*/
  197. uchar I2cReadByte()//读一个字节
  198. {
  199. uchar i,DAT;
  200. for(i =0;i<8;i++)//分别读8次,每次读一位
  201. {
  202. DAT<<=1; //数据左移1位,准备接收一位******************************************
  203. SCL =0; //拉低时钟总线,允许从机控制SDA变化
  204. SCL =1; //拉高时钟总线,读取SDA上的数据
  205. if(SDA)
  206. DAT |=0x01; //1则写1,否则不行执行写1,通过左移补0
  207. }
  208. return(DAT);
  209. }
  210. /* 从机要发送的值为 1010 0000
  211. DAT的初始值为 0000 0000
  212. DAT<<1 =0000 0000
  213. DAT|=0x01;
  214. 0000 0001
  215. DAT<<1 =0000 0010
  216. DAT<<1 =0000 0100
  217. DAT|=0x01 =0000 0101
  218. 最后成功发送1010 0000*/
  219. //读取AT24c02函数
  220. /*====================================
  221. 函数 :At24c02Read(uchar ADDR)
  222. 参数 :ADDR 单元地址 0-255
  223. 返回值 :返回指定单元的数据
  224. 描述 :读AT24C02指定单元内数据
  225. ====================================*/
  226. uchar AT24c02Read(uchar ADDR)
  227. {
  228. uchar DAT; //返回数据
  229. I2cStart();//I2C起始信号
  230. I2cSendByte(AT24c02ADDR +I2cWrite);//IC发送一个字节//发送器件地址加写方向位
  231. if(ReadACK()) //读从机应答
  232. AckFlag =1; //无应答
  233. else
  234. AckFlag =0; //应答
  235. I2cSendByte(ADDR);//IC发送一个字节
  236. ReadACK(); //读从机应答
  237. I2cStart(); //再次产生I2C起始信号
  238. I2cSendByte(AT24c02ADDR +I2cRead);//IC读取
  239. if(ReadACK()) //读从机应答
  240. AckFlag =1; //无应答
  241. else
  242. AckFlag =0; //应答
  243. DAT=I2cReadByte();//读取一个字节
  244. SendACK(1); //主机发送非应答
  245. I2cStop(); //I2C停止信号
  246. return(DAT); //返回读出数据
  247. }
  248. void timer0() interrupt 1 //定时器0中断
  249. {
  250. TH0 =0xed;
  251. TL0 =0xff;
  252. display(num);
  253. }
  254. void main()
  255. {
  256. timer0Init(); //定时器0初始化
  257. EA =0; //屏蔽中断
  258. AT24c02Write(55,119); //给第55单元写入数据“119
  259. delay(5); //延时等待AT24C02处理*******************************************
  260. num =AT24c02Read(55); //读出第55单元内数据送给显示变量 返回值为DAT
  261. if(AckFlag) //当从机非应答
  262. P1 = 0; //亮P1所有灯
  263. else
  264. P1 = 0XFF; //灭P1所有灯
  265. EA =1; //开总中断
  266. while(1);
  267. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/495115
推荐阅读