[CW32L083系列] 基于CW32L083SorKit sht30x驱动

[复制链接]
 楼主| lulugl 发表于 2023-6-22 09:57 | 显示全部楼层 |阅读模式
#申请原创# #有奖活动# [color=rgba(0, 0, 0, 0.75)]     @21小跑堂[color=rgba(0, 0, 0, 0.75)] SHT3x是新一代的温湿度传感器,精度为±2%RH和±0.3℃,输入电压范围从2.4V到5.5V,采用IIC总线接口,速率可达1MHz。测量温湿度范围分别为是-40℃ ~ 125℃和0 ~ 100%。工作电流为600uA,空闲电流在2ua。因此非常适合用在低功耗温湿度监测项目之上。[color=rgba(0, 0, 0, 0.75)]     SHT3X的获取温度只需要二步,一是发送温度转换命令,接着读取6个字节。进行温湿度测量,需先发送一个开始信号,然后发送一个 I2C的写操作头,然后再跟随一个 16 位的温湿度转换命令。传感器收到上位机发送的每个字节数据后,会通过将 SDA 总线拉到低电平给出ACK 信号。在正确的收到温湿度转换命令并发送 ACK 信号给微处理器之后,SHT3x 内部开始启动温度和湿度的转换测量。二是在传感器完成温湿度测量之后,上位机可以通过发送 START信号+I2C 读取数据头来 读取温湿度数据,如果温湿度数据已经准备好,那么芯片会向上位机发送 ACK 信号,并随后发送 2 字节的温度数据加 1 字节的 CRC 校验数据,然后再发送 2 字节的湿度数据加 1 字节的 CRC 校验数据。上位机需要对接收到的每个字节数据发送 ACK,否则芯片会停止发送数据。微处理器在收到湿度数据的CRC 字节后应该发送一个NACK 和一个 STOP 信号来结束本次数据传输,
[color=rgba(0, 0, 0, 0.75)]下面开始CW32L083的温度采集:

[color=rgba(0, 0, 0, 0.75)]1、选取PB10、PB11为I2C通信,采取软件I2C。初始化代码如下:
  1. void IIC_Init(void)
  2. {
  3.           //配置PB10 为输出
  4.         //使能GPIOB时钟
  5.         CW_SYSCTRL->AHBEN_f.GPIOB  = 1;
  6.         //配置PB10 为输出
  7.         CW_GPIOB->ANALOG_f.PIN10 = 0; //设置 GPIOx_ANALOG.PINy 为 0,将端口配置为数字功能;
  8.         CW_GPIOB->DIR_f.PIN10 = 0;    //设置 GPIOx_DIR.PINy 为 0,将端口配置成输出;
  9.         CW_GPIOB->OPENDRAIN_f.PIN10 = 0;  //0:推挽输出
  10.         CW_GPIOB->ODR_f.PIN10 = 1;
  11.        
  12.         CW_GPIOB->ANALOG_f.PIN11 = 0; //设置 GPIOx_ANALOG.PINy 为 0,将端口配置为数字功能;
  13.         CW_GPIOB->DIR_f.PIN11 = 0;    //设置 GPIOx_DIR.PINy 为 0,将端口配置成输出;
  14.         CW_GPIOB->OPENDRAIN_f.PIN11 = 0;  //0:推挽输出
  15.         CW_GPIOB->ODR_f.PIN11 = 1;
  16.                
  17. }
2、设置IO方向,SDA需要转换输出与输入,我们采用对 GPIOx_DIR.PINy进行设置,来实现IO的数据输入与输出的转换。
  1. //IO方向设置(SDA)
  2. /*********xxxxxxxxxxxxxx*************/
  3. void SDA_IN()  
  4. {
  5.         CW_GPIOB->DIR_f.PIN11 = 1;    //设置 GPIOx_DIR.PINy 为 0,将端口配置成输出;
  6. }

  7. void SDA_OUT()
  8. {
  9.   CW_GPIOB->DIR_f.PIN11 = 0;    //设置 GPIOx_DIR.PINy 为 0,将端口配置成输出;
  10.         CW_GPIOB->OPENDRAIN_f.PIN11 = 0;  //0:推挽输出
  11. }
