作为完结篇,本帖试图完成以下目标:利用内置I2C总线且具有防水功能的压力传感器,配备简单人机接口,根据检测压力值执行相应动作。这些部件可以组成液位开关或呼吸机压力检测及控制的功能原型。为此,我们基于ARDUINO和ROHM的BM1390GLV作为主控和传感器,加入0.96”的OLED屏,按键及继电器,组成了一个简单的压力开关。(图1)
图1 显然,在之前的试用中我们已经有了主控器和传感器,还有OLED屏,但不幸的是由于疫情居家隔离,设计图中的按键和继电器并不在工具箱里,为了将项目的检测控制过程可视化,找到了红绿LED灯并将其焊在了一块废 PCB上,作为压力正常和超限报警的指示(图2)。抱歉做了改动和简化,但它的价值原本就在于探讨BM1390GLV作为压力传感器的应用可能,管中窥豹,引导聪明的 电子发烧友们了解传感器的魅力并拓展出更多更丰富的应用场景。
图2 将BM1390GLV传感器插入传感器扩展板的I2C接口,而扩展板和ARDUINO也通过排针排母连接好,按照图1指示用杜邦线连接OLED屏和红绿LED灯。如此,一个简陋但包括了输入输出且有显示功能的压力开关出现了。(图3)
图3 接着就是软件部分了。程序中主要包括传感器和OLED的驱动,本人编程水平实在low,但受共享开放的开源精神鼓舞,把主要部分源码摘录,如果能给网友一点点帮助,实属荣幸。
- //******************************************************************************/
- //本程序仅供交流学习使用
- // 版 本 号 : v1.0
- // 作 者 : BRUCEHAO
- // 生成日期 : 2022-3-20
- // 功能描述 : 基于ARDUINO的采用BM1390GLV-Z压力传感器带OLED显示的压力指示开关
- // 说明:
- // 0.96OLED屏SPI接口:GND-电源地 VCC-5v D0-13 D1-11 RES-8 DC-9 CS-10
- // BM1390GLV-Z连接传感器扩展板J5 I2C接口
- //******************************************************************************/
- #include
- #include
- #include
- #include
- #include "oledfont.h"
- #define SYSTEM_BAUDRATE (9600)
- #define SYSTEM_WAIT (200) // ms
- #define ALARM (1017) //hpa
- BM1390GLV bm1390glv;
- #define scl 13 //SCLK
- #define sda 11 //MOSI
- #define res 8 //RES
- #define dc 9 //DC
- #define cs 10 //CS
- #define red 6 //红灯
- #define green 7 //绿灯
- #define OLED_SCL_Clr() digitalWrite(scl,LOW)//SCL
- #define OLED_SCL_Set() digitalWrite(scl,HIGH)
- #define OLED_SDA_Clr() digitalWrite(sda,LOW)//SDA
- #define OLED_SDA_Set() digitalWrite(sda,HIGH)
- #define OLED_RES_Clr() digitalWrite(res,LOW)//RES
- #define OLED_RES_Set() digitalWrite(res,HIGH)
- #define OLED_DC_Clr() digitalWrite(dc,LOW)//DC
- #define OLED_DC_Set() digitalWrite(dc,HIGH)
-
- #define OLED_CS_Clr() digitalWrite(cs,LOW)//CS
- #define OLED_CS_Set() digitalWrite(cs,HIGH)
- #define LED_RED_ON() digitalWrite(red,LOW)//red
- #define LED_RED_OFF() digitalWrite(red,HIGH)
- #define LED_GREEN_ON() digitalWrite(green,LOW)//green
- #define LED_GREEN_OFF() digitalWrite(green,HIGH)
- #define OLED_CMD 0 //写命令
- #define OLED_DATA 1 //写数据
- void setup()
- {
- int32_t result;
- Serial.begin(SYSTEM_BAUDRATE);
- while (!Serial) {
- }
- Wire.begin();
- result = bm1390glv.init();
- if (result == BM1390GLV_COMM_OK) {
- (void)bm1390glv.start();
- }
- OLED_Init();
- OLED_ColorTurn(0);//0正常显示 1反色显示
- OLED_DisplayTurn(0);//0正常显示 1翻转180度显示
- OLED_Clear();
- }
- void loop()
- {
- int32_t result;
- float32 press, temp;
- result = bm1390glv.get_val(&press, &temp);
- if (result == BM1390GLV_COMM_OK) {
- (void)Serial.write("Pressure(hPa):Temperature(degree Celsius) = ");
- (void)Serial.print(press);
- (void)Serial.write(", ");
- (void)Serial.print(temp);
- (void)Serial.println();
- }
- OLED_ShowChinese(16,0,0,16);//电
- OLED_ShowChinese(34,0,1,16);//子
- OLED_ShowChinese(52,0,2,16);//发
- OLED_ShowChinese(70,0,3,16);//烧
- OLED_ShowChinese(88,0,4,16);//友
- OLED_ShowString(26,2,"BM1390GLV",16);
- OLED_ShowString(8,4,"Pressure:",16);
- OLED_ShowNum(48,6,press,4,16);
- OLED_ShowString(88,6,"hPa",16);
- if (press
- LED_RED_OFF(); }
- else{ LED_RED_ON();
- LED_GREEN_OFF();}
- delay(SYSTEM_WAIT);
- return;
- }
- //OLED的初始化
- void OLED_Init(void)
- {
- pinMode(red,OUTPUT);//设置数字6
- pinMode(green,OUTPUT);//设置数字7
- pinMode(scl,OUTPUT);//设置数字8
- pinMode(sda,OUTPUT);//设置数字9
- pinMode(res,OUTPUT);//设置数字10
- pinMode(dc,OUTPUT);//设置数字11
- pinMode(cs,OUTPUT);//设置数字12
- SPCR=(1<
- OLED_RES_Clr();
- delay(200);
- OLED_RES_Set();
-
- OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
- OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
- OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
- OLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
- OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
- OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
- OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
- OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
- OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
- OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
- OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
- OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
- OLED_WR_Byte(0x00,OLED_CMD);//-not offset
- OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
- OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
- OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
- OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
- OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
- OLED_WR_Byte(0x12,OLED_CMD);
- OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
- OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
- OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
- OLED_WR_Byte(0x02,OLED_CMD);//
- OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
- OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
- OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
- OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
- OLED_Clear();
- OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
- }
- void OLED_ColorTurn(u8 i)
- {
- if(!i) OLED_WR_Byte(0xA6,OLED_CMD);//正常显示
- else OLED_WR_Byte(0xA7,OLED_CMD);//反色显示
- }
- //屏幕旋转180度
- void OLED_DisplayTurn(u8 i)
- {
- if(i==0)
- {
- OLED_WR_Byte(0xC8,OLED_CMD);//正常显示
- OLED_WR_Byte(0xA1,OLED_CMD);
- }
- else
- {
- OLED_WR_Byte(0xC0,OLED_CMD);//反转显示
- OLED_WR_Byte(0xA0,OLED_CMD);
- }
- }
- //写入一个字节
- void OLED_WR_Byte(u8 dat,u8 cmd)
- {
- u8 i;
- if(cmd)
- OLED_DC_Set();
- else
- OLED_DC_Clr();
- OLED_CS_Clr();
-
- SPDR=dat;
- while(!(SPSR&(1<
-
- OLED_CS_Set();
- OLED_DC_Set();
- }
- //坐标设置
- void OLED_Set_Pos(u8 x, u8 y)
- {
- OLED_WR_Byte(0xb0+y,OLED_CMD);
- OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
- OLED_WR_Byte((x&0x0f),OLED_CMD);
- }
- //开启OLED显示
- void OLED_Display_On(void)
- {
- OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
- OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON
- OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
- }
- //关闭OLED显示
- void OLED_Display_Off(void)
- {
- OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
- OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
- OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
- }
- //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
- void OLED_Clear(void)
- {
- u8 i,n;
- for(i=0;i<8;i++)
- {
- OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
- OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
- OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
- for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
- } //更新显示
- }
- //在指定位置显示一个字符
- //x:0~127
- //y:0~63
- //sizey:选择字体 6x8 8x16
- void OLED_ShowChar(u8 x,u8 y,const u8 chr,u8 sizey)
- {
- u8 c=0,sizex=sizey/2,temp;
- u16 i=0,size1;
- if(sizey==8)size1=6;
- else size1=(sizey/8+((sizey%8)?1:0))*(sizey/2);
- c=chr-' ';//得到偏移后的值
- OLED_Set_Pos(x,y);
- for(i=0;i
- {
- if(i%sizex==0&&sizey!=8) OLED_Set_Pos(x,y++);
- if(sizey==8)
- {
- temp=pgm_read_byte(&asc2_0806[c][i]);
- OLED_WR_Byte(temp,OLED_DATA);//6X8字号
- }
- else if(sizey==16)
- {
- temp=pgm_read_byte(&asc2_1608[c][i]);
- OLED_WR_Byte(temp,OLED_DATA);//8x16字号
- }
- else return;
- }
- }
- //m^n函数
- u32 oled_pow(u8 m,u8 n)
- {
- u32 result=1;
- while(n--)result*=m;
- return result;
- }
- //显示数字
- //x,y :起点坐标
- //num:要显示的数字
- //len :数字的位数
- //sizey:字体大小
- void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey)
- {
- u8 t,temp,m=0;
- u8 enshow=0;
- if(sizey==8)m=2;
- for(t=0;t
- {
- temp=(num/oled_pow(10,len-t-1))%10;
- if(enshow==0&&t<(len-1))
- {
- if(temp==0)
- {
- OLED_ShowChar(x+(sizey/2+m)*t,y,' ',sizey);
- continue;
- }else enshow=1;
- }
- OLED_ShowChar(x+(sizey/2+m)*t,y,temp+'0',sizey);
- }
- }
- //显示一个字符号串
- void OLED_ShowString(u8 x,u8 y,const char *chr,u8 sizey)
- {
- u8 j=0;
- while (chr[j]!='\0')
- {
- OLED_ShowChar(x,y,chr[j++],sizey);
- if(sizey==8)x+=6;
- else x+=sizey/2;
- }
- }
- //显示汉字
- void OLED_ShowChinese(u8 x,u8 y,const u8 no,u8 sizey)
- {
- u16 i,size1=(sizey/8+((sizey%8)?1:0))*sizey;
- u8 temp;
- for(i=0;i
- {
- if(i%sizey==0) OLED_Set_Pos(x,y++);
- if(sizey==16)
- {
- temp=pgm_read_byte(&Hzk[no][i]);
- OLED_WR_Byte(temp,OLED_DATA);//16x16字号
- }
- // else if(sizey==xx) OLED_WR_Byte(xxx[c][i],OLED_DATA);//用户添加字号
- else return;
- }
- }
- //显示图片
- //x,y显示坐标
- //sizex,sizey,图片长宽
- //BMP:要显示的图片
- void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,const u8 BMP[])
- {
- u16 j=0;
- u8 i,m,temp;
- sizey=sizey/8+((sizey%8)?1:0);
- for(i=0;i
- {
- OLED_Set_Pos(x,i+y);
- for(m=0;m
- {
- temp=pgm_read_byte(&BMP[j++]);
- OLED_WR_Byte(temp,OLED_DATA);
- }
- }
- }
复制代码
程序上传运行后,打开串口监视器,输出当前压力值和温度值。(图4)
图4 关于压力传感器的测试,来自ROHM官网BM1390GLV的测试视频截图显示,将BM1390GLV放在密闭且有水淹没传感器的罐子里面,随着针筒的上下移动,压力变化在笔记本电脑上直观地显示出来。(图5)
图5 碍于条件所限和项目设定,这里以压力值比较阀值方式控制输出指示,大于阀值红灯亮,否则绿灯亮(见文底视频)。而改变压力采取了用吸管对着传感器上方吹的方式,虽原始但有效,某种程度也验证了传感器的防水效果。 自收到传感器评估套件月余,经历了一番特别的体验,第一次接触ARDUINO,第一次使用ROHM传感器,第一次在电子发烧友网发帖,而最后这张帖子也是在第一次居家隔离中完成的。敲完最后一行文字,就像结束了一段旅程,开心、疲惫、遗憾、不舍,然而对传感器世界的探索,还在继续……
test
|