[硬件设计] 想知道室内气压是多少吗?想知道此地的海拔是多少吗?看我如何从零手搓室内气压计

[复制链接]
swtman 发表于 2025-8-17 08:31 | 显示全部楼层 |阅读模式
本帖最后由 swtman 于 2025-8-17 08:31 编辑

#申请原创#
@21小跑堂

室内气压计
1. 前言
1-拿到一款瑞萨的开发板:RA6E2,已经有一段时间了。一直没想好做点啥,整理物品的时候,发现一个闲置的BMP 180气压温度模块。刚好家里也有没有气压计,那就做一个室内气压计吧。顺便把日历时钟也做上了。
2. 实际效果图
本来以为会很简单呢,断断续续的弄了好一阵子才完成啊。果然打工人有点爱好不容易啊,卡克了都没有一起讨论,只能自己为爱发热啊。不过自己还挺满意的,实现最终效果如下:


1 项目验证实物图-气压温度海拔功能


2 项目验证实物图-日历时钟功能

后续若做成无线模式的,就可以连接手机和电脑,效果会更好。硬件方面可以做一个桌面小盒子,会更方便摆放哦。
3. 系统硬件设计

本项目需要使用一些外设和模块,因此需要进行硬件设计。

3.1. 系统整体设计

主控采用RA-Eco-RA6E2-64PIN-V1.0开发板,通过模拟IIC采集BMP180传感器数据,然后通过OLED显示屏显示计算的气压和温度,并通过串口将数据发送给电脑或者手机等终端。通过按键可以更改显示模式。开发板通过LED闪烁提示系统正常运行。

3 整体硬件架构图

3.2. RA6E2开发板

RA-Eco-RA6E2-64PIN-V1.0是一款基于100MHz Arm® Cortex®-M33内核架构的核心板,主控芯片为R7FA6E2BB3CFMRA6E2组是RA6系列中最新的入门级微控制器,基于带有TrustZone®200MHz Arm® Cortex®-M33内核。RA6E2 MCU作为入门级微控制器,在追求成本优化的同时提供了最佳的性能。与RA4E2组的引脚和外设兼容,使其成为要求更高性能、小尺寸和低引脚数的应用的理想选择。

以上是官方的介绍,这个开发板的相关接口和资源介绍如下:

·1个复位按键,1个用户按键,2LED2PMOD接口,板载USBTTL模块,可用于串口通信和烧录,板载SWD接口,方便用户调试与下载,200MHzArm Cortex-M33,具有TrustZone功能,256KB的闪存和40KBSRAM4KB数据闪存,类似EEPROM数据存储功能,1KB待机SRAM64引脚封装,USB 2.0全速,CAN FDI3CHDMI CECSSIQuad SPI12A/D转换器,12D/A转换器,通用PWM定时器。

本项目只是使用部分接口和资源。

3.3. OLED显示屏

0.96OLED显示屏窄白光IIC接口,屏幕分辨率为128X64。这个屏幕从立创商城购买来。链接如下:

https://item.szlcsc.com/5960631.html?spm=sc.ols.it2-1___sc.hm.hd.dd&lcsc_vid=TgJXAgVTFgdaUVFeQVZaBAFfFAJbU11e**MUV0FRlQxVlNTQlBdX1xQQFRaUDtW

相关参数如下:

4 OLED显示屏采购


3.4. 气压传感器

本项目采用BMP180传感器,这是是一款高精度、小体积、低能耗的压力传感器可以应用在移动设备中。它的性能卓越,精度可以达到0.03hPa,并且耗电低,只有3uA。建议在淘宝上购买,链接如下:

BMP180 BME280 高精度大气压强传感器模块 气压传感器模块 高度计-淘宝网

规格参数如下:

工作电压:1.8~3.6V

工作电流:0.1~1000uA

温度精度:±1

温度范围:0~65

气压范围:300~1100 hPa

气压精度:1 hPa

输出方式: IIC


5 BMP180传感器模块

3.5. LED

这里直接使用开发板上的2LED灯,不再详述,相关原理图如下图所示:

6 LED控制IO

需要对相关GPIO进行配置。

3.6. 按键

这里直接使用开发板上的1key,不再详述,相关原理图如下图所示:

7 KEY控制IO

需要对相关GPIO进行配置,后续软件使用中断模式。

3.7. 调试下载接口

这里直接使用开发板上的SWD接口,不再详述,相关原理图如下图所示:

8 SWD接口

需要对相关GPIO进行配置,本项目采用JLINK下载和调试。

4. 系统软件设计

通过RASC进行初始参数配置,基于keil MDK平台使用C语言进行编码。

4.1. OLEDIIC配置与关键代码实现

