【专题STM32F103】STM32+HAL库+SHT30温湿度传感器模块I2C通讯数字型

模块与接线

 

SHT30模块与引脚

SCL -------PA4

SCL--------PA5

实现步骤:

    1、IIC地址  0x45 (板子上有)

    2、启动温湿度测量 写入 0x2c 0x06

    3、延时10ms,等待测量结束

    4、读测量值,发读指令,延时1ms,接收测量结果。

    5、采样值转换为温度值、湿度值

程序代码

 在标准库基础上,修改出HAL库代码如下:

#ifndef __MYIIC_H
#define __MYIIC_H
//#include "sys.h"
#include "main.h" /*有PAout(),PAin()宏定义*/
//IO方向设置  PA11 
// 每组的高8位  
//#define SDA_IN()  {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=0X00008000;}    
//#define SDA_OUT() {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=0X00003000;}

//IO操作函数     
//#define IIC_SCL    PAout(12) //SCL PA12
//#define IIC_SDA    PAout(11) //SDA PA11     
//#define READ_SDA   PAin(11)  //输入SDA 

//PA4 SCL   PA5 SDA
// 每组的低5位  
#define SDA_IN()  {GPIOA->CRL&=0XFF0FFFFF;GPIOA->CRL|=0X00800000;}    
#define SDA_OUT() {GPIOA->CRL&=0XFF0FFFFF;GPIOA->CRL|=0X00300000;}
//IO操作函数     
#define IIC_SCL    PAout(4) //SCL PA12
#define IIC_SDA    PAout(5) //SDA PA11     
#define READ_SDA   PAin(5)  //输入SDA 

//添加的函数
void SHT30_Init(void); //相关的GPIO初始化
void SHT30_read_result(u8 addr);//读取温湿度
void SHT30_Test(void);//测试温湿度SHT30
//IIC所有操作函数
void IIC_Init(void);           //初始化IIC的IO口                 
void IIC_Start(void);                   //发送IIC开始信号
void IIC_Stop(void);                   //发送IIC停止信号
void IIC_Send_Byte(u8 txd);         //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void);                 //IIC等待ACK信号
void IIC_Ack(void);                      //IIC发送ACK信号
void IIC_NAck(void);                  //IIC不发送ACK信号

void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);      
#endif
#include "iic.h"
#include "string.h"/*字符串打印功能*/
#include "stdio.h"
//#include "delay.h"
#define SHT30_ADD  0x45U /*地址*/
#define WRITE_MODE 0x00U
#define READ_MODE  0x01U
//
char humiture_buff1[20];
//
void SHT30_Test(void)//测试温湿度SHT30
{
    uint8_t count=0;
   SHT30_Init();
    
    while(count<128)
    {
        count++;
      SHT30_read_result((uint8_t)SHT30_ADD);
    }
}
//
void SHT30_Init(void) //相关的GPIO初始化
{
   IIC_Init();
}
//
/*
for循环实现延时us
*/
//void delay_us(uint32_t nus)//for循环实现延时us
//{
// uint32_t Delay = nus * 168/4;
// do
// {
//     __NOP();
// }
// while (Delay --);
//}
//
/*******************************************************************
温湿度获取函数               
函数原型: SHT30_read_result(u8 addr);
功能: 用来接收从器件采集并合成温湿度
********************************************************************/
void SHT30_read_result(u8 addr)//读取温湿度
{
        u16 tem,hum;
        u16 buff[6];
        float Temperature=0;
        float Humidity=0;
       
          /*写命令,启动一次温湿度测量*/
        IIC_Start();          
        IIC_Send_Byte(addr<<1 | WRITE_MODE);//写7位I2C设备地址加0作为写取位,1为读取位
        IIC_Wait_Ack();
        IIC_Send_Byte(0x2C); 
        IIC_Wait_Ack();
        IIC_Send_Byte(0x06);
        IIC_Wait_Ack();
        IIC_Stop();
        HAL_Delay(10);
        IIC_Start();
        IIC_Send_Byte(addr<<1 | READ_MODE);//写7位I2C设备地址加0作为写取位,1为读取位        
          HAL_Delay(1);//在STM32,72MHz 时加入,否者读不出数据
        if(IIC_Wait_Ack()==0)
        {
                buff[0]=IIC_Read_Byte(1);
                //IIC_ACK();
                buff[1]=IIC_Read_Byte(1);
                //IIC_ACK();
                buff[2]=IIC_Read_Byte(1);
                //IIC_ACK();
                buff[3]=IIC_Read_Byte(1);
                //IIC_ACK();
                buff[4]=IIC_Read_Byte(1);
                //IIC_ACK();
                buff[5]=IIC_Read_Byte(0);
                //IIC_NACK();
                IIC_Stop();
        }
       
        tem = ((buff[0]<<8) | buff[1]);//温度拼接
        hum = ((buff[3]<<8) | buff[4]);//湿度拼接
       
        /*转换实际温度*/
        Temperature= (175.0*(float)tem/65535.0-45.0) ;// T = -45 + 175 * tem / (2^16-1)
        Humidity= (100.0*(float)hum/65535.0);// RH = hum*100 / (2^16-1)
       
        if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100))//过滤错误数据
        {
//                humiture[0]=Temperature;
//                humiture[2]=Humidity;
                sprintf(humiture_buff1,"%6.2f*C %6.2f%%",Temperature,Humidity);//111.01*C 100.01%(保留2位小数)
        }
        //printf("温湿度:%s\n",humiture_buff1);
        hum=0;
        tem=0;
}

