打印
[AVR单片机]

用AVR普通IO口模拟IIC

[复制链接]
10073|21
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
沙发
hotpower| | 2011-5-19 00:34 | 只看该作者

使用特权

评论回复
板凳
zhao9183| | 2011-5-19 22:48 | 只看该作者
呵呵,对啊,现成的

使用特权

评论回复
地板
宇航3000|  楼主 | 2011-5-20 11:38 | 只看该作者
我也想用现成的啊,但是我现在用的这个芯片不是完整的IIC协议啊, 读和写完全一样,只是用第一个字节的最后一位高和低来区分, 所以只能模拟一个了

iicd.JPG (46.58 KB )

iicd.JPG

使用特权

评论回复
5
andymmbbs| | 2011-5-20 11:44 | 只看该作者
要顶要顶的!!!!!!!!!!1

使用特权

评论回复
6
宇航3000|  楼主 | 2011-5-20 14:48 | 只看该作者
多谢帮顶。
我现在用普通IO口模拟,还不成功呢

使用特权

评论回复
7
mugenwon| | 2011-5-21 20:28 | 只看该作者
今天就做了你要做的事情。以前用c来写了堆专门读IIC的代码,后来想修改来在AVR用,结果太麻烦了最后还是用硬件处理算了!

使用特权

评论回复
8
宇航3000|  楼主 | 2011-5-21 23:09 | 只看该作者
今天就做了你要做的事情。以前用c来写了堆专门读IIC的代码,后来想修改来在AVR用,结果太麻烦了最后还是用硬件处理算了!
mugenwon 发表于 2011-5-21 20:28


最后成功了吗,还是最后也是用的AVR自己的TWI寄存器来实现的?
你认为麻烦在哪里了,我感觉AVR每次输入和输出都要重新来设置一下,不能直接读。很麻烦的

使用特权

评论回复
9
hotpower| | 2011-5-22 19:48 | 只看该作者
可以模拟,但要注意开漏

使用特权

评论回复
10
宇航3000|  楼主 | 2011-5-23 10:02 | 只看该作者
可以模拟,但要注意开漏
hotpower 发表于 2011-5-22 19:48


怎么开漏呢, 是设置输入输出吗

使用特权

评论回复
11
宇航3000|  楼主 | 2011-5-23 13:59 | 只看该作者
终于弄出来了,用IO口模拟的,但是最后一位不知道为什么总是为0呢
#include<avr/io.h>

#define uint unsigned int
#define uchar unsigned char
#define BIT(x) (1<<x)

//PORTA0=SCL
//PORTA1=SDA
void delay1(uint n)
{  uint i,j;
for(i=0;i<n;i++)
        for(j=0;j<367;j++);
}

void delay()
{  asm("NOP"); asm("NOP");asm("NOP"); }

void start()  //开始信号
{       
        PORTA|=BIT(1);
        delay();
        PORTA|=BIT(0);
        delay(); asm("NOP");asm("NOP");
        PORTA&=~BIT(1);
        delay(); asm("NOP");asm("NOP");
        PORTA&=~BIT(0);
    delay();

}

void stop()   //停止
{
        PORTA&=~BIT(1);
        delay();
        PORTA|=BIT(0);
        delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP");
        PORTA|=BIT(1);
        delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP");
}

void respons()  //应答
{
        //uchar i;
        PORTA&=~BIT(1);
        delay();
        PORTA|=BIT(0);
        delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP");
        PORTA&=~BIT(0);
        delay();

}

/*
void respons_send()  //应答
{
        uchar i;
        PORTA|=BIT(0);
        delay();
       
        while(((PORA&BIT(1))==1)&&(i<250))i++;
        PORTA&=~BIT(0);
        delay();
}
*/

void init()
{
        PORTA|=BIT(1);
        delay();
        PORTA|=BIT(0);
        delay();
}

void write_byte(uchar date)
{
        uchar i,temp;
       
  for(i=0;i<8;i++)  //要传送的数据长度为8位
    {
     if((date<<i)&0x80)
         PORTA|=BIT(1);  //判断发送位
       else  PORTA&=~BIT(1);               
      delay();
     PORTA|=BIT(0);               //置时钟线为高,通知被控器开始接收数据位
     delay(); delay();           //在此期间取走数据
     PORTA&=~BIT(0);
         delay(); delay();   
    }

    PORTA&=~BIT(0);
        delay();
        PORTA|=BIT(1);
        delay();
}

uchar read_byte()
{
        uchar i,k,temp=0;
        PORTA&=~BIT(0);
        delay();
        PORTA|=BIT(1);   //释放数据线SDA
        delay();

        for(i=0;i<8;i++)
        {
                PORTA|=BIT(0);
                delay();
                DDRA&=~BIT(1);
                PORTA|=BIT(1);
                       
                delay();
                temp=(PINA&0x02);
                k=((k<<1)|temp);
        //        DDRA|=BIT(1);

                PORTA&=~BIT(0);
                delay();       
        }

        DDRA|=BIT(1);
        delay();

        return k;
}