3、定义读取SDA的宏:#define READ_SDA   PB11_GETVALUE() //输入SDA
4、定义IIC的STAT、STOP、ACK、NACK等时序,代码如下:
  1. //产生IIC起始信号
  2. void IIC_Start(void)
  3. {
  4.         SDA_OUT();     //sda线输出
  5.         IIC_SDA=1;                    
  6.         IIC_SCL=1;
  7.         delay_us(4);
  8.         IIC_SDA=0;//START:when CLK is high,DATA change form high to low
  9.         delay_us(4);
  10.         IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
  11. }       

  12. //产生IIC停止信号
  13. void IIC_Stop(void)
  14. {
  15.         SDA_OUT();//sda线输出
  16.         IIC_SCL=0;
  17.         IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
  18.         delay_us(4);
  19.         IIC_SCL=1;
  20.         IIC_SDA=1;//发送I2C总线结束信号
  21.         delay_us(4);                                                                  
  22. }

  23. //等待应答信号到来
  24. //返回值:1,接收应答失败
  25. //        0,接收应答成功
  26. /*********xxxx修改超时时间************/
  27. uint8_t IIC_Wait_Ack(void)
  28. {
  29.         uint8_t ucErrTime=0;
  30.         SDA_IN();      //SDA设置为输入  
  31.         IIC_SDA=1;delay_us(3);          
  32.         IIC_SCL=1;delay_us(3);         
  33.         while(READ_SDA)
  34.         {
  35.                 ucErrTime++;
  36.                 if(ucErrTime>250)
  37.                 {
  38.                         //printf("超时\n");
  39.                         IIC_Stop();
  40.                         return 1;
  41.                 }
  42.         }
  43.         IIC_SCL=0;//时钟输出0           
  44.         return 0;  
  45. }

  46. //产生ACK应答
  47. void IIC_Ack(void)
  48. {
  49.         IIC_SCL=0;
  50.         SDA_OUT();
  51.         IIC_SDA=0;
  52.         delay_us(2);
  53.         IIC_SCL=1;
  54.         delay_us(2);
  55.         IIC_SCL=0;
  56. }

  57. //不产生ACK应答                    
  58. void IIC_NAck(void)
  59. {
  60.         IIC_SCL=0;
  61.         SDA_OUT();
  62.         IIC_SDA=1;
  63.         delay_us(2);
  64.         IIC_SCL=1;
  65.         delay_us(2);
  66.         IIC_SCL=0;
  67. }                       
5、定义发送一个字节:
  1. //IIC发送一个字节
  2. //返回从机有无应答
  3. //1,有应答
  4. //0,无应答                          
  5. void IIC_Send_Byte(uint8_t txd)
  6. {                        
  7.     uint8_t t;   
  8.                 SDA_OUT();             
  9.     IIC_SCL=0;//拉低时钟开始数据传输
  10.     for(t=0;t<8;t++)
  11.     {              
  12.                 if((txd&0x80)>>7)
  13.                         IIC_SDA=1;
  14.                 else
  15.                         IIC_SDA=0;
  16.                 txd<<=1;           
  17.                 delay_us(2);   //对TEA5767这三个延时都是必须的
  18.                 IIC_SCL=1;
  19.                 delay_us(2);
  20.                 IIC_SCL=0;       
  21.                 delay_us(2);
  22.     }         
  23. }           
6、定义读取一个字节
  1. //读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
  2. uint8_t IIC_Read_Byte(unsigned char ack)
  3. {
  4.         unsigned char i,receive=0;
  5.         SDA_IN();//SDA设置为输入
  6.   for(i=0;i<8;i++ )
  7.         {
  8.         IIC_SCL=0;
  9.         delay_us(100);
  10.                     IIC_SCL=1;
  11.         receive<<=1;
  12.         if(READ_SDA)receive++;   
  13.                     delay_us(100);
  14.     }                                         
  15.     if (!ack)
  16.         IIC_NAck();//发送nACK
  17.     else
  18.         IIC_Ack(); //发送ACK   
  19.     return receive;
  20. }
