[AVR单片机] 怎么在MEGA128上编写模拟IIC啊

[复制链接]
4444|12
 楼主| Karlshen 发表于 2009-12-11 23:12 | 显示全部楼层 |阅读模式
这里有个模拟IIC程序,可是最后用示波器观测,得不到我想要的IIC。有高手知道一下吗?
#include <iom128v.h>
#include <macros.h>
#define SDAI DDRC&=0xfd
#define SDAO DDRC|=0x02
#define SDAR PINC&0x02
#define SDA1 PORTC|=0x02
#define SDA0 PORTC&=0xfd
#define SCL1 PORTC|=0x01
#define SCL0 PORTC&=0xfe
#define SCLO DDRC|=0X01
unsigned char SystemError,AskFlag;
void io_init(void) {

   DDRA = 0x00;                                       
   PORTA = 0xFF;                                       
   DDRB = 0x00;                           
   PORTB = 0xFF;                    
   DDRC = 0xFF;                                    
   PORTC = 0xFF;
   DDRD = 0x00;
   PORTD = 0xFF;
   DDRE = 0x00;
   PORTE = 0xFF;
   DDRF = 0x00;
   PORTF = 0xFF;
   DDRG = 0x00;
   PORTG = 0xFF;
}
void delay(unsigned char n)
{
    unsigned char i;
    for(i=0;i<n;i++) ;
}
// 函数名称: iic_start()
// 函数功能: 启动I2C总线子程序
void iic_start(void)
{     
    SDAO;
      SCLO;
    SDA1;
    delay(10);
      SCL1;
    delay(15);
    SDA0;
    delay(10);
    SCL0;
}
/*===================================================================================*/
// 函数名称: iic_stop()
// 函数功能: 停止I2C总线数据传送子程序
void iic_stop(void)
{     
    SDAO;
      SCLO;
    SDA0;/*SDA=0*/
    delay(10);
    SCL1;/*SCL=1*/
    delay(15);
    SDA1;/*SDA=1*/
    delay(10);
    SCL0;
}

/*====================================================================================*/
// 函数名称: iic_check
// 函数功能: 主机应答位检查子程序,迫使数据传输过程结束
void iic_check(void)
{     
    SDAI;
      SCLO;
    delay(80);
    SCL1;
    AskFlag = 0;
    if(SDAR)
    {
        AskFlag = 1; // 若SDA=1表明非应答,置位非应答标志AskFlag
    }
    SCL0;
}
/*====================================================================================*/
// 函数名称: iic_putc
// 入口参数: ch
// 函数功能: 发送一个字节
void iic_putc(unsigned char pChar)
{
    unsigned char i=8;
      SCLO;
    SDAO;
    SCL0;
    while(i--)
    {
    if(pChar&0x80)
    {
        SDA1;
    }
    else
    {
        SDA0;
    }
    delay(10);
    SCL1;
    pChar<<=1;
    delay(20);
    SCL0;
}
}
/*===================================================================================*/
// 函数名称: iic_getc
// 返回接收的数据
// 函数功能: 接收一字节子程序
unsigned char iic_getc(void)
{
    unsigned char i=8,pChar=0;
      SCLO;
    SDAI;
    SCL0;
    while(i--)
    {
        SCL1;
        delay(5);
        pChar<<=1;
        if(SDAR)
        {
              pChar++;
        }
        delay(10);
        SCL0;
        delay(20);
    }
    return(pChar);
}
  void main (void)
    {
    io_init();
    while(1)
    {
      iic_start();
        iic_putc(0xf2);
        iic_stop();
        }
        }
commp 发表于 2009-12-12 00:20 | 显示全部楼层
我做过,关键是数据线的方向寄存器,老要变来变去,没有准双向的好用
用示波器观察IO的波形看错在哪里,这样比较方便找到问题。别忘了先写IIC的器件地址。

评分

参与人数 2威望 +2 收起 理由
suoma + 1
lovelyegle + 1

查看全部评分

lovelyegle 发表于 2009-12-12 22:20 | 显示全部楼层
楼上的回答很好,学习了!
suoma 发表于 2009-12-12 22:49 | 显示全部楼层
huamunv 发表于 2009-12-14 20:51 | 显示全部楼层
顶一个
双龙 发表于 2009-12-16 16:25 | 显示全部楼层
MEGA128 自带 I2C
commp 发表于 2009-12-16 20:33 | 显示全部楼层
我用AVR也是IO口模拟,自带的I2C用起来比较麻烦
 楼主| Karlshen 发表于 2009-12-29 22:33 | 显示全部楼层