void write_add(uchar address,uchar date)
{
        start();
        write_byte(0x56);
        respons();
        write_byte(address);
        respons();
        write_byte(date);
        respons();
        stop();
}

uchar read_add(uchar address)
{
        uchar date;
        start();
        write_byte(0x57);
        respons();
        write_byte(address);
        respons();
        date=read_byte();
        stop();
        return date;
}

main()
{
    DDRA=0xff;
        DDRB=0xFF;


    init();
        write_add(0x03,0x3f);
        delay();
        write_add(0x00,0x41);
    delay(1);
        write_add(0x08,0xab);
        delay1(10);

        PORTB=read_add(0x08);
        delay();
//        PORTB=0XFF;

        delay();

        while(1);
}

使用特权

评论回复
12
宇航3000|  楼主 | 2011-5-23 22:35 | 只看该作者
为什么最后一位会丢失呢,比如我写入的是0xab , 读出来就变成了0xaa , 百思不得其解

使用特权

评论回复
13
宇航3000|  楼主 | 2011-5-23 23:47 | 只看该作者
自己搞定了,找到是哪条语句存在问题了, temp=(PINA&0x02);
                k=((k<<1)|temp);

应该改成这样: temp=(PINA&0x02);   // 读进SDA的值即PA1口
                if(temp)            // 如果读到的高电平即为真
                k=((k<<1)|0x01);    // 则将上一次的K左移一位,地位补1
                else
                k=k<<1;              // 否则地位补0

使用特权

评论回复
14
Light_David| | 2011-5-25 01:57 | 只看该作者
看到AVR的位操作,有种说不出的感觉...:@
hotpower大师所说的软I2C开漏那是一定要有滴
端口寄存器永久设置为0,用方向寄存器当端口寄存器发送数据不就OVER了...

使用特权

评论回复
15
hotpower| | 2011-5-26 15:56 | 只看该作者
楼上说对了。真双向模拟io时,要用方向做0和1的控制的,输出要恒为0的。
不知楼主明白否?

使用特权

评论回复
16
宇航3000|  楼主 | 2011-5-29 22:52 | 只看该作者
楼上说对了。真双向模拟io时,要用方向做0和1的控制的,输出要恒为0的。
不知楼主明白否?
hotpower 发表于 2011-5-26 15:56

不是太明白~~

不过我看了一个论坛有这样写:

模拟OC结构的IIC总线的技巧:

虽然AVR大多带有硬件IIC接口,但也有需要使用软件模拟IIC的情况

可以通过使用外部上拉电阻+控制DDRx的方法来实现OC结构的IIC总线。
          IIC的速度跟上拉电阻有关,内部的上拉电阻阻值较大(Rup=20K~50K),只能用于低速的场合
          #define SDA     0    //PC0
          #define SCL     1    //PC1
          (
程序初始化设定  SDA和SCL都是 PORT=0,DDR=0)
          #define  SDA_0()   DDRA|=(1<<SDA)    //输出低电平

          #define  SDA_1()   DDRA&=~(1<<SDA)   //输入,外部电阻上拉为高电平
          #define  SCL_0()   DDRA|=(1<<SCL)    //输出低电平
          #define  SCL_1()   DDRA&=~(1<<SCL)   //输入,外部电阻上拉为高电平

          使用上面的SDA_0()/SDA_1()/SCL_0()/SCL_1()宏即可,直观,而且效率跟汇编是一样的

使用特权

评论回复
17
yangganglone| | 2013-12-19 13:24 | 只看该作者
宇航3000 发表于 2011-5-23 23:47
自己搞定了,找到是哪条语句存在问题了, temp=(PINA&0x02);
                k=((k

您好:我现在也在用avr做软件模拟iic,但是遇到了点麻烦,想向您请教一下,我的qq是971947289

使用特权

评论回复
18
yls0221| | 2014-4-24 10:20 | 只看该作者
学习一下

使用特权

评论回复
19
lantian510| | 2014-5-5 19:33 | 只看该作者
把51的I2C程序拿过来,改一下就可以呢

使用特权

评论回复
20
perry_peng| | 2014-5-6 08:35 | 只看该作者
宇航3000 发表于 2011-5-20 11:38
我也想用现成的啊,但是我现在用的这个芯片不是完整的IIC协议啊, 读和写完全一样,只是用第一个字节的最后 ...

I2C也是用地址的最低位来决定是读或写。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

30

主题

165

帖子

2

粉丝