[Cortex-M0技术交流] 菜鸟学习M0第十六帖——I2C

[复制链接]
 楼主| lixiaoxu2meng 发表于 2011-9-24 11:35 | 显示全部楼层 |阅读模式
I2c, TI, IO, gp, TE
本工程实现I2C的读写AT24L16 工程部分参照了 官方的固件库 以及三心前辈的例子 在此声明并对三心前辈表示感谢
main函数
  1. /*---------------------------------------------------------------------------------------------------------*/
  2. /* */
  3. /* Copyright(c) 2011 Nuvoton Technology Corp. All rights reserved. */
  4. /* */
  5. /*---------------------------------------------------------------------------------------------------------*/
  6. #include "includes.h" //包含所需的头文件
  7. /*************************************************************************************
  8. ** Function name: main
  9. ** Descriptions: 本函数实现:I2C功能,向AT24C16的0x00地址写入0x03 然后读出来 并用数码管显示出来
  10. 注:本例程的I2C读写部分移植了论坛三心前辈的例子 特此声明并感谢三心前辈
  11. ** input parameters: 无
  12. ** output parameters: 无
  13. ** Returned value: 无
  14. *************************************************************************************/
  15. int main (void)
  16. {
  17. Set_System(); //封装一些初始化模块
  18. I2C_WriteByte (0x00,0x03 );
  19. delay_ms(1000);
  20. value = I2C_ReadByte(0x00);
  21. while(1)
  22. {}
  23. }