OLED使用的IICIO分别是SDAP408SCLP409。为了屏幕刷新的更快,这里配置速度为FAST-MODE。大约400KBPS。需要注意选择IIC的通道,SLAVE的地址:0x3c,并命名好回调函数。具体配置如下图所示:

9 OLEDIIC配置

回调函数实现如下:

i2c_master_event_t i2c_event = I2C_MASTER_EVENT_ABORTED;

void sci_i2c_master_callback(i2c_master_callback_args_t *p_args)

{

    i2c_event = I2C_MASTER_EVENT_ABORTED;

    if (NULL != p_args)

    {

        /* capture callback event for validating the i2c transfer event*/

        i2c_event = p_args->event;

    }

}

int  timeout_ms = 100;

当然这里还有屏幕的驱动代码等,由于篇幅所限,不再详述。该屏幕的使用属于常规操作。具体可以查看工程源码。

在这里需要注意一下汉字取模,我采用的是在线进行汉字取模。网站链接如下:

https://www.23bei.com/tool/216.html

我需要使用的汉字是:年月日温度气压海拔桌面电子时钟室内计。通过在线取模,参数配置如下图所示:
10汉字在线取模配置与生成
4.2. BMP180传感器的IO配置与关键代码实现

该传感器需要2IO,为了和屏幕区分开来。这里使用了模拟IIC。即SCLP303SDAP304,否则通信会有问题。管脚的软件配件如下图所示:


11 BMP180传感器通信IO-SCL
12 BMP180传感器通信IO-SDA

该传感器的驱动代码官方已经写好,只需要对IO和延时程序重新移植即可。

相关需要自行配置和修改的函数如下:

#define I2C_SDA_PORT    BSP_IO_PORT_03 // SDA引脚

#define I2C_SCL_PORT    BSP_IO_PORT_03  // SCL引脚

// 定义I2C引脚 - 根据实际硬件连接修改

#define I2C_SDA_PIN    BSP_IO_PORT_03_PIN_04  // SDA引脚

#define I2C_SCL_PIN    BSP_IO_PORT_03_PIN_03  // SCL引脚

#define delay_us(N) R_BSP_SoftwareDelay(N, BSP_DELAY_UNITS_MICROSECONDS)

#define delay_1ms(N) R_BSP_SoftwareDelay(N, BSP_DELAY_UNITS_MILLISECONDS)

//设置SDA输出模式

#define SDA_OUT() R_IOPORT_PortDirectionSet(&g_ioport_ctrl, I2C_SDA_PORT,0x0010,0x0010)

//设置SDA输入模式

#define SDA_IN() R_IOPORT_PortDirectionSet(&g_ioport_ctrl, I2C_SDA_PORT,0,0x0010)

//SDASCL输出

#define SDA(x)          R_IOPORT_PinWrite(&g_ioport_ctrl, I2C_SDA_PIN, (x?BSP_IO_LEVEL_HIGH:BSP_IO_LEVEL_LOW))

#define SCL(x)          R_IOPORT_PinWrite(&g_ioport_ctrl, I2C_SCL_PIN, (x?BSP_IO_LEVEL_HIGH:BSP_IO_LEVEL_LOW))

bsp_io_level_t SDA_GET(void)

{

bsp_io_level_t x=0;

if(R_IOPORT_PinRead(&g_ioport_ctrl,I2C_SDA_PIN,&x)==FSP_SUCCESS){

return x;

}

return 1;

}

4.3. LEDGPIO配置与关键代码实现

这里需要配置2IO分别是P207P113分别对应LED1LED2。配置起来非常简单,将设置为输出即可,配置分别如下图所示:


13 LED1控制IO配置
14 LED2控制IO配置

具体代码实现控制LED亮灭非常简单,如下所示:

#define LED1_TOGGLE R_PORT2->PODR ^= 1<<(BSP_IO_PORT_02_PIN_07 & 0xFF)

#define LED2_TOGGLE R_PORT1->PODR ^= 1<<(BSP_IO_PORT_01_PIN_13 & 0xFF)

4.4. KEYGPIO配置与关键代码实现

这里需要配置1IOP0055。配置起来非常简单,将设置为输入,类型位中断即可,配置分别如下图所示:


15 KEY控制IO配置
16 KEY中断配置


需要自己编写中断初始化和回调函数,如下所示:

/* KEY 外部中断初始化函数 */

void Key_IRQ_Init(void)

{

   /* Open ICU module */

   err = R_ICU_ExternalIrqOpen(&g_external_irq10_ctrl, &g_external_irq10_cfg);

   /* 允许中断 */

   err = R_ICU_ExternalIrqEnable(&g_external_irq10_ctrl);

}

uint8_t key_cnt=0;

uint8_t key_clr=0;

/* 按键中断回调函数 */

