掌上实验室V8系列教程(七)I2C应用 HP203B

目录

1 项目功能

2 电路原理图

3 传感器HP203B

3.1 HP203B功能

3.2 HP203B技术指标

3.3 HP203B I2C总线接口命令

4 示例代码


1 项目功能

通过HB203B测量温度、大气压和海拔高度,并用数码管显示大气压。

2 电路原理图

3 传感器HP203B

3.1 HP203B功能

HP203B是一款超小型集高精度气压计、 高度计和温度计于一体的传感器。内部集成了24位ADC,硅传感芯片,以及存放内部参数的OTP。该传感器通过设计公司获得的专利补偿算法在传感器器件片内进行采样,信号处理以及运算,最终计算出实际的直接结果值,所以外部应用MCU只需发出信号采集命令,待完成温度压力采样后,HP203B自动计算海拔高度,单片机可以通过I²C接口直接读取压力,温度及绝对海拔高度三者的值。

每个设备都是由工厂单独校准温度和压力测量。修正的值存储在芯片上的 128 字节的非易失性内存(NVM)。在正常情况下, 用户完成没有必要做进一步校准。

3.2 HP203B技术指标

3.3 HP203B I2C总线接口命令

I2C地址

掌上实验室V8把HP203B的CSB连接了高电平。所以读写地址分别为0xED和0xEC。

  

 HP203B上电后先自校准,然后进入休眠模式等待指令,收到指令后执行指令,执行完毕则再次进进入休眠模式等待下一条指令。

 ADC_CVT转换指令

设置转换分辨率、转换通道(温度、压力或者温度+压力)并开始转换。

bit7bit6bit5bit4bit3bit2bit1bit0
010分辨率OSR通道

 例如采用最高分辨率4096,选择压力+温度,则二进制为 010 000 00,此时 ADC_CVT=0x40。

下表是分辨率对应的转换时间,可以看到分辨率越高所需的时间越长。

 I2C主机发送指令如下,

设备地址WACK指令ACK
S11101100A01000000AP

其中S-起始信号,P-终止信号,A-应答信号。深色表示从机发送。

READ_P读气压值

需要分两帧发送,先发送读气压值命令0x30,然后再读3个字节气压值(高字节MSB在前)。

 其中S-起始信号,P-终止信号,A-应答信号,N-非应答信号。深色表示从机发送。

气压值是由24位补码表示,最高 4 位的数据是无用,而最低有效 20 位代表气压的值。用户应当把这 20 位以 2 的补码的二进制值转换成一个整数,然后整数除以 100 获得最终结果。

 READ_A读高度值

需要分两帧发送,先发送读高度值命令0x31,然后再读3个字节高度值(高字节MSB在前)。

 其中S-起始信号,P-终止信号,A-应答信号,N-非应答信号。深色表示从机发送。

高度值是由24位补码表示,最高 4 位的数据是无用,而最低有效 20 位代表高度的值。用户应当把这 20 位以 2 的补码的二进制值转换成一个整数,然后整数除以 100 获得最终结果。

  READ_T读温度值

需要分两帧发送,先发送读压力值命令0x32,然后再读3个字节温度值(高字节MSB在前)。

 其中S-起始信号,P-终止信号,A-应答信号,N-非应答信号。深色表示从机发送。

温度值是由24位补码表示,最高 4 位的数据是无用,而最低有效 20 位代表温度的值。用户应当把这 20 位以 2 的补码的二进制值转换成一个整数,然后整数除以 100 获得最终结果。

//20位补码处理

int data;

data &= 0xfffff;         //保留20位
if(data & 0x80000)
    data |= 0xfff00000;  //扩展符号位

READ_REG读寄存器值

寄存器INT_SRC的bit5(DEV_RDY)表示处于Sleep状态(可以作为转换完成标志)。比如读取寄存器INT_SRC,命令为0x80+6位寄存器地址,即0x8D。

其中S-起始信号,P-终止信号,A-应答信号,N-非应答信号。深色表示从机发送。

4 示例代码

本例用到的驱动包有crm、gpio、misc和tmr。采用GPIO模拟I2C操作,项目包含以下几个文件

main.c

#include "at32f403a_407_conf.h"

#include "util.h"
#include "display.h"
#include "hp203b.h"