hw_config函数
  1. #include "includes.h" //包含所需的头文件
  2. /*************************************************************************************
  3. ** Function name: Set_System
  4. ** Descriptions: 封装一些初始化模块
  5. ** input parameters: count
  6. ** output parameters: 无
  7. ** Returned value: 无
  8. *************************************************************************************/
  9. void Set_System(void)
  10. {
  11. RCC_Configuration(); //配置系统时钟

  12. GPIO_Configuration(); //配置GPIO

  13. TIMER_Configuration(); //配置TIMER

  14. I2C_Configuration(); //配置I2C
  15. }
  16. /*************************************************************************************
  17. ** Function name: RCC_Configuration
  18. ** Descriptions: 系统时钟源设置
  19. ** input parameters: none
  20. ** output parameters: none
  21. ** Returned value: none
  22. *************************************************************************************/
  23. void RCC_Configuration(void)
  24. {
  25. UNLOCKREG(); // 对写保护位操作时 需要一次向0x50000 0100写入 0x59,0x16,0x88,
  26. DrvSYS_SetOscCtrl(E_SYS_XTL12M, 1);// 与其 SYSCLK->PWRCON.XTL12M_EN = 1; 等同
  27. // PWRCON寄存器(这些寄存器在上电复位到用户解锁定之前是锁定的)除了 BIT[6]位其他位都受写保护
  28. // 解除这些需要向 0x50000 0100写入 0x59,0x16,0x88,
  29. // 令PWRCON寄存器的BITP[0]为1(即设定12M外部晶振)
  30. delay_ms(100); // while (DrvSYS_GetChipClockSourceStatus(E_SYS_XTL12M) != 1);//等待外部12MHZ晶振就绪
  31. LOCKREG(); // 向“0x5000_0100”写入任何值,就可以重锁保护寄存器
  32. }
  33. /*************************************************************************************
  34. ** Function name: GPIO_Configuration
  35. ** Descriptions: GPIO配置
  36. ** input parameters: none
  37. ** output parameters: none
  38. ** Returned value: none
  39. *************************************************************************************/
  40. void GPIO_Configuration()
  41. {
  42. DrvGPIO_Open( E_GPA, 2, E_IO_OUTPUT );//数码管段选
  43. DrvGPIO_Open( E_GPA, 3, E_IO_OUTPUT );
  44. DrvGPIO_Open( E_GPA, 4, E_IO_OUTPUT );
  45. DrvGPIO_Open( E_GPA, 5, E_IO_OUTPUT );
  46. DrvGPIO_Open( E_GPA, 6, E_IO_OUTPUT );
  47. DrvGPIO_Open( E_GPA, 7, E_IO_OUTPUT );
  48. DrvGPIO_Open( E_GPA, 8, E_IO_OUTPUT );
  49. DrvGPIO_Open( E_GPA, 9, E_IO_OUTPUT );
  50. DrvGPIO_Open( E_GPC, 14, E_IO_OUTPUT );//数码管位选
  51. DrvGPIO_Open( E_GPC, 15, E_IO_OUTPUT );
  52. DrvGPIO_Open( E_GPC, 6, E_IO_OUTPUT );
  53. DrvGPIO_Open( E_GPC, 7, E_IO_OUTPUT );
  54. }
  55. /*************************************************************************************
  56. ** Function name: TIMER_Configuration
  57. ** Descriptions: TIMER配置
  58. ** input parameters: none
  59. ** output parameters: none
  60. ** Returned value: none
  61. *************************************************************************************/
  62. void TIMER_Configuration()
  63. {
  64. DrvTIMER_Init(); //初始化定时器

  65. DrvSYS_SelectIPClockSource(E_SYS_TMR0_CLKSRC,0); //使用外设时注意必须设置该外设的时钟 设置TIMER0的时钟源为外部12MHZ

  66. DrvTIMER_Open(E_TMR0,1000,E_PERIODIC_MODE); //设定定时器timer0的tick周期,并且启动定时器:定时器通道 TMR0 每秒1000次 周期模式

  67. DrvTIMER_SetTimerEvent(E_TMR0,5,(TIMER_CALLBACK) Timer0_Callback,0); //安装一个定时处理事件到 timer0通道

  68. DrvTIMER_EnableInt(E_TMR0); //使能定时器中断 //TIMER0->TCSR.IE = 1

  69. DrvTIMER_Start(E_TMR0); //定时器timer0开始计数 //TIMER0->TCSR.CEN = 1;
  70. }
  71. /*************************************************************************************
  72. ** Function name: Timer0_Callback
  73. ** Descriptions: 定时处理事件,LED动态扫描
  74. ** input parameters: none
  75. ** output parameters: none
  76. ** Returned value: none
  77. *************************************************************************************/
  78. void Timer0_Callback (void)
  79. {
  80. static uint8_t count= 0;
  81. static uint8_t i,xx[4];
  82. uint32_t data;
  83. uint16_t ValueBuff ;
  84. ValueBuff = value;
  85. count++;
  86. if(count >= 5)
  87. count = 1;
  88. for(i=0;i<4;i++)
  89. {
  90. xx[i] = ValueBuff%10;
  91. ValueBuff = ValueBuff/10;
  92. }
  93. switch(count)
  94. {
  95. case 1:
  96. DrvGPIO_SetBit(E_GPC,14);
  97. DrvGPIO_ClrBit(E_GPC,15);
  98. DrvGPIO_ClrBit(E_GPC,6);
  99. DrvGPIO_ClrBit(E_GPC,7);
  100. data = Table[xx[0]]<<2;
  101. GPIOA->DOUT = data;
  102. break;
  103. case 2:
  104. DrvGPIO_SetBit(E_GPC,15);
  105. DrvGPIO_ClrBit(E_GPC,14);
  106. DrvGPIO_ClrBit(E_GPC,6);
  107. DrvGPIO_ClrBit(E_GPC,7);
  108. data = Table[xx[1]]<<2;
  109. GPIOA->DOUT = data;
  110. break;
  111. case 3:
  112. DrvGPIO_SetBit(E_GPC,7);
  113. DrvGPIO_ClrBit(E_GPC,14);
  114. DrvGPIO_ClrBit(E_GPC,15);
  115. DrvGPIO_ClrBit(E_GPC,6);
  116. data = Table[xx[2]]<<2;
  117. GPIOA->DOUT = data;
  118. break;
  119. case 4:
  120. DrvGPIO_SetBit(E_GPC,6);
  121. DrvGPIO_ClrBit(E_GPC,14);
  122. DrvGPIO_ClrBit(E_GPC,15);
  123. DrvGPIO_ClrBit(E_GPC,7);
  124. data = Table[xx[3]]<<2;
  125. GPIOA->DOUT = data;
  126. //DrvGPIO_ClrBit(E_GPA,9); //显示小数点
  127. break;
  128. default:break;
  129. }
  130. }
  131. /*************************************************************************************
  132. ** Function name: I2C_Configuration
  133. ** Descriptions: I2C配置(注:一些配置都在 读写I2C的子程序里了)
  134. ** input parameters: none
  135. ** output parameters: none
  136. ** Returned value: none
  137. *************************************************************************************/
  138. void I2C_Configuration()
  139. {
  140. DrvGPIO_InitFunction(E_FUNC_I2C1);//注意:在使用引脚特殊功能时 必须进行复用功能引脚设置(此时I2C1引脚为开漏输出)
  141. DrvGPIO_SetBit(E_GPA,10); //在使用之前需将 I2C1_SDA 置高
  142. DrvGPIO_SetBit(E_GPA,11); //在使用之前需将 I2C1_SCL 置高
  143. }
  144. /*************************************************************************************
  145. ** Function name: I2C_WriteByte
  146. ** Descriptions: I2C向写单字节函数(注:此函数是将论坛三心前辈的例子移植过来的 在此声明并表示感谢)
  147. ** input parameters: 地址:address 数据:data
  148. ** output parameters: none
  149. ** Returned value: none
  150. *************************************************************************************/
  151. void I2C_WriteByte ( uint32_t address,uint8_t data )
  152. {
  153. /*
  154. 在字节写模式下,主器件发送起始命令和从器件地址信息(R/W 位置 0)给从器件,
  155. 主器件在收到从器件产生应答信号后,主器件发送1个8位字节地址写入AT24C01/
  156. 02/04/08/16 的地址指针,对于 AT24C31/64/128/256 来说,所不同的是主器件
  157. 发送两个8位地址字写入AT24C32/64/128/256的地址指针。主器件在收到从器件的
  158. 另一个应答信号后,再发送数据到被寻址的存储单元。AT24Cxx 再次应答,并在
  159. 主器件产生停止信号后开始内部数据的擦写,在内部擦写过程中,AT24Cxx 不再
  160. 应答主器件的任何请求。
  161. */
  162. uint32_t i;

  163. DrvI2C_Open(I2C_PORT1, 100000); //打开I2C1功能,并配置 I2C总线时钟为100KHZ (该函数进行了四舍五入操作)
  164. /* Parameters:port - [in] I2C_PORT0 / I2C_PORT1 */
  165. /* u32BusClock - [in] I2C bus clock frequency (Hz) */

  166. DrvI2C_Ctrl(I2C_PORT1, 1, 0, 0, 0); //设定I2C控制位 START
  167. /* Parameters:port - [in] I2C_PORT0 / I2C_PORT1 */
  168. /* start - [in] 1:Enable / 0:Disable I2C开始 进入主机模式 */
  169. /* stop - [in] 1:Enable / 0:Disable I2C停止 */
  170. /* intFlag - [in] Wrtie '1' to clear this flag (I2C_SI) */
  171. /* ack - [in] 1:Enable / 0:Disable 应答位 */
  172. while (I2C1->CON.SI == 0); //查询中断标志位 SI 如果忙则一直等待

  173. //I2C1->DATA = ;
  174. DrvI2C_WriteData (I2C_PORT1, 0xA0);//发送写命令 即从器件地址
  175. DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0); //清标志位 SI
  176. while( I2C1->CON.SI == 0 ); //查询中断标志位 SI

  177. I2C1->DATA = address&0XFF; //发送地址
  178. DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1); //清标志位 SI 并使能应答
  179. while( I2C1->CON.SI == 0 ); //查询中断标志位 SI 如果忙则一直等待

  180. I2C1->DATA = data; //发送待写内容
  181. DrvI2C_WriteData (I2C_PORT1, data);//发送写入的数据
  182. DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1); //清标志位 SI 并使能应答
  183. while( I2C1->CON.SI == 0 ); //查询中断标志位 SI 如果忙则一直等待

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

  185. for(i=0;i<60;i++);
  186. DrvI2C_Close(I2C_PORT1); //关闭I2C1功能

  187. for(i=0;i<6000;i++);
  188. for(i=0;i<6000;i++);
  189. }
  190. /*************************************************************************************
  191. ** Function name: I2C_ReadByte
  192. ** Descriptions: I2C向读单字节函数(注:此函数是将论坛三心前辈的例子移植过来的 在此声明并表示感谢)
  193. ** input parameters: 地址:address
  194. ** output parameters: DATA
  195. ** Returned value: none
  196. *************************************************************************************/
  197. uint8_t I2C_ReadByte ( uint32_t address )
  198. {
  199. /*
  200. 随机读操作允许主器件对寄存器的任意字节进行读操作,主器件
  201. 首先通过发送起始信号、从器件地址和它想读取的字节数据的地
  202. 址执行一个伪写操作。在AT24Cxx 应答之后,主器件重新发送起
  203. 始信号和从器件地址,此时R/W 位置1,AT24CXX 响应并发送应答
  204. 信号,然后输出所要求的一个 8位字节数据,主器件不发送应答
  205. 信号但产生一个停止信号。
  206. */
  207. uint8_t DATA;

  208. DrvI2C_Open(I2C_PORT1, 100000); //打开I2C1功能,并配置 I2C总线时钟为100KHZ

  209. DrvI2C_Ctrl(I2C_PORT1, 1, 0, 1, 0); //设定I2C控制比位 START并清中断标志
  210. while (I2C1->CON.SI == 0); //查询中断标志位 SI 如果忙则一直等待

  211. DrvI2C_WriteData (I2C_PORT1, 0xA0); //发送写命令 即从器件地址
  212. DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0); //清标志位 SI
  213. while( I2C1->CON.SI == 0 ); //查询中断标志位 SI 如果忙则一直等待

  214. DrvI2C_WriteData (I2C_PORT1, address&0xFF); //发送需要读写的地址
  215. DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1); //清标志位 SI 并使能应答
  216. while( I2C1->CON.SI == 0 ); //查询中断标志位 SI 如果忙则一直等待

  217. DrvI2C_Ctrl(I2C_PORT1, 1, 0, 1, 0); //设定I2C控制比位 START并清中断标志
  218. while( I2C1->CON.SI == 0 ); //查询中断标志位 SI 如果忙则一直等待

  219. DrvI2C_WriteData (I2C_PORT1, 0xA1); //发送写命令 即从器件地址的最低位 R/W 位设置为 1
  220. DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1); //清标志位 SI 并使能应答
  221. while( I2C1->CON.SI == 0 ); //查询中断标志位 SI 如果忙则一直等待

  222. //I2C1->DATA = 0xFF; //通过操作数据寄存器配合控制位的设置启动一次新的I2C操作(此句加与不加未影响到结果)
  223. /*"Software should load the data byte (to be transmitted)into I2DAT before new I2CON setting is done." 手册中该句怎么解释?*/
  224. DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0); //清标志位 SI
  225. while( I2C1->CON.SI == 0 ); //查询中断标志位 SI 如果忙则一直等待
  226. DATA= DrvI2C_ReadData(I2C_PORT1); //读数据

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

  228. DrvI2C_Close(I2C_PORT1); //关闭I2C1功能

  229. return DATA;
  230. }
  231. /*************************************************************************************
  232. ** Function name: delay_ms
  233. ** Descriptions: 1ms(晶振为12MHZ)延时子程序
  234. ** input parameters: count
  235. ** output parameters: 无
  236. ** Returned value: 无
  237. *************************************************************************************/
  238. void delay_ms(uint32_t count)
  239. {
  240. uint32_t i,j;
  241. for(i=count;i>0;i--)
  242. for(j=2395;j>0;j--);
  243. }

hw_config头文件
  1. #ifndef __HW_CONFIG_H__
  2. #define __HW_CONFIG_H__
  3. void Set_System(void);
  4. void RCC_Configuration(void);
  5. void GPIO_Configuration(void);
  6. void TIMER_Configuration(void);
  7. void Timer0_Callback (void);
  8. void I2C_Configuration(void);
  9. void I2C_WriteByte ( uint32_t address,uint8_t data );
  10. uint8_t I2C_ReadByte ( uint32_t address );
  11. void delay_ms(uint32_t count);
  12. #endif

已测试通过 OK
工程

本帖子中包含更多资源

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

×
296895536 发表于 2013-3-20 11:30 | 显示全部楼层
下载学习。  感谢LZ:victory:
a437916817 发表于 2013-4-9 15:18 | 显示全部楼层
多谢楼主多次分享,菜鸟学习了。。
劳烦继续分享啊。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

1679

帖子

2

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