大家好:我最近在做MSP430F149的I2C通讯, 从HTU21D模块中读取湿度,用P3.3和P3.3口做SCL和SDA。从单片机向模块写地址和命令时,模块能正确响应,即能返回ACK,但是读到的数据都是0xff。求高手解答~!万分感激~!
下面是我编写的代码,只读取湿度:
#include <msp430x14x.h>
#include "config.h"
#define SDA_1 P3OUT |= BIT3
#define SDA_0 P3OUT &= ~BIT3
#define SCL_1 P3OUT |= BIT2
#define SCL_0 P3OUT &= ~BIT2
#define DIR_IN P3DIR &= ~BIT3; SDA_1;
#define DIR_OUT P3DIR |= BIT3;
#define SDA_IN ((P3IN>>3)&0x01)
uchar ack; //0 为ACK,1 为NACK
uint shidu;
void I2C_init(void)
{
P3SEL=0;
P3DIR |= BIT2+BIT3; //输出
}
void I2C_Start()
{
DIR_OUT;
SDA_1; //发送起始条件的数据信号
SCL_1;
delay_us(10); //起始条件建立时间大于4.7us,延时
SDA_0; //发送起始信号
delay_us(10); //起始条件建立时间大于4us,延时
SCL_0; //钳住I2C总线准备发送或接收数据
delay_us(10);
}
void I2C_Stop()
{
DIR_OUT;
SDA_0; //发送结束条件的数据信号
delay_us(10);
SCL_1; //发送结束条件的时钟信号
delay_us(10); //结束条件建立时间大于4us,延时
SDA_1; //发送I2C总线结束信号
delay_us(10);
}
//完成IIC的主机应答操作
void Mack()
{
DIR_OUT;
SDA_0; //发送结束条件的数据信号
delay_us(10);
SCL_1; //发送结束条件的时钟信号
delay_us(10); //结束条件建立时间大于4us,延时
SCL_0;
delay_us(10);
SDA_1;
delay_us(10);
}
//完成IIC的主机无应答操作
void MNack()
{
DIR_OUT;
SDA_1;
delay_us(10);
SCL_1;
delay_us(10);
SCL_0;
delay_us(10);
SDA_0;
delay_us(10);
}
//从机发送的应答信号
void check()
{
SDA_1; //释放数据线
delay_us(20);
SCL_1; //发送结束条件的时钟信号
delay_us(20);
DIR_IN;
ack=SDA_IN;
SCL_0;
delay_us(20);
DIR_OUT;
}
uchar I2C_writebyte(uchar a)
{
uchar i;
DIR_OUT;
//SDA_0;
//delay_us(10);
for(i=0;i<8;i++)
{
if((a<<i)&0x80)
{
SDA_1;
}
else
{
SDA_0;
}
delay_us(20);
SCL_1;
delay_us(20);
SCL_0;
delay_us(20);
}
SCL_0;
delay_us(20);
check();
return ack;
}
uchar I2C_readbyte(void)//读一个字节
{
uchar i,k; //i读取位数,k存储读到的字节
k=0x00;
DIR_IN;
for(i=0;i<8;i++)
{
SCL_0;//拉低SCL,使发送端可以把数据放在SDA上
delay_us(20);
SDA_1;//释放数据线
delay_us(20);
SCL_1;//上升沿时,IIC设备将数据放在sda线上,并在高电平期间数据已经稳定,可以接收啦
delay_us(20);
//DIR_IN;
k=(k<<1);
if(SDA_IN==0)
{
k=k+0x00;
}
else
{k=k+0x01;}
//DIR_OUT;
SCL_0;//拉低SCL,使发送端可以把数据放在SDA上
delay_us(20);
}
return k;
}
ulong I2C_readword(uchar address)//读取一个16为数字
{
ulong date;
uchar MSB,LSB;
I2C_Start();//启动
if(I2C_writebyte(0x80)==0)
{
if(I2C_writebyte(address)==0) //发送芯片内地址
{
delay_ms(20);
I2C_Start();//启动
while(I2C_writebyte(0x81)==0);
MSB=I2C_readbyte();//获取数据
Mack();
LSB=I2C_readbyte();//获取数据
MNack();
I2C_Stop();//停止
}
else
{I2C_readword(address);}
}
else
{
I2C_readword(address);
}
date=(ulong)MSB*256+(LSB&0xfc);
delay_us(20);
return date;//返回数据
}
void main()
{
WDT_Init(); //看门狗设置
Clock_Init(); //系统时钟设置
I2C_init();
Close_LED(); //关闭LED数码管,避免显示乱码
delay_ms(100); //延时100ms
LCD_init(); //液晶参数初始化设置
LCD_clear(); //清屏
delay_us(5);
while(1)
{
ulong m=I2C_readword(0xf5);
m=m*1250/65536-60;
shidu=(uint)m;
}
}
此帖出自
小平头技术问答
谢谢~!
确实是 写完地址后再次启动 时出错了。修改后可以正常读数了~!
修改后的I2C_readword(uchar)函数是:
ulong I2C_readword(uchar address)//读取一个16位数字
{
ulong date;
uchar MSB,LSB;
I2C_Start();//启动
if(I2C_writebyte(0x80)==0)
{
if(I2C_writebyte(address)==0) //发送芯片内地址
{
delay_ms(10);
I2C_Start();//启动
while(I2C_writebyte(0x81)==1)
{
delay_us(100);
I2C_Start();
}
MSB=I2C_readbyte();//获取数据
Mack();
LSB=I2C_readbyte();//获取数据
MNack();
I2C_Stop();//停止
LSB=LSB&0xfc;
}
else
{I2C_readword(address);}
}
else
{
I2C_readword(address);
}
date=(ulong)MSB*256+LSB;
delay_us(10);
return date;//返回数据
}
一周热门 更多>