借助各种传感器的使用,可有效地拓展开发板的功能。这里仅以2种常用的I2C接口的传感器来进行环境状态的检测并通过开发板上的液晶显示屏来加以显示。 1 . BMP085 BMP085是一种温度与大气压传感器,它与开发板的连接关系为: SCL ---PB7 SDA ---PB8 为便于自由地使用相应的引脚,这里是以GPIO模拟I2C的方式来驱动。 所用引脚输出高低电平的语句定义为: #define SCL_Set1() Gpio_SetIO(GpioPortB, GpioPin7) #define SCL_Clr1() Gpio_ClrIO(GpioPortB, GpioPin7) #define SDA_Set1() Gpio_SetIO(GpioPortB, GpioPin8) #define SDA_Clr1() Gpio_ClrIO(GpioPortB, GpioPin8) 数据引脚读取输入信号状态的语句定义为: #define SDA_IN Gpio_GetInputIO(GpioPortB, GpioPin8) 对BMP085所用引脚进行配置的函数为: void App_bmp085_Init(void)
{
stc_gpio_cfg_t stcGpioCfg;
Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
stcGpioCfg.enDir = GpioDirOut;
stcGpioCfg.enPu = GpioPuEnable;
stcGpioCfg.enPd = GpioPdDisable;
Gpio_Init(GpioPortB, GpioPin7, &stcGpioCfg);
Gpio_Init(GpioPortB, GpioPin8, &stcGpioCfg);
}
由于在使用过程中,数据引脚既要进行数据输出,又要读取数据,故常要要进行输入与输出模式的转换,为此定义了2个模式设置的函数以供模式切换来使用,其函数内容为: void INPUT_MODE_SET()
{
stc_gpio_cfg_t stcGpioCfg;
Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
stcGpioCfg.enDir = GpioDirIn;
stcGpioCfg.enPu = GpioPuDisable;
stcGpioCfg.enPd = GpioPdEnable;
Gpio_ClrIO(GpioPortB, GpioPin8);
Gpio_Init(GpioPortB, GpioPin8, &stcGpioCfg);
}
void OUTPUT_MODE_SET()
{
stc_gpio_cfg_t stcGpioCfg;
Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
stcGpioCfg.enDir = GpioDirOut;
stcGpioCfg.enPu = GpioPuDisable;
stcGpioCfg.enPd = GpioPdEnable;
Gpio_ClrIO(GpioPortB, GpioPin8);
Gpio_Init(GpioPortB, GpioPin8, &stcGpioCfg);
}
BMP085的初始化函数为: void Init_BMP085()
{
ac1 = Multiple_read(0xAA);
ac2 = Multiple_read(0xAC);
ac3 = Multiple_read(0xAE);
ac4 = Multiple_read(0xB0);
ac5 = Multiple_read(0xB2);
ac6 = Multiple_read(0xB4);
b1 = Multiple_read(0xB6);
b2 = Multiple_read(0xB8);
mb = Multiple_read(0xBA);
mc = Multiple_read(0xBC);
md = Multiple_read(0xBE);
}
此外,BMP085模拟I2C发送字节数据的函数为: void BMP085_Send_Byte(char txd)
{
char t;
OUTPUT_MODE_SET();
SCL_Clr1();
for(t=0;t<8;t++)
{
if((txd&0x80)>>7)
SDA_Set1();
else
SDA_Clr1();
txd<<=1;
delay1us(1);
SCL_Set1();
delay1us(1);
SCL_Clr1();
delay1us(1);
}
}
BMP085读取字节数据的函数为: char BMP085_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
INPUT_MODE_SET();
for(i=0;i<8;i++)
{
SCL_Clr1();
delay1us(1);
SCL_Set1();
receive<<=1;
if(SDA_IN) receive++;
delay1us(1);
}
if(!ack)
BMP085_NAck();
else
BMP085_Ack();
return receive;
}
BMP085读取温度与大气压的功能函数为: long bmp085ReadTemp(void)
{
BMP085_Start();
BMP085_Send_Byte(BMP085_SlaveAddress);
while(BMP085_Wait_Ack());
BMP085_Send_Byte(0xF4);
while(BMP085_Wait_Ack());
BMP085_Send_Byte(0x2E);
while(BMP085_Wait_Ack());
BMP085_Stop();
delay1ms(10);
return (long) Multiple_read(0xF6);
}
long bmp085ReadPressure(void)
{
long pressure = 0;
BMP085_Start();
BMP085_Send_Byte(BMP085_SlaveAddress);
while(BMP085_Wait_Ack()){}
BMP085_Send_Byte(0xF4);
while(BMP085_Wait_Ack()){}
BMP085_Send_Byte(0x34);
while(BMP085_Wait_Ack()){}
BMP085_Stop();
delay1ms(10);
pressure = Multiple_read(0xF6);
pressure &= 0x0000FFFF;
return pressure;
}
实现检测数据数值变换的函数为: void bmp085Convert()
{
unsigned int ut;
unsigned long up;
long x1, x2, b5, b6, x3, b3, p;
unsigned long b4, b7;
ut = bmp085ReadTemp();
up = bmp085ReadPressure();
x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;
x2 = ((long) mc << 11) / (x1 + md);
b5 = x1 + x2;
temperature1 = ((b5 + 8) >> 4);
b6 = b5 - 4000;
x1 = (b2 * (b6 * b6)>>12)>>11;
x2 = (ac2 * b6)>>11;
x3 = x1 + x2;
b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2;
x1 = (ac3 * b6)>>13;
x2 = (b1 * ((b6 * b6)>>12))>>16;
x3 = ((x1 + x2) + 2)>>2;
b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;
b7 = ((unsigned long)(up - b3) * (50000>>OSS));
if (b7 < 0x80000000)
p = (b7<<1)/b4;
else
p = (b7/b4)<<1;
x1 = (p>>8) * (p>>8);
x1 = (x1 * 3038)>>16;
x2 = (-7357 * p)>>16;
pressure = p+((x1 + x2 + 3791)>>4);
}
利用液晶显示屏实现温度与大气压检测值显示的主程序为: int32_t main(void)
{
int8_t i=0;
Sysctrl_ClkSourceEnable(SysctrlClkRCL,TRUE); ///< 使能RCL时钟
Sysctrl_SetRCLTrim(SysctrlRclFreq32768); ///< 配置内部低速时钟频率为32.768kHz
Sysctrl_SetPeripheralGate(SysctrlPeripheralLcd,TRUE); ///< 开启LCD时钟
Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE); ///< 开启GPIO时钟
App_PortCfg(); ///< LCD端口配置
App_LcdCfg(); ///< LCD模块配置
Lcd_ClearDisp(); ///< 清屏
Lcd_WriteRam(0,0x00000000); ///< 赋值寄存器LCDRAM0
Lcd_WriteRam(1,0x00000000); ///< 赋值寄存器LCDRAM1
App_bmp085_Init();
Init_BMP085();
bmp085Convert();
delay1ms(500);
key_init();
while(1)
{
if(Gpio_GetInputIO(GpioPortA, GpioPin7)==0)
{
s=(d[(pressure/100)%1000/100]<<16)+d[(pressure/100)/1000];
Lcd_WriteRam(0,s);
s=(d[(pressure/100)%10]<<16)+d[(pressure/100)%100/10];
Lcd_WriteRam(1,s);
}
else
{
s=0;
Lcd_WriteRam(0,s);
s=(d[(temperature1/10)%10]<<16)+d[(temperature1/10)/10];
Lcd_WriteRam(1,s);
}
delay1ms(500);
bmp085Convert();
}
}
经程序的编译与下载,其相应效果如图1和图2所示。
由于液晶显示屏的显示内容有限,故在显示时是通过开发板上的用户键来切换显示的内容,其通常状态下是显示温度值,而在按下按键后是显示大气压值。 图1 温度检测
图2 气压检测
2.BH1750 所用的另一种传感器是光照强度传感器BH1750,由于它也是一种I2C器件,故在基本用法上较为相同,其主要区别在于功能处理方面。
BH1750发送字节数据的函数为: void BH1750_SendByte(char data)
{
char i;
IIC_OUTPUT_MODE_SET();
SCL_Clr();
delay1us(2);
for (i=0;i<8;i++)
{
if(data&0x80) SDA_Set();
else SDA_Clr();
data <<= 1;
SCL_Set();
delay1us(2);
SCL_Clr();
delay1us(2);
}
}
BH1750接收字节数据的函数为: char BH1750_RecvByte()
{
char i;
char data = 0;
IIC_INPUT_MODE_SET();
for (i=0;i<8;i++)
{
SCL_Clr();
delay1us(2);
SCL_Set();
data <<= 1;
SCL_Set();
if(IIC_SDA_IN) data|=0x01;
delay1us(2);
}
SCL_Clr();
return data;
}
读取光照强度的函数为: void Get_Sunlight_Value()
{
int dis_data=0;
float temp;
char i=0;
unsigned int sd;
Single_Write_BH1750(0x01);
Single_Write_BH1750(0x10);
delay1ms(180);
Multiple_Read_BH1750();
for(i=0;i<3;i++) dis_data=BUF[0];
dis_data=(dis_data<<8)+BUF[1];
temp=(float)dis_data/1.2;
sd=temp;
s=(d[sd%1000/100]<<16)+d[sd/1000];
Lcd_WriteRam(0,s);
s=(d[sd%10]<<16)+d[sd%100/10];
Lcd_WriteRam(1,s);
}
使用液晶屏来显示光照强度的主程序为: int32_t main(void)
{
int8_t i=0;
Sysctrl_ClkSourceEnable(SysctrlClkRCL,TRUE); ///< 使能RCL时钟
Sysctrl_SetRCLTrim(SysctrlRclFreq32768); ///< 配置内部低速时钟频率为32.768kHz
Sysctrl_SetPeripheralGate(SysctrlPeripheralLcd,TRUE); ///< 开启LCD时钟
Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE); ///< 开启GPIO时钟
App_PortCfg(); ///< LCD端口配置
App_LcdCfg(); ///< LCD模块配置
Lcd_ClearDisp(); ///< 清屏
Lcd_WriteRam(0,0x00000000); ///< 赋值寄存器LCDRAM0
Lcd_WriteRam(1,0x00000000); ///< 赋值寄存器LCDRAM1
BH1750_Init();
delay1ms(500);
key_init();
while(1)
{
Get_Sunlight_Value();
delay1ms(500);
}
}
经程序的编译与下载,其相应效果如图3所示。 图3 检测效果
|