【沁恒微CH32V307评估板试用体验】读取SHT20温湿度传感器 - RISC-V MCU技术社区 - 电子技术william hill官网 - 广受欢迎的专业电子william hill官网 - 威廉希尔官方网站
分享 收藏 返回

[文章]

【沁恒微CH32V307评估板试用体验】读取SHT20温湿度传感器

今天我们测试下读取温湿度传感器SHT20的传感器数值,此传感器是IIC接口的,数字输出。
图片1.png
我们接在板子的PB6,PB7接口上,这个有外部上拉,所以我们只需要使用两个IO即可,然后我们通过模拟IIC总线方式即可完成传感器数值获取。
图片2.png
之后我在原有的点灯基础上,添加4个文件,分别是IIC接口的,和传感器的。




  1. //硬件驱动

  2. #include "iic.h"











  3. IIC_INFO iicInfo;







  4. /*

  5. ************************************************************

  6. *   函数名称:   IIC_SpeedCtl

  7. *

  8. *   函数功能:   软件IIC速度控制

  9. *

  10. *   入口参数:   speed:延时参数

  11. *

  12. *   返回参数:   无

  13. *

  14. *   说明:     单位:微秒

  15. ************************************************************

  16. */

  17. void IIC_SpeedCtl(unsigned short speed)

  18. {



  19.     iicInfo.speed = speed;



  20. }



  21. /*

  22. ************************************************************

  23. *   函数名称:   IIC_Init

  24. *

  25. *   函数功能:   软件IIC总线IO初始化

  26. *

  27. *   入口参数:   无

  28. *

  29. *   返回参数:   无

  30. *

  31. *   说明:     使用开漏方式,这样可以不用切换IO口的输入输出方向

  32. ************************************************************

  33. */

  34. void IIC_Init(void)

  35. {



  36.     GPIO_InitTypeDef gpioInitStruct;



  37.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);



  38.     gpioInitStruct.GPIO_Mode = GPIO_Mode_Out_OD;            //开漏,这样不用去切换输出输入方向

  39.     gpioInitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

  40.     gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;

  41.     GPIO_Init(GPIOB, &gpioInitStruct);



  42.     IIC_SpeedCtl(5);



  43.     SDA_H;                                                  //拉高SDA线,处于空闲状态

  44.     SCL_H;                                                  //拉高SCL线,处于空闲状态



  45. }



  46. /*

  47. ************************************************************

  48. *   函数名称:   IIC_Start

  49. *

  50. *   函数功能:   软件IIC开始信号

  51. *

  52. *   入口参数:   无

  53. *

  54. *   返回参数:   无

  55. *

  56. *   说明:

  57. ************************************************************

  58. */

  59. void IIC_Start(void)

  60. {



  61.     SDA_H;                      //拉高SDA线

  62.     SCL_H;                      //拉高SCL线

  63.     Delay_Us(iicInfo.speed);     //延时,速度控制



  64.     SDA_L;                      //当SCL线为高时,SDA线一个下降沿代表开始信号

  65.     Delay_Us(iicInfo.speed);     //延时,速度控制

  66.     SCL_L;                      //钳住SCL线,以便发送数据



  67. }



  68. /*

  69. ************************************************************

  70. *   函数名称:   IIC_Stop

  71. *

  72. *   函数功能:   软件IIC停止信号

  73. *

  74. *   入口参数:   无

  75. *

  76. *   返回参数:   无

  77. *

  78. *   说明:

  79. ************************************************************

  80. */

  81. void IIC_Stop(void)

  82. {



  83.     SDA_L;                      //拉低SDA线

  84.     SCL_L;                      //拉低SCL先

  85.     Delay_Us(iicInfo.speed);     //延时,速度控制



  86.     SCL_H;                      //拉高SCL线

  87.     SDA_H;                      //拉高SDA线,当SCL线为高时,SDA线一个上升沿代表停止信号

  88.     Delay_Us(iicInfo.speed);



  89. }



  90. /*

  91. ************************************************************

  92. *   函数名称:   IIC_WaitAck

  93. *

  94. *   函数功能:   软件IIC等待应答

  95. *

  96. *   入口参数:   timeOut:超时时间

  97. *

  98. *   返回参数:   无

  99. *

  100. *   说明:     单位:微秒

  101. ************************************************************

  102. */

  103. _Bool IIC_WaitAck(unsigned int timeOut)

  104. {





  105.     SDA_H;Delay_Us(iicInfo.speed);           //拉高SDA线

  106.     SCL_H;Delay_Us(iicInfo.speed);           //拉高SCL线



  107.     while(SDA_R)                            //如果读到SDA线为1,则等待。应答信号应是0

  108.     {

  109.         if(--timeOut == 0)

  110.         {





  111.             IIC_Stop();                     //超时未收到应答,则停止总线



  112.             return IIC_Err;                 //返回失败

  113.         }



  114.         Delay_Us(iicInfo.speed);

  115.     }



  116.     SCL_L;                                  //拉低SCL线,以便继续收发数据



  117.     return IIC_OK;                          //返回成功



  118. }



  119. /*

  120. ************************************************************

  121. *   函数名称:   IIC_Ack

  122. *

  123. *   函数功能:   软件IIC产生一个应答

  124. *

  125. *   入口参数:   无

  126. *

  127. *   返回参数:   无

  128. *

  129. *   说明:     当SDA线为低时,SCL线一个正脉冲代表发送一个应答信号

  130. ************************************************************

  131. */

  132. void IIC_Ack(void)

  133. {



  134.     SCL_L;                      //拉低SCL线

  135.     SDA_L;                      //拉低SDA线

  136.     Delay_Us(iicInfo.speed);

  137.     SCL_H;                      //拉高SCL线

  138.     Delay_Us(iicInfo.speed);

  139.     SCL_L;                      //拉低SCL线



  140. }



  141. /*

  142. ************************************************************

  143. *   函数名称:   IIC_NAck

  144. *

  145. *   函数功能:   软件IIC产生一非个应答

  146. *

  147. *   入口参数:   无

  148. *

  149. *   返回参数:   无

  150. *

  151. *   说明:     当SDA线为高时,SCL线一个正脉冲代表发送一个非应答信号

  152. ************************************************************

  153. */

  154. void IIC_NAck(void)

  155. {



  156.     SCL_L;                      //拉低SCL线

  157.     SDA_H;                      //拉高SDA线

  158.     Delay_Us(iicInfo.speed);

  159.     SCL_H;                      //拉高SCL线

  160.     Delay_Us(iicInfo.speed);

  161.     SCL_L;                      //拉低SCL线



  162. }



  163. /*

  164. ************************************************************

  165. *   函数名称:   IIC_SendByte

  166. *

  167. *   函数功能:   软件IIC发送一个字节

  168. *

  169. *   入口参数:   byte:需要发送的字节

  170. *

  171. *   返回参数:   无

  172. *

  173. *   说明:

  174. ************************************************************

  175. */

  176. void IIC_SendByte(unsigned char byte)

  177. {



  178.     unsigned char count = 0;



  179.     SCL_L;                          //拉低时钟开始数据传输



  180.     for(; count < 8; count++)       //循环8次,每次发送一个bit

  181.     {

  182.         if(byte & 0x80)             //发送最高位

  183.             SDA_H;

  184.         else

  185.             SDA_L;



  186.         byte <<= 1;                 //byte左移1位



  187.         Delay_Us(iicInfo.speed);

  188.         SCL_H;

  189.         Delay_Us(iicInfo.speed);

  190.         SCL_L;

  191.     }



  192. }



  193. /*

  194. ************************************************************

  195. *   函数名称:   IIC_RecvByte

  196. *

  197. *   函数功能:   软件IIC接收一个字节

  198. *

  199. *   入口参数:   无

  200. *

  201. *   返回参数:   接收到的字节数据

  202. *

  203. *   说明:

  204. ************************************************************

  205. */

  206. unsigned char IIC_RecvByte(void)

  207. {



  208.     unsigned char count = 0, receive = 0;



  209.     SDA_H;                          //拉高SDA线,开漏状态下,需线拉高以便读取数据



  210.     for(; count < 8; count++ )      //循环8次,每次发送一个bit

  211.     {

  212.         SCL_L;

  213.         Delay_Us(iicInfo.speed);

  214.         SCL_H;



  215.         receive <<= 1;              //左移一位



  216.         if(SDA_R)                   //如果SDA线为1,则receive变量自增,每次自增都是对bit0的+1,然后下一次循环会先左移一次

  217.             receive++;



  218.         Delay_Us(iicInfo.speed);

  219.     }



  220.     return receive;



  221. }



  222. /*

  223. ************************************************************

  224. *   函数名称:   I2C_WriteByte

  225. *

  226. *   函数功能:   软件IIC写一个数据

  227. *

  228. *   入口参数:   slaveAddr:从机地址

  229. *               regAddr:寄存器地址

  230. *               byte:需要写入的数据

  231. *

  232. *   返回参数:   0-写入成功  1-写入失败

  233. *

  234. *   说明:     *byte是缓存写入数据的变量的地址,因为有些寄存器只需要控制下寄存器,并不需要写入值

  235. ************************************************************

  236. */

  237. _Bool I2C_WriteByte(unsigned char slaveAddr, unsigned char regAddr, unsigned char *byte)

  238. {



  239.     unsigned char addr = 0;



  240.     addr = slaveAddr << 1;      //IIC地址是7bit,这里需要左移1位,bit0:1-读  0-写



  241.     IIC_Start();                //起始信号



  242.     IIC_SendByte(addr);         //发送设备地址(写)

  243.     if(IIC_WaitAck(5000))       //等待应答

  244.         return IIC_Err;



  245.     IIC_SendByte(regAddr);      //发送寄存器地址

  246.     if(IIC_WaitAck(5000))       //等待应答

  247.         return IIC_Err;



  248.     if(byte)

  249.     {

  250.         IIC_SendByte(*byte);    //发送数据

  251.         if(IIC_WaitAck(5000))   //等待应答

  252.             return IIC_Err;

  253.     }



  254.     IIC_Stop();                 //停止信号



  255.     return IIC_OK;



  256. }



  257. /*

  258. ************************************************************

  259. *   函数名称:   I2C_ReadByte

  260. *

  261. *   函数功能:   软件IIC读取一个字节

  262. *

  263. *   入口参数:   slaveAddr:从机地址

  264. *               regAddr:寄存器地址

  265. *               val:需要读取的数据缓存

  266. *

  267. *   返回参数:   0-成功        1-失败

  268. *

  269. *   说明:     val是一个缓存变量的地址

  270. ************************************************************

  271. */

  272. _Bool I2C_ReadByte(unsigned char slaveAddr, unsigned char regAddr, unsigned char *val)

  273. {



  274.     unsigned char addr = 0;



  275.     addr = slaveAddr << 1;      //IIC地址是7bit,这里需要左移1位,bit0:1-读  0-写



  276.     IIC_Start();                //起始信号



  277.     IIC_SendByte(addr);         //发送设备地址(写)

  278.     if(IIC_WaitAck(5000))       //等待应答

  279.         return IIC_Err;



  280.     IIC_SendByte(regAddr);      //发送寄存器地址

  281.     if(IIC_WaitAck(5000))       //等待应答

  282.         return IIC_Err;



  283.     IIC_Start();                //重启信号



  284.     IIC_SendByte(addr + 1);     //发送设备地址(读)

  285.     if(IIC_WaitAck(5000))       //等待应答

  286.         return IIC_Err;



  287.     *val = IIC_RecvByte();      //接收

  288.     IIC_NAck();                 //产生一个非应答信号,代表读取接收



  289.     IIC_Stop();                 //停止信号



  290.     return IIC_OK;



  291. }



  292. /*

  293. ************************************************************

  294. *   函数名称:   I2C_WriteBytes

  295. *

  296. *   函数功能:   软件IIC写多个数据

  297. *

  298. *   入口参数:   slaveAddr:从机地址

  299. *               regAddr:寄存器地址

  300. *               buf:需要写入的数据缓存

  301. *               num:数据长度

  302. *

  303. *   返回参数:   0-写入成功  1-写入失败

  304. *

  305. *   说明:     *buf是一个数组或指向一个缓存区的指针

  306. ************************************************************

  307. */

  308. _Bool I2C_WriteBytes(unsigned char slaveAddr, unsigned char regAddr, unsigned char *buf, unsigned char num)

  309. {



  310.     unsigned char addr = 0;



  311.     addr = slaveAddr << 1;      //IIC地址是7bit,这里需要左移1位,bit0:1-读  0-写



  312.     IIC_Start();                //起始信号



  313.     IIC_SendByte(addr);         //发送设备地址(写)

  314.     if(IIC_WaitAck(5000))       //等待应答

  315.         return IIC_Err;



  316.     IIC_SendByte(regAddr);      //发送寄存器地址

  317.     if(IIC_WaitAck(5000))       //等待应答

  318.         return IIC_Err;



  319.     while(num--)                //循环写入数据

  320.     {

  321.         IIC_SendByte(*buf);     //发送数据

  322.         if(IIC_WaitAck(5000))   //等待应答

  323.             return IIC_Err;



  324.         buf++;                  //数据指针偏移到下一个



  325.         Delay_Us(10);

  326.     }



  327.     IIC_Stop();                 //停止信号



  328.     return IIC_OK;



  329. }



  330. /*

  331. ************************************************************

  332. *   函数名称:   I2C_ReadBytes

  333. *

  334. *   函数功能:   软件IIC读多个数据

  335. *

  336. *   入口参数:   slaveAddr:从机地址

  337. *               regAddr:寄存器地址

  338. *               buf:需要读取的数据缓存

  339. *               num:数据长度

  340. *

  341. *   返回参数:   0-写入成功  1-写入失败

  342. *

  343. *   说明:     *buf是一个数组或指向一个缓存区的指针

  344. ************************************************************

  345. */

  346. _Bool I2C_ReadBytes(unsigned char slaveAddr, unsigned char regAddr, unsigned char *buf, unsigned char num)

  347. {



  348.     unsigned short addr = 0;



  349.     addr = slaveAddr << 1;      //IIC地址是7bit,这里需要左移1位,bit0:1-读  0-写



  350.     IIC_Start();                //起始信号



  351.     IIC_SendByte(addr);         //发送设备地址(写)

  352.     if(IIC_WaitAck(5000))       //等待应答

  353.         return IIC_Err;



  354.     IIC_SendByte(regAddr);      //发送寄存器地址

  355.     if(IIC_WaitAck(5000))       //等待应答

  356.         return IIC_Err;



  357.     IIC_Start();                //重启信号



  358.     IIC_SendByte(addr + 1);     //发送设备地址(读)

  359.     if(IIC_WaitAck(5000))       //等待应答

  360.         return IIC_Err;



  361.     while(num--)

  362.     {

  363.         *buf = IIC_RecvByte();

  364.         buf++;                  //偏移到下一个数据存储地址



  365.         if(num == 0)

  366.         {

  367.            IIC_NAck();          //最后一个数据需要回NOACK

  368.         }

  369.         else

  370.         {

  371.           IIC_Ack();            //回应ACK

  372.         }

  373.     }



  374.     IIC_Stop();



  375.     return IIC_OK;



  376. }

IIC接口我们直接选择开漏模式,这样我们需要转换IO口的方向。
图片3.png
之后注意下其换算方式即可。套用公式就能得到最终温度。
图片4.png
主函数中一直打印,这里打印也有点奇怪用%f居然不显示,我强转了下,其实还有其他办法,本次测试的就这样下弄下吧。
图片5.png
其实还可以放在看数据,不过不知道是不是不支持全局变量自动刷新,如果我全速运行也是不显示变量的,得打上断点。不过使用下来,还是感觉方便,代码提示,报错都是比较准确的。
图片6.png
看下接线实物图。
图片7.jpg

搜索
复制

更多回帖

×
发帖