当前位置:   article > 正文

IIC总线读取温度湿度传感器数据实验

IIC总线读取温度湿度传感器数据实验

iic.c

  1. #include "iic.h"
  2. extern void printf(const char* fmt, ...);
  3. /*
  4. * 函数名 : delay_us
  5. * 函数功能:延时函数
  6. * 函数参数:无
  7. * 函数返回值:无
  8. * */
  9. void delay_us(void) //微秒级延时
  10. {
  11. unsigned int i = 2000;
  12. while(i--);
  13. }
  14. /*
  15. * 函数名 : i2c_init
  16. * 函数功能: i2C总线引脚的初始化, 通用输出,推挽输出,输出速度,
  17. * 函数参数:无
  18. * 函数返回值:无
  19. * */
  20. void i2c_init(void)
  21. {
  22. // 使能GPIOF端口的时钟
  23. RCC->MP_AHB4ENSETR |= (0x1 << 5);
  24. // 设置PF14PF15引脚为通用的输出功能
  25. GPIOF->MODER &= (~(0xF << 28));
  26. GPIOF->MODER |= (0x5 << 28);
  27. // 设置PF14, PF15引脚为推挽输出
  28. GPIOF->OTYPER &= (~(0x3 << 14));
  29. // 设置PF14, PF15引脚为高速输出
  30. GPIOF->OSPEEDR |= (0xF << 28);
  31. // 设置PF14, PF15引脚的禁止上拉和下拉
  32. GPIOF->PUPDR &= (~(0xF << 28));
  33. // 空闲状态SDA和SCL拉高
  34. I2C_SCL_H;
  35. I2C_SDA_H;
  36. }
  37. /*
  38. * 函数名:i2c_start
  39. * 函数功能:模拟i2c开始信号的时序
  40. * 函数参数:无
  41. * 函数返回值:无
  42. * */
  43. void i2c_start(void)
  44. {
  45. /*
  46. * 开始信号:时钟在高电平期间,数据线从高到低的变化
  47. * --------
  48. * SCL \
  49. * --------
  50. * ----
  51. * SDA \
  52. * --------
  53. * */
  54. //确保SDA是输出状态 PF15输出
  55. SET_SDA_OUT;
  56. // 空闲状态SDA和SCL拉高
  57. I2C_SCL_H;
  58. I2C_SDA_H;
  59. delay_us();//延时等待一段时间
  60. I2C_SDA_L;//数据线拉低
  61. delay_us();//延时等待一段时间
  62. I2C_SCL_L;//时钟线拉低,让总线处于占用状态
  63. }
  64. /*
  65. * 函数名:i2c_stop
  66. * 函数功能:模拟i2c停止信号的时序
  67. * 函数参数:无
  68. * 函数返回值:无
  69. * */
  70. void i2c_stop(void)
  71. {
  72. /*
  73. * 停止信号 : 时钟在高电平期间,数据线从低到高的变化
  74. * ----------
  75. * SCL /
  76. * --------
  77. * --- -------
  78. * SDA X /
  79. * --- -------
  80. * */
  81. //确保SDA是输出状态 PF15输出
  82. SET_SDA_OUT;
  83. //时钟线拉低
  84. I2C_SCL_L;//为了修改数据线的电平
  85. delay_us();//延时等待一段时间
  86. I2C_SDA_L;//数据线拉低
  87. delay_us();//延时等待一段时间
  88. //时钟线拉高
  89. I2C_SCL_H;
  90. delay_us();//延时等待一段时间
  91. I2C_SDA_H;//数据线拉高
  92. }
  93. /*
  94. * 函数名: i2c_write_byte
  95. * 函数功能:主机向i2c总线上的从设备写8bits数据
  96. * 函数参数:dat : 等待发送的字节数据
  97. * 函数返回值: 无
  98. * */
  99. void i2c_write_byte(unsigned char dat)
  100. {
  101. /*
  102. * 数据信号:时钟在低电平期间,发送器向数据线上写入数据
  103. * 时钟在高电平期间,接收器从数据线上读取数据
  104. * ---- --------
  105. * SCL \ / \
  106. * -------- --------
  107. * -------- ------------------ ---
  108. * SDA X X
  109. * -------- ------------------ ---
  110. *
  111. * 先发送高位在发送低位
  112. * */
  113. //确保SDA是输出状态 PF15输出
  114. SET_SDA_OUT;
  115. unsigned int i;
  116. for(i=0;i<8;i++)
  117. {
  118. //时钟线拉低
  119. I2C_SCL_L;
  120. delay_us();//延时
  121. //0X3A->0011 1010 0X80->10000000
  122. if(dat&0X80)//最高位为1
  123. {
  124. //发送1
  125. I2C_SDA_H;
  126. }
  127. else //最高位为0
  128. {
  129. I2C_SDA_L;//发送0
  130. }
  131. delay_us();//延时
  132. //时钟线拉高,接收器接收
  133. I2C_SCL_H;
  134. delay_us();//延时,用于等待接收器接收数据
  135. delay_us();//延时
  136. //将数据左移一位,让原来第6位变为第7
  137. dat = dat<<1;
  138. }
  139. }
  140. /*
  141. * 函数名:i2c_read_byte
  142. * 函数功能: 主机从i2c总线上的从设备读8bits数据,
  143. * 主机发送一个应答或者非应答信号
  144. * 函数参数: 0 : 应答信号 1 : 非应答信号
  145. * 函数返回值:读到的有效数据
  146. *
  147. * */
  148. unsigned char i2c_read_byte(unsigned char ack)
  149. {
  150. /*
  151. * 数据信号:时钟在低电平期间,发送器向数据线上写入数据
  152. * 时钟在高电平期间,接收器从数据线上读取数据
  153. * ---- --------
  154. * SCL \ / \
  155. * -------- --------
  156. * -------- ------------------ ---
  157. * SDA X X
  158. * -------- ------------------ ---
  159. *
  160. * 先接收高位, 在接收低位
  161. * */
  162. unsigned int i;
  163. unsigned char dat;//保存接受的数据
  164. //将数据线设置为输入
  165. SET_SDA_IN;
  166. for(i=0;i<8;i++)
  167. {
  168. //先把时钟线拉低,等一段时间,保证发送器发送完毕数据
  169. I2C_SCL_L;
  170. delay_us();
  171. delay_us();//保证发送器发送完数据
  172. //时钟线拉高,读取数据
  173. I2C_SCL_H;
  174. delay_us();
  175. dat=dat<<1;//数值左移 一定要先左移在赋值,不然数据会溢出
  176. if(I2C_SDA_READ)//pf15管脚得到了一个高电平输入
  177. {
  178. dat |=1; //0000 0110
  179. }
  180. else
  181. {
  182. dat &=(~0X1);
  183. }
  184. delay_us();
  185. }
  186. if(ack)
  187. {
  188. i2c_nack();//发送非应答信号,不再接收下一次数据
  189. }
  190. else
  191. {
  192. i2c_ack();//发送应答信号
  193. }
  194. return dat;//将读取到的数据返回
  195. }
  196. /*
  197. * 函数名: i2c_wait_ack
  198. * 函数功能: 主机作为发送器时,等待接收器返回的应答信号
  199. * 函数参数:无
  200. * 函数返回值:
  201. * 0:接收到的应答信号
  202. * 1:接收到的非应答信号
  203. * */
  204. unsigned char i2c_wait_ack(void)
  205. {
  206. /*
  207. * 主机发送一个字节之后,从机给主机返回一个应答信号
  208. *
  209. * -----------
  210. * SCL / M:读 \
  211. * ------------- --------
  212. * --- ---- --------------------
  213. * SDA X X
  214. * --- --------------------
  215. * 主 释 从机 主机
  216. * 机 放 向数据 读数据线
  217. * 总 线写 上的数据
  218. * 线 数据
  219. * */
  220. //时钟线拉低,接收器可以发送信号
  221. I2C_SCL_L;
  222. I2C_SDA_H;//先把数据线拉高,当接收器回应应答信号时,数据线会拉低
  223. delay_us();
  224. SET_SDA_IN;//设置数据线为输入
  225. delay_us();//等待从机响应
  226. delay_us();
  227. I2C_SCL_H;//用于读取数据线数据
  228. if(I2C_SDA_READ)//PF15得到一个高电平输入,收到非应答信号
  229. return 1;
  230. I2C_SCL_L;//时钟线拉低,让数据线处于占用状态
  231. return 0;
  232. }
  233. /*
  234. * 函数名: iic_ack
  235. * 函数功能: 主机作为接收器时,给发送器发送应答信号
  236. * 函数参数:无
  237. * 函数返回值:无
  238. * */
  239. void i2c_ack(void)
  240. {
  241. /* --------
  242. * SCL / \
  243. * ------- ------
  244. * ---
  245. * SDA X
  246. * --- -------------
  247. * */
  248. //保证数据线是输出
  249. SET_SDA_OUT;
  250. I2C_SCL_L;//拉低时钟线
  251. delay_us();
  252. I2C_SDA_L;//数据线拉低,表示应答信号
  253. delay_us();
  254. I2C_SCL_H;//时钟线拉高,等待发送器读取应答信号
  255. delay_us();//让从机读取我们当前的回应
  256. delay_us();
  257. I2C_SCL_L;//数据线处于占用状态,发送器发送下一次数据
  258. }
  259. /*
  260. * 函数名: iic_nack
  261. * 函数功能: 主机作为接收器时,给发送器发送非应答信号
  262. * 函数参数:无
  263. * 函数返回值:无
  264. * */
  265. void i2c_nack(void)
  266. {
  267. /* --------
  268. * SCL / \
  269. * ------- ------
  270. * --- ---------------
  271. * SDA X
  272. * ---
  273. * */
  274. //保证数据线是输出
  275. SET_SDA_OUT;
  276. I2C_SCL_L;//拉低时钟线
  277. delay_us();
  278. I2C_SDA_H;//数据线拉高,表示非应答信号
  279. delay_us();
  280. I2C_SCL_H;//时钟线拉高,等待发送器读取应答信号
  281. delay_us();
  282. delay_us();
  283. I2C_SCL_L;//数据线处于占用状态,发送器发送下一次数据
  284. }

