搜索
bottom↓
回复: 3

基于中断的I2C库

[复制链接]

出0入0汤圆

发表于 2012-6-24 15:42:29 | 显示全部楼层 |阅读模式
本帖最后由 js200300953 于 2012-6-24 15:50 编辑

这个库是NUC140的,应该很容易就可以移植到其他芯片上(其实这个库是从AVRi移植过来的),特别是同为M3的STM32。
希望对大家有帮助。
废话少说,上代码。
这是头文件:
  1. /* lib/bus/i2c/i2c.h
  2. * 2012-5-11 16:05:24 */

  3. #ifndef __FILE_LIB_BUS_I2C_I2C_H__
  4. #define __FILE_LIB_BUS_I2C_I2C_H__

  5. #include "NUC1xx.h"
  6. #include "../../common/common.h"

  7. /* 数据传输回调函数。
  8. * 每(准备)传输一个字节都调用一次。
  9. * 参数:
  10. *      seq  => 序号,第一次调用时为0,以后每次调用递增。
  11. *      data => seq==0时写(从机地址+W/R)到data。
  12. *              seq!=0时data是数据。发送就写data,接收就读data。
  13. * 返回值表示下一步的行为:
  14. *   I2C_RT_START => 发送开始信号。
  15. *   I2C_RT_STOP  => 发送停止信号。
  16. *   I2C_RT_REPEAT_START_OR_STOP => 如果有下一次传输,就发送RepeatStart,否则发送Stop。
  17. *   I2C_RT_ACK   => 继续传送,回应ACK。
  18. *   I2C_RT_NACK  => 继续传送,回应NACK。  */
  19. typedef uint8_t (* I2C_transmitCallback)(uint8_t seq,uint8_t * data);

  20. /* 异常回调函数。
  21. * 总线出现异常就会被调用。
  22. * 参数:
  23. *   exception => 异常类型,{I2C_EXCEPTION_NACK,I2C_EXCEPTION_ARBITRATION_LOST}。
  24. * 返回值表示下一步的行为:
  25. *   I2C_RT_START => 发送开始信号。
  26. *   I2C_RT_STOP  => 发送停止信号,终止传输(推荐)。
  27. *   I2C_RT_ACK   => 继续传送,回应ACK。
  28. *   I2C_RT_NACK  => 继续传送,回应NACK。  */
  29. typedef uint8_t (* I2C_exceptionCallback)(uint8_t exception);
  30. enum {I2C_EXCEPTION_NACK,I2C_EXCEPTION_ARBITRATION_LOST};

  31. #define I2C_NO_CALLBACK 0
  32. #define I2C_isCallback(cb) ((cb) != I2C_NO_CALLBACK)

  33. /* 包装变量的结构体。*/
  34. typedef struct
  35. {
  36.         I2C_transmitCallback transmitCallback;
  37.         I2C_transmitCallback nextCallback;
  38.         I2C_exceptionCallback exceptionCallback;
  39.         uint32_t curSeq : 7;
  40.         uint32_t isIdle : 1;
  41. }I2C_t;

  42. /*
  43. * 函数声明。 */
  44. void I2C_init                  (uint8_t which,uint32_t rate);
  45. uint8_t I2C_transmit           (uint8_t which,I2C_transmitCallback cb);
  46. uint8_t I2C_isIdle             (uint8_t which);
  47. void I2C_setNextCallback       (uint8_t which,I2C_transmitCallback cb);
  48. void I2C_setExceptionCallback  (uint8_t which,I2C_exceptionCallback cb);
  49. //
  50. void I2C_IRQHandler            (uint8_t which);
  51. void I2C_actionStart           (uint8_t which);
  52. void I2C_actionStop            (uint8_t which);
  53. void I2C_actionAck             (uint8_t which);
  54. void I2C_actionNack            (uint8_t which);
  55. void I2C_actionStart_notInIRQ  (uint8_t which);

  56. /* 用7位的地址构造(地址+W/R)字节。*/
  57. #define I2C_addressToByte_write(addr7) ((addr7)<<1)
  58. #define I2C_addressToByte_read(addr7)  (((addr7)<<1) | 1)

  59. /*
  60. * 函数返回值。
  61. * RT : return */
  62. enum
  63. {
  64.         I2C_RT_IS_IDLE_NO  = 0,
  65.         I2C_RT_IS_IDLE_YES = 1
  66. };
  67. enum
  68. {
  69.         I2C_RT_TRANSMIT_NORMAL = 0,
  70.         I2C_RT_TRANSMIT_BUSY,
  71.         I2C_RT_TRANSMIT_ERROR,
  72. };
  73. enum
  74. {
  75.         I2C_RT_START,
  76.         I2C_RT_REPEAT_START_OR_STOP,
  77.         I2C_RT_STOP,
  78.         I2C_RT_ACK,
  79.         I2C_RT_NACK,
  80. };

  81. /*
  82. * 总线状态。
  83. * ST : status
  84. * MA : master
  85. * MT : master transmit
  86. * MR : master receive */
  87. enum
  88. {
  89.     I2C_ST_MA_STARTED          = 0x08,
  90.     I2C_ST_MA_REPEAT_STARTED   = 0x10,
  91.     I2C_ST_MT_ADDR_ACK         = 0x18,
  92.     I2C_ST_MT_ADDR_NACK        = 0x20,
  93.     I2C_ST_MT_DATA_ACK         = 0x28,
  94.     I2C_ST_MT_DATA_NACK        = 0x30,
  95.     I2C_ST_MA_ARBITRATION_LOST = 0x38,
  96.     I2C_ST_MR_ADDR_ACK         = 0x40,
  97.     I2C_ST_MR_ADDR_NACK        = 0x48,
  98.     I2C_ST_MR_DATA_ACK         = 0x50,
  99.     I2C_ST_MR_DATA_NACK        = 0x58,
  100.     I2C_ST_ERROR               = 0x00,
  101. };

  102. #endif // __FILE_LIB_BUS_I2C_I2C_H__
