[新手园地] HOT大叔NUC120助学板第七贴----I2C(查询方式)

[复制链接]
 楼主| Swallow_0322 发表于 2011-4-11 17:12 | 显示全部楼层 |阅读模式
菜鸟玩I2C查询方式完成单字节写及随机地址读操作,望各位多多交流,多多指教!

源代码:

  1. /**************************************************
  2. ** 文件名称:NUC120_HOT_I2C.c
  3. ** 文件说明:NUC120助学板练习程序
  4. ** 创建日期:2011-04-11
  5. ** 修改日期:
  6. ** 备    注:I2C查询方式完成单字节写及随机地址读操作
  7. **************************************************/
  8. #include <stdio.h>
  9. #include "NUC1xx.h"
  10. #include "Driver\DrvGPIO.h"
  11. #include "Driver\DrvSYS.h"
  12. #include "Driver\DrvUART.h"
  13. #include "Driver\DrvI2C.h"

  14. uint8_t  Run_Led = 4;    //2----LED1  3----LED2   4----LED3  5----LED4
  15. volatile uint8_t Receive_Data = 0;
  16. volatile uint8_t IsStart = FALSE;
  17. /***************
  18. **  函数声明  **
  19. ***************/
  20. void Init_System (void);
  21. void Init_Uart (void);
  22. void UART_INT_HANDLE(uint32_t u32IntStatus);
  23. void I2C_WriteByte ( uint32_t address,uint8_t data );
  24. uint8_t I2C_ReadByte ( uint32_t address );


  25. /*****************************
  26. ** Name:      UART_INT_HANDLE
  27. ** Function:  UART Callback function
  28. ** Input:     u32IntStatus
  29. ** OutPut:    None
  30. ** Data:      2011-03-17
  31. ** Note:      
  32. ****************************/
  33. void UART_INT_HANDLE(uint32_t u32IntStatus)
  34. {
  35.   uint8_t bInChar[1]={0xFF};
  36. if(u32IntStatus & DRVUART_RDAINT)
  37. {
  38.   /* Get all the input characters */
  39.   while(UART0->ISR.RDA_IF==1)
  40.   {
  41.    /* Get the character from UART Buffer */
  42.    DrvUART_Read(UART_PORT0,bInChar,1);
  43.    if (IsStart!=TRUE)
  44.    {
  45.     IsStart = TRUE;
  46.     Receive_Data = bInChar[0];
  47.    }
  48.   }
  49. }
  50. }
  51. /*****************************
  52. ** Name:      Init_System
  53. ** Function:  系统初始化函数
  54. ** Input:      None
  55. ** OutPut:     None
  56. ** Data:       2011-03-17
  57. ** Note:      
  58. ****************************/
  59. void Init_System(void)
  60. {
  61. /* Unlock the locked registers before access */
  62.     UNLOCKREG(x); //寄存器锁定键地址寄存器(RegLockAddr) :有些系统控制寄存器需要被保护起来,以防止误操作而影响芯片运行,
  63.         //这些寄存器在上电复位到用户解锁定之前是锁定的。用户可以连续依次写入“59h”, “16h” “88h”到0x5000_0100解锁定.
  64. /* Enable the 12MHz oscillator oscillation */
  65. DrvSYS_SetOscCtrl(E_SYS_XTL12M, 1);        //SYSCLK->PWRCON.XTL12M_EN = 1;
  66. /* Waiting for 12M Xtal stable */
  67. //while (DrvSYS_GetChipClockSourceStatus(E_SYS_XTL12M) != 1);  //SYSCLK->CLKSTATUS.XTL12M_STB
  68. /*eClkSrc  - [in]  E_SYS_XTL12M / E_SYS_XTL32K / E_SYS_OSC22M / E_SYS_OSC10K / E_SYS_PLL    */
  69. // Note: Only some of NuMicro NUC100 Series support this function.
  70. DrvSYS_Delay(5000);
  71. LOCKREG(x);
  72. //向“0x5000_0100”写入任何值,就可以重锁保护寄存器
  73. }
  74. /*****************************
  75. ** Name:      Init_Uart
  76. ** Function:  UART初始化函数
  77. ** Input:      None
  78. ** OutPut:     None
  79. ** Data:       2011-03-17
  80. ** Note:      
  81. ****************************/
  82. void Init_Uart(void)
  83. {
  84. STR_UART_T param;
  85. /*
  86. 声明 UART设置的结构体 位于DRVUART.H
  87. 结构体如下
  88. typedef struct DRVUART_STRUCT
  89. {
  90.   uint32_t            u32BaudRate;   
  91.   E_DATABITS_SETTINS  u8cDataBits;   
  92.   E_STOPBITS_SETTINS  u8cStopBits;   
  93.   E_PARITY_SETTINS  u8cParity;     
  94.   E_FIFO_SETTINGS     u8cRxTriggerLevel;   
  95.   uint8_t             u8TimeOut ;     
  96.       }STR_UART_T;
  97. */
  98. DrvSYS_SelectIPClockSource(E_SYS_UART_CLKSRC,0);      //使能UART时钟
  99. //SYSCLK->CLKSEL1.UART_S = 0;  //UART时钟源选择. 00 =外部12MHz 晶振 01 = PLL 1x =内部 22MHz 振荡器
  100. DrvGPIO_InitFunction(E_FUNC_UART0);          //GPB_MFP0-1-2-3置位 GPIO使能UART功能
  101. //outpw(&SYS->GPBMFP, inpw(&SYS->GPBMFP) | (0xF<<0));
  102. param.u32BaudRate        = 115200;       //  波特率
  103. param.u8cDataBits        = DRVUART_DATABITS_8;    //  数据位
  104. param.u8cStopBits        = DRVUART_STOPBITS_1;    //  停止位
  105. param.u8cParity          = DRVUART_PARITY_NONE;    //  校验位
  106. param.u8cRxTriggerLevel  = DRVUART_FIFO_1BYTES;    //  FIFO存储深度 1 字节
  107. param.u8TimeOut          = 0;        //  FIFO超时设定
  108. /* Set UART Configuration */
  109.   if(DrvUART_Open(UART_PORT0,&param) != E_SUCCESS)   //  串口开启、结构体整体赋值
  110.   printf("UART0 open failed\n");      
  111. /* u32Port -[in] UART Channel:  UART_PORT0 / UART_PORT1 /UART_PORT2 */
  112. /* sParam  -[in] the struct parameter to configure UART    */   
  113. /* Enable Interrupt and install the call back function */
  114. DrvUART_EnableInt(UART_PORT0, DRVUART_RDAINT,UART_INT_HANDLE);
  115. /*u32Port     -[in] UART Channel:  UART_PORT0 / UART_PORT1 / UART_PORT2                   */
  116. /*u32InterruptFlag -[in] DRVUART_LININT/DRVUART_WAKEUPINT/DRVUART_BUFERRINT/DRVUART_RLSINT     */
  117. /*          DRVUART_MOSINT/DRVUART_THREINT/DRVUART_RDAINT/DRVUART_TOUTINT   */
  118. /*pfncallback      -[in] A function pointer for callback function                              */
  119. }
  120. int main (void)
  121. {
  122. uint8_t test = 250;
  123. uint8_t EEPROM_Data = 0;

  124. Init_System();

  125. Init_Uart();
  126. DrvGPIO_InitFunction(E_FUNC_I2C1);  
  127. DrvGPIO_Open(E_GPA,Run_Led, E_IO_OUTPUT);      //程序运行指示
  128. DrvGPIO_ClrBit(E_GPA,Run_Led);
  129. printf("\n");
  130. printf("/*==========================\n");
  131. printf("======菜农 %d 助学计划======\n",test);
  132. printf("========NUC120助学板========\n");
  133. printf("======程序参考新唐BSP库======\n");
  134. printf("=======2011年04月11日=======\n");
  135. printf("========I2C(查询)实验=======\n");
  136. printf("I2C查询方式完成单字节写及随机地址读操作\n");
  137. printf("'R/r'为读指令、'U/u'为加1并存储指令、'D/d'为减1并存储指令\n");
  138. printf("===========================/\n");
  139. EEPROM_Data = I2C_ReadByte(0x00);
  140. printf("AT24C16地址0的内容为:0x%x!\n",EEPROM_Data);
  141. printf("====请输入字符开始测试!===\n");
  142. printf("==========================*/\n");
  143.     while(1)
  144.     {
  145.         if (IsStart)
  146.         {
  147.          switch (Receive_Data)
  148.          {
  149.           case 'R':
  150.     case 'r':
  151.      EEPROM_Data = I2C_ReadByte(0x00);
  152.      printf("AT24C16地址0的内容为:0x%x!\n",EEPROM_Data);
  153.      break;
  154.     case 'U':
  155.     case 'u':
  156.      I2C_WriteByte(0x00,++EEPROM_Data);
  157.      printf("AT24C16地址0的内容加1成功!\n");
  158.      break;
  159.     case 'D':
  160.     case 'd':
  161.      I2C_WriteByte(0x00,--EEPROM_Data);
  162.      printf("AT24C16地址0的内容减1成功!\n");
  163.      break;
  164.     default:
  165.      printf("请确认您输入的指令是否合法!\n");
  166.    
  167.          }
  168.          IsStart = FALSE;
  169.         }
  170.     }
  171. }
  172. /*****************************
  173. ** Name:      I2C_WriteByte
  174. ** Function:  I2C向写单字节函数
  175. ** Input:     uint32_t address,uint8_t data
  176. ** OutPut:    None
  177. ** Data:      2011-04-11
  178. ** Note:      
  179. ****************************/
  180. void I2C_WriteByte ( uint32_t address,uint8_t data )
  181. {
  182. /*
  183. 在字节写模式下,主器件发送起始命令和从器件地址信息(R/W 位置 0)给从器件,
  184. 主器件在收到从器件产生应答信号后,主器件发送1个8位字节地址写入AT24C01/
  185. 02/04/08/16 的地址指针,对于 AT24C31/64/128/256 来说,所不同的是主器件
  186. 发送两个8位地址字写入AT24C32/64/128/256的地址指针。主器件在收到从器件的
  187. 另一个应答信号后,再发送数据到被寻址的存储单元。AT24Cxx 再次应答,并在
  188. 主器件产生停止信号后开始内部数据的擦写,在内部擦写过程中,AT24Cxx 不再
  189. 应答主器件的任何请求。
  190. */
  191. uint32_t i;

  192. DrvI2C_Open(I2C_PORT1, 50000);  //打开I2C1功能,并配置 I2C总线时钟为50KHZ
  193. /* Parameters:port      - [in]  I2C_PORT0 / I2C_PORT1        */
  194. /*           u32BusClock   - [in]  I2C bus clock frequency (Hz)      */

  195. DrvI2C_Ctrl(I2C_PORT1, 1, 0, 0, 0); //设定I2C控制比特   START
  196. /* Parameters:port   - [in]  I2C_PORT0 / I2C_PORT1       */
  197. /*            start   - [in]  1:Enable / 0:Disable       */
  198. /*            stop   - [in]  1:Enable / 0:Disable       */
  199. /*            intFlag   - [in]  Wrtie '1' to clear this flag */
  200. /*            ack   - [in]  1:Enable / 0:Disable       */
  201. while (I2C1->CON.SI == 0);   //查询中断标志位 SI
  202. I2C1->DATA = 0xA0;     //发送写命令
  203.     DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0); //清标志位 SI
  204.     while( I2C1->CON.SI == 0 );      //查询中断标志位 SI

  205. I2C1->DATA = address&0XFF;   //发送地址
  206. DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1); //清标志位 SI 并使能应答
  207. while( I2C1->CON.SI == 0 );   //查询中断标志位 SI

  208. I2C1->DATA = data;     //发送待写内容
  209. DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1); //清标志位 SI 并使能应答
  210. while( I2C1->CON.SI == 0 );   //查询中断标志位 SI

  211. DrvI2C_Ctrl(I2C_PORT1, 0, 1, 1, 0); //清标志位 SI 并STOP

  212. for(i=0;i<60;i++);
  213. DrvI2C_Close(I2C_PORT1);
  214.    
  215. for(i=0;i<6000;i++);
  216. for(i=0;i<6000;i++);
  217. }
  218. /*****************************
  219. ** Name:      I2C_ReadByte
  220. ** Function:  I2C向读单字节函数
  221. ** Input:     uint32_t address,uint8_t data
  222. ** OutPut:    None
  223. ** Data:      2011-04-11
  224. ** Note:      
  225. ****************************/
  226. uint8_t I2C_ReadByte ( uint32_t address )
  227. {
  228. /*
  229. 随机读操作允许主器件对寄存器的任意字节进行读操作,主器件
  230. 首先通过发送起始信号、从器件地址和它想读取的字节数据的地
  231. 址执行一个伪写操作。在AT24Cxx 应答之后,主器件重新发送起
  232. 始信号和从器件地址,此时R/W 位置1,AT24CXX 响应并发送应答
  233. 信号,然后输出所要求的一个 8位字节数据,主器件不发送应答
  234. 信号但产生一个停止信号。
  235. */
  236. uint8_t TEMP;

  237. DrvI2C_Open(I2C_PORT1, 50000);

  238.     DrvI2C_Ctrl(I2C_PORT1, 1, 0, 1, 0);   //设定I2C控制比特   START并清中断标志
  239. while (I2C1->CON.SI == 0);    //查询中断标志位 SI
  240.   
  241. I2C1->DATA = 0XA0;      //发送写命令
  242.     DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0);     //清标志位 SI
  243.     while( I2C1->CON.SI == 0 );      //查询中断标志位 SI
  244.    
  245. I2C1->DATA = address&0xFF;    //发送地址
  246. DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1);     //清标志位 SI 并使能应答
  247. while( I2C1->CON.SI == 0 );       //查询中断标志位 SI

  248. DrvI2C_Ctrl(I2C_PORT1, 1, 0, 1, 0);     //设定I2C控制比特   START并清中断标志
  249. while( I2C1->CON.SI == 0 );       //查询中断标志位 SI

  250. I2C1->DATA = 0XA1;      //发送读命令
  251. DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1);     //清标志位 SI 并使能应答
  252.     while( I2C1->CON.SI == 0 );       //查询中断标志位 SI
  253. //I2C1->DATA = 0xFF;     //通过操作数据寄存器配合控制位的设置启动一次新的I2C操作(此句加与不加未影响到结果)
  254. /*"Software should load the data byte (to be transmitted)into I2DAT before new I2CON setting is done." 手册中该句怎么解释?*/
  255. DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0);     //清标志位 SI
  256. while( I2C1->CON.SI == 0 );       //查询中断标志位 SI
  257. TEMP= I2C1->DATA;      //读数据
  258.   
  259.   DrvI2C_Ctrl(I2C_PORT1, 0, 1, 1, 0);    //清标志位 SI 并STOP
  260. DrvI2C_Close(I2C_PORT1);
  261. return TEMP;
  262. }