iic.h

  1. #ifndef __IIC_H__
  2. #define __IIC_H__
  3. #include "stm32mp1xx_gpio.h"
  4. #include "stm32mp1xx_rcc.h"
  5. /* 通过程序模拟实现I2C总线的时序和协议
  6. * GPIOF ---> AHB4
  7. * I2C1_SCL ---> PF14
  8. * I2C1_SDA ---> PF15
  9. *
  10. * */
  11. #define SET_SDA_OUT do{GPIOF->MODER &= (~(0x3 << 30)); \
  12. GPIOF->MODER |= (0x1 << 30);}while(0)
  13. #define SET_SDA_IN do{GPIOF->MODER &= (~(0x3 << 30));}while(0)
  14. #define I2C_SCL_H do{GPIOF->BSRR |= (0x1 << 14);}while(0)
  15. #define I2C_SCL_L do{GPIOF->BRR |= (0x1 << 14);}while(0)
  16. #define I2C_SDA_H do{GPIOF->BSRR |= (0x1 << 15);}while(0)
  17. #define I2C_SDA_L do{GPIOF->BRR |= (0x1 << 15);}while(0)
  18. #define I2C_SDA_READ (GPIOF->IDR & (0x1 << 15))
  19. void delay_us(void);//微秒延时
  20. void delay(int ms);
  21. void i2c_init(void);//初始化
  22. void i2c_start(void);//起始信号
  23. void i2c_stop(void);//终止信号
  24. void i2c_write_byte(unsigned char dat);//写一个字节数据
  25. unsigned char i2c_read_byte(unsigned char ack);//读取一个字节数据
  26. unsigned char i2c_wait_ack(void); //等待应答信号
  27. void i2c_ack(void);//发送应答信号
  28. void i2c_nack(void);//发送非应答信号
  29. #endif