/**
  * @brief  config sclk 64 mhz with hick clock source.
  * @note   the system clock is configured as follow:
  *         - system clock        = hick / 2 * pll_mult
  *         - system clock source = pll (hick)
  *         - hick                = 8000000
  *         - sclk                = 64000000
  *         - ahbdiv              = 1
  *         - ahbclk              = 64000000
  *         - apb2div             = 2
  *         - apb2clk             = 32000000
  *         - apb1div             = 2
  *         - apb1clk             = 32000000
  *         - pll_mult            = 16
  *         - pll_range           = LE72MHZ (less equal 72 mhz)
  * @param  none
  * @retval none
  */
static void sclk_64m_hick_config(void)
{
  /* reset crm */
  crm_reset();

  crm_clock_source_enable(CRM_CLOCK_SOURCE_HICK, TRUE);

   /* wait till hick is ready */
  while(crm_flag_get(CRM_HICK_STABLE_FLAG) != SET)
  {
  }

  /* config pll clock resource */
  crm_pll_config(CRM_PLL_SOURCE_HICK, CRM_PLL_MULT_16, CRM_PLL_OUTPUT_RANGE_LE72MHZ);

  /* enable pll */
  crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE);

  /* wait till pll is ready */
  while(crm_flag_get(CRM_PLL_STABLE_FLAG) != SET)
  {
  }

  /* config ahbclk */
  crm_ahb_div_set(CRM_AHB_DIV_1);

  /* config apb2clk */
  crm_apb2_div_set(CRM_APB2_DIV_2);

  /* config apb1clk */
  crm_apb1_div_set(CRM_APB1_DIV_2);

  /* enable auto step mode */
  crm_auto_step_mode_enable(TRUE);

  /* select pll as system clock source */
  crm_sysclk_switch(CRM_SCLK_PLL);

  /* wait till pll is used as system clock source */
  while(crm_sysclk_switch_status_get() != CRM_SCLK_PLL)
  {
  }

  /* disable auto step mode */
  crm_auto_step_mode_enable(FALSE);

  /* update system_core_clock global variable */
  system_core_clock_update();
}

int main(void)
{
	static int count = 0;
	sclk_64m_hick_config();
	
	HP203B_gpio_pins_init();
	DISP_gpio_pins_init();
	
	HP203B_Reset();
	delay_ms(100);


	HP203B_StartConv();
	for(;;){
		dispaly_scan();
		if(HP203B_ReadReg(0x0d) & 0x40)
		{
			float pressure, temperature, altitude;
			HP203B_ReadData(&temperature, &pressure, &altitude);
			display_dec_int(pressure+0.5); //四舍五入显示
			HP203B_StartConv();
		}
	}
}

util.h

#ifndef __UTIL_H
#define __UTIL_H

void delay_us(int us);
void delay_ms(int ms);

#endif

util.c

#include "at32f403a_407_conf.h"
 
 
void delay_us(int us)
{
	SysTick->LOAD = system_core_clock/1000000 * us; 
	SysTick->VAL = 0;
	SysTick->CTRL = 0x5; //Systick采用系统时钟为时钟源,并启动
	while((SysTick->CTRL & (1<<16))==0);
	SysTick->CTRL = 0;	 //停止Systick
}
 
void delay_ms(int ms)
{
	for(;ms>0;ms--)
		delay_us(1000);
}

display.h

#ifndef __DISPLAY_H
#define __DISPLAY_H

void DISP_gpio_pins_init(void);

void display_scan();

void display_dec_int(int num);

#endif

display.c

#include "at32f403a_407_conf.h"
 
void DISP_gpio_pins_init(void)
{
	//打开GPIO时钟
	crm_periph_clock_enable(CRM_GPIOE_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);
	
	//配置PD2~PD5, PE0~PE7为输出
	gpio_init_type gpio_init_struct;
	
	gpio_init_struct.gpio_pins  = GPIO_PINS_0 | GPIO_PINS_1 | GPIO_PINS_2 | GPIO_PINS_3 | GPIO_PINS_4 | GPIO_PINS_5 | GPIO_PINS_6 | GPIO_PINS_7;
	gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
	gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
	gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
 
	gpio_init(GPIOE, &gpio_init_struct);
 
	gpio_init_struct.gpio_pins  = GPIO_PINS_2 | GPIO_PINS_3 | GPIO_PINS_4 | GPIO_PINS_5;
	gpio_init(GPIOD, &gpio_init_struct);
}
 