谢谢各位
tcy65 发表于 2010-1-25 10:29 | 显示全部楼层
登记一下,以后再来看。
大碗拉面 发表于 2010-1-25 13:29 | 显示全部楼层
其实AVR的硬件IIC模块挺好用的。我在Mega32上用过,控制EEPROM
现把驱动代码给你,希望有所帮助

  1. void I2C_init(void)
  2. {
  3.   TWSR = 0x00;           //TWI状态寄存器初始化
  4.   TWAR = 0x00;           //本机从机地址为0H
  5.   //TWBR = 0x08;           //速率为100K
  6.   TWBR = 0x20;
  7.   TWCR = 0x44;           //允许ack应答,使能TWI
  8. }
  9. /***************************
  10. 产生启动信号
  11. ****************************/
  12. unsigned char I2C_Start(void)
  13. {
  14.   unsigned char count = 0;
  15.   TWCR = (1 << TWINT)|(1 << TWSTA)|(1 << TWEN);
  16.   while( (!(TWCR & (1 << TWINT)))&&(count < 200) )
  17.   {
  18.       count++;
  19.   }
  20.   if( (TWSR & 0xf8) != TW_START )
  21.      return I2C_ERR;
  22.   else
  23.       return I2C_OK;
  24. }
  25. /************************
  26. 产生停止信号
  27. ************************/
  28. void I2C_Stop(void)
  29. {
  30.    TWCR = (1 << TWINT)|(1 << TWEN)|(1 << TWSTO);
  31. }
  32. /******************************
  33. 向总线写1字节,并返回有无应答
  34. *******************************/
  35. unsigned char I2C_Write(unsigned char data)
  36. {
  37.   unsigned char count = 0;
  38.   TWDR = data;
  39.   TWCR = (1 << TWINT)|(1 << TWEN);
  40.    while( (!(TWCR & (1 << TWINT)))&&(count < 200) )
  41.   {
  42.        count++;
  43.   }
  44.   if( (TWSR & 0xf8) != TW_MT_SLA_ACK )
  45.       return I2C_ERR;
  46.   else
  47.       return I2C_OK;
  48. }
  49. /********************************
  50. 读1字节,
  51. ack = 1时,应答。
  52. ack = 0时,不应答
  53. ********************************/
  54. unsigned char I2C_Read(unsigned char ack)
  55. {
  56.   unsigned char count = 0;
  57.   if(ack)
  58.     TWCR = (1 << TWINT)|(1 << TWEN)|(1 << TWEA);   
  59.   else
  60.     TWCR = (1 << TWINT)|(1 << TWEN);               
  61.   while( (!(TWCR & (1 << TWINT)))&&(count < 200) )
  62.   {
  63.      count++;
  64.   }
  65.    return TWDR;                  
  66. }

laslison 发表于 2010-1-26 12:02 | 显示全部楼层
大江名誉 发表于 2010-1-28 14:25 | 显示全部楼层
本帖最后由 大江名誉 于 2010-1-28 14:36 编辑

我做过,关键是数据线的方向寄存器,老要变来变去,没有准双向的好用
-------------------------------------------------------------------------------
其实并不麻烦,把 PORTx 寄存器对应位设为0,加个上拉电阻,只设方向寄存器DDRX就可以了。
例如以B口的 1:SDA,2:SCL为例:
#define    SDA1    DDRB &= ~(1<<1)       //设 SDA 为 1
#define    SDA0    DDRB |=    (1<<1)       //设 SDA 为 0
#define    SDA      (PINB & (1<<1))          //读  SDA

#define    SCL1    DDRB &= ~(1<<2)       //设 SCL 为 1
#define    SCL0    DDRB |=    (1<<2)       //设 SCL 为 0
#define    SCL      (PINB & (1<<2))          //读  SCL

楼主的你外部引脚有加外部上拉电阻吗?加个5k的就可以了。
大江名誉 发表于 2010-1-28 14:39 | 显示全部楼层
DDRC = 0xFF;                                    
   PORTC = 0xFF;
---------------------

DDRC = 0xfc;                                    
   PORTC = 0xFc;
试下。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

81

主题

734

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部