论坛» 活动中心» 板卡试用

【换取手持数字示波器】+利用STM32F103C8T6芯片,0.96寸液晶屏显示与MPL3115A模块对大气压,海拔和温度的读取

菜鸟
2024-06-12 20:14 1楼


简介:利用STM32F103C8T6芯片,0.96寸液晶屏显示与MPL3115A模块对大气压,海拔和温度的读取。

利用STM32作为主控对MPL3115A模块进行读取,并将显示的大气压值,温度值显示到液晶屏上面。

MPL3115A模块介绍:

20bit压力测量(Pascal);20bit高度测量(米);12bit温度测量;

绝对压力测量范围:20110 kPa

相对测量精度:- + 0.05 kPa

有效分辨率:1.5Pa / 0.3m

工作温度范围:-4085摄氏度;

I2C数字输出接口;

内置32FIFO采样缓冲区;

软件代码流程如下:

/*配置SDA的IO口模式信息*/ void GPIO_Output_I2C_Configuration(GPIO_TypeDef* SDA, u16 GPIO_Pin) { GPIO_InitTypeDef GPIO_Initstructure; GPIO_Initstructure.GPIO_Pin = GPIO_Pin; GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Initstructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(SDA, &GPIO_Initstructure); } /*配置SCL的IO口模式信息*/ void GPIO_Input_I2C_Configuration(GPIO_TypeDef* SDA, u16 GPIO_Pin) { GPIO_InitTypeDef GPIO_Initstructure; GPIO_Initstructure.GPIO_Pin = GPIO_Pin; GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(SDA, &GPIO_Initstructure); } /*IIC总线启动*/ void I2C_Start ()//I2C开始 { GPIO_Output_I2C_Configuration(SCL.GPIOx, SCL.GPIO_Pin); //SCL置输出 GPIO_Output_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输出 GPIO_SetBits(SDA.GPIOx, SDA.GPIO_Pin);//SDA=1; delay_us(50); //此处延时50us GPIO_SetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=1; delay_us(50); //此处延时50us GPIO_ResetBits(SDA.GPIOx, SDA.GPIO_Pin);//SDA=0; delay_us(50); //此处延时50us GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=0; delay_us(50); //此处延时50us } /*IIC总线结束*/ void I2C_Stop () //I2C结束 { GPIO_Output_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输出 GPIO_ResetBits(SDA.GPIOx, SDA.GPIO_Pin);//SDA=0; delay_us(50); //此处延时50us GPIO_SetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=1; delay_us(50); //此处延时50us GPIO_SetBits(SDA.GPIOx, SDA.GPIO_Pin);//SDA=1; delay_us(50); //此处延时50us } /*主机检查从机的响应信号*/ int I2C_Slave_ACK(void) // 检查从机应答信号,返回0有ACK,返回1无ACK { int ACK; u8 s1; GPIO_Input_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输入 GPIO_SetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=1; delay_us(50); //此处延时50us s1 = GPIO_ReadInputDataBit(SDA.GPIOx, SDA.GPIO_Pin); if (s1) //判断返回的数据类型,确定是否正常 { ACK = 1; } else { ACK = 0; } GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=0; delay_us(50); //此处延时50us return(ACK); //返回应答信号 } /*主机发送IIC总线上一个字节数据*/ void I2C_SendByte(u8 data) //发送一个字节 { u8 i; //发送8位 GPIO_Output_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输出 for(i = 0; i < 8; i++) { if((data & 0x80) == 0x80) { GPIO_SetBits(SDA.GPIOx, SDA.GPIO_Pin); } //SDA=1,写 1 else { GPIO_ResetBits(SDA.GPIOx, SDA.GPIO_Pin); } //SDA=0,写 0 GPIO_SetBits(SCL.GPIOx, SCL.GPIO_Pin); //SCL=1; delay_us(50); //在时钟大于4u秒期间写数据 GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=0; delay_us(50); //此处延时50us data = data << 1; //将返回的数据进行移位处理 } } /*主机接收IIC总线上一个字节数据*/ u8 I2C_ReciveByte(void) //接受一个字节 { u8 s1 = 0, temp1 = 0; u8 i; GPIO_Input_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输入 for(i = 0; i < 8; i++) { temp1 = temp1 << 1; GPIO_SetBits(SCL.GPIOx, SCL.GPIO_Pin); //SCL=1; delay_us(50); //在时钟大于4u秒期间读数据 s1 = GPIO_ReadInputDataBit(SDA.GPIOx, SDA.GPIO_Pin); if(s1) //读 1 { temp1 = temp1 | 0x01; } else //读 0 { temp1 = temp1 & 0xfe; } GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=0; delay_us(50); //此处延时50us } return(temp1); } /*主机向IC总线发送连续读信号*/ void I2C_ack(void) // 发送连续读信号 { GPIO_Output_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输出; GPIO_ResetBits(SDA.GPIOx, SDA.GPIO_Pin);//SDA=0; delay_us(50); //此处延时50us GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin); //SCL=1; delay_us(50); //此处延时50us GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=0; } /*主机向IC总线发送不连续读信号*/ void I2C_nack(void) // 发送不连续读信号 { GPIO_Output_I2C_Configuration(SDA.GPIOx, SDA.GPIO_Pin); //SDA置输出 ; GPIO_SetBits(SDA.GPIOx, SDA.GPIO_Pin);//SDA=1; delay_us(50); //此处延时50us GPIO_SetBits(SCL.GPIOx, SCL.GPIO_Pin); //SCL=1; delay_us(50); //此处延时50us GPIO_ResetBits(SCL.GPIOx, SCL.GPIO_Pin);//SCL=0; delay_us(50); //此处延时50us } void Write_MPL3115A2(u8 Address, u8 Dat) { I2C_Start(); //启动IIC时序 I2C_SendByte(MPL3115A2Wcmd);//主机发送MPL3115A2W的发送字节命令 I2C_Slave_ACK(); //主机等待模块返回应答指令 I2C_SendByte(Address);//主机发送MPL3115A2W的地址 I2C_Slave_ACK(); //主机等待模块返回应答指令 I2C_SendByte(Dat); //主机发送MPL3115A2W的数据 I2C_Slave_ACK(); //主机等待模块返回应答指令 I2C_Stop(); //停止IIC时序 } u8 MPL3115A2Read(u8 adrr) { char p; I2C_Start(); //启动IIC时序 I2C_SendByte(MPL3115A2Wcmd);//主机发送MPL3115A2W的发送字节命令 I2C_Slave_ACK(); //主机等待模块返回应答指令 I2C_SendByte(adrr); //主机发送MPL3115A2W的发送地址命令信息 I2C_Slave_ACK(); //主机等待模块返回应答指令 I2C_Start(); //启动IIC时序 I2C_SendByte(MPL3115A2Rcmd); I2C_Slave_ACK(); //主机等待模块返回应答指令 p = I2C_ReciveByte();//将模块返回 I2C_nack(); //确定IIC无应答 I2C_Stop(); //停止IIC时序 return p; } void MPL3115A2_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); /************引脚设置******************/ SDA.GPIOx = GPIOB; SDA.GPIO_Pin = GPIO_Pin_13; SCL.GPIOx = GPIOB; SCL.GPIO_Pin = GPIO_Pin_12; /**************************************/ /* Set to Altimeter with an OSR = 1 */ Write_MPL3115A2(0x26, 0x80); /* Enable Data Flags in PT_DATA_CFG */ Write_MPL3115A2(0x13, 0x07); /* Set Active */ Write_MPL3115A2(0x26, 0xB9); } void MPL3115A2_Read(struct MPL3115A2 *p) { static u16 AData; static u8 BData, CData, DData; u16 pre; loat Alt_Integer,Alt_Fraction,Tmp_Integer,Tmp_Fraction,Pre_Integer,Pre_Fraction; //临时变量存放气压高度温度的小数和整数部分 /* Set to Altimeter with an OSR = 1 *///高度模式 Write_MPL3115A2(0x26, 0x80); /* Enable Data Flags in PT_DATA_CFG */ Write_MPL3115A2(0x13, 0x07); Write_MPL3115A2(0x26, 0xB9); /* Read STATUS Register */ while((MPL3115A2Read(0x00) & 0x08) == 0); AData = MPL3115A2Read(0x01) << 8 | MPL3115A2Read(0x02); BData = MPL3115A2Read(0x03); CData = MPL3115A2Read(0x04); DData = MPL3115A2Read(0x05); Alt_Integer = (s16)AData; Alt_Fraction=0; if (BData & 0x80) { Alt_Fraction += FRAC_2d1; } if (BData & 0x40) { Alt_Fraction += FRAC_2d2; } if (BData & 0x20) { Alt_Fraction += FRAC_2d3; } if (BData & 0x10) { Alt_Fraction += FRAC_2d4; } if(Alt_Integer>0) { p->Alt = Alt_Integer + Alt_Fraction/10000; } else { p->Alt = Alt_Integer - Alt_Fraction/10000; } Tmp_Integer = (s8)CData; Tmp_Fraction=0; if (DData & 0x80) { Tmp_Fraction += FRAC_2d1; } if (DData & 0x40) { Tmp_Fraction += FRAC_2d2; } if (DData & 0x20) { Tmp_Fraction += FRAC_2d3; } if (DData & 0x10) { Tmp_Fraction += FRAC_2d4; } if(Tmp_Integer>0) { p->Tmp = Tmp_Integer + Tmp_Fraction/10000; } else { p->Tmp = Tmp_Integer - Tmp_Fraction/10000; } /* Set to Altimeter with an OSR = 1 *///气压模式 /* Enable Data Flags in PT_DATA_CFG */ Write_MPL3115A2(0x26, 0x00); Write_MPL3115A2(0x13, 0x07); Write_MPL3115A2(0x26, 0x39); /* Read STATUS Register */ while((MPL3115A2Read(0x00) & 0x08) == 0); AData = MPL3115A2Read(0x01) << 8 | MPL3115A2Read(0x02); BData = MPL3115A2Read(0x03); CData = MPL3115A2Read(0x04); DData = MPL3115A2Read(0x05); pre=AData; pre=pre<<2; pre|=BData>>6; Pre_Integer=(float)pre; Pre_Fraction = 0; if (BData & 0x20)//第5位 { Pre_Fraction += FRAC_2d1; } if (BData & 0x10)//第4位 { Pre_Fraction += FRAC_2d2; } p->pre=(Pre_Integer+Pre_Fraction/10000)/100; }