工程结构:


串口调试截图:


工程文件:


一点疑问:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
lanrongye 发表于 2011-4-11 17:15 | 显示全部楼层
我坐上传说中的沙发
wzywzy12 发表于 2011-4-11 17:35 | 显示全部楼层
//我的理解是这样的
//发送读命令
I2C1->DATA = 0xA1;//本句先把数据写进相应的寄存器,但不发送数据到总线
DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1);//清SI并要求应答,I2CON内容发生变化,启动发送到总线
while( I2C1->CON.SI == 0 );//直到发送完成
wzywzy12 发表于 2011-4-11 17:53 | 显示全部楼层
还有一点,我觉得下面这句要加的。在接收数据时候起拉高DATA线的作用,才能读到从机发来数据。
//I2C1->DATA = 0xFF;     //通过操作数据寄存器配合控制位的设置启动一次新的I2C操作(此句加与不加未影响到结果)
hotpower 发表于 2011-4-11 18:38 | 显示全部楼层
还有一点,我觉得下面这句要加的。在接收数据时候起拉高DATA线的作用,才能读到从机发来数据。
//I2C1->DATA = 0xFF;     //通过操作数据寄存器配合控制位的设置启动一次新的I2C操作(此句加与不加未影响到结果) ...
wzywzy12 发表于 2011-4-11 17:53


