共2条
1/1 1 跳转至页
430,IIC 请教冲大侠等430的朋友们?模拟IIC程序问题?
问
以下是我编的程序---用P47(SDA)P46(SCL)模拟IIC总线,SDA SCL已接上拉电阻,目的:将努num的16个数写到eeprom:24lc01中,然后将2401中的16个数再读到num1
??? 单独写读一个数,没问题;写读两个以上就不对了,请朋友们帮帮忙,小虾在此谢过!
#include <in430.h>
#include <msp430x44x.h>
#define ERRORCOUNT 10
unsigned char num[16]={88,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
unsigned char num1[16];
unsigned char CY;
void IICStart(void);
void IICStop(void);
void delay(void);
void IICAck(void);
void IICNoAck(void);
unsigned char IICRecAck(void);
void IICSendByte(unsigned char sendbyte);
unsigned char IICReceiveByte(void);
void Read_word(unsigned int Address,
unsigned char ControlByte,unsigned char j);
void Write_word(unsigned int Address,
unsigned char ControlByte,unsigned char j);
void delay(void)
{
_NOP();
_NOP();
_NOP();
_NOP();
}
void IICStart(void)
{
P4DIR|=0Xc0;//SDA=SCL=0占用总线
P4OUT&=0X3F;
P4DIR&=0X7F;//SDA=1
delay();
P4DIR&=0XBF;//SCL=1
delay();
P4DIR|=0X80;//SDA=0(前面P4OUT&=0X3F;)
delay();
P4DIR|=0X40;//SCL=0关掉时钟线
delay();
}
void IICStop(void)//出现一个SCL高SDA由低到高的脉冲
{
P4DIR|=0Xc0;//原为0x80
P4OUT&=0X3f;//HOUJIA
P4DIR|=0X80;//SDA=0
delay();
P4DIR&=0XBF;//SCL=1
delay();
P4DIR&=0X7F;//SDA=1
delay();
P4DIR|=0X80;
delay();
P4DIR|=0X40;
delay();
}
void IICAck(void)//对IIC总线产生应答
{
P4DIR|=0Xc0;//SDA=SCL=0占用总线
P4OUT&=0X3F;
P4DIR|=0X80;//SDA=0
delay();
P4DIR&=0XBF;//SCL=1;
delay();
P4DIR|=0X40;//SCL=0
delay();
P4DIR&=0X7F;//SDA=1
delay();
}
void IICNoAck(void)//不对IIC总线产生应答
{
P4DIR|=0Xc0;//SDA=SCL=0占用总线
P4OUT&=0X3F;
P4DIR&=0X7F;//SDA=1
delay();
P4DIR&=0XBF;//SCL=1;
delay();
P4DIR|=0X40;
delay();
P4DIR|=0X80;
delay();
}
unsigned char IICRecAck(void)//返回1无应答
{
P4DIR|=0X40;
P4OUT&=0XBF; //SCL=0
P4DIR&=0X7F;//SDA=1
P4DIR&=0XBF;//SCL=1
delay();
if((P4IN&0X80)==0x80) CY=1;
else CY=0; //因为返回值总是放在CY中的
P4DIR|=0X40;//SCL=0
return(CY);
}
void IICSendByte(unsigned char sendbyte)
{
unsigned char j;
P4DIR|=0Xc0;//SDA=SCL=0占用总线
P4OUT&=0X3F;
for(j=0;j<8;j++)//,高位再先
{
if((sendbyte&0x80)==0x80)//WR1
{
P4DIR&=0X7F;//SDA=1
delay();
P4DIR&=0XBF;//SCL=1//通知eeprom接收数据,SCL由高到底
delay();
delay();
P4DIR|=0X40;//SCL=0
delay();
}
else //wr0
{
P4DIR|=0X80;//SDA=0
delay();
P4DIR&=0XBF;//SCL=1
delay();
delay();
P4DIR|=0X40;//SCL=0
delay();
}
sendbyte<<=1;
}
}
unsigned char IICReceiveByte(void)
{
unsigned char receivebyte=0;
unsigned char data=0;
unsigned char i;
P4DIR|=0Xc0;//SDA=SCL=0占用总线
P4OUT&=0X3F;
for(i=0;i<8;i++)// 波形图中SCL由低到高接受
{
P4DIR&=0X7F;//SDA=1 释放总线
delay();
P4DIR|=0X40;//SCL=0;
delay();
delay();
P4DIR&=0XBF;//houjia SCL=1
delay();
if((P4IN&0X80)==0x80) receivebyte=1;
else receivebyte=0;
delay();
data=(data<<1)|receivebyte;
}
return(data);
}
void Write_word(unsigned int Address,
unsigned char ControlByte,unsigned char j)
{
unsigned char i,l,m;
unsigned char errorflag=1;
for(i=0;i<ERRORCOUNT;i++)
{
IICStart();
IICSendByte(ControlByte&0xfe);//发送控制字
if(IICRecAck()) continue;
IICSendByte((unsigned char)Address);//发送地字节地址
if(IICRecAck()) continue;
for(l=0;l<j;l++)
{
IICSendByte(num[l]);
for(m=0;m<ERRORCOUNT;m++)
{
if(IICRecAck()) continue;
else m=ERRORCOUNT-1;
}
}
}
IICStop();
}
void Read_word(unsigned int Address,
unsigned char ControlByte,unsigned char j)
{
unsigned char i,l,add;
add=0;
for(i=0;i<ERRORCOUNT;i++)
{
IICStart();
IICSendByte(ControlByte&0xfe);//发送控制字
if(IICRecAck()) continue;
IICSendByte((unsigned char)Address);//发送地字节地址
if(IICRecAck()) continue;
IICStart();
IICSendByte(ControlByte);
if(IICRecAck()) continue;
for(l=0;l<j-1;l++)
{
num1[l]=IICReceiveByte();
IICAck();
}
num1[j-1]=IICReceiveByte();
IICNoAck();
break;
}
IICStop();
}
void main(void)
{
unsigned char time=0;
unsigned int i;
WDTCTL = WDTPW + WDTHOLD;
P6SEL&=0X7F;
P4SEL&=0X3F;
P4DIR|=0Xc0;
P4OUT&=0X3f; // ;要发送数据个数为15个
do
{
if(!time)
{
Write_word(0xf0,0xa0,16);
for(i=0;i<1000;i++);
Read_word(0xf0,0xa1,16);
time=1;
}
}
while(1);
} 答 1: 我以前发过一个贴子,上面有I2C的程序,你可以参考一下,就这样把一个大程序贴上来让别人看。恐怕没有人有那么多时间闲着给你看錒! 答 2: 在连续写程序和读程序之间加上几个毫秒的延时 答 3: 连续读出时,是需要加延时的。同意楼上的看法 答 4: 连续读应该不要延时吧!
循环"连续写"要加延时 答 5: 注意第一次操作完后的端口设置回原状态。 答 6: 我用的是24C32,P3.3(SDA),P3.4(SCL),开始不行,后来参考了你的程序,经测试连续写(page write)没问题.程序如下:
void start_i2c(void)
{
P3DIR |= 0x18;
P3OUT &= 0xe7; //SDA=SCL=LOW,10us
P3DIR &= 0xf7; //SDA=HIGH
P3DIR &= 0xef; //SCL=HIGH
P3DIR |= 0x08; //SDA=LOW
P3DIR |= 0x10; //SCL=LOW
}
void stop_i2c(void)
{
P3DIR |= 0x18;
P3OUT &= 0xe7; //SDA=SCL=LOW
P3DIR |= 0x08; //SDA=LOW
P3DIR &= 0xef; //SCL=HIGH
P3DIR &= 0xf7; //SDA=HIGH
P3DIR |= 0x18; //SCL=SDA=LOW
}
BOOL receive_ack(void)
{
BOOL flag = FALSE;
P3DIR |= 0x10;
P3OUT &= 0xef; //SCL=LOW
P3DIR &= 0xf7; //SDA=HIGH
P3DIR &= 0xef; //SCL=HIGH
if ((P3IN & 0x08) == 0x08)
{
flag = TRUE;
}
P3DIR |= 0x10;
return flag;
}
void send_i2c(ABYTE i_data)
{
ABYTE i;
P3DIR |= 0x18;
P3OUT &= 0xe7; //SDA=SCL=LOW
for (i=0;i<8;i++)
{
if((i_data & 0x80) == 0x80)
{
P3DIR &= 0xf7;
}
else
{
P3DIR |= 0x08;
}
P3DIR &= 0xef; //SCL=HIGH
P3DIR |= 0x10; //SLC=LOW
i_data <<= 1;
}
}
ABYTE receive_i2c(void)
{
ABYTE i=0;
ABYTE out_data=0;
P3DIR |= 0x18;
P3OUT &= 0xe7; //SDA=SCL=LOW
for (i=0;i<8;i++)
{
out_data <<= 1;
P3DIR &= 0xf7;
P3DIR |= 0x10; //SCL=LOW
P3DIR &= 0xef;
if ((P3IN & 0x08) == 0x08)
{
out_data++;
}
}
return out_data;
}
BOOL write_address(AWORD address)
{
start_i2c();
send_i2c(WRITE);
if (receive_ack() == TRUE)
{
return FALSE;
}
else
{
send_i2c(MSB(address));
if (receive_ack() == TRUE)
{
return FALSE;
}
else
{
send_i2c(LSB(address));
if (receive_ack() == TRUE)
{
return FALSE;
}
else
{
return TRUE;
}
}
}
}
BOOL byte_write(AWORD address,ABYTE user_data)
{
BOOL flag=FALSE;
if (write_address(address) == TRUE)
{
send_i2c(user_data);
if (receive_ack() == FALSE)
{
flag = TRUE;
}
}
stop_i2c();
return flag;
}
ABYTE random_read(AWORD address)
{
ABYTE data_receive=0x00;
if (write_address(address) == TRUE)
{
start_i2c();
send_i2c(READ);
if (receive_ack() == FALSE)
{
data_receive = receive_i2c();
if (receive_ack() == FALSE)
{
data_receive = 0x00;
}
}
}
stop_i2c();
return data_receive;
}
BOOL page_write(AWORD address,ABYTE *data_buf,ABYTE data_length)
{
ABYTE i=0;
ABYTE write_flag = TRUE;
if (write_address(address) == TRUE)
{
do
{
send_i2c(*(data_buf + i));
if (receive_ack() == TRUE)
{
stop_i2c();
write_flag = FALSE;
return write_flag;
}
}while(write_flag && (++i != data_length));
}
else
{
write_flag = FALSE;
}
stop_i2c();
return write_flag;
} 答 7: 想问一下,改变方向寄存器的值,例如上面的P3DIR |= 0x08; //SDA=LOW 是改变与SDA接的那个引脚为输出模式,那么就等于给SDA一个低电平了吗?这个语句和P3OUT &=0xf7;在
P3.3位输出模式时,有什么不同吗?
谢谢! 答 8: 一样的.当设置好P3OUT &= 0xf7后,P3OUT的值就不会因为P3DIR的改变而改变.所以只要P3.3是输出模式时,就会输出低电平.
??? 单独写读一个数,没问题;写读两个以上就不对了,请朋友们帮帮忙,小虾在此谢过!
#include <in430.h>
#include <msp430x44x.h>
#define ERRORCOUNT 10
unsigned char num[16]={88,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
unsigned char num1[16];
unsigned char CY;
void IICStart(void);
void IICStop(void);
void delay(void);
void IICAck(void);
void IICNoAck(void);
unsigned char IICRecAck(void);
void IICSendByte(unsigned char sendbyte);
unsigned char IICReceiveByte(void);
void Read_word(unsigned int Address,
unsigned char ControlByte,unsigned char j);
void Write_word(unsigned int Address,
unsigned char ControlByte,unsigned char j);
void delay(void)
{
_NOP();
_NOP();
_NOP();
_NOP();
}
void IICStart(void)
{
P4DIR|=0Xc0;//SDA=SCL=0占用总线
P4OUT&=0X3F;
P4DIR&=0X7F;//SDA=1
delay();
P4DIR&=0XBF;//SCL=1
delay();
P4DIR|=0X80;//SDA=0(前面P4OUT&=0X3F;)
delay();
P4DIR|=0X40;//SCL=0关掉时钟线
delay();
}
void IICStop(void)//出现一个SCL高SDA由低到高的脉冲
{
P4DIR|=0Xc0;//原为0x80
P4OUT&=0X3f;//HOUJIA
P4DIR|=0X80;//SDA=0
delay();
P4DIR&=0XBF;//SCL=1
delay();
P4DIR&=0X7F;//SDA=1
delay();
P4DIR|=0X80;
delay();
P4DIR|=0X40;
delay();
}
void IICAck(void)//对IIC总线产生应答
{
P4DIR|=0Xc0;//SDA=SCL=0占用总线
P4OUT&=0X3F;
P4DIR|=0X80;//SDA=0
delay();
P4DIR&=0XBF;//SCL=1;
delay();
P4DIR|=0X40;//SCL=0
delay();
P4DIR&=0X7F;//SDA=1
delay();
}
void IICNoAck(void)//不对IIC总线产生应答
{
P4DIR|=0Xc0;//SDA=SCL=0占用总线
P4OUT&=0X3F;
P4DIR&=0X7F;//SDA=1
delay();
P4DIR&=0XBF;//SCL=1;
delay();
P4DIR|=0X40;
delay();
P4DIR|=0X80;
delay();
}
unsigned char IICRecAck(void)//返回1无应答
{
P4DIR|=0X40;
P4OUT&=0XBF; //SCL=0
P4DIR&=0X7F;//SDA=1
P4DIR&=0XBF;//SCL=1
delay();
if((P4IN&0X80)==0x80) CY=1;
else CY=0; //因为返回值总是放在CY中的
P4DIR|=0X40;//SCL=0
return(CY);
}
void IICSendByte(unsigned char sendbyte)
{
unsigned char j;
P4DIR|=0Xc0;//SDA=SCL=0占用总线
P4OUT&=0X3F;
for(j=0;j<8;j++)//,高位再先
{
if((sendbyte&0x80)==0x80)//WR1
{
P4DIR&=0X7F;//SDA=1
delay();
P4DIR&=0XBF;//SCL=1//通知eeprom接收数据,SCL由高到底
delay();
delay();
P4DIR|=0X40;//SCL=0
delay();
}
else //wr0
{
P4DIR|=0X80;//SDA=0
delay();
P4DIR&=0XBF;//SCL=1
delay();
delay();
P4DIR|=0X40;//SCL=0
delay();
}
sendbyte<<=1;
}
}
unsigned char IICReceiveByte(void)
{
unsigned char receivebyte=0;
unsigned char data=0;
unsigned char i;
P4DIR|=0Xc0;//SDA=SCL=0占用总线
P4OUT&=0X3F;
for(i=0;i<8;i++)// 波形图中SCL由低到高接受
{
P4DIR&=0X7F;//SDA=1 释放总线
delay();
P4DIR|=0X40;//SCL=0;
delay();
delay();
P4DIR&=0XBF;//houjia SCL=1
delay();
if((P4IN&0X80)==0x80) receivebyte=1;
else receivebyte=0;
delay();
data=(data<<1)|receivebyte;
}
return(data);
}
void Write_word(unsigned int Address,
unsigned char ControlByte,unsigned char j)
{
unsigned char i,l,m;
unsigned char errorflag=1;
for(i=0;i<ERRORCOUNT;i++)
{
IICStart();
IICSendByte(ControlByte&0xfe);//发送控制字
if(IICRecAck()) continue;
IICSendByte((unsigned char)Address);//发送地字节地址
if(IICRecAck()) continue;
for(l=0;l<j;l++)
{
IICSendByte(num[l]);
for(m=0;m<ERRORCOUNT;m++)
{
if(IICRecAck()) continue;
else m=ERRORCOUNT-1;
}
}
}
IICStop();
}
void Read_word(unsigned int Address,
unsigned char ControlByte,unsigned char j)
{
unsigned char i,l,add;
add=0;
for(i=0;i<ERRORCOUNT;i++)
{
IICStart();
IICSendByte(ControlByte&0xfe);//发送控制字
if(IICRecAck()) continue;
IICSendByte((unsigned char)Address);//发送地字节地址
if(IICRecAck()) continue;
IICStart();
IICSendByte(ControlByte);
if(IICRecAck()) continue;
for(l=0;l<j-1;l++)
{
num1[l]=IICReceiveByte();
IICAck();
}
num1[j-1]=IICReceiveByte();
IICNoAck();
break;
}
IICStop();
}
void main(void)
{
unsigned char time=0;
unsigned int i;
WDTCTL = WDTPW + WDTHOLD;
P6SEL&=0X7F;
P4SEL&=0X3F;
P4DIR|=0Xc0;
P4OUT&=0X3f; // ;要发送数据个数为15个
do
{
if(!time)
{
Write_word(0xf0,0xa0,16);
for(i=0;i<1000;i++);
Read_word(0xf0,0xa1,16);
time=1;
}
}
while(1);
} 答 1: 我以前发过一个贴子,上面有I2C的程序,你可以参考一下,就这样把一个大程序贴上来让别人看。恐怕没有人有那么多时间闲着给你看錒! 答 2: 在连续写程序和读程序之间加上几个毫秒的延时 答 3: 连续读出时,是需要加延时的。同意楼上的看法 答 4: 连续读应该不要延时吧!
循环"连续写"要加延时 答 5: 注意第一次操作完后的端口设置回原状态。 答 6: 我用的是24C32,P3.3(SDA),P3.4(SCL),开始不行,后来参考了你的程序,经测试连续写(page write)没问题.程序如下:
void start_i2c(void)
{
P3DIR |= 0x18;
P3OUT &= 0xe7; //SDA=SCL=LOW,10us
P3DIR &= 0xf7; //SDA=HIGH
P3DIR &= 0xef; //SCL=HIGH
P3DIR |= 0x08; //SDA=LOW
P3DIR |= 0x10; //SCL=LOW
}
void stop_i2c(void)
{
P3DIR |= 0x18;
P3OUT &= 0xe7; //SDA=SCL=LOW
P3DIR |= 0x08; //SDA=LOW
P3DIR &= 0xef; //SCL=HIGH
P3DIR &= 0xf7; //SDA=HIGH
P3DIR |= 0x18; //SCL=SDA=LOW
}
BOOL receive_ack(void)
{
BOOL flag = FALSE;
P3DIR |= 0x10;
P3OUT &= 0xef; //SCL=LOW
P3DIR &= 0xf7; //SDA=HIGH
P3DIR &= 0xef; //SCL=HIGH
if ((P3IN & 0x08) == 0x08)
{
flag = TRUE;
}
P3DIR |= 0x10;
return flag;
}
void send_i2c(ABYTE i_data)
{
ABYTE i;
P3DIR |= 0x18;
P3OUT &= 0xe7; //SDA=SCL=LOW
for (i=0;i<8;i++)
{
if((i_data & 0x80) == 0x80)
{
P3DIR &= 0xf7;
}
else
{
P3DIR |= 0x08;
}
P3DIR &= 0xef; //SCL=HIGH
P3DIR |= 0x10; //SLC=LOW
i_data <<= 1;
}
}
ABYTE receive_i2c(void)
{
ABYTE i=0;
ABYTE out_data=0;
P3DIR |= 0x18;
P3OUT &= 0xe7; //SDA=SCL=LOW
for (i=0;i<8;i++)
{
out_data <<= 1;
P3DIR &= 0xf7;
P3DIR |= 0x10; //SCL=LOW
P3DIR &= 0xef;
if ((P3IN & 0x08) == 0x08)
{
out_data++;
}
}
return out_data;
}
BOOL write_address(AWORD address)
{
start_i2c();
send_i2c(WRITE);
if (receive_ack() == TRUE)
{
return FALSE;
}
else
{
send_i2c(MSB(address));
if (receive_ack() == TRUE)
{
return FALSE;
}
else
{
send_i2c(LSB(address));
if (receive_ack() == TRUE)
{
return FALSE;
}
else
{
return TRUE;
}
}
}
}
BOOL byte_write(AWORD address,ABYTE user_data)
{
BOOL flag=FALSE;
if (write_address(address) == TRUE)
{
send_i2c(user_data);
if (receive_ack() == FALSE)
{
flag = TRUE;
}
}
stop_i2c();
return flag;
}
ABYTE random_read(AWORD address)
{
ABYTE data_receive=0x00;
if (write_address(address) == TRUE)
{
start_i2c();
send_i2c(READ);
if (receive_ack() == FALSE)
{
data_receive = receive_i2c();
if (receive_ack() == FALSE)
{
data_receive = 0x00;
}
}
}
stop_i2c();
return data_receive;
}
BOOL page_write(AWORD address,ABYTE *data_buf,ABYTE data_length)
{
ABYTE i=0;
ABYTE write_flag = TRUE;
if (write_address(address) == TRUE)
{
do
{
send_i2c(*(data_buf + i));
if (receive_ack() == TRUE)
{
stop_i2c();
write_flag = FALSE;
return write_flag;
}
}while(write_flag && (++i != data_length));
}
else
{
write_flag = FALSE;
}
stop_i2c();
return write_flag;
} 答 7: 想问一下,改变方向寄存器的值,例如上面的P3DIR |= 0x08; //SDA=LOW 是改变与SDA接的那个引脚为输出模式,那么就等于给SDA一个低电平了吗?这个语句和P3OUT &=0xf7;在
P3.3位输出模式时,有什么不同吗?
谢谢! 答 8: 一样的.当设置好P3OUT &= 0xf7后,P3OUT的值就不会因为P3DIR的改变而改变.所以只要P3.3是输出模式时,就会输出低电平.
共2条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
vscode+cmake搭建雅特力AT32L021开发环境被打赏30分 | |
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 |