si7006.c

  1. #include"si7006.h"
  2. //封装延时函数
  3. void delay(int ms)
  4. {
  5. int i,j;
  6. for(i=0;i<ms;i++)
  7. {
  8. for(j=0;j<2000;j++)
  9. {}
  10. }
  11. }
  12. void si7006_init()
  13. {
  14. //发起起始信号
  15. i2c_start();
  16. //发送从机地址+写标志
  17. i2c_write_byte(0X40<<1|0);
  18. //等待从机应答
  19. i2c_wait_ack();
  20. //发送寄存器地址 0XE6
  21. i2c_write_byte(0XE6);
  22. //等待从机应答
  23. i2c_wait_ack();
  24. //传输要写入的数据0X3A、
  25. i2c_write_byte(0X3A);
  26. //等待从机应答
  27. i2c_wait_ack();
  28. //发送终止信号
  29. i2c_stop();
  30. }
  31. short si7006_read_tem()
  32. {
  33. short tem;
  34. char tem_h,tem_l;
  35. //发起起始信号
  36. i2c_start();
  37. //发送从机地址+写标志
  38. i2c_write_byte(0x40<<1|0);
  39. //等待从机应答
  40. i2c_wait_ack();
  41. //发送寄存器地址 0XE3
  42. i2c_write_byte(0xe3);
  43. //等待从机应答
  44. i2c_wait_ack();
  45. //重复起始信号
  46. i2c_start();
  47. //发送从机地址+读标志
  48. i2c_write_byte(0x40<<1|1);
  49. //等待从机应答
  50. i2c_wait_ack();
  51. delay(100);//等待从机测量数据
  52. //接收数据高八位
  53. //发送应答信号
  54. tem_h=i2c_read_byte(0);
  55. //接收数据低八位
  56. //发送非应答信号
  57. tem_l=i2c_read_byte(1);
  58. //将高八位和低八位合成一个数据 高八位<<8|低8
  59. tem=tem_h<<8|tem_l;
  60. return tem;
  61. }
  62. unsigned short si7006_read_hum()
  63. {
  64. unsigned short hum;
  65. unsigned char hum_h,hum_l;
  66. //发起起始信号
  67. i2c_start();
  68. //发送从机地址+写标志
  69. i2c_write_byte(0x40<<1|0);
  70. //等待从机应答
  71. i2c_wait_ack();
  72. //发送寄存器地址 0XE3
  73. i2c_write_byte(0xe5);
  74. //等待从机应答
  75. i2c_wait_ack();
  76. //重复起始信号
  77. i2c_start();
  78. //发送从机地址+读标志
  79. i2c_write_byte(0x40<<1|1);
  80. //等待从机应答
  81. i2c_wait_ack();
  82. delay(100);//等待从机测量数据
  83. //接收数据高八位
  84. //发送应答信号
  85. hum_h=i2c_read_byte(0);
  86. //接收数据低八位
  87. //发送非应答信号
  88. hum_l=i2c_read_byte(1);
  89. //将高八位和低八位合成一个数据 高八位<<8|低8
  90. hum=hum_h<<8|hum_l;
  91. return hum;
  92. }

si7006.h

  1. #ifndef __SI7006_H__
  2. #define __SI7006_H__
  3. #include"iic.h"
  4. void delay_ms(int ms);
  5. void si7006_init();
  6. unsigned short si7006_read_hum();
  7. short si7006_read_tem();
  8. #endif

main.c

  1. #include "si7006.h"
  2. int main()
  3. {
  4. //si7006初始化
  5. si7006_init();
  6. i2c_init();
  7. unsigned short hum;
  8. short tem;
  9. while(1)
  10. {
  11. //读取温度和湿度
  12. hum=si7006_read_hum();
  13. tem=si7006_read_tem();
  14. //计算温湿度数据
  15. hum=hum*125/65536-6;
  16. tem=tem*175.72/65536-46.85;
  17. printf("hum:%d\n",hum);
  18. printf("tem:%d\n",tem);
  19. delay(1000);
  20. }
  21. return 0;
  22. }

运行结果:

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

闽ICP备14008679号