uint8_t disp_buf[4];
void display_dec_int(int num)
{
	static uint8_t tab[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
	disp_buf[0] = tab[num/1000%10];
	disp_buf[1] = tab[num/100%10];
	disp_buf[2] = tab[num/10%10];
	disp_buf[3] = tab[num%10];
}
 
void display_scan()
{
	static int cur_digit = 0;
	
	//全关
	gpio_bits_set(GPIOD, GPIO_PINS_2 | GPIO_PINS_3 | GPIO_PINS_4 | GPIO_PINS_5); 
	
	//输出字形码
	gpio_bits_reset(GPIOE, 0xff); //PE0~PE7 = 0
	gpio_bits_set(GPIOE, disp_buf[cur_digit]); 
	
	//打开对应位开关
	gpio_bits_reset(GPIOD, GPIO_PINS_2 << cur_digit);
	
	//更新cur_digit, 准备下一次扫描
	cur_digit = (cur_digit + 1) % 4;
}

hp203b.h

#ifndef __HP203B_H
#define __HP203B_H

void HP203B_gpio_pins_init(void);

void HP203B_Reset(void);
void HP203B_StartConv(void);
unsigned char HP203B_ReadReg(unsigned char reg_addr);
void HP203B_WriteReg(unsigned char reg_addr, unsigned char reg_val);

void HP203B_ReadData(float *T, float *P, float *A);

#endif

hp203b.c

#include "at32f403a_407_conf.h"

#include "util.h"


/******************************************************************************
I2C 基本操作
*/
void HP203B_gpio_pins_init(void)
{
	crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);

	gpio_init_type gpio_init_struct;
	gpio_default_para_init(&gpio_init_struct);

	gpio_init_struct.gpio_pins  = GPIO_PINS_8;
	gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
	gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
	gpio_init(GPIOA, &gpio_init_struct);
	
	gpio_init_struct.gpio_pins  = GPIO_PINS_9;
	gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
	gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
	gpio_init(GPIOC, &gpio_init_struct);

}


static void SCL_OPEN(void)
{
	gpio_bits_set(GPIOA, GPIO_PINS_8);
}
static void SCL_LOW(void)
{
	gpio_bits_reset(GPIOA, GPIO_PINS_8);
}
static void SDA_OPEN(void)
{
	gpio_bits_set(GPIOC, GPIO_PINS_9);
}
static void SDA_LOW(void)
{
	gpio_bits_reset(GPIOC, GPIO_PINS_9);
}
static uint8_t SCL_READ()
{
	return gpio_input_data_bit_read(GPIOA, GPIO_PINS_8);
}
static uint8_t SDA_READ()
{
	return gpio_input_data_bit_read(GPIOC, GPIO_PINS_9);
}
 
static void I2c_GenStart()
{
	SDA_OPEN();
	delay_us(1);
	SCL_OPEN();
	delay_us(1);
	SDA_LOW();
	delay_us(4);  // hold time start condition (t_HD;STA)
	SCL_LOW();
	delay_us(4);
}
static void I2c_GenStop()
{
	SCL_LOW();
	delay_us(1);
	SDA_LOW();
	delay_us(1);
	SCL_OPEN();
	delay_us(4); // set-up time stop condition (t_SU;STO)
	SDA_OPEN();
	delay_us(4);
}
 
static int I2c_WriteByte(uint8_t txByte)
{
	uint8_t mask;
	int Acked = 1;
	for(mask = 0x80; mask > 0; mask >>= 1) { // shift bit for masking (8 times)
		if((mask & txByte) == 0) 
			SDA_LOW();				// masking txByte & write to SDA-Line
		else                     
			SDA_OPEN();   
		delay_us(1);				// data set-up time (t_SU;DAT)
		SCL_OPEN();         // generate clock pulse on SCL
		delay_us(5);        // SCL high time (t_HIGH)
		SCL_LOW();                             
		delay_us(1);        // data hold time(t_HD;DAT)
	}                       

	SDA_OPEN();           // release SDA-line
	SCL_OPEN();           // clk #9 for ack

	delay_us(5);          // data set-up time (t_SU;DAT)
	if(SDA_READ()) 
		Acked = 0;          // check ack from i2c slave
	SCL_LOW();                               
	delay_us(20);         // wait to see byte package on scope
	return Acked;         // return error code
}
 