模块使用心得:手册中提到读取气压的方式有轮询法和中断法。轮询法就是不使用中断的方法。我这里只是测试模块功能,对精度要求不是很高,所以就选择的该方式。只需要接SDA和SCI,而IN1 IN2只有在中断法中才会使用到,这里就不做过多的介绍。

MPL3115A2有3种工作模式。就绪模式、活动测高模式、活动测压模式。

步骤1:先进入就绪模式,CTRL_REG1寄存器(0x26)写入0x04,即就绪模式;

步骤2:再对该寄存器写入0xB9,进入活动测高模式;

步骤3:将PT_DATA_CDG寄存器(0x13)的值写为0x07。配置工作就完成了。

然后它就可以开始按照iic的工作时序开始工作了。我们需要的数据在0x01 0x02 0x03 这三个寄存器中。0x01和0x02都是以米做单位的,读出来就直接是海拔。

在大多数城市 0x01这个寄存器的值都是0,如果你在青藏高原就当我没说;

0x02的数据就是你城市的海拔,0x03的数据,就可以理解为小数点后的数值了。

2:OLED模块介绍:

2.1OLED简介:

OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display, OELD)。因为具备轻薄、省电等特性,因此从2003年开始,这种显示设备在MP3播放器上得到了广泛应用,而对于同属数码类产品的DC与手机,此前只是在一些展会上展示过采用OLED屏幕的工程样品。自2007年后,寿命得 到很大提高,具备了许多LCD不可比拟的优势。

