CCS811_IIC.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /////////////////////////////////////////////////////////////////
  2. //
  3. // 本程序只供学习使用,未经作者许可,不得用于其它任何用途
  4. // STM32F103C8T6核心板
  5. // by Pang
  6. // 修改日期:2019/01/02
  7. // 版本:V1.0
  8. // 版权所有,盗版必究。
  9. // All rights reserved
  10. //
  11. ////////////////////////////////////////////////////////////////
  12. #include "CCS811_IIC.h"
  13. #include "delay.h"
  14. #include "usart.h"
  15. void CCS811_I2C_GPIO_Config(void)
  16. {
  17. GPIO_InitTypeDef GPIO_InitStructure;
  18. /* 使能与 I2C有关的时钟 */
  19. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );
  20. /* PB10-I2C_SCL、PB11-I2C_SDA*/
  21. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6| GPIO_Pin_7;
  22. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  23. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
  24. GPIO_Init(GPIOA, &GPIO_InitStructure);
  25. SCL_H;
  26. SDA_H;
  27. }
  28. void delay_1us(u8 x)//粗略延时,iic_40K
  29. {
  30. u8 i = 20;
  31. x = i * x;
  32. while(x--);
  33. // delay_us(6);
  34. }
  35. //////// IIC起始函数 //////////
  36. /*
  37. IIC起始:当SCL处于高电平期间,SDA由高电平变成低电平出现一个下降沿,然后SCL拉低
  38. */
  39. u8 I2C_Start(void)
  40. {
  41. SDA_H;
  42. delay_1us(5); //延时保证时钟频率低于40K,以便从机识别
  43. SCL_H;
  44. delay_1us(5);//延时保证时钟频率低于40K,以便从机识别
  45. if(!SDA_read) return 0;//SDA线为低电平则总线忙,退出
  46. SDA_L; //SCL处于高电平的时候,SDA拉低
  47. delay_1us(5);
  48. if(SDA_read) return 0;//SDA线为高电平则总线出错,退出
  49. SCL_L;
  50. delay_1us(5);
  51. return 1;
  52. }
  53. //**************************************
  54. //IIC停止信号
  55. /*
  56. IIC停止:当SCL处于高电平期间,SDA由低电平变成高电平出现一个上升沿
  57. */
  58. //**************************************
  59. void CCS811_I2C_Stop(void)
  60. {
  61. SDA_L;
  62. SCL_L;
  63. delay_1us(5);
  64. SCL_H;
  65. delay_1us(5);
  66. SDA_H;//当SCL处于高电平期间,SDA由低电平变成高电平 //延时
  67. }
  68. //**************************************
  69. //IIC发送应答信号
  70. //入口参数:ack (0:ACK 1:NAK)
  71. /*
  72. 应答:当从机接收到数据后,向主机发送一个低电平信号
  73. 先准备好SDA电平状态,在SCL高电平时,主机采样SDA
  74. */
  75. //**************************************
  76. void I2C_SendACK(u8 i)
  77. {
  78. if(1==i)
  79. SDA_H; //准备好SDA电平状态,不应答
  80. else
  81. SDA_L; //准备好SDA电平状态,应答
  82. SCL_H; //拉高时钟线
  83. delay_1us(5); //延时
  84. SCL_L ; //拉低时钟线
  85. delay_1us(5);
  86. }
  87. ///////等待从机应答////////
  88. /*
  89. 当本机(主机)发送了一个数据后,等待从机应答
  90. 先释放SDA,让从机使用,然后采集SDA状态
  91. */
  92. /////////////////
  93. u8 I2C_WaitAck(void) //返回为:=1有ACK,=0无ACK
  94. {
  95. uint16_t i=0;
  96. SDA_H; //释放SDA
  97. SCL_H; //SCL拉高进行采样
  98. while(SDA_read)//等待SDA拉低
  99. {
  100. i++; //等待计数
  101. if(i==500)//超时跳出循环
  102. break;
  103. }
  104. if(SDA_read)//再次判断SDA是否拉低
  105. {
  106. SCL_L;
  107. return RESET;//从机应答失败,返回0
  108. }
  109. delay_1us(5);//延时保证时钟频率低于40K,
  110. SCL_L;
  111. delay_1us(5); //延时保证时钟频率低于40K,
  112. return SET;//从机应答成功,返回1
  113. }
  114. //**************************************
  115. //向IIC总线发送一个字节数据
  116. /*
  117. 一个字节8bit,当SCL低电平时,准备好SDA,SCL高电平时,从机采样SDA
  118. */
  119. //**************************************
  120. void I2C_SendByte(u8 dat)
  121. {
  122. u8 i;
  123. SCL_L;//SCL拉低,给SDA准备
  124. for (i=0; i<8; i++) //8位计数器
  125. {
  126. if(dat&0x80)//SDA准备
  127. SDA_H;
  128. else
  129. SDA_L;
  130. SCL_H; //拉高时钟,给从机采样
  131. delay_1us(5); //延时保持IIC时钟频率,也是给从机采样有充足时间
  132. SCL_L; //拉低时钟,给SDA准备
  133. delay_1us(5); //延时保持IIC时钟频率
  134. dat <<= 1; //移出数据的最高位
  135. }
  136. }
  137. //**************************************
  138. //从IIC总线接收一个字节数据
  139. //**************************************
  140. u8 I2C_RecvByte()
  141. {
  142. u8 i;
  143. u8 dat = 0;
  144. SDA_H;//释放SDA,给从机使用
  145. delay_1us(1); //延时给从机准备SDA时间
  146. for (i=0; i<8; i++) //8位计数器
  147. {
  148. dat <<= 1;
  149. SCL_H; //拉高时钟线,采样从机SDA
  150. if(SDA_read) //读数据
  151. dat |=0x01;
  152. delay_1us(5); //延时保持IIC时钟频率
  153. SCL_L; //拉低时钟线,处理接收到的数据
  154. delay_1us(5); //延时给从机准备SDA时间
  155. }
  156. return dat;
  157. }
  158. //**************************************
  159. //向IIC设备写入一个字节数据
  160. //**************************************
  161. u8 CCS811_WriteI2C_byte(u8 Slave_Address,u8 REG_Address,u8 data)
  162. {
  163. if(I2C_Start()==0) //起始信号
  164. {CCS811_I2C_Stop(); return RESET;}
  165. I2C_SendByte(Slave_Address); //发送设备地址+写信号
  166. if(!I2C_WaitAck()){CCS811_I2C_Stop(); return RESET;}
  167. I2C_SendByte(REG_Address); //内部寄存器地址,
  168. if(!I2C_WaitAck()){CCS811_I2C_Stop(); return RESET;}
  169. I2C_SendByte(data); //内部寄存器数据,
  170. if(!I2C_WaitAck()){CCS811_I2C_Stop(); return RESET;}
  171. CCS811_I2C_Stop(); //发送停止信号
  172. return SET;
  173. }
  174. u8 CCS811_MWriteI2C_byte(u8 Slave_Address,u8 REG_Address,u8 const *data,u8 length)
  175. {
  176. if(I2C_Start()==0) //起始信号
  177. {CCS811_I2C_Stop(); return RESET;}
  178. I2C_SendByte(Slave_Address); //发送设备地址+写信号
  179. if(!I2C_WaitAck()){CCS811_I2C_Stop(); return RESET;}
  180. I2C_SendByte(REG_Address); //内部寄存器地址,
  181. if(!I2C_WaitAck()){CCS811_I2C_Stop(); return RESET;}
  182. while(length)
  183. {
  184. I2C_SendByte(*data++); //内部寄存器数据,
  185. if(!I2C_WaitAck()){CCS811_I2C_Stop(); return RESET;} //应答
  186. length--;
  187. }
  188. // I2C_SendByte(*data); //内部寄存器数据,
  189. // if(!I2C_WaitAck()){CCS811_I2C_Stop(); return RESET;}
  190. CCS811_I2C_Stop(); //发送停止信号
  191. return SET;
  192. }
  193. //**************************************
  194. //从IIC设备读取一个字节数据
  195. //**************************************
  196. u8 CCS811_ReadI2C(u8 Slave_Address,u8 REG_Address,u8 *REG_data,u8 length)
  197. {
  198. if(I2C_Start()==0) //起始信号
  199. {CCS811_I2C_Stop(); return RESET;}
  200. I2C_SendByte(Slave_Address); //发送设备地址+写信号
  201. if(!I2C_WaitAck()){CCS811_I2C_Stop(); return RESET;}
  202. I2C_SendByte(REG_Address); //发送存储单元地址
  203. if(!I2C_WaitAck()){CCS811_I2C_Stop(); return RESET;}
  204. if(I2C_Start()==0) //起始信号
  205. {CCS811_I2C_Stop(); return RESET;}
  206. I2C_SendByte(Slave_Address+1); //发送设备地址+读信号
  207. if(!I2C_WaitAck()){CCS811_I2C_Stop(); return RESET;}
  208. while(length-1)
  209. {
  210. *REG_data++=I2C_RecvByte(); //读出寄存器数据
  211. I2C_SendACK(0); //应答
  212. length--;
  213. }
  214. *REG_data=I2C_RecvByte();
  215. I2C_SendACK(1); //发送停止传输信号
  216. CCS811_I2C_Stop(); //停止信号
  217. return SET;
  218. }