复制代码
然后是代码:
  1. /* lib/bus/i2c/i2c.c
  2. * 2012-5-11 16:04:52 */

  3. #include "NUC1xx.h"
  4. #include "../../common/common.h"
  5. #include "i2c.h"

  6. /*
  7. * 定义变量  */
  8. I2C_T * const I2C_Base[2] = {I2C0,I2C1};
  9. volatile static I2C_t I2C_var[2];

  10. /*
  11. * 初始化I2C。
  12. * 参数
  13. *   which => 指定总线,{0,1}。
  14. *   rate  => 时钟,kHz,[48,12000]。基于48Mhz的系统时钟。*/
  15. void I2C_init(uint8_t which,uint32_t rate)
  16. {
  17.         if(which == 0)
  18.         {
  19.                 /*
  20.                  * 设置针脚功能。 */
  21.                 SYS->GPAMFP.I2C0_SCL = 1;
  22.                 SYS->GPAMFP.I2C0_SDA = 1;
  23.                 /*
  24.                  * 允许中断。 */
  25.                 NVIC_ISER->I2C0_INT = 1;
  26.                 /*
  27.                  * 通入时钟。 */
  28.                 SYSCLK->APBCLK.I2C0_EN = 1;
  29.         }
  30.         else if(which == 1)
  31.         {
  32.                 /*
  33.                  * 设置针脚功能。 */
  34.                 SYS->GPAMFP.I2C1_SCL_nRD = 1;
  35.                 SYS->GPAMFP.I2C1_SDA_nWR = 1;
  36.                 SYS->ALTMFP.EBI_EN = 0;
  37.                 /*
  38.                  * 允许中断。 */
  39.                 NVIC_ISER->I2C1_INT = 1;
  40.                 /*
  41.                  * 通入时钟。 */
  42.                 SYSCLK->APBCLK.I2C1_EN = 1;
  43.         }
  44.         I2C_var[which].isIdle = 1;
  45.         I2C_var[which].transmitCallback = I2C_NO_CALLBACK;
  46.         I2C_var[which].nextCallback = I2C_NO_CALLBACK;
  47.         I2C_var[which].exceptionCallback = I2C_NO_CALLBACK;
  48.         /*
  49.          * 设置时钟。 */
  50.         I2C_Base[which]->u32I2CLK = 12000 / rate - 1;
  51. }

  52. /* 判断I2C是否空闲。
  53. * 参数
  54. *   which => 指定总线,{0,1}。*/
  55. uint8_t I2C_isIdle(uint8_t which)
  56. {
  57.         return I2C_var[which].isIdle;
  58. }

  59. /*
  60. * 传送数据,异步。
  61. * 参数
  62. *   which => 指定总线,{0,1}。
  63. *   cb    => 回调函数,传送是发送还是接收,取决于回调函数的具体实现。
  64. * 返回值
  65. *   I2C_RT_TRANSMIT_NORMAL => 正常。但不保证发送成功。
  66. *   I2C_RT_TRANSMIT_BUSY   => 总线忙。
  67. *   I2C_RT_TRANSMIT_ERROR  => 指定的总线不存在。*/
  68. uint8_t I2C_transmit(uint8_t which,I2C_transmitCallback cb)
  69. {
  70.         if(!I2C_isIdle(which))
  71.                 return I2C_RT_TRANSMIT_BUSY;
  72.         I2C_var[which].isIdle = 0;
  73.         //
  74.         if(which > 1)
  75.                 return I2C_RT_TRANSMIT_ERROR;
  76.         //
  77.         I2C_var[which].transmitCallback = cb;
  78.         I2C_var[which].nextCallback = I2C_NO_CALLBACK;
  79.         I2C_var[which].exceptionCallback = I2C_NO_CALLBACK;
  80.         //
  81.         I2C_actionStart(which);
  82.         return I2C_RT_TRANSMIT_NORMAL;
  83. }

  84. /*
  85. * 设置下一个任务。
  86. * 用于连续传输,中间是Repeat Start,而不是Stop。
  87. * 本次传输有效,下次调用I2C_transmit()时会重置。 */
  88. void I2C_setNextCallback(uint8_t which,I2C_transmitCallback cb)
  89. {
  90.         I2C_var[which].nextCallback = cb;
  91. }

  92. /*
  93. * 设置错误回调函数。
  94. * 详细见I2C_transmitCallback的定义。
  95. * 本次传输有效,下次调用I2C_transmit()时会重置。 */
  96. void I2C_setExceptionCallback(uint8_t which,I2C_exceptionCallback cb)
  97. {
  98.         I2C_var[which].exceptionCallback = cb;
  99. }

  100. /*
  101. * I2C通用中断处理函数。
  102. * 参数
  103. *   which => 指定总线。 */
  104. void I2C_IRQHandler(uint8_t which)
  105. {
  106.         /*
  107.          * 根据总线状态决定下一步动作。 */
  108.         uint8_t action = I2C_RT_REPEAT_START_OR_STOP;
  109.         switch(I2C_Base[which]->I2CSTATUS)
  110.         {
  111.         case I2C_ST_MA_STARTED :
  112.         case I2C_ST_MA_REPEAT_STARTED :
  113.                 /* Start信号已发出,初始化计数,发送(地址+W/R)。 */
  114.                 I2C_var[which].curSeq = 0;
  115.                 action = I2C_var[which].transmitCallback(I2C_var[which].curSeq,
  116.                                 (uint8_t *)&(I2C_Base[which]->u32I2CDAT));
  117.                 break;
  118.         case I2C_ST_MT_ADDR_ACK :
  119.         case I2C_ST_MT_DATA_ACK :
  120.         case I2C_ST_MR_DATA_ACK :
  121.                 /* 处理数据和获取下一步动作。 */
  122.                 I2C_var[which].curSeq ++;
  123.                 action = I2C_var[which].transmitCallback(I2C_var[which].curSeq,
  124.                                 (uint8_t *)&(I2C_Base[which]->u32I2CDAT));
  125.                 break;
  126.         case I2C_ST_MR_ADDR_ACK :
  127.                 /* 接收模式,发送完地址,直接ACK就可以。 */
  128.                 action = I2C_RT_ACK;
  129.                 break;
  130.         case I2C_ST_MT_ADDR_NACK :
  131.         case I2C_ST_MT_DATA_NACK :
  132.         case I2C_ST_MR_ADDR_NACK :
  133.                 /* 发送数据后收到NACK,默认动作是Stop。 */
  134.                 if(I2C_isCallback(I2C_var[which].exceptionCallback))
  135.                         action = I2C_var[which].exceptionCallback(I2C_EXCEPTION_NACK);
  136.                 else
  137.                         action = I2C_RT_REPEAT_START_OR_STOP;
  138.                 break;
  139.         case I2C_ST_MR_DATA_NACK :
  140.                 /* 如果接收数据时响应了NACK,自动Stop。 */
  141.                 action = I2C_RT_REPEAT_START_OR_STOP;
  142.                 break;
  143.         case I2C_ST_MA_ARBITRATION_LOST :
  144.                 /* 总线失控,默认等待重新开始。*/
  145.                 if(I2C_isCallback(I2C_var[which].exceptionCallback))
  146.                         action = I2C_var[which].exceptionCallback(I2C_EXCEPTION_ARBITRATION_LOST);
  147.                 else
  148.                         action = I2C_RT_START;
  149.                 break;
  150.         case I2C_ST_ERROR :
  151.         default :
  152.                 action = I2C_RT_STOP;
  153.                 break;
  154.         }
  155.         /*
  156.          * 执行动作。 */
  157.         switch(action)
  158.         {
  159.         case I2C_RT_START :
  160.                 I2C_actionStart(which);
  161.                 break;
  162.         case I2C_RT_REPEAT_START_OR_STOP :
  163.                 /* 检查有没有连续的任务,有就Repeat Start,否则Stop。 */
  164.                 if(I2C_isCallback(I2C_var[which].nextCallback))
  165.                 {
  166.                         I2C_var[which].transmitCallback = I2C_var[which].nextCallback;
  167.                         I2C_var[which].nextCallback = I2C_NO_CALLBACK;
  168.                         I2C_actionStart(which);
  169.                 }
  170.                 else
  171.                 {
  172.                         I2C_actionStop(which);
  173.                 }
  174.                 break;
  175.         case I2C_RT_STOP :
  176.                 I2C_actionStop(which);
  177.                 break;
  178.         case I2C_RT_ACK :
  179.                 I2C_actionAck(which);
  180.                 break;
  181.         case I2C_RT_NACK :
  182.                 I2C_actionNack(which);
  183.                 break;
  184.         }
  185. }

  186. /*
  187. * I2C0中断处理函数。 */
  188. void I2C0_IRQHandler(void)
  189. {
  190.         I2C_IRQHandler(0);
  191. }

  192. /*
  193. * I2C1中断处理函数。 */
  194. void I2C1_IRQHandler(void)
  195. {
  196.         I2C_IRQHandler(1);
  197. }

  198. void I2C_actionStart(uint8_t which)
  199. {
  200.         I2C_Base[which]->u32I2CON = (_BV(3)|_BV(6)|_BV(7)|_BV(5));
  201. }

  202. void I2C_actionStop(uint8_t which)
  203. {
  204.         I2C_Base[which]->u32I2CON = (_BV(3)|_BV(6)|_BV(7)|_BV(4));
  205.         I2C_var[which].isIdle = 1;
  206. }

  207. void I2C_actionAck(uint8_t which)
  208. {
  209.         I2C_Base[which]->u32I2CON = (_BV(3)|_BV(6)|_BV(7)|_BV(2));
  210. }

  211. void I2C_actionNack(uint8_t which)
  212. {
  213.         I2C_Base[which]->u32I2CON = (_BV(3)|_BV(6)|_BV(7));
  214. }

  215. void I2C_actionStart_notInIRQ(uint8_t which)
  216. {
  217.         I2C_Base[which]->u32I2CON = (_BV(6)|_BV(7)|_BV(5));
  218. }
复制代码
接口只有5个函数:
  1. void I2C_init                  (uint8_t which,uint32_t rate);
  2. uint8_t I2C_transmit           (uint8_t which,I2C_transmitCallback cb);
  3. uint8_t I2C_isIdle             (uint8_t which);
  4. void I2C_setNextCallback       (uint8_t which,I2C_transmitCallback cb);
  5. void I2C_setExceptionCallback  (uint8_t which,I2C_exceptionCallback cb);
复制代码

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2012-6-24 18:54:54 | 显示全部楼层
收藏下  过些天研究下STM32的硬件IIC                                                                                                                             

出0入0汤圆

发表于 2012-6-25 00:16:45 | 显示全部楼层
Name_006 发表于 2012-6-24 18:54
收藏下  过些天研究下STM32的硬件IIC                                                                   ...

me,too.不过我是研究stm32基础

出0入0汤圆

发表于 2012-7-5 08:03:39 | 显示全部楼层
留待备用
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 04:26

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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