1 VEML6040颜色传感器
1.1 芯片简介
关于VEML6040颜色传感器的详细介绍可以到这个网址去看
简单点来说,VEML6040是一款颜色传感器,可以获取当前颜色的RGBW值(W值有什么用我也不知道),然后通过计算得到色坐标,最终得到采集的颜色。
VEML6040适用于3.3V的单片机系统,采用I2C总线传输数据,使用OPLG封装(这种封装手焊很难的,因为引脚在芯片正下面)
芯片长这样的,手册里面也给出了推荐的焊盘尺寸:
手册里面得到4个焊盘的大小是不一样的,在立创商城里面也给出了推荐的尺寸:
这里面给出的是4个一样的,我实际用的这种封装焊接过,大小正好,但是还是差点,我推荐用手册中给出的,但是可以画成一样的4个焊盘。
1.2 芯片外围电路
手册中给出了芯片的推荐电路:
外围电路非常简单,
1.GND接地就可以
2.VDD接电源,但是要接0.1UF的电容滤波,所以在给芯片供电的时候,电源线要先经过电容再接入芯片
3.I2C的2根数据线分别接入单片机的I2C总线的引脚。当然你也可以使用I/O口软件模拟I2C的时序,这样的话就直接接2个普通的I/O口就可以了。
4.2跟数据线要通过2个上啦电阻拉高至3.3V(电源电压)
2 I2C总线
至于什么是I2C总线,百度比我解释的更加清楚,大家可以自己去查,VEML6040采用的是I2C总线进行数据传输,我们得首先知道I2C中的几个命令:
还有VEML6040在进行数据传输的时候的方式,手册里面给出了在进行获取颜色数据时候的时序:
3 基于STM32的程序
3.1 I2C驱动
首先我们应该写出I2C的驱动程序,就是上面说的那几个信号,开始、结束、应答信号。我这里采用的是是使用软件模拟的方式来驱动。
3.1.1 I/O口设置
使用软件模拟的话,就随便使用2个I/O就可以了,I/O口设置为输出模式就可以
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
3.1.2 开始信号
这里的SDA1和SCL1是我之前久宏定义好的,就是对应相应的I/O口
void IIC1_Start(void)
{
SDA1_OUT(); //sda线输出
SDA1=1;
SCL1=1;
delay_us(4);
SDA1=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
SCL1=0;//钳住I2C总线,准备发送或接收数据
}
3.1.3 停止信号
void IIC1_Stop(void)
{
SDA1_OUT();//sda线输出
SCL1=0;
SDA1=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
SCL1=1;
SDA1=1;//发送I2C总线结束信号
delay_us(4);
}
3.1.4 等待应答信号
这里的SDA1_IN()是把这个I/O口设置为输入模式
我这里使操作寄存器实现的,就是把相应的寄存器置位就可以。
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
#define SDA7_IN() {GPIOB->CRH&=0XF0FFFFFF;GPIOB->CRH|=(u32)8<<24;}
u8 IIC1_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA1_IN(); //SDA设置为输入
SDA1=1;delay_us(1);
SCL1=1;delay_us(1);
while(Read_SDA1)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC1_Stop();
return 1;
}
}
SCL1=0;//时钟输出0
return 0;
}
3.1.5 应答信号
这里的SDA1_OUT()是把这个I/O口设置为输出模式
我这里使操作寄存器实现的,就是把相应的寄存器置位就可以。
//不产生ACK应答
void IIC1_NAck(void)
{
SCL1=0;
SDA1_OUT();
SDA1=1;
delay_us(2);
SCL1=1;
delay_us(2);
SCL1=0;
}
3.1.7 给指定地址发送信号
void IIC1_Send_Byte(u8 txd)
{
u8 t;
SDA1_OUT();
SCL1=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
SDA1=(txd&0x80)>>7;
if(txd==1) SDA1=1;
if(txd==0) SDA1=0;
txd<<=1;
delay_us(2);
SCL1=1;
delay_us(2);
SCL1=0;
delay_us(2);
}
}
经过以上几个步骤,I2C的驱动代码基本上就完成了。
3.2 VEML6040驱动
3.2.1 读取数据
这个函数可以在制定的地址读取数据
#define VEML6040_ADDR 0x20
u16 VEML6040_1_ReadByte(u16 ReadAddr) //指定地址读取一个字节
{
u16 data=0;
u8 m***=0;
u8 l***=1;
IIC1_Start();
IIC1_Send_Byte(VEML6040_ADDR); //发送写命令
if(IIC1_Wait_Ack()==1) return 1;
IIC1_Send_Byte(ReadAddr);
if(IIC1_Wait_Ack()==1) return 1;
IIC1_Start();
IIC1_Send_Byte((VEML6040_ADDR)+1); //
if(IIC1_Wait_Ack()==1) return 1;
l***=IIC1_Read_Byte(0);
m***=IIC1_Read_Byte(0);
IIC1_Stop();
data=((uint16_t)m*** << 8)|l***;
return data;
}
3.2.2 写入数据
这个函数可以在制定的地址写入制定的数据或者命令,用来设置颜色传感器里面的一些参数
uint8_t VEML6040_1_Write_Bytes(uint8_t res,uint8_t cmd)
{
uint8_t m***,l***;
m***=0x00;
l***=cmd;
IIC1_Start();
IIC1_Send_Byte(VEML6040_ADDR);
if(IIC1_Wait_Ack()==1) return 1;
IIC1_Send_Byte(res);
if(IIC1_Wait_Ack()==1) return 1;
IIC1_Send_Byte(l***);
if(IIC1_Wait_Ack()==1) return 1;
IIC1_Send_Byte(m***);
if(IIC1_Wait_Ack()==1) return 1;
IIC1_Stop();
return 0;
}
3.3 设置参数
这里的意思是向0X10这个地址里面写入了0X00这个命令,是用来设置传感器的相应参数,
veml_1_Ack = VEML6040_1_Write_Bytes(0x10,0x00);
如果你想设置别的参数,只需要按照手册里面的表格设置相应的参数就可以了
3.4 读取数据
分别从不同的地址读取不同的颜色数据
if(veml_1_Ack==0)
{
VEML6040_No_Read(1,0x08);
VEML6040_1_R = VEML6040_1_ReadByte(0x08);//红
VEML6040_1_G = VEML6040_1_ReadByte(0x09);//绿
VEML6040_1_B = VEML6040_1_ReadByte(0x0A);//蓝
VEML6040_1_W = VEML6040_1_ReadByte(0x0B);//白
}
1 VEML6040颜色传感器
1.1 芯片简介
关于VEML6040颜色传感器的详细介绍可以到这个网址去看
简单点来说,VEML6040是一款颜色传感器,可以获取当前颜色的RGBW值(W值有什么用我也不知道),然后通过计算得到色坐标,最终得到采集的颜色。
VEML6040适用于3.3V的单片机系统,采用I2C总线传输数据,使用OPLG封装(这种封装手焊很难的,因为引脚在芯片正下面)
芯片长这样的,手册里面也给出了推荐的焊盘尺寸:
手册里面得到4个焊盘的大小是不一样的,在立创商城里面也给出了推荐的尺寸:
这里面给出的是4个一样的,我实际用的这种封装焊接过,大小正好,但是还是差点,我推荐用手册中给出的,但是可以画成一样的4个焊盘。
1.2 芯片外围电路
手册中给出了芯片的推荐电路:
外围电路非常简单,
1.GND接地就可以
2.VDD接电源,但是要接0.1UF的电容滤波,所以在给芯片供电的时候,电源线要先经过电容再接入芯片
3.I2C的2根数据线分别接入单片机的I2C总线的引脚。当然你也可以使用I/O口软件模拟I2C的时序,这样的话就直接接2个普通的I/O口就可以了。
4.2跟数据线要通过2个上啦电阻拉高至3.3V(电源电压)
2 I2C总线
至于什么是I2C总线,百度比我解释的更加清楚,大家可以自己去查,VEML6040采用的是I2C总线进行数据传输,我们得首先知道I2C中的几个命令:
还有VEML6040在进行数据传输的时候的方式,手册里面给出了在进行获取颜色数据时候的时序:
3 基于STM32的程序
3.1 I2C驱动
首先我们应该写出I2C的驱动程序,就是上面说的那几个信号,开始、结束、应答信号。我这里采用的是是使用软件模拟的方式来驱动。
3.1.1 I/O口设置
使用软件模拟的话,就随便使用2个I/O就可以了,I/O口设置为输出模式就可以
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
3.1.2 开始信号
这里的SDA1和SCL1是我之前久宏定义好的,就是对应相应的I/O口
void IIC1_Start(void)
{
SDA1_OUT(); //sda线输出
SDA1=1;
SCL1=1;
delay_us(4);
SDA1=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
SCL1=0;//钳住I2C总线,准备发送或接收数据
}
3.1.3 停止信号
void IIC1_Stop(void)
{
SDA1_OUT();//sda线输出
SCL1=0;
SDA1=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
SCL1=1;
SDA1=1;//发送I2C总线结束信号
delay_us(4);
}
3.1.4 等待应答信号
这里的SDA1_IN()是把这个I/O口设置为输入模式
我这里使操作寄存器实现的,就是把相应的寄存器置位就可以。
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
#define SDA7_IN() {GPIOB->CRH&=0XF0FFFFFF;GPIOB->CRH|=(u32)8<<24;}
u8 IIC1_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA1_IN(); //SDA设置为输入
SDA1=1;delay_us(1);
SCL1=1;delay_us(1);
while(Read_SDA1)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC1_Stop();
return 1;
}
}
SCL1=0;//时钟输出0
return 0;
}
3.1.5 应答信号
这里的SDA1_OUT()是把这个I/O口设置为输出模式
我这里使操作寄存器实现的,就是把相应的寄存器置位就可以。
//不产生ACK应答
void IIC1_NAck(void)
{
SCL1=0;
SDA1_OUT();
SDA1=1;
delay_us(2);
SCL1=1;
delay_us(2);
SCL1=0;
}
3.1.7 给指定地址发送信号
void IIC1_Send_Byte(u8 txd)
{
u8 t;
SDA1_OUT();
SCL1=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
SDA1=(txd&0x80)>>7;
if(txd==1) SDA1=1;
if(txd==0) SDA1=0;
txd<<=1;
delay_us(2);
SCL1=1;
delay_us(2);
SCL1=0;
delay_us(2);
}
}
经过以上几个步骤,I2C的驱动代码基本上就完成了。
3.2 VEML6040驱动
3.2.1 读取数据
这个函数可以在制定的地址读取数据
#define VEML6040_ADDR 0x20
u16 VEML6040_1_ReadByte(u16 ReadAddr) //指定地址读取一个字节
{
u16 data=0;
u8 m***=0;
u8 l***=1;
IIC1_Start();
IIC1_Send_Byte(VEML6040_ADDR); //发送写命令
if(IIC1_Wait_Ack()==1) return 1;
IIC1_Send_Byte(ReadAddr);
if(IIC1_Wait_Ack()==1) return 1;
IIC1_Start();
IIC1_Send_Byte((VEML6040_ADDR)+1); //
if(IIC1_Wait_Ack()==1) return 1;
l***=IIC1_Read_Byte(0);
m***=IIC1_Read_Byte(0);
IIC1_Stop();
data=((uint16_t)m*** << 8)|l***;
return data;
}
3.2.2 写入数据
这个函数可以在制定的地址写入制定的数据或者命令,用来设置颜色传感器里面的一些参数
uint8_t VEML6040_1_Write_Bytes(uint8_t res,uint8_t cmd)
{
uint8_t m***,l***;
m***=0x00;
l***=cmd;
IIC1_Start();
IIC1_Send_Byte(VEML6040_ADDR);
if(IIC1_Wait_Ack()==1) return 1;
IIC1_Send_Byte(res);
if(IIC1_Wait_Ack()==1) return 1;
IIC1_Send_Byte(l***);
if(IIC1_Wait_Ack()==1) return 1;
IIC1_Send_Byte(m***);
if(IIC1_Wait_Ack()==1) return 1;
IIC1_Stop();
return 0;
}
3.3 设置参数
这里的意思是向0X10这个地址里面写入了0X00这个命令,是用来设置传感器的相应参数,
veml_1_Ack = VEML6040_1_Write_Bytes(0x10,0x00);
如果你想设置别的参数,只需要按照手册里面的表格设置相应的参数就可以了
3.4 读取数据
分别从不同的地址读取不同的颜色数据
if(veml_1_Ack==0)
{
VEML6040_No_Read(1,0x08);
VEML6040_1_R = VEML6040_1_ReadByte(0x08);//红
VEML6040_1_G = VEML6040_1_ReadByte(0x09);//绿
VEML6040_1_B = VEML6040_1_ReadByte(0x0A);//蓝
VEML6040_1_W = VEML6040_1_ReadByte(0x0B);//白
}
举报