【专题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>© 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 --); }