static uint8_t I2c_ReadByte(int GenAck)
{
	uint8_t mask;
	uint8_t rxByte = 0;
	SDA_OPEN();                              	// release SDA-line
	for(mask = 0x80; mask > 0; mask >>= 1) { 	// shift bit for masking (8 times)
		SCL_OPEN();                            	// generate clock pulse on SCL
		delay_us(1);                  					// data set-up time (t_SU;DAT)
		while(SCL_READ() == 0){}                // wait while hold master
		delay_us(5);                  					// SCL high time (t_HIGH)
		if(SDA_READ()) rxByte = rxByte | mask;  // read bit
		SCL_LOW();                             
		delay_us(1);                  					// data hold time(t_HD;DAT)
	}                                        
	if(GenAck) 
	  SDA_LOW();                							// send acknowledge if necessary
	else           
	  SDA_OPEN();
	
	delay_us(1);                    					// data set-up time (t_SU;DAT)
	SCL_OPEN();                              	// clk #9 for ack
	delay_us(5);                    					// SCL high time (t_HIGH)
	SCL_LOW();                               
	SDA_OPEN();                              	// release SDA-line
	delay_us(20);                   					// wait to see byte package on scope
	return rxByte;                           	// return error code
}

/******************************************************************************
HP203B 基本操作
*/

void HP203B_Reset(void)
{
	I2c_GenStart();
	I2c_WriteByte(0xEC); //addr+w
	I2c_WriteByte(0x06); //cmd reset
	I2c_GenStop();
}
void HP203B_StartConv(void)
{
	I2c_GenStart();
	I2c_WriteByte(0xEC); //addr+w
	I2c_WriteByte(0x40); //cmd conv+osr(4096)+ch(pt)
	I2c_GenStop();
}

unsigned char HP203B_ReadReg(unsigned char reg_addr)
{
	I2c_GenStart();
	I2c_WriteByte(0xEC); //devaddr+w
	I2c_WriteByte(0x80|reg_addr); //reg addr
	I2c_GenStop();

	I2c_GenStart();
	I2c_WriteByte(0xED); //addr+r
	char val = I2c_ReadByte(0); //read + nack
	I2c_GenStop();
	
	return val;
}
void HP203B_WriteReg(unsigned char reg_addr, unsigned char reg_val)
{
	I2c_GenStart();
	I2c_WriteByte(0xEC); //devaddr+w
	I2c_WriteByte(0x80|reg_addr); //reg addr
	I2c_WriteByte(reg_val);
	I2c_GenStop();
}

void HP203B_ReadData(float *T, float *P, float *A)
{
	uint8_t buf[6],status;
	int data;
	
	//read Pressure
	I2c_GenStart();
	I2c_WriteByte(0xEC); //addr+w
	I2c_WriteByte(0x30); //cmd read p
	I2c_GenStop();
	
	I2c_GenStart();
	I2c_WriteByte(0xED); //addr+r
	buf[0] = I2c_ReadByte(1); //read + ack
	buf[1] = I2c_ReadByte(1); //read + ack
	buf[2] = I2c_ReadByte(0); //read + nack
	I2c_GenStop();
	
	data = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) & 0xfffff;
	if(data & 0x80000)
		data |= 0xfff00000;			//补码处理
	*P = data/100.0;					//单位 mbar
	
	//read Temperature
	I2c_GenStart();
	I2c_WriteByte(0xEC); //addr+w
	I2c_WriteByte(0x32); //cmd read t
	I2c_GenStop();
	
	I2c_GenStart();
	I2c_WriteByte(0xED); //addr+r
	buf[0] = I2c_ReadByte(1); //read + ack
	buf[1] = I2c_ReadByte(1); //read + ack
	buf[2] = I2c_ReadByte(0); //read + nack
	I2c_GenStop();
	
	data = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) & 0xfffff;
	if(data & 0x80000)
		data |= 0xfff00000;			//补码处理
	
	*T = data/100.0;					//单位 摄氏度
	//read Altitude
	I2c_GenStart();
	I2c_WriteByte(0xEC); //addr+w
	I2c_WriteByte(0x31); //cmd read a
	I2c_GenStop();
	
	I2c_GenStart();
	I2c_WriteByte(0xED); //addr+r
	buf[0] = I2c_ReadByte(1); //read + ack
	buf[1] = I2c_ReadByte(1); //read + ack
	buf[2] = I2c_ReadByte(0); //read + nack
	I2c_GenStop();
	
	data = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) & 0xfffff;
	if(data & 0x80000)
		data |= 0xfff00000;			//补码处理
	*A = data/100.0;					//单位 0.01m
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值