到这里IIC的初始化工作结束。
6、SHT3x的数据获取,采集厂家出厂的标准DEMO。主要是发送转换温度的命令与读取命令,sth30.c代码如下:
  1. #include "sht30.h"

  2. #define POLYNOMIAL_CXDZ 0x31 // X^8 + X^5 + X^4 + 1
  3. //SHT3X CRC校验
  4. unsigned char SHT3X_CRC(uint8_t *data, uint8_t len)
  5. {
  6.         unsigned char bit;        // bit mask
  7.         unsigned char crc = 0xFF; // calculated checksum
  8.         unsigned char byteCtr;    // byte counter

  9.         // calculates 8-Bit checksum with given polynomial @GZCXDZ
  10.         for(byteCtr = 0; byteCtr < len; byteCtr++) {
  11.                         crc ^= (data[byteCtr]);
  12.                         for(bit = 8; bit > 0; --bit) {
  13.                                         if(crc & 0x80) {
  14.                                                         crc = (crc << 1) ^ POLYNOMIAL_CXDZ;
  15.                                         }  else {
  16.                                                         crc = (crc << 1);
  17.                                         }
  18.                         }
  19.         }
  20.   return crc;
  21. }

  22. //SHT30命令函数
  23. //addr:表示产品的序号,因为SHT30使用IIC总线的话一条线上可以挂两个
  24. void SHT30_CMD(uint16_t cmd)
  25. {
  26.         IIC_Start();
  27.   IIC_Send_Byte(SHT30_ADDR+0);  //发送设备地址,写寄存器
  28.         IIC_Wait_Ack();
  29.         IIC_Send_Byte((cmd>>8)&0xff); //MSB

  30.         IIC_Wait_Ack();
  31.         IIC_Send_Byte(cmd&0xff); //LSB

  32.         IIC_Wait_Ack();
  33.         IIC_Stop();
  34.         SysTickDelay(500);//命令发完后需要等待20ms以上才能读写
  35. }



  36. //SHT30读取温湿度
  37. //temp:温度,-400~1250,实际温度=temp/10,分辨率0.1℃,精度±0.3℃
  38. //humi:湿度,0~1000,实际湿度=humi/10,分辨率0.1%rh,精度±3
  39. //返回0成功,1失败
  40. uint8_t SHT30_Read_Humiture(int *temp,uint16_t *humi)
  41. {
  42.         uint8_t buff[6];
  43.        
  44.         SHT30_CMD(SHT30_READ_HUMITURE);//读温湿度命令
  45.        
  46.         IIC_Start();
  47.         IIC_Send_Byte(SHT30_ADDR+1); //发送设备地址,读寄存器
  48.         IIC_Wait_Ack();
  49.         buff[0]=IIC_Read_Byte(1);//继续读,给应答
  50.         buff[1]=IIC_Read_Byte(1);//继续读,给应答
  51.         buff[2]=IIC_Read_Byte(1);//继续读,给应答
  52.         buff[3]=IIC_Read_Byte(1);//继续读,给应答
  53.         buff[4]=IIC_Read_Byte(1);//继续读,给应答
  54.         buff[5]=IIC_Read_Byte(0);//不继续给停止应答
  55.         IIC_Stop();

  56.        
  57.         //printf("buff=%d,%d,%d,%d,%d,%d\r\n",buff[0],buff[1],buff[2],buff[3],buff[4],buff[5]);
  58.         //CRC校验
  59.         if(SHT3X_CRC(&buff[0],2)==buff[2] && SHT3X_CRC(&buff[3],2)==buff[5])
  60.         {

  61.                 *temp=(-45+(175.0*((buff[0]<<8)+buff[1])/65535.0))*10;
  62.                 *humi=10*100*((buff[3]<<8)+buff[4])/65535.0;
  63.                 if(*temp>1250) *temp=1250;
  64.                 else if(*temp<-400) *temp=-400;
  65.                 return 0;
  66.         }
  67.         else return 1;       
  68.        
  69. }

  70. //SHT30初始化
  71. void SHT30_Init()
  72. {
  73.         IIC_Init();
  74. }
sht30.h头文件代码如下:
  1. #ifndef __SHT30_H__
  2. #define __SHT30_H__
  3. #include "main.h"

  4. #define SHT30_ADDR (uint8_t)(0x44<<1) //sht30 i2c地址,ADDR管脚接低电平时为0x44,接高电平为0x45

  5. //SHT30命令
  6. #define SHT30_READ_HUMITURE (uint16_t)0x2c06  //读温湿度

  7. //CRC多项式
  8. #define POLYNOMIAL 0x31 // X^8 + X^5 + X^4 + 1

  9. uint8_t SHT30_Read_Humiture(int *temp,uint16_t *humi);
  10. void SHT30_Init(void);

  11. #endif
8、在主程序中,我们把读取到的数据显示到LCD段码屏上:
  1.     while(1)
  2.     {
  3.                         SHT30_Read_Humiture(t,h);
  4.                         temp = t[0];
  5.                         Lcd_clear();
  6.                         show_num(2, temp/100,0);
  7.                         show_num(1, (temp/10)%10,1);
  8.                         show_num(0, temp%10,0);
  9.                        
  10.                         temp = h[0];
  11.                         show_num(7, temp/100,0);
  12.                         show_num(6, (temp/10)%10,1);
  13.                         show_num(5, temp%10,0);
  14.                         SysTickDelay(50000);
  15.     }
最后实现的效果如图:
温湿计.jpg
[color=rgba(0, 0, 0, 0.75)]


您需要登录后才可以回帖 登录 | 注册

本版积分规则

180

主题

830

帖子

12

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