掌上实验室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转换指令
设置转换分辨率、转换通道(温度、压力或者温度+压力)并开始转换。
bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
0 | 1 | 0 | 分辨率OSR | 通道 |
例如采用最高分辨率4096,选择压力+温度,则二进制为 010 000 00,此时 ADC_CVT=0x40。
下表是分辨率对应的转换时间,可以看到分辨率越高所需的时间越长。
I2C主机发送指令如下,
设备地址 | W | ACK | 指令 | ACK | |||||||||||||||
S | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | A | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | A | P |
其中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_Hvoid 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_Hvoid 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 = 0gpio_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_Hvoid 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-Lineelse SDA_OPEN(); delay_us(1); // data set-up time (t_SU;DAT)SCL_OPEN(); // generate clock pulse on SCLdelay_us(5); // SCL high time (t_HIGH)SCL_LOW(); delay_us(1); // data hold time(t_HD;DAT)} SDA_OPEN(); // release SDA-lineSCL_OPEN(); // clk #9 for ackdelay_us(5); // data set-up time (t_SU;DAT)if(SDA_READ()) Acked = 0; // check ack from i2c slaveSCL_LOW(); delay_us(20); // wait to see byte package on scopereturn Acked; // return error code
}static uint8_t I2c_ReadByte(int GenAck)
{uint8_t mask;uint8_t rxByte = 0;SDA_OPEN(); // release SDA-linefor(mask = 0x80; mask > 0; mask >>= 1) { // shift bit for masking (8 times)SCL_OPEN(); // generate clock pulse on SCLdelay_us(1); // data set-up time (t_SU;DAT)while(SCL_READ() == 0){} // wait while hold masterdelay_us(5); // SCL high time (t_HIGH)if(SDA_READ()) rxByte = rxByte | mask; // read bitSCL_LOW(); delay_us(1); // data hold time(t_HD;DAT)} if(GenAck) SDA_LOW(); // send acknowledge if necessaryelse SDA_OPEN();delay_us(1); // data set-up time (t_SU;DAT)SCL_OPEN(); // clk #9 for ackdelay_us(5); // SCL high time (t_HIGH)SCL_LOW(); SDA_OPEN(); // release SDA-linedelay_us(20); // wait to see byte package on scopereturn rxByte; // return error code
}/******************************************************************************
HP203B 基本操作
*/void HP203B_Reset(void)
{I2c_GenStart();I2c_WriteByte(0xEC); //addr+wI2c_WriteByte(0x06); //cmd resetI2c_GenStop();
}
void HP203B_StartConv(void)
{I2c_GenStart();I2c_WriteByte(0xEC); //addr+wI2c_WriteByte(0x40); //cmd conv+osr(4096)+ch(pt)I2c_GenStop();
}unsigned char HP203B_ReadReg(unsigned char reg_addr)
{I2c_GenStart();I2c_WriteByte(0xEC); //devaddr+wI2c_WriteByte(0x80|reg_addr); //reg addrI2c_GenStop();I2c_GenStart();I2c_WriteByte(0xED); //addr+rchar val = I2c_ReadByte(0); //read + nackI2c_GenStop();return val;
}
void HP203B_WriteReg(unsigned char reg_addr, unsigned char reg_val)
{I2c_GenStart();I2c_WriteByte(0xEC); //devaddr+wI2c_WriteByte(0x80|reg_addr); //reg addrI2c_WriteByte(reg_val);I2c_GenStop();
}void HP203B_ReadData(float *T, float *P, float *A)
{uint8_t buf[6],status;int data;//read PressureI2c_GenStart();I2c_WriteByte(0xEC); //addr+wI2c_WriteByte(0x30); //cmd read pI2c_GenStop();I2c_GenStart();I2c_WriteByte(0xED); //addr+rbuf[0] = I2c_ReadByte(1); //read + ackbuf[1] = I2c_ReadByte(1); //read + ackbuf[2] = I2c_ReadByte(0); //read + nackI2c_GenStop();data = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) & 0xfffff;if(data & 0x80000)data |= 0xfff00000; //补码处理*P = data/100.0; //单位 mbar//read TemperatureI2c_GenStart();I2c_WriteByte(0xEC); //addr+wI2c_WriteByte(0x32); //cmd read tI2c_GenStop();I2c_GenStart();I2c_WriteByte(0xED); //addr+rbuf[0] = I2c_ReadByte(1); //read + ackbuf[1] = I2c_ReadByte(1); //read + ackbuf[2] = I2c_ReadByte(0); //read + nackI2c_GenStop();data = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) & 0xfffff;if(data & 0x80000)data |= 0xfff00000; //补码处理*T = data/100.0; //单位 摄氏度//read AltitudeI2c_GenStart();I2c_WriteByte(0xEC); //addr+wI2c_WriteByte(0x31); //cmd read aI2c_GenStop();I2c_GenStart();I2c_WriteByte(0xED); //addr+rbuf[0] = I2c_ReadByte(1); //read + ackbuf[1] = I2c_ReadByte(1); //read + ackbuf[2] = I2c_ReadByte(0); //read + nackI2c_GenStop();data = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) & 0xfffff;if(data & 0x80000)data |= 0xfff00000; //补码处理*A = data/100.0; //单位 0.01m
}
掌上实验室V8系列教程(七)I2C应用 HP203B相关推荐
- 掌上实验室V8系列教程(八)ADC模数转换
目录 1 项目功能 2 ADC工作原理 3 电路原理图 4 AT32 ADC应用 4.1 ADC基础操作流程 4.2 ADC触发 4.3 ADC采样和转换时间 4.4 读取ADC转换结果 5 示例程序 ...
- 掌上实验室V8系列教程(四)定时器PWM输出
1 项目功能 三色RGB LED 通过PWM 调色 2 电路原理 我们可以通过3路PWM波分别调整RGB三个二极管的亮度,即调整RGB的比例,合成不同的颜色. PWM,英文名Pulse Width M ...
- 掌上实验室V8系列教程(二)跑马灯
目录 1 项目功能 2 电路原理 3 软件流程 4 程序设计 5.参考资源 1 项目功能 循环点亮LED4, LED5, LED6, LED7 2 电路原理 根据硬件电路图,PC0输出"0& ...
- 掌上实验室V8系列教程(九)光电编码器转速测量
1 项目功能 通过光电编码器进行转速测量 2 光电编码器工作原理 光电编码器,是一种通过光电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器.这是应用最多的传感器,光电编码器是由光源.光码盘和 ...
- 掌上实验室V8系列教程(三)数码管动态显示
目录 1 项目功能 2 电路原理 3 动态显示原理 4 示例代码 6 扩展功能 7 参考资源 1 项目功能 4位数码管动态显示 2 电路原理 3 动态显示原理 一位八段式数码管内部有8个LED,习惯上 ...
- 掌上实验室V8系列教程(五)定时器中断及应用
1 项目目标 利用定时器产生周期为1ms的中断,作为系统时基.并在数码管上显示开机时间(分辨率为0.1秒):同时实现LED4.LED5.LED6和LED7分别以300ms.220ms.450ms和70 ...
- 基于雅特力AT32的 《掌上实验室》V8
1 项目介绍 掌上实验室V8是由中国计量大学现代科技学院和雅特力共同研发的一款ARM学习板,内置AT-Link-Ez仿真器. 主MCU采用雅特力AT32F407VGT7. 板上资源: 1.通信接口 1 ...
- 汇川小型PLC梯形图编程系列教程(七):数值存储与二进制数据知识详解
原文链接:汇川小型PLC梯形图编程系列教程(七):数值存储与二进制数据知识详解 PLC数据存储原理简介 H123U小型PLC内部采用的是32位的处理器,PLC中的数据处理和电脑中的数据处理基本是一致的 ...
- ASP.NET 5系列教程(七)完结篇-解读代码
在本文中,我们将一起查看TodoController 类代码. [Route] 属性定义了Controller的URL 模板: [Route("api/[controller]&quo ...
最新文章
- java 数组的基本操作
- 刚刚,Python 3.10 正式发布了,我发现了一个可怕的功能..
- 关于域帐户将计算机加入域登陆上限问题
- ZYNQ中断示例修改
- Python模块之XlsxWriter
- 简单struts,spring,mybatis组合使用
- Kevin专栏---如何制作试用版安装包
- Ubuntu16.04下制作deb包的方法详解
- php 安装zip,php zip拓展安装
- php nginx错误,PHP/Nginx错误(Win)
- 如果使用Node.js不存在该如何创建目录?
- vscode配置及快捷键(未完成待续)
- linux新建mysql用户命令_使用MySQL命令行新建用户并授予权限
- 斐讯盒子T1_【YYF固件】夏杰语音实用版刷机固件及教程分享
- gateway权限统一认证
- 地球人来源2【地底爬虫人访谈】
- java代码实现端口是否ping通
- 信息学奥赛一本通【21CSPS提高组】和【21NOIP提高组】题解
- 互联网-3互联网思维的应用
- JavaScript中的柯里化(currying)
热门文章
- 按照100分制,90分以上成绩为A,80到90为B, 60到80为C,60一下为D,写一个程序, 当用户输入分数,自动转换为ABCD的形式打印,Python三种解决方法
- QQ音乐推荐召回算法的探索与实践
- 反arp攻击软件_技术干货透析中间人攻击
- 工作的意义,人生的意义,自由、快乐与幻觉
- 课程向:深度学习与人类语言处理 ——李宏毅,2020 (P12)
- 量化风控从入门到放弃
- Python批量处理大量excel数据(含完整代码)
- JVM出现OOM的八种原因及解决办法
- 极光IM + 极光推送,集成中遇到的问题
- 〖Python自动化办公篇⑪〗- word文件自动化 - word 转 PDF(pdfkit与pydocx相结合)