如果用准双向IO的理解是对的,但这是硬件控制器,不应该涉及这些。
hotpower 发表于 2011-4-11 18:38 | 显示全部楼层
  1. void I2cObj::Start(void)
  2. {
  3. Busy = true;
  4. State = I2C_START;//主机准备发送启始位
  5. Count = 0;//发送数据个数
  6. SystickCount = 0;//清除节拍计数器
  7. I2C1s.CON.Regs &= ~((1 << I2C_CON_STO)
  8. | (1 << I2C_CON_AA));
  9. I2C1s.CON.Regs |= (1 << I2C_CON_EI)
  10. | (1 << I2C_CON_ENSI)
  11. | (1 << I2C_CON_SI);
  12. I2C1s.CON.Bits.STA = 1;
  13. Wait();
  14. }

  15. void I2cObj::REStart(void)
  16. {
  17. Busy = true;
  18. State = I2C_REP_START;//主机准备发送启始位
  19. Count = 0;//发送数据个数
  20. I2C1s.CON.Regs |= (1 << I2C_CON_STA) | (1 << I2C_CON_SI);
  21. }

  22. void I2cObj::Stop(void)
  23. {
  24. Busy = false;
  25. State = I2C_BUS_OK;//通讯成功
  26. I2C1s.CON.Regs |= (1 << I2C_CON_STO) | (1 << I2C_CON_SI);
  27. }

  28. void I2cObj::Exit(void)
  29. {
  30. Busy = false;
  31. State = I2C_BUS_ERROR;//通讯失败
  32. I2C1s.CON.Bits.SI = 1;//清除中断标志
  33. }

  34. void I2cObj::Wait(void)
  35. {
  36. SystickCount = 0;//清除节拍计数器
  37. // while (Busy && SystickCount < 10);//100mS超时
  38. while (SystickCount < 10);//100mS超时
  39. }

  40. void I2cObj::WriteWait(void)
  41. {
  42. SystickCount = 0;//清除节拍计数器
  43. while (SystickCount < 10);//延时100mS等待写入完成
  44. }

  45. //I2C回调函数(静态成员函数)
  46. void I2cObj::Exec(void)
  47. {
  48. NU_REG I2cStatus;
  49. I2cStatus = I2C1s.STATUS.Regs & 0xf8;
  50. switch(I2cStatus) {
  51. // switch(I2C1s.STATUS.Regs & 0xf8) {
  52. case I2C_START://主机收到自己发送的开始信号
  53. if (I2c.State == I2C_START) {//本次中断应该接收TW_START信号
  54. I2C1s.DATA.Regs = I2c.SubAddr & 0xfe;//发送子机地址(写)
  55. I2C1s.CON.Bits.STA = 0;//此位必须清除,否则死机
  56. I2C1s.CON.Bits.SI = 1;//清除中断标志
  57. I2c.State = I2C_MT_SLA_ACK;//Status下次I2C_MT_SLA_ACK
  58. }
  59. else I2c.Exit();//通讯失败
  60. break;
  61. case I2C_REP_START://主机收到自己发送的重新开始信号
  62. if (I2c.State == I2C_REP_START) {//本次中断应该接收TW_RESTART信号
  63. I2C1s.DATA.Regs = I2c.SubAddr | 0x01;//发送子机地址(读)
  64. I2c.State = I2C_MR_SLA_ACK;//Status下次I2C_MR_SLA_ACK
  65. I2C1s.CON.Bits.STA = 0;//此位必须清除,否则读不出数据
  66. I2C1s.CON.Regs |= (1 << I2C_CON_SI) | (1 << I2C_CON_AA);
  67. }
  68. else I2c.Exit();//通讯失败
  69. break;
  70. case I2C_MT_SLA_ACK://主发机接收到从机的地址应答信号后发送命令
  71. if (I2c.State == I2C_MT_SLA_ACK) {//本次中断应该接收TW_MT_SLA_ACK信号
  72. I2c.State = I2C_MT_DATA_ACK;//Status下次应该收TW_MT_DATA_ACK
  73. I2C1s.DATA.Regs = I2c.SubComm;//发送子机命令
  74. I2C1s.CON.Regs |= (1 << I2C_CON_SI) | (1 << I2C_CON_AA);
  75. }
  76. else I2c.Exit();//通讯失败
  77. break;
  78. case I2C_MR_SLA_ACK://主收机接收到从机的地址应答信号
  79. if ((I2c.State == I2C_MR_SLA_ACK) && I2c.SubCount) {//本次中断应该接收TW_MR_SLA_ACK信号
  80. I2c.State = I2C_MR_DATA_ACK;//Status下次应该收TW_MR_DATA_ACK
  81. // I2C1s.DATA.Regs = 0XFF;//
  82. I2C1s.CON.Bits.SI = 1;//清除中断标志
  83. }
  84. else I2c.Exit();//通讯失败
  85. break;
  86. case I2C_MT_DATA_ACK://主收机接收到从机的数据应答信号
  87. if ((I2c.State == I2C_MT_DATA_ACK) && (I2c.Count < I2c.MainCount)) {//本次中断应该接收TW_MT_DATA_ACK信号
  88. I2C1s.DATA.Regs = I2c.TxBuffer[I2c.Count ++];//发送子机数据
  89. I2C1s.CON.Regs |= (1 << I2C_CON_SI) | (1 << I2C_CON_AA);
  90. }
  91. else {
  92. if ((I2c.State == I2C_MT_DATA_ACK) && (I2c.Count == I2c.MainCount) && (I2c.SubAddr & 1)) {//本次中断应该接收TW_MT_DATA_ACK信号
  93. I2c.REStart();//
  94. }
  95. else I2c.Stop();//通讯成功
  96. }
  97. break;
  98. case I2C_MR_DATA_ACK:
  99. if ((I2c.State == I2C_MR_DATA_ACK) && (I2c.Count < I2c.SubCount)) {
  100. I2c.RxBuffer[I2c.Count ++] = I2C1s.DATA.Regs;//接收子机数据
  101. if (I2c.Count < I2c.SubCount) {
  102. I2C1s.CON.Regs |= (1 << I2C_CON_SI) | (1 << I2C_CON_AA);//主机转入接收状态
  103. }
  104. else {
  105. I2C1s.CON.Bits.AA = 0;//清除ACK标志
  106. I2C1s.CON.Bits.SI = 1;//清除中断标志
  107. I2c.State = I2C_MR_DATA_NACK;//下次进入I2C_MR_DATA_NACK,接收数据准备完成
  108. }
  109. }
  110. else I2c.Exit();//通讯失败
  111. break;
  112. case I2C_MR_DATA_NACK://数据接收结束
  113. if ((I2c.State == I2C_MR_DATA_NACK) && (I2c.Count == I2c.SubCount)) {
  114. I2c.Stop();//通讯成功
  115. }
  116. else I2c.Exit();//通讯失败
  117. break;
  118. // case I2C_MT_DATA_NACK:
  119. // Exit();//通讯失败
  120. // break;
  121. default:
  122. I2c.Exit();//通讯失败
  123. }
  124. }