//初始化IIC  板 PA11 PA12  修改位PA4 和PA5
void IIC_Init(void)
{                         
//    GPIO_InitTypeDef GPIO_InitStructure;
//    RCC_APB2PeriphClockCmd(    RCC_APB2Periph_GPIOA, ENABLE );    //使能GPIOA时钟
//       
////    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12;
//    GPIO_InitStructure.Pin = GPIO_Pin_4|GPIO_Pin_5;
//    GPIO_InitStructure.Mode = GPIO_Mode_Out_PP ;   //推挽输出
//    GPIO_InitStructure.Speed = GPIO_Speed_50MHz;
//    GPIO_Init(GPIOA, &GPIO_InitStructure);
//    GPIO_SetBits(GPIOA,GPIO_Pin_11|GPIO_Pin_12);     // 输出高
    
    GPIO_InitTypeDef GPIO_InitStruct = {0};
  __HAL_RCC_GPIOA_CLK_ENABLE (  );//启动外设工作的时钟
     
  GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull  = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

  GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);//初始化引脚设置
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4
|
GPIO_PIN_5,GPIO_PIN_SET);
//PAout(4)=1;PAout(5)=1;
}
//产生IIC起始信号 void IIC_Start(void) { SDA_OUT(); //sda线输出 IIC_SDA=1; IIC_SCL=1; delay_us(4); IIC_SDA=0;//START:when CLK is high,DATA change form high to low delay_us(4); IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 } //产生IIC停止信号 void IIC_Stop(void) { SDA_OUT();//sda线输出 IIC_SCL=0; IIC_SDA=0;//STOP:when CLK is high DATA change form low to high delay_us(4); IIC_SCL=1; IIC_SDA=1;//发送I2C总线结束信号 delay_us(4); } //等待应答信号到来 //返回值:1,接收应答失败 // 0,接收应答成功 u8 IIC_Wait_Ack(void) { u8 ucErrTime=0; SDA_IN(); //SDA设置为输入 IIC_SDA=1;delay_us(1); IIC_SCL=1;delay_us(1); while(READ_SDA) { ucErrTime++; if(ucErrTime>250) { IIC_Stop(); return 1; } } IIC_SCL=0;//时钟输出0 return 0; } //产生ACK应答 void IIC_Ack(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=0; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; } //不产生ACK应答 void IIC_NAck(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=1; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; } //IIC发送一个字节 //返回从机有无应答 //1,有应答 //0,无应答 void IIC_Send_Byte(u8 txd) { u8 t; SDA_OUT(); IIC_SCL=0;//拉低时钟开始数据传输 for(t=0;t<8;t++) { //IIC_SDA=(txd&0x80)>>7; if((txd&0x80)>>7) IIC_SDA=1; else IIC_SDA=0; txd<<=1; delay_us(2); //对TEA5767这三个延时都是必须的 IIC_SCL=1; delay_us(2); IIC_SCL=0; delay_us(2); } } //读1个字节,ack=1时,发送ACK,ack=0,发送nACK u8 IIC_Read_Byte(unsigned char ack) { unsigned char i,receive=0; SDA_IN();//SDA设置为输入 for(i=0;i<8;i++ ) { IIC_SCL=0; delay_us(2); IIC_SCL=1; receive<<=1; if(READ_SDA)receive++; delay_us(1); } if (!ack) IIC_NAck();//发送nACK else IIC_Ack(); //发送ACK return receive; }

补充 main.h

/**
  ******************************************************************************
  * @file    TIM/TIM_TimeBase/Inc/main.h
  * @author  MCD Application Team
  * @brief   Header for main.c module
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H

/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include "stm3210e_eval.h"

#define u16 uint16_t
#define u8 uint8_t
#define u32 uint32_t
#define vu16  volatile uint16_t
/* Exported types ------------------------------------------------------------*/

//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入


void delay_us(uint32_t nus);//for循环实现延时us

#endif /* __MAIN_H */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

其中 void delay_us(uint32_t nus);//for循环实现延时us的代码如下:

/*
for循环实现延时us,适合72MHz,STM32
*/
void delay_us(uint32_t nus)//for循环实现延时us
{
 uint32_t Delay = nus * 168/4;
 do
 {
     __NOP();
 }
 while (Delay --);
}

 

posted @ 2023-05-18 11:08  辛河  阅读(850)  评论(0编辑  收藏  举报