void key_external_irq_callback(external_irq_callback_args_t *p_args)

{

   /* 判断中断通道 */

if (10 == p_args->channel)

   {

key_cnt++;

key_cnt %=2;

key_clr=1;

   }

}

4.5. UART接口配置与关键代码实现

UART的相关配置如下:

17 UART通信接口配置



相关的回调函数需要自己进行实现,相关代码如下:

fsp_err_t err = FSP_SUCCESS;

unsigned char send_buff[100];

volatile bool uart_send_complete_flag = false;

void g_uart9_callback (uart_callback_args_t * p_args)

{

    if(p_args->event == UART_EVENT_TX_COMPLETE)

    {

        uart_send_complete_flag = true;

    }

}

为了方便调试,和打印相关信息。这里对printf函数进行了重定向,相关代码如下所示:

/* 重定向 printf 输出 */

#if defined __GNUC__ && !defined __clang__

int _write(int fd, char *pBuffer, int size); //防止编译警告

int _write(int fd, char *pBuffer, int size)

{

   (void)fd;

   R_SCI_UART_Write(&g_uart4_ctrl, (uint8_t *)pBuffer, (uint32_t)size);

   while(uart_send_complete_flag == false);

   uart_send_complete_flag = false;

   return size;

}

#else

int fputc(int ch, FILE *f)

{

   (void)f;

   R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&ch, 1);

   while(uart_send_complete_flag == false);

   uart_send_complete_flag = false;

   return ch;

}

#endif


4.6. SWD调试与下载接口配置
由于我手头上有j-link调试器,所以配置SWD接口,不仅能适配我的调试器,还可以节省IO。具体配置如下图所示:

18 SWD调试下载接口配置


4.7. RTC配置
为了实现日历和时钟功能,需要进行如下配置:
19 RTC配置

RTC还需要进行初始化和各种配置函数,如下所示:

/* rtc_time_t is an alias for the C Standard time.h struct 'tm' */

rtc_time_t set_time =

{

    .tm_sec  = 50,      /* 秒,范围从 0 59 */

    .tm_min  = 58,      /* 分,范围从 0 59 */

    .tm_hour = 10,      /* 小时,范围从 0 23*/

    .tm_mday = 9,       /* 一月中的第几天,范围从 1 31*/

    .tm_mon  = 7,      /* 月份,范围从 0 11*/

    .tm_year = 125,     /* 1900 起的年数,2021121*/

//    .tm_wday = 5,       /* 一周中的第几天,范围从 0 6*/

//    .tm_yday=0,         /* 一年中的第几天,范围从 0 365*/

//    .tm_isdst=0;        /* 夏令时*/

};

    /* Initialize the RTC module*/

       err = R_RTC_Open(&g_rtc0_ctrl, &g_rtc0_cfg);

       /* Handle any errors. This function should be defined by the user. */

       assert(FSP_SUCCESS == err);

       /* R_RTC_CalendarTimeSet must be called at least once to start the RTC */

       R_RTC_CalendarTimeSet(&g_rtc0_ctrl, &set_time);

       /* Set the periodic interrupt rate to 1 second */

       R_RTC_PeriodicIrqRateSet(&g_rtc0_ctrl, RTC_PERIODIC_IRQ_SELECT_1_SECOND);

4.8. 低功耗模式配置
为了板子的功耗更低,这里采用了空闲时候让系统进入休眠模式,通过RTC中断可以唤醒。
20 低功耗模式配置