hotpower 发表于 2011-4-11 18:40 | 显示全部楼层

  1. unsigned char I2cObj::ReadByte(unsigned int Address, unsigned char &Data)
  2. {
  3. SubAddr |= 0x01;
  4. MainCount = 0;//发送0个数据(只读)
  5. //本程序为通用I2C,故发送器件后一般为命令,对EEPROM来说,命令实际是EEPROM地址
  6. SubComm = Address;//读出地址
  7. SubCount = 1;//接收1个数据
  8. Start();//启动I2C模块
  9. if (State == I2C_BUS_OK) {//通讯成功
  10.   Data = RxBuffer[0];//从接收缓冲区取出一个字节
  11. }
  12. return State;//(读出数据在RxBuffer[0]~RxBuffer[15])
  13. }
  14. unsigned char I2cObj::ReadBuffer(unsigned int Address, unsigned char *Data, unsigned int Cnt)
  15. {
  16. SubAddr |= 0x01;
  17. MainCount = 0;//发送0个数据(只读)
  18. //本程序为通用I2C,故发送器件后一般为命令,对EEPROM来说,命令实际是EEPROM地址
  19. SubComm = Address;//读出地址
  20. SubCount = (Cnt <= sizeof(RxBuffer)) ? Cnt : sizeof(RxBuffer);//接收Cnt个数据
  21. Start();//启动I2C模块
  22. if (State == I2C_BUS_OK) {//通讯成功
  23.   for (int i = 0; i < SubCount; i ++) Data[i] = RxBuffer[i];//从接收缓冲区取出Cnt个字节
  24. }
  25. return State;//(读出数据在RxBuffer[0]~RxBuffer[15])
  26. }
  27. unsigned char I2cObj::WriteByte(unsigned int Address, unsigned char Data)
  28. {
  29. SubAddr &= 0xfe;
  30. MainCount = 1;//发送1个数据
  31. //本程序为通用I2C,故发送器件后一般为命令,对EEPROM来说,命令实际是EEPROM地址
  32. SubComm = Address;//写入地址
  33. TxBuffer[0] = Data;//写入1个数据到发送缓冲区
  34. SubCount = 0;//接收0个数据
  35. Start();//启动I2C模块
  36. WriteWait();//延时100mS等待写入完成
  37. return State;
  38. }
  39. unsigned char I2cObj::WriteBuffer(unsigned int Address, unsigned char *Data, unsigned int Cnt)
  40. {
  41. SubAddr &= 0xfe;
  42. MainCount = (Cnt <= sizeof(TxBuffer)) ? Cnt : sizeof(TxBuffer);//发送Cnt个数据
  43. //本程序为通用I2C,故发送器件后一般为命令,对EEPROM来说,命令实际是EEPROM地址
  44. SubComm = Address;//写入地址
  45. for (int i = 0; i < MainCount; i ++) TxBuffer[i] = Data[i];//写入Cnt个数据到发送缓冲区
  46. SubCount = 0;//接收0个数据
  47. Start();//启动I2C模块
  48. WriteWait();//延时100mS等待写入完成
  49. return State;
  50. }

