×
单片机 > 单片机程序设计 > 详情

avr单片机的TWI两线串行接口

发布时间:2020-06-04 发布时间:
|
ATMEL的TWI   和 PHILIPS的IIC   基本上应该是算一个东西,但是他们在名义上是不同的,这样谁都不用支付给对方使用费。他们的协议是一样的,所有我们作为使用者基本可以简单的看成 TWI就是IIC 。

      废话说完,开始正题。这次是关于在ATMega16 平台下的硬件IIC(还不太习惯说TWI)的使用。在ATMega16的Datasheet里我们可以看到很强大的功能,主从设置很多。本文只说一种最常用的方式,那就是“ATMega16 硬件TWI 的 扫描发送 和 扫描读取”。

      首先要明确TWI 发送和接受的流程:

发送:

1,设定数据传输波特率

2,发送START信号,等待应答        ==》      《== 应答信号

3,发送芯片地址,等待应答            ==》         《==应答信号

4,发送数据的绝对地址,等待应答 ==》        《==应答信号

5,发送要写入的数据,等待应答    ==》          《==应答信号

6,发送STOP信号,释放总线         ==》            数据写入成功

接收:

1,设定数据传输波特率

2,发送START信号,等待应答        ==》      《== 应答信号

3,发送芯片地址,等待应答            ==》         《==应答信号

4,发送数据的绝对地址,等待应答 ==》        《==应答信号

5,发送RESTART信号,等待应答   ==》         《==应答信号      

6,发送芯片地址并注明读操作,等待应答 ==》      《==应答信号   

7,读取数据,等待应答                    ==》         《==应答信号

8,发送STOP信号,释放总线         ==》            数据读操作成功

应用芯片 :ATMega 16                         晶振 : 7.3728

代码文件:Project

                        |___TWI.C

                        |           |_____ IAR_DELAY.H

                        |___UART.C

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

IAR_DELAY.H

#ifndef __IAR_DELAY_H
#define __IAR_DELAY_H

#include

#define XTAL 7.3728                  //可定义为你所用的晶振频率(单位Mhz)


#define delay_us(x) __delay_cycles ( (unsigned long)(x * XTAL) )
#define delay_ms(x) __delay_cycles ( (unsigned long)(x * XTAL*1000) )
#define delay_s(x) __delay_cycles ( (unsigned long)(x * XTAL*1000000) )

#endif

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

UART.C

#include
#define uchar unsigned char
#define uint unsigned int

//###########################################################

