2014 4.17
最近一直在研究这个东西,查了查资料,感觉挺简单的,但是实际应用的时候也碰到一些问题。
比方说I2C配置不正确,导致数据错误,TSL设备地址不正确,根本读取不到数据。
关于TSL设备地址,这个刚刚开始根本没注意,可以看技术手册可以发现,共有三个地址,这三个地址根据你硬件连接可变。
接地的时候是0x52;
浮空的时候是0x72;
还有一个忘了。
解决这个以后,基本数据就能上来了,然后根据技术手册上的计算公式可以计算出需要的数据。
关于代码,其实东西也没多少,就是一个I2C驱动程序,根据它读取传感器数据。代码明天贴上。
2014 1.18
好吧我又来了,写的东西居然有人看,那我就积极一点了。
废话不多说,贴上我的代码。
下面是我的I2C驱动代码:
myiic.c 文件
#include "myiic.h"
#include "delay.h"
//初始化IIC
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); //PB10,PB11 输出高
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
//IIC_SDA=(txd&0x80)>>7;
if((txd&0x80)>>7)
IIC_SDA=1;
else
IIC_SDA=0;
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(2);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
/**************************实现函数********************************************
*函数原型: unsigned char I2C_ReadOneByte(unsigned char I2C_Addr,unsigned char addr)
*功 能: 读取指定设备 指定寄存器的一个值
输入 I2C_Addr 目标设备地址
addr 寄存器地址
返回 读出来的值
*******************************************************************************/
unsigned char I2C_ReadOneByte(unsigned char I2C_Addr,unsigned char addr)
{
unsigned char res=0;
IIC_Start();
IIC_Send_Byte(I2C_Addr); //发送写命令
res++;
IIC_Wait_Ack();
IIC_Send_Byte(addr); res++; //发送地址
IIC_Wait_Ack();
//IIC_Stop();//产生一个停止条件
IIC_Start();
IIC_Send_Byte(I2C_Addr+1); res++; //进入接收模式
IIC_Wait_Ack();
res=IIC_Read_Byte(0);
IIC_Stop();//产生一个停止条件
return res;
}
/**************************实现函数********************************************
*函数原型: u8 IICreadBytes(u8 dev, u8 reg, u8 length, u8 *data)
*功 能: 读取指定设备 指定寄存器的 length个值
输入 dev 目标设备地址
reg 寄存器地址
length 要读的字节数
*data 读出的数据将要存放的指针
返回 读出来的字节数量
*******************************************************************************/
u8 IICreadBytes(u8 dev, u8 reg, u8 length, u8 *data){
u8 count = 0;
IIC_Start();
IIC_Send_Byte(dev); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(reg); //发送地址
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(dev+1); //进入接收模式
IIC_Wait_Ack();
for(count=0;count<length;count++){
if(count!=length-1)data[count]=IIC_Read_Byte(1); //带ACK的读数据
else data[count]=IIC_Read_Byte(0); //最后一个字节NACK
}
IIC_Stop();//产生一个停止条件
return count;
}
/**************************实现函数********************************************
*函数原型: u8 IICwriteBytes(u8 dev, u8 reg, u8 length, u8* data)
*功 能: 将多个字节写入指定设备 指定寄存器
输入 dev 目标设备地址
reg 寄存器地址
length 要写的字节数
*data 将要写的数据的首地址
返回 返回是否成功
*******************************************************************************/
u8 IICwriteBytes(u8 dev, u8 reg, u8 length, u8* data){
u8 count = 0;
IIC_Start();
IIC_Send_Byte(dev); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(reg); //发送地址
IIC_Wait_Ack();
for(count=0;count<length;count++){
IIC_Send_Byte(data[count]);
IIC_Wait_Ack();
}
IIC_Stop();//产生一个停止条件
return 1; //status == 0;
}
/**************************实现函数********************************************
*函数原型: u8 IICreadByte(u8 dev, u8 reg, u8 *data)
*功 能: 读取指定设备 指定寄存器的一个值
输入 dev 目标设备地址
reg 寄存器地址
*data 读出的数据将要存放的地址
返回 1
*******************************************************************************/
u8 IICreadByte(u8 dev, u8 reg, u8 *data){
*data=I2C_ReadOneByte(dev, reg);
return 1;
}
/**************************实现函数********************************************
*函数原型: unsigned char IICwriteByte(unsigned char dev, unsigned char reg, unsigned char data)
*功 能: 写入指定设备 指定寄存器一个字节
输入 dev 目标设备地址
reg 寄存器地址
data 将要写入的字节
返回 1
*******************************************************************************/
unsigned char IICwriteByte(unsigned char dev, unsigned char reg, unsigned char data){
return IICwriteBytes(dev, reg, 1, &data);
}
/**************************实现函数********************************************
*函数原型: u8 IICwriteBits(u8 dev,u8 reg,u8 bitStart,u8 length,u8 data)
*功 能: 读 修改 写 指定设备 指定寄存器一个字节 中的多个位
输入 dev 目标设备地址
reg 寄存器地址
bitStart 目标字节的起始位
length 位长度
data 存放改变目标字节位的值
返回 成功 为1
失败为0
*******************************************************************************/
u8 IICwriteBits(u8 dev,u8 reg,u8 bitStart,u8 length,u8 data)
{
u8 b;
if (IICreadByte(dev, reg, &b) != 0) {
u8 mask = (0xFF << (bitStart + 1)) | 0xFF >> ((8 - bitStart) + length - 1);
data <<= (8 - length);
data >>= (7 - bitStart);
b &= mask;
b |= data;
return IICwriteByte(dev, reg, b);
} else {
return 0;
}
}
/**************************实现函数********************************************
*函数原型: u8 IICwriteBit(u8 dev, u8 reg, u8 bitNum, u8 data)
*功 能: 读 修改 写 指定设备 指定寄存器一个字节 中的1个位
输入 dev 目标设备地址
reg 寄存器地址
bitNum 要修改目标字节的bitNum位
data 为0 时,目标位将被清0 否则将被置位
返回 成功 为1
失败为0
*******************************************************************************/
u8 IICwriteBit(u8 dev, u8 reg, u8 bitNum, u8 data){
u8 b;
IICreadByte(dev, reg, &b);
b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum));
return IICwriteByte(dev, reg, b);
}
//------------------End of File----------------------------
myiic.h文件
#ifndef __MYIIC_H
#define __MYIIC_H
#include "stm32f10x.h"
#include "delay.h"
//IO方向设置
#define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
//IO操作函数
#define IIC_SCL PBout(6) //SCL
#define IIC_SDA PBout(7) //SDA
#define READ_SDA PBin(7) //输入SDA
//IIC所有操作函数
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //发送IIC开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(u8 txd); //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); //IIC等待ACK信号
void IIC_Ack(void); //IIC发送ACK信号
void IIC_NAck(void); //IIC不发送ACK信号
unsigned char I2C_ReadOneByte(unsigned char I2C_Addr,unsigned char addr);
unsigned char IICwriteByte(unsigned char dev, unsigned char reg, unsigned char data);
u8 IICwriteBytes(u8 dev, u8 reg, u8 length, u8* data);
u8 IICwriteBits(u8 dev,u8 reg,u8 bitStart,u8 length,u8 data);
u8 IICwriteBit(u8 dev,u8 reg,u8 bitNum,u8 data);
u8 IICreadBytes(u8 dev, u8 reg, u8 length, u8 *data);
#endif
本次i2c接口使用的是pb6与pb7,大家都懂的。不在多解释了。
然后主要的来了。
下面附上我的tsl2561代码:
tsl2561.c文件
#include "tsl2561.h"
#include "delay.h"
#include "myiic.h"
#include <stdio.h>
#include <math.h>
uchar DataLow0,DataHigh0,DataLow1,DataHigh1,commad,Channel0,Channel1,temp;
void tsl2561_Init(void)
{
TSL2561_Write(0x80,0x03); //设置TSL2561未开启状态
}
void respons()
{
uchar i;
IIC_SCL=1;
delay_us(4);
while((IIC_SDA==1)&&(i<250))
i++;
IIC_SCL=0;
delay_us(4);
}
void TSL2561_Write(uchar command,uchar date)
{
IIC_Start();
IIC_Send_Byte(0x52);
respons();
IIC_Send_Byte(command);
respons();
IIC_Send_Byte(date);
respons();
IIC_Stop();
}
uchar TSL2561_Read(uchar command)
{
uchar date;
IIC_Start();
IIC_Send_Byte(0x52);
respons();
IIC_Send_Byte(command);
IIC_Ack();
IIC_Start();
IIC_Send_Byte(0x53);
IIC_Ack();
date = IIC_Read_Byte(0);
IIC_Stop();
return date;
}
u32 E=0; //光强
//这里非常关键 是官方提供的运算公式,根据这个公式得到我们需要的光强数据,并不是只需要读取传感器中的寄存器数据就足够了,要注意
void Read_Light(void)
{
DataLow0 = TSL2561_Read(DATA0LOW);
DataHigh0 = TSL2561_Read(DATA0HIGH);
Channel0 = 256*DataHigh0 + DataLow0;
DataLow1 = TSL2561_Read(DATA1LOW);
DataHigh1 = TSL2561_Read(DATA1HIGH);
Channel1 = 256*DataHigh1 + DataLow1;
delay_ms(100);
if(0.0<Channel1/Channel0&&Channel1/Channel0<=0.50)E=(0.0304*Channel0-0.062*Channel0*pow(Channel1/Channel0, 1.4));
if(0.50<Channel1/Channel0&&Channel1/Channel0<=0.61)E=(0.0224*Channel0-0.031*Channel1);
if(0.61<Channel1/Channel0&&Channel1/Channel0<=0.80)E=(0.0128*Channel0-0.0153*Channel1);
if(0.80<Channel1/Channel0&&Channel1/Channel0<=1.30)E=(0.00146*Channel0-0.00112*Channel1);
if(Channel1/Channel0>1.30)E=0;
delay_ms(100);
}
tsl2561.h文件
#ifndef TSL2561_H
#define TSL2561_H
#define uchar unsigned char
//命令控制寄存器
#define TIMING 0x81
#define DATA0LOW 0x8C
#define DATA0HIGH 0x8D
#define DATA1LOW 0x8E
#define DATA1HIGH 0x8F
void tsl2561_Init(void);
void TSL2561_Write(uchar command,uchar date);
uchar TSL2561_Read(uchar command);
void Read_Light(void);
#endif
好了,今天就到这了,学习是一件不容易的事情,做这件事整整花了我3个星期,大家也没必要急,一步一步慢慢来,只要有信心,总可以成功的。