4.9. 主程序设计
由于在RASC中已经配置了相关的外设,这里只需要调用即可。因此主程序实现如下:
/*******************************************************************************************************************//**
* main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function
* is called by main() when no RTOS is used.
**********************************************************************************************************************/
void hal_entry(void)
{
    /* TODO: add your own code here */

    err = R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
    assert(FSP_SUCCESS == err);
    /* Initialize the RTC module*/
       err = R_RTC_Open(&g_rtc0_ctrl, &g_rtc0_cfg);
       /* Handle any errors. This function should be defined by the user. */
       assert(FSP_SUCCESS == err);
       /* R_RTC_CalendarTimeSet must be called at least once to start the RTC */
       R_RTC_CalendarTimeSet(&g_rtc0_ctrl, &set_time);
       /* Set the periodic interrupt rate to 1 second */
       R_RTC_PeriodicIrqRateSet(&g_rtc0_ctrl, RTC_PERIODIC_IRQ_SELECT_1_SECOND);
       uint8_t rtc_second= 8;      //
       uint8_t rtc_minute =8;      //
       uint8_t rtc_hour =12;         //
       uint8_t rtc_day =30;          //
       uint8_t rtc_month =06;      //
       uint16_t rtc_year =122;        //
       uint8_t rtc_week =0;        //
       rtc_time_t get_time;

        /* IIC初始化*/
        err = R_SCI_I2C_Open(&g_i2c0_ctrl, &g_i2c0_cfg);
        assert(FSP_SUCCESS == err);
        WriteCmd();//OLED初始化
        OLED_Clear();//清屏
BMP180_GPIO_Init();
BMP180_Get_param();
printf("start\r\n");
R_BSP_PinAccessEnable(); //启用对PFS寄存器的访问,因为后面写IO口都用BSP内联函数
R_LPM_Open(sleep.p_ctrl, sleep.p_cfg); //打开LPM
Key_IRQ_Init();
    while(1)
       {
if(rtc_flag)
{
R_RTC_CalendarTimeGet(&g_rtc0_ctrl, &get_time);//获取RTC计数时间
rtc_flag=0;
rtc_second=get_time.tm_sec;//
rtc_minute=get_time.tm_min;//
rtc_hour=get_time.tm_hour;//
rtc_day=get_time.tm_mday;//
rtc_month=get_time.tm_mon;//
rtc_year=get_time.tm_year; //
rtc_week=get_time.tm_wday;//
printf ("\r\n%4d%02d%02d%02d:%02d:%02d\r\n", get_time.tm_year + 1900, get_time.tm_mon + 1, get_time.tm_mday,
                     get_time.tm_hour, get_time.tm_min, get_time.tm_sec);

if(1==key_clr)
{
printf("Key Press:%d\r\n",key_cnt);
key_clr=0;
OLED_Clear();//清屏
}
switch(key_cnt){
case 1:
OLED_ShowCHinese(16,1,9);//桌面电子时钟
OLED_ShowCHinese(32,1,10);//
OLED_ShowCHinese(48,1,11);//
OLED_ShowCHinese(64,1,12);//
OLED_ShowCHinese(80,1,13);//
OLED_ShowCHinese(96,1,14);//

OLED_ShowCHinese(40,5,0);//
OLED_ShowCHinese(72,5,1);//
OLED_ShowCHinese(104,5,2);//

OLED_ShowNum(8,5,rtc_year+1900,4,16);//
OLED_ShowNum(56,5,rtc_month,2,16);//
OLED_ShowNum(88,5,rtc_day,2,16);//

OLED_ShowChar(48,3,':',16);
OLED_ShowChar(72,3,':',16);
OLED_ShowNum(32,3,rtc_hour,2,16);//
OLED_ShowNum(56,3,rtc_minute,2,16);//
OLED_ShowNum(80,3,rtc_second,2,16);//秒   
break;
case 0:
char str[16]={0};
OLED_ShowCHinese(16,0,15);//室内气压计
OLED_ShowCHinese(32,0,16);//
OLED_ShowCHinese(48,0,5);//
OLED_ShowCHinese(64,0,6);//
OLED_ShowCHinese(80,0,17);//

BMP180_Get_Pressure();
printf("temp = %.2f\r\n", T);
printf("Pressure = %.2f\r\n",P);
BMP180_Get_Altitude();
printf("altitude = %.2f\r\n",H);

OLED_ShowCHinese(0,2,3);//
OLED_ShowCHinese(16,2,4);//
sprintf(str,":%7.2fC",T);
OLED_ShowString(32,2,str,16);

OLED_ShowCHinese(0,4,5);//
OLED_ShowCHinese(16,4,6);//
sprintf(str,":%6.0fPa",P);
OLED_ShowString(32,4,str,16);

OLED_ShowCHinese(0,6,7);//
OLED_ShowCHinese(16,6,8);//
sprintf(str,":%7.2fm",H);
OLED_ShowString(32,6,str,16);

break;
default:break;
}
/*打印当前时间*/
LED1_TOGGLE;
LED2_TOGGLE;
}
/*睡眠前打印*/
printf("MCU进入睡眠模式\r\n");
/*执行完流水灯任务,进入睡眠模式*/
R_LPM_LowPowerModeEnter(sleep.p_ctrl);
/*被唤醒后打印*/
printf("MCU已被唤醒\r\n");
       }
#if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}

代码编译成功后,会有如下提示:
21 代码编译成功提示

下载之前需要进行配置:
22 程序下载配置
程序下载成功后会有提示,并需要重新手动复位:

23 程序下载成功提示

需要注意的是,下载器必须支持ARMV8,否则下载不了。
程序调试,可以观测到串口输出如下:
24 程序调试输出验证

切换模式正常,低功耗模式进入和唤醒正常。说明程序运行正常。
最终的效果图参见第二章节的最终成品图。
系统演示可以查看如下链接:
https://www.bilibili.com/video/BV1rYYezeEqB/?vd_source=e36622a05269c0356d6cd566056a2488






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

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

本版积分规则

9

主题

44

帖子

0

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