void Uart_Init(void)
                       
   UCSRB = (1<      //允许发送和接收
UCSRC = (1<

UBRRH=0x00;                                                          //设置波特率寄存器低位字节
UBRRL=47;                                                            //9600    //设置波特率寄存器高位字节

DDRD_Bit1=1;                                                         //配置TX为输出(很重要)
}
//###########################################################

void Uart_Transmit(uchar data)
{
     while(!(UCSRA&(1< 
   //while(UCSRA_UDRE==0);                             
UDR = data;                                                    
}
  

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

#include
#include "IAR_DELAY.H"
#define uchar unsigned char
#define uint unsigned int

void Uart_Init(void);
void Uart_Transmit(uchar data);


//变量声明
#define EEPROM_BUS_ADDRESS 0xA0         //器件地址
                                                                            
                                                                            
                                                                             
                                                                            
                                                                            
//主机发送模式时各状态字的后续动作
#define TW_START                   0x08         //开始信号已发出
#define TW_REP_START          0x10        //重复开始信号已发出
#define TW_MT_SLA_ACK          0x18        //写字节已发出并受到ACK信号
#define TW_MT_SLA_NACK       0x20        //写字节已发出并受到NACK信号
#define TW_MT_DATA_ACK      0x28        //数据已发出并受到ACK 信号
#define TW_MT_DATA_NACK     0x30      //数据已发出并受到NACK 信号
#define TW_MT_ARB_LOST      0x38       //丢失总线控制权
//主机接收模式时各状态字的后续动作
#define TW_MR_ARB_LOST      0x38        //丢失总线控制权,未收到应答信号
#define TW_MR_SLA_ACK        0x40        //读命令已发出并受到ACK
#define TW_MR_SLA_NACK       0x48        //读命令已发出并受到NACK
#define TW_MR_DATA_ACK     0x50        //数据已收到,ACK已发出
#define TW_MR_DATA_NACK     0x58        //数据已收到,NACK已发出

#define IIC_Start()         TWCR =(1<    // TWINT位 通过写1进行清零,一旦清零则TWI开始工作,当相应硬件工作完成后 TWINT位会重新置位为1
                                                                      // TWSTA位 会让硬件在总线上产生一个START的信号 , 声明自己希望成为主机
                                                                      // TWEN 位 使能TWI功能,将 PC0 和 PC1 管脚切换到第二功能上来, 如果清零则为中断 TWI的传输
#define IIC_Stop()          TWCR =(1<    // TWSTO位 在主机模式下,会让硬件在总线上产生一个STOP得信号,并且SCL 和 SDA 两个引脚位高阻态

#define IIC_Wait()          while(!(TWCR&(1<                // TWINT位 经过一次置位使硬件TWI开始工作 ,然后在检测 TWCR 寄存器的 TWINT 位是不是被置位,如果置位为1则表示工作完成可以向下进行

//##############################################################################[page]

unsigned char twi_write(unsigned char addr, unsigned char dd)
{
        TWBR = 10;                           //设定波特率


IIC_Start();                         //硬件发送START信号,并且清零TWINT位,使能硬件TWI,使TWI开始工作
IIC_Wait();                          //等待 发送START完成 TWINT位置位
if ((TWSR & 0xF8) != 0x08) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量,如果正确则向下进行数据传输,错误返回 0
       
       
TWDR = EEPROM_BUS_ADDRESS ;          //芯片地址 0xA0 ,赋值给数据寄存器 TWDR ,等待发送
TWCR = (1 << TWINT) | (1 << TWEN);   //对控制寄存器TWCR的 TWINT 位软件写1进行清零,然后 使能TWI硬件接口 ,让TWI进行工作,发送 TWDR寄存器 中的数据
IIC_Wait();                          //等待数据发送完毕 TWINT重新置位
if ((TWSR & 0xF8) != 0x18) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量 , 如果正确则向下进行数据传输,错误返回 0
       
      
TWDR = addr;                         //将写入数据的绝对地址 ,赋值给数据寄存器 TWDR ,等待发送
TWCR = (1 << TWINT) | (1 << TWEN);   //对控制寄存器TWCR的 TWINT 位软件写1进行清零,然后 使能TWI硬件接口 ,让TWI进行工作,发送 TWDR寄存器 中的数据
IIC_Wait();                          //等待数据发送完毕 TWINT重新置位
if ((TWSR & 0xF8) != 0x28) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量 , 如果正确则向下进行数据传输,错误返回 0
       
       
TWDR = dd;                           //将要写入的数据 ,赋值给数据寄存器 TWDR ,等待发送
TWCR = (1 << TWINT) | (1 << TWEN);   //对控制寄存器TWCR的 TWINT 位软件写1进行清零,然后 使能TWI硬件接口 ,让TWI进行工作,发送 TWDR寄存器 中的数据
IIC_Wait();                          //等待数据发送完毕 TWINT重新置位
if ((TWSR & 0xF8) != 0x28) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量 , 如果正确则向下进行数据传输,错误返回 0

       
IIC_Stop();                          //数据传输完成,发送STOP信号,释放对总线的控制
return 1;                            //写入数据成功 ,返回1 ,用来判断是否成功写入数据
       
}
//##############################################################################

unsigned char twi_read(unsigned char addr)
{

unsigned char Receive_Byte ;
TWBR = 2;                            //设定波特率
      
       
IIC_Start();                         //硬件发送START信号,并且清零TWINT位,使能硬件TWI,使TWI开始工作
IIC_Wait();                          //等待 发送START完成 TWINT位置位
if ((TWSR & 0xF8) != 0x08) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量,如果正确则向下进行数据传输,错误返回 0
      
   
TWDR = EEPROM_BUS_ADDRESS;           //芯片地址 0xA0 ,赋值给数据寄存器 TWDR ,等待发送
TWCR = (1 << TWINT) | (1 << TWEN);   //对控制寄存器TWCR的 TWINT 位软件写1进行清零,然后 使能TWI硬件接口 ,让TWI进行工作,发送 TWDR寄存器 中的数据
IIC_Wait();                          //等待数据发送完毕 TWINT重新置位
if ((TWSR & 0xF8) != 0x18) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量 , 如果正确则向下进行数据传输,错误返回 0
       
      
TWDR = addr;                         //将写入数据的绝对地址 ,赋值给数据寄存器 TWDR ,等待发送
TWCR = (1 << TWINT) | (1 << TWEN);   //对控制寄存器TWCR的 TWINT 位软件写1进行清零,然后 使能TWI硬件接口 ,让TWI进行工作,发送 TWDR寄存器 中的数据
IIC_Wait();                          //等待数据发送完毕 TWINT重新置位
if ((TWSR & 0xF8) != 0x28) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量 , 如果正确则向下进行数据传输,错误返回 0
       
       
IIC_Start();                         //硬件发送 RESTART 信号,并且清零TWINT位,使能硬件TWI,使TWI开始工作
        IIC_Wait();                          //等待数据发送完毕 TWINT重新置位
if ((TWSR & 0xF8) != 0x10) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量 , 如果正确则向下进行数据传输,错误返回 0
       
      
TWDR = 0xA1;                         //芯片地址 0xA0 并注明是读取操作(最后一位为 1 ),赋值给数据寄存器 TWDR ,等待发送   
TWCR = (1 << TWINT) | (1 << TWEN);   //对控制寄存器TWCR的 TWINT 位软件写1进行清零,然后 使能TWI硬件接口 ,让TWI进行工作,发送 TWDR寄存器 中的数据
IIC_Wait();                          //等待数据发送完毕 TWINT重新置位
if ((TWSR & 0xF8) != 0x40) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量 , 如果正确则向下进行数据传输,错误返回 0
       
       
TWCR = (1 << TWINT) | (1 << TWEN);   //对控制寄存器TWCR的 TWINT 位软件写1进行清零,然后 使能TWI硬件接口 ,让TWI进行工作,发送 TWDR寄存器 中的数据
IIC_Wait();                          //等待数据发送完毕 TWINT重新置位
if ((TWSR & 0xF8) != 0x58) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量 , 如果正确则向下进行数据传输,错误返回 0
Receive_Byte = TWDR;                 //读取到的数据放到局部变量里
       
       
IIC_Stop();                          //数据传输完成,发送STOP信号,释放对总线的控制
       
        return Receive_Byte;                 //将读取到的数据作为函数的输出


}
//##############################################################################

void main(void)
{
uchar c,d;
Uart_Init();                           //串口初始化
delay_us(20);                        
Uart_Transmit(0x55);                   //测试串口

c = twi_write(0x51,0xf8);              //在地址0x51里写入数据0x22
Uart_Transmit(c);                      //将返回值发送到串口测试是否写入成功

delay_ms(2);
   
d = twi_read(0x51);                    //将地址0x51里的数据读出来
Uart_Transmit(d);                      //将读取到的数据发送串口
while(1);
}



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
浅谈AVR中定时器几种工作模式