GND:电源地VCC2.2V~5.5V SCLD0):CLK时钟 (高电平2.2V~5.5VSDA(D1)MOSI数据(高电平2.2V~5.5VRST:复位(高电平2.2V~5.5VD/C:数据/命令(高电平2.2V~5.5V) 兼容3.3V5V控制芯片的I/O电平(无需任何设置,直接兼容)

实物图片

OLED 屏幕界面.png

2.2:汉字显示方法:

需要使用软件做自己的字库

取模软件界面.png


//向SSD1106写入一个字节。 //dat:要写入的数据/命令 //cmd:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte(u8 dat,u8 cmd) { u8 i; if(cmd) OLED_DC_Set(); else OLED_DC_Clr(); OLED_CS_Clr(); for(i=0;i<8;i++) { OLED_SCLK_Clr(); if(dat&0x80) OLED_SDIN_Set(); else OLED_SDIN_Clr(); OLED_SCLK_Set(); dat<<=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)|0x01,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 (0x02,OLED_CMD); //设置显示位置—列低地址 OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址 for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA); } //更新显示 } //在指定位置显示一个字符 调用OLED_ShowChar(48,6,16,t); //x0,y0显示起点坐标,x0(范围0~127),y0(范围0~7)*8 //size:选择字体 16/12 //chr:字符串ascii码 void OLED_ShowChar(u8 x, u8 y, u8 size, u8 chr) { u8 c=0,i=0; c=chr-' ';//得到偏移后的值 if(x>X_WIDTH-1){x=0;y=y+2;} if(size ==ASCII32x32) { OLED_Set_Pos(x,y); for(i=0;iX_WIDTH-size){x=0;y+=size/8;} j++; } } //显示显示BMP图片 调用OLED_DrawBMP(0,0,128,8,BMP1);最大图片 //x0,y0:显示起点坐标,x0(范围0~127),y0(范围0~7)*8 //x1,y1:显示图片长度和宽度,x1(范围0~127),y1(范围0~7)*8 //BMP[]:图片首地址 void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[]) { u16 j=0; u8 x,y; if(y1%8==0) y=y1/8; else y=y1/8+1; for(y=y0;yac) max=mid-1; else min=mid+1; } return (u32*)(ChineseCharDot+mid*CHINESECHARDOTSIZE); } void Get_Code(u8* dis_buf,u32* address,u8 leng) { u8 i; for(i=0;i>8; dis_buf++; *dis_buf=*address>>16; dis_buf++; *dis_buf=*address>>24; dis_buf++; address++; } } void LCD_Char_CH(u8 x,u8 y,vu8 *str) { u8 i,buffer[CHINESECHARDOTSIZE]={0}; u16 chinese_ascii; u32 *p_address; chinese_ascii = *str; str++; chinese_ascii = chinese_ascii<<8|*str; //找到汉字内码 p_address=getchinesecodepos(chinese_ascii); Get_Code(buffer,p_address,32); // 取字模数据 OLED_Set_Pos(x,y); for(i=0;iCR = DBGMCU->CR & ~((uint32_t)1<<5); // RCC->APB2ENR = 1 | (1<<3); /*AFIO/ GPIOB*/ // AFIO->MAPR = (AFIO->MAPR & ~((uint32_t)0x7 << 24)) | (2 << 24); /*释放 PA15 PB3 PB4*/ OLED_RST_Set(); delay_ms(100); OLED_RST_Clr(); delay_ms(100); OLED_RST_Set(); OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel OLED_WR_Byte(0x02,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(0x81,OLED_CMD); //对比度设置 OLED_WR_Byte(0xfF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮) 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_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/ OLED_Clear(); OLED_Set_Pos(0,0); }


测试图片如下:

MPL3115图片.png



专家
2024-06-19 12:13 2楼

谢谢分享

共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]