hotpower 发表于 2011-4-11 18:48 | 显示全部楼层
本帖最后由 hotpower 于 2011-4-11 18:49 编辑

PIC24系列的I2C(注意里面的读写回调)

  1. #include "i2c.h"
  2. _PERSISTENT volatile I2CREGS I2CRegs;
  3. _PERSISTENT volatile I2CBITS I2CBits;
  4. void I2cInit(void)
  5. {
  6. unsigned int i;
  7. // TRIS_WP   = PORTOUTMODE;//定义WP为输出IO
  8. TRIS_SCL1 = PORTOUTMODE;//定义SCL为输出IO
  9. TRIS_SDA1 = PORTINPUTMODE;//定义SDA为输出入IO
  10. ODC_SCL1 = 1;//OC输出
  11. ODC_SDA1 = 1;//OC输出
  12. // WP = 1;//写保护
  13. //    I2CRegs.MaxCount = 0x200;//8KByte
  14.     I2CRegs.MaxCount = 256;//256Byte
  15. I2CRegs.I2CAddr = 0xb2;//器件地址
  16. I2CRegs.Command = 0;//EEPROM读写地址命令
  17. I2CRegs.TxCount = 0;//发送数据字节个数
  18. I2CRegs.RxCount = 0;//接收数据字节个数
  19. for (i = 0; i < sizeof(I2CRegs.TxBuffer); i ++)
  20. {
  21.   I2CRegs.TxBuffer = 0;//发送缓冲区清零
  22. }
  23. for (i = 0; i < sizeof(I2CRegs.RxBuffer); i ++)
  24. {
  25.   I2CRegs.RxBuffer = 0;//接收缓冲区清零
  26. }
  27. I2C1CON = 0;
  28. // I2C1CONbits.A10M = 0;//7位地址模式
  29. I2C1CONbits.SCLREL = 1;
  30. I2C1MSK = 0;
  31. I2C1STAT = 0;
  32. _MI2C1IF = 0;
  33. _SI2C1IF = 0;
  34. I2C1BRG = (FCY / (2 * I2CBAUD)) - 1;//波特率计算
  35. /*------------------------------------------------------------------------
  36.     定义I2C串口2中断优先级位1111)
  37. -------------------------------------------------------------------------*/
  38. IPC4bits.MI2C1P0 = 1;
  39. IPC4bits.MI2C1P1 = 1;
  40. IPC4bits.MI2C1P2 = 1;
  41. I2C1CONbits.I2CEN = 1;//允许I2C功能
  42. _MI2C1IE = 1;//允许主设备中断
  43. // I2cStop();
  44. }
  45. /*------------------------------------------------------------------
  46. EEPROM读块函数(只能在回调函数I2CReadCallBack中得到读出的数据)
  47. -------------------------------------------------------------------*/
  48. void I2CTest(void)
  49. {
  50. I2CRegs.TxCount = 19;
  51. I2CRegs.RxCount = 20;
  52. I2CRegs.Command = '$';
  53. I2CRegs.I2CAddr |= 1;//0xa3
  54. I2cStart();
  55. }
  56. void I2CReadBuffers(unsigned int Command, unsigned char ReadBuffer[], unsigned int ReadSize)
  57. {
  58. if (ReadSize && (ReadSize <= 256))
  59. {
  60.   I2CRegs.TxCount = 0;
  61.   I2CRegs.RxCount = ReadSize;
  62.   I2CRegs.Command = Command;
  63.   I2CRegs.I2CAddr |= 1;//0xa3
  64.   I2cStart();
  65. }
  66. }
  67. /*------------------------------------------------------------------
  68. EEPROM写块函数
  69. -------------------------------------------------------------------*/
  70. void I2CWriteBuffers(unsigned int Command, unsigned char WriteBuffer[], unsigned int WriteSize)
  71. {
  72. if (WriteSize && (WriteSize <= 16))
  73. {
  74.   I2CRegs.TxCount = WriteSize;
  75.   I2CRegs.RxCount = 0;
  76.   I2CRegs.Command = Command;
  77.   I2CRegs.I2CAddr &= 0xfe;//0xa0
  78.   I2cStart();
  79. }
  80. }
  81. /*------------------------------------------------------------------
  82. 用户读回调函数
  83. -------------------------------------------------------------------*/
  84. void I2CReadCallBack(void)
  85. {
  86. I2CBits.ReadFlag = 0;
  87. I2CRegs.I2CAddr ^= 0x10;
  88. I2CTest();
  89. }
  90. /*------------------------------------------------------------------
  91. 用户写回调函数
  92. -------------------------------------------------------------------*/
  93. void I2CWriteCallBack(void)
  94. {
  95. I2CBits.WriteFlag = 0;
  96. }

  97. /*------------------------------------------------------------------
  98. EEPROM读写启动函数
  99. -------------------------------------------------------------------*/
  100. void I2cStart(void)
  101. {
  102. /*------------------------------------------------------------------------
  103. //本程序在状态I2C_MT_ADDRL_ACK下进行瞬间打开,也可在此打开,不过安全不好
  104. if (I2CRegs.TxCount)//需要写入字节
  105. {
  106.   WP = 0;//不写保护
  107. }
  108. else
  109. {
  110.   WP = 1;//写保护
  111. }
  112. --------------------------------------------------------------------------*/
  113. I2C1STATbits.IWCOL = 0;
  114.     I2CBits.BusyFlag = 1;
  115.     I2CRegs.State = I2C_START;//主机准备发送启始位
  116.     I2CRegs.Count = 0;//发送数据个数
  117. I2CBits.I2CFlag = 0;
  118. I2C1CONbits.SEN = 1;//发送Start信号
  119. }
  120. /*------------------------------------------------------------------
  121. EEPROM读再启动函数
  122. -------------------------------------------------------------------*/
  123. void I2cReStart(void)
  124. {
  125. I2C1STATbits.IWCOL = 0;
  126.     I2CBits.BusyFlag = 1;
  127.     I2CRegs.State = I2C_REP_START;//主机准备发送重新启始位
  128.     I2CRegs.Count = 0;//发送数据个数
  129. I2C1CONbits.RSEN = 1;//发送ReStart信号
  130. I2C1CONbits.ACKEN = 0;
  131. }
  132. /*------------------------------------------------------------------
  133. EEPROM读写正确停止函数
  134. -------------------------------------------------------------------*/
  135. void I2cStop(void)
  136. {
  137. I2C1STATbits.IWCOL = 0;
  138.     I2CBits.BusyFlag = 0;
  139. I2CRegs.State = I2C_SUCCEEDED;//通讯成功
  140. I2C1CONbits.PEN = 1;//发送Stop信号
  141. // WP = 1;//写保护
  142. }

  143. /*------------------------------------------------------------------
  144. EEPROM读写错误退出函数
  145. -------------------------------------------------------------------*/
  146. void I2cExit(void)
  147. {
  148. I2C1STATbits.IWCOL = 0;
  149.     I2CBits.BusyFlag = 0;
  150. I2CRegs.State = I2C_FAILED;
  151. I2C1CONbits.PEN = 1;//发送Stop信号
  152. // WP = 1;//写保护
  153. }
  154. /*------------------------------------------------------------------
  155.   EEPROM读写中断事件处理函数(说明见文件头部)
  156. -------------------------------------------------------------------*/
  157. void I2CExec(void)
  158. {
  159. if (I2C1STATbits.S)//收到Start过信号
  160. {
  161.   switch (I2CRegs.State)
  162.   {
  163.    case I2C_START://收到Start信号
  164.     I2C1TRN = I2CRegs.I2CAddr & 0xfe;//发送器件写地址(通知从机只能听)
  165.     I2CRegs.State = I2C_MT_SLA_ACK;//下次应该接收器件写地址应答信号
  166.     break;
  167.    case I2C_MT_SLA_ACK://收到器件写地址应答信号
  168.     if (!I2C1STATbits.ACKSTAT)//收到Ack信号
  169.     {
  170.      if (I2CRegs.MaxCount > 0x100)//EEPROM容量超过256个字节,EEPROM地址需要两次发送
  171.      {
  172.       I2C1TRN = I2CRegs.Command >> 8;//发送EEPROM写高8位地址
  173.       I2CRegs.State = I2C_MT_ADDRH_ACK;//下次应该接收EEPROM写高8位地址应答信号
  174.      }
  175.      else//小容量只需一次发送!!!
  176.      {
  177.       I2C1TRN = I2CRegs.Command;//发送EEPROM写低8位地址
  178.       I2CRegs.State = I2C_MT_ADDRL_ACK;//下次应该接收EEPROM写低8位地址应答信号
  179.       I2CRegs.Count = 0;//清空发送缓冲计数器
  180.      }
  181.     }
  182.     else//收到NAck信号
  183.     {
  184.      I2cExit();//错误的ACK信号
  185.     }
  186.     break;
  187.    case I2C_MT_ADDRH_ACK://收到EEPROM写高8位地址应答信号
  188.     if (!I2C1STATbits.ACKSTAT)//收到Ack信号
  189.     {
  190.      I2C1TRN = I2CRegs.Command & 0xff;//发送EEPROM写低8位地址
  191.      I2CRegs.State = I2C_MT_ADDRL_ACK;//下次应该接收EEPROM写低8位地址应答信号
  192.      I2CRegs.Count = 0;//清空发送缓冲计数器
  193.     }
  194.     else//收到NAck信号
  195.     {
  196.      I2cExit();//错误的ACK信号
  197.     }
  198.     break;
  199.    case I2C_MT_ADDRL_ACK://收到EEPROM写高低8位地址应答信号
  200.     if (I2CRegs.TxCount)//写保护只在写入期间不保护,增加了对误写入的安全防护能力!!!
  201.     {
  202. //      WP = 0;//不写保护
  203.     }
  204.    case I2C_MT_DATA_ACK://收到应答信号
  205.     if (!I2C1STATbits.ACKSTAT)//收到Ack信号
  206.     {
  207.      if (I2CRegs.Count < I2CRegs.TxCount)//缓冲区未空
  208.      {
  209.       I2C1TRN = I2CRegs.TxBuffer[I2CRegs.Count ++];//继续发送数据
  210.      }
  211.      else if (I2CRegs.Count == I2CRegs.TxCount)//缓冲区已空
  212.      {
  213.       if (I2CRegs.I2CAddr & 1)//应该开始接收数据
  214.       {
  215.        I2cReStart();//发送重复位命令
  216.       }
  217.       else//只写退出
  218.       {
  219.        I2cStop();//正常发送结束
  220.       }
  221.      }
  222.      else//干扰出错
  223.      {
  224.       I2cExit();//错误
  225.      }
  226.     }
  227.     else//收到NAck信号(可能被写保护)
  228.     {
  229.      I2cExit();//错误的ACK信号
  230.     }
  231.     break;
  232.    case I2C_REP_START://收到ReStart信号
  233.     I2C1TRN = I2CRegs.I2CAddr | I2C_READ;//发送器件读地址(通知从机可以说话)
  234.     I2CRegs.State = I2C_MR_SLA_ACK;//下次应该接收器件写读地址应答信号
  235.     break;
  236.    case I2C_MR_SLA_ACK://收到器件读地址应答信号
  237.     if (!I2C1STATbits.ACKSTAT)//收到Ack信号
  238.     {
  239.      I2C1CONbits.RCEN = 1;//开始接收数据
  240.      I2CRegs.State = I2C_MR_DATA;//下次应该收接收数据
  241.     }
  242.     else//收到NAck信号
  243.     {
  244.      I2cExit();//错误的ACK信号
  245.     }
  246.     break;
  247.    case I2C_MR_DATA://收到接收数据
  248.     if (I2CRegs.Count < I2CRegs.RxCount)
  249.     {
  250. //     I2C1STATbits.I2COV = 0;
  251.      I2CRegs.RxBuffer[I2CRegs.Count ++] = I2C1RCV;
  252.      if (I2CRegs.Count < I2CRegs.RxCount)
  253.      {
  254.        I2C1CONbits.ACKDT = 0;//应答子机
  255.       I2CRegs.State = I2C_MR_DATA_EN;//下次应该收到器件允许继续读信号
  256.      }
  257.      else
  258.      {
  259.       I2C1CONbits.ACKDT = 1;//非应答子机
  260.       I2CRegs.State = I2C_MR_DATA_STOP;//下次应该收到退出信号
  261.      }
  262.       I2C1CONbits.ACKEN = 1;//向从机发送(非)应答信号
  263.     }
  264.     else//正确的状态已分支到I2C_MR_DATA_STOP
  265.     {
  266.      I2cExit();//错误
  267.     }
  268.     break;
  269.    case I2C_MR_DATA_EN://收到器件允许继续读信号
  270.     I2C1CONbits.RCEN = 1;//开始接收数据
  271.     I2CRegs.State = I2C_MR_DATA;//下次应该继续接收数据
  272.     break;
  273.    case I2C_MR_DATA_STOP://收到器件退出信号
  274.     I2cStop();//正常接收结束
  275.     break;
  276.    default://其他不可预料的错误
  277.     I2cExit();//错误
  278.   }
  279. }
  280. else if (I2C1STATbits.P)//收到Stop信号
  281. {
  282.   if (I2CRegs.State == I2C_SUCCEEDED)//成功,回调
  283.   {
  284.    if (I2CRegs.I2CAddr & 1)//读
  285.    {
  286.     I2CBits.ReadFlag = 1;//激活用户读回调函数I2CReadCallBack()
  287.     I2CReadCallBack();
  288.    }
  289.    else//写
  290.    {
  291.     I2CBits.WriteFlag = 1;//激活用户写回调函数I2CWriteCallBack()
  292.     I2CWriteCallBack();
  293.    }
  294.   }
  295. }
  296. else//无法确认的复杂错误
  297. {
  298.   I2cExit();//错误出错退出
  299. }
  300. }

 楼主| Swallow_0322 发表于 2011-4-11 20:04 | 显示全部楼层
