AVR 主从通信

来源:互联网 发布:虚拟机mac os x 10.11 编辑:程序博客网 时间:2024/06/07 06:00

/************************************
* 功   能:用TWI主从通信   *
* 建立日期:2008年11月04日         *
* 设 计 者:             *
* 版   本:            *
* 修改日期:2012-9-6          *
* 主控芯片:ATmega16           *
* 时钟频率:外部晶体7.3728MHz     *
* 编 译 器:ICCAVR6.31A           *
************************************/
#include "config.h"
uint8 IIC_transmit[TXNUM];
uint8 IIC_receive [RXNUM];

#if TWI_MOD == 1 //从机模式

void twi_master_init(void)
{
 PORTC |= (1<<SCL)|(1<<SDA);
 DDRC &= ~((1<<SCL)|(1<<SDA));
 TWCR= 0x00;
 TWSR= 0x00; //set prescale
 TWBR= (F_CPU/F_IIC_SCL - 16)>>1;//250; //set bit rate
/*          
                   CPU Clock frequency
 SCL frequency  =  --------------------
                   16 + 2(TWBR) * 4
       */

 TWAR= 0x00; //set slave address
 TWCR= 0x04; //enable twi
}

//总线上起动开始条件
void i2c_start(void)
{
 TWCR= (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    while (!(TWCR & (1<<TWINT))); //等待START 信号成功发送
}

//把一个字节数据输入器件, 返回TWI状态
//发送地址,r_w:1为读,0为写
uint8 i2c_write_addr(uint8 addr,uint8 r_w)
{
  if(r_w)
 {
  TWDR = addr|r_w;     //RW 为1:读操作
 }
 else
 {
 TWDR = addr & 0xFE;   // RW 为0: 写操作
 }

    TWCR = (1<<TWINT)|(1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    _NOP();
    return(TWSR&0b11111000); //TWSR高五位为I2C工作状态。
}

//把一个字节数据输入器件, 返回TWI状态
//发送数据
uint8 i2c_write_data(uint8 data)
{
 TWDR = data;
    TWCR |= (1<<TWINT)|(1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    _NOP();
    return(TWSR&0b11111000); //TWSR高五位为I2C工作状态。
}

void i2c_Read_Ack(void)
{  
    uint8 i=0;
 for(i=0; i<100; i++)
    {
     if((TWSR&0b11111000) == MT_SLA_ACK)
        {
         _NOP();
            break;
     }
  _NOP();
  _NOP(); 
  }
}


//从器件读出一个字节
uint8 i2c_read(void)
{  
    
    return(TWDR);
}

//总线上起动停止条件
void i2c_stop(void)
{
   TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

//操作步骤: 启动,发送地址,发送数据,关闭总线
void i2c_maste_transt(uint8 addr,uint8 *data,uint8 tx_count)
{
 uint8 i=0;
 i2c_start();
 if(i2c_write_addr(addr<<1, 0)==MT_SLA_ACK) //发送地址成功并收到ACK
 {
   for(i=0; i<tx_count; i++)
   {
       i2c_write_data(*data);
       data++; 
       i2c_Read_Ack();
   }
 }
 i2c_stop();
}
//操作步骤,启动,发送地址,读数据,关闭总线
void i2c_maste_read(uint8 addr, uint8 *data,uint8 rx_count)
{
   unsigned char i = 0;
   unsigned char j = 0;
  
   PORTD |= 0xCC;
   DDRD |= 0xCC;
   DDRB = 0xFF;
   DDRA |= 0xff;
 
   i2c_start();
   if(i2c_write_addr(addr<<1, 1)!= MR_SLA_ACK) //发送地址成功并收到ACK
   {
       return;
   }
   for(i=0; i<rx_count-1; i++)
   {
     Twi_Ack();
  Twi_WaitForComplete();
     *data = TWDR;
     data++; 
   }
 Twi_NoAck();
    Twi_WaitForComplete();
    *data = TWDR; 
    i2c_stop();
}
#endif

#if TWI_MOD == 0 //从机模式
void  twi_slave_init(uint8 addr)
{
    PORTC |= (1<<SCL)|(1<<SDA);
 DDRC &= ~((1<<SCL)|(1<<SDA));
 TWCR = 0x00;
 TWSR= 0x00; //set prescale
    TWBR= (F_CPU/F_IIC_SCL - 16)>>1;//250; //set bit rate
    /*          
                       CPU Clock frequency
    SCL frequency  =  --------------------
                       16 + 2(TWBR) * 4
       */
  TWAR = addr<<1;
 TWDR = 0x00;
 TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)|(1<<TWEA);
}
#pragma interrupt_handler TWI_ISR:18
void TWI_ISR(void)

   static  volatile uint8 transmit_cnt = 0;
   static  volatile uint8 receive_cnt = 0;
   uint8 *p_sr = &IIC_receive[0];
   uint8 *p_st = &IIC_receive[0];
    //uint8 receive[2]= {2,3};
 SREG &= ~0x80;
 switch(TWSR&0xf8)
 {
     case SR_SLA_ACK: 
  case SR_ARB_LOST_SLA_ACK:  
      receive_cnt = 0;
   transmit_cnt = 0;                    
      Twi_Ack()
   break;
  case SR_DATA_ACK:   
   if (receive_cnt < (RXNUM-1))
         {
             *(p_sr+receive_cnt) = TWDR;
         }
         else if (receive_cnt == (RXNUM-1))
         {
            *(p_sr+receive_cnt) = TWDR;
         receive_ready = 1;
         }
         receive_cnt++;  ;
   Twi_Ack()
   break;
        case SR_STOP:                              // 0xA0:从机工作时收到STOP或RESTART     
   Twi_Ack()
   break;
  case ST_SLA_ACK:                                   // 0XA8:从机发送地址应答
            transmit_cnt = 0;
   TWDR = *(p_st);
   transmit_cnt++;
      Twi_Ack() 
   break; 
  case ST_DATA_ACK:                                  // 0XB8:从机发送数据应答 
            if (transmit_cnt < TXNUM)
   {
      TWDR = *(p_st+transmit_cnt);   
   }
   transmit_cnt++;
   Twi_Ack()
   break;
  case ST_DATA_NACK:
      //transmit_ready = 1;
   transmit_cnt = 0;
   Twi_Ack()
   break; 
  case BUS_ERROR:
  case NO_INFO:  
   TWI_RESUME();
   break;
 } 
 SREG |= 0x80;
}
#endif

 

原创粉丝点击