多谢大叔送裤子一条!

再次谢谢HOT大叔及wzywzy12的指教!在此表示感谢!:handshake

回头认真学习大叔中断方式的IIC程序!
arto 发表于 2011-4-11 20:04 | 显示全部楼层
顶一下.........
plc_avr 发表于 2011-4-12 14:34 | 显示全部楼层
顶!!!
hotpower 发表于 2011-4-13 15:10 | 显示全部楼层
这个俺将会在群课里讲解革命道理的.
 楼主| Swallow_0322 发表于 2011-4-13 17:21 | 显示全部楼层
12# hotpower

耐心等待...
hotpower 发表于 2011-4-26 18:03 | 显示全部楼层
帮你顶起来,与中断方式比较。
tlb 发表于 2011-4-27 05:59 | 显示全部楼层
顶上去
weshiluwei6 发表于 2011-4-27 19:03 | 显示全部楼层
顶上去 高手啊 羡慕啊 支持 流口水
tlb 发表于 2011-4-28 07:24 | 显示全部楼层
要输就输给理想,要败就败给高手

水王是高人见解呀
 楼主| Swallow_0322 发表于 2011-4-28 13:39 | 显示全部楼层
呵呵!楼上各位太抬举我了,多谢顶帖!:handshake
lixupengarm 发表于 2011-5-23 17:59 | 显示全部楼层
:D学习!!
电子write_cai 发表于 2011-8-20 23:30 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

121

主题

1393

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部

121

主题

1393

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部