这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » IIC 各位大哥帮忙看看IIC

共3条 1/1 1 跳转至

IIC 各位大哥帮忙看看IIC

院士
2006-09-17 18:14:16     打赏
IIC 各位大哥帮忙看看IIC



关键词: 各位     大哥     帮忙     看看    

院士
2006-12-22 22:43:00     打赏
2楼
问 S1CON     DATA     0D8H
S1STA     DATA     0D9H
S1DAT     DATA     0DAH
S1ADR     DATA     0DBH

;/*  S1CON   */
CR0       BIT     0D8H
CR1       BIT     0D9H
AA        BIT     0DAH
SI        BIT     0DBH
STO       BIT     0DCH
STA       BIT     0DDH
ENS1      BIT     0DEH
CR2       BIT     0DFH

;/*  P1  */
SDA       BIT      97H;
SCL       BIT      96H;

ES1       BIT     0ADH

;为平台定义变量
       ACK       BIT 10H  ;应答标志位
       SLA       DATA 60H ;器件从地址
       SUBA      DATA 61H ;器件子地址
       NUMBYTE   DATA 62H ;读/写的字节数

       
       MTD EQU  30H  ;发送数据缓冲区首址 (缓冲区30H-4FH)   
       MRD EQU  50H  ;接收数据缓冲区首址 (缓冲区50-5FH)


;    内存分配:
;              堆栈区        STACK    (70H--7FH)
;              显示缓冲区    DISP_RAM  (发送缓冲区MTD)

;===================常量定义=======================================>
        SAA7111 EQU  48H           ; SAA7111的地址
         

;================程序代码段================================================={
              ORG   0000H
              AJMP  MAIN           


;==========================================================>
;申请总线
;功能:进行I2C总线的初始化--包括时钟速率,I2C使能,发送起始信号等等。
GETBUS:
       MOV   S1CON,#0C5H  ;设置时钟为100K(MCU主频为12M),ENS1和AA置位
       SETB  STA          ;申请成为主机,起动总线
       JNB   SI,$         ;等待起始信号的发送
       RET

;==========================================================>
;发送数据函数
;功能:用于向总线发送数据
;入口参数:ACC--待发送的数据
SENDBYTE:
          MOV  S1DAT,A     ;发送数据
          MOV  S1CON,#0C5H ;清除SI位等等
          JNB  SI,$        ;等待数据的发送
          RET


;==========================================================>
;进行随机地址多字节写多字节
;占用R0,R1,ACC
;入口参数:器件从地址SLA 子地址SUBA  发送数据区MTD  读入字节数NUMBYTE
;出口参数:ACK,ACK=1时操作正确。
IWRNBYTE:
         CLR   ACK
         MOV   R0,#MTD
         MOV   R1,NUMBYTE
         ACALL GETBUS           ;启动总线
         MOV   A,SLA
         ACALL SENDBYTE
         MOV   A,S1STA
         CJNE  A,#18H,IWRNEND
         MOV   A,SUBA
         ACALL SENDBYTE
         MOV   A,S1STA
         CJNE  A,#28H,IWRNEND   ;无应答则退出
         
IWRN_L1: MOV   A,@R0
         ACALL SENDBYTE        ;发送数据
         MOV   A,S1STA
         CJNE  A,#28H,IWRNEND  ;无应答则退出
         INC   R0
         DJNZ  R1,IWRN_L1          
         SETB  ACK             ;置标志位
         CLR   P1.5
IWRNEND: MOV   S1CON,#0D5H
         RET                  

;==========================================================>
;进行随机地址多字节读
;占用R0,R1,ACC
;入口参数:器件从地址SLA 子地址SUBA  接收数据区MRD  读入字节数NUMBYTE
;出口参数:ACK,ACK=1时操作正确。
IRDNBYTE:    
         CLR   ACK
         SETB  P1.5
         MOV   R0,#MRD
         MOV   R1,NUMBYTE
         ACALL GETBUS
         MOV   A,SLA
         ACALL SENDBYTE       ;器件寻址
         MOV   A,S1STA
         CJNE  A,#18H,IRDNEND ;无器件应答即退出
         MOV   A,SUBA         ;写入器件子地址
         ACALL SENDBYTE
         MOV   A,S1STA
         CJNE  A,#28H,IRDNEND ;总线出错即退出
         MOV   S1CON,#0E5H    ;重新启动总线
         JNB   SI,$
         MOV   A,SLA
         INC   A              ;读操作的器件寻址
         ACALL SENDBYTE
         MOV   A,S1STA
         CJNE  A,#40H,IRDNEND
         
IRDN_L1: DJNZ   R1,IRDN_L2
         MOV    S1CON,#0C1H   ;取最后一个数据后发送非应答位
         JNB    SI,$        
         MOV    A,S1STA       ;将数据取出
         CJNE   A,#58H,IRDNEND
         MOV    A,S1DAT
         MOV    @R0,A         ;数据存入MRD区中(R0指针指向MRD区)
         SETB   ACK
         CLR    P1.5
IRDNEND: MOV    S1CON,#0D5H
         RET           
IRDN_L2: MOV    S1CON,#0C5H   ;接收数据并发送应答位
         JNB    SI,$
         MOV    A,S1STA
         CJNE   A,#50H,IRDNEND;总线出错即退出
         MOV    A,S1DAT       ;取数据
         MOV    @R0,A         ;数据存入MRD区
         INC    R0
         SJMP   IRDN_L1


;===============================================================================
;                         主程序MAIN
;   主要负责整个系统的监控,如发指令给各芯片,读取各芯片的状态.
              ORG   0080H
MAIN:         
              MOV      R5,#0FH
              DJNZ     R5,$              ;延时,等待其它芯片复位
              CLR      SCL
              SETB     SDA
              JNB      SDA,I2CWRO        ; SCL SDA 短路或SDA 被锁为低
              SETB     SCL
              JNB      SCL,I2CWRO
              
              
              ACALL    INI_SAA7111       ;初始化SAA7111
              ACALL    READ_SAA7111      ;读SAA7111状态
              SJMP     $
              
              
; 子程序  INI_SAA7111         
; 作用:  对SAA7111进行初始化
; 出入参数: 无             
INI_SAA7111:  
              MOV        SLA,#SAA7111
              MOV        SUBA,#00H
              MOV        NUMBYTE,#1CH     ;写入28个命令参数    
              MOV        R0,#MTD
              MOV        @R0,#00H  
              INC        R0
              MOV        @R0,#00H
              INC        R0
              MOV        @R0,#0C0H
              INC        R0
              MOV        @R0,#33H
              INC        R0
              MOV        @R0,#00H
              INC        R0
              MOV        @R0,#00H
              INC        R0
              MOV        @R0,#0EBH
              INC        R0
              MOV        @R0,#0E0H
              INC        R0
              MOV        @R0,#88H
              INC        R0
              MOV        @R0,#01H
              INC        R0
              MOV        @R0,#80H
              INC        R0
              MOV        @R0,#47H
              INC        R0
              MOV        @R0,#40H              
              INC        R0
              MOV        @R0,#00H
              INC        R0
              MOV        @R0,#01H
              INC        R0
              MOV        @R0,#00H
              INC        R0
              MOV        @R0,#40H
              INC        R0
              MOV        @R0,#1CH
              INC        R0
              MOV        @R0,#03H
              INC        R0
              MOV        @R0,#00H
              INC        R0
              MOV        @R0,#00H
              INC        R0
              MOV        @R0,#00H  
              INC        R0
              MOV        @R0,#00H
              INC        R0
              MOV        @R0,#00H
              INC        R0
              MOV        @R0,#00H
              INC        R0
              MOV        @R0,#00H
              INC        R0
              MOV        @R0,#00H
              INC        R0
              MOV        @R0,#00H
                             
              
              LCALL      IWRNBYTE
              RET
              
; 子程序  READ_SAA7111         
; 作用:  读SAA7111状态
; 出入参数: 无       
READ_SAA7111: MOV     SLA,#SAA7111
              MOV     SUBA,#1AH
              MOV     NUMBYTE,#03H
              LCALL   IRDNBYTE
              RET     
              
                                  
I2CWRO:CLR P0.0
        SJMP $
                           
;==========================================================<
            END

    我用EASYPACK的仿真器仿87c652控制saa7111,仿真器可以写入,示波器看写过程(即从“进行随机地址多字节写多字节”的整个过程到“进行随机地址多字节读”的写入49H)都没问题,连返回的ACK都正确,但怎么读都读不回来,将读的子地址改成00或者其他的也不行,每次到读数据时钟线都被拉低了,然后就跳到I2CWRO。
    刚刚用单片机,各位老大帮忙看看哪儿的问题。
    数据线和时钟线都接1K上拉电阻到+5v了。
1: 51我不熟悉,给你一个AVR的把。硬件上过了的。/*本程序验证基于I2C通讯协议的EEPROM芯片
24LC256的读出通讯时序
程序开发:西南科技大学 江某*/
# include <iom8v.h>
# include <macros.h>

unsigned char addr_h,addr_l,data_send,data_rec=0;
unsigned char i2c_flag=1;
unsigned char bit[8];

/***************************************/
//             子程序段                //

#pragma ctask delay
/*微秒级延迟函数,函数参数"dt"
延迟时间为(dt+2)微秒*/
void delay (unsigned char dt)
{
while (dt)
  dt--;
  asm("nop");
}

void i2c_start (void)
/*本程序启动I2C总线

硬件环境:AVR单片机对基于I2C协议的EEPROM芯片24LC256通讯

在调用本函数前,必须确定I2C总线所使用的端口口线
这里假设PD.0为SDA线,PD.1为SCK线。
*/
{
i2c_flag=1;                    //清除总线传输标志位,以便等待应答信号
DDRD=0b00000011;                //为避免逻辑混乱,再次定义端口方向
PORTD|=0b00000011;                 //准备总线,将两根线全部拉高
delay(2);                         //延时2微秒
/*本过程对应为Tsu(sta),I2C协议规定为160ns(min),本器件规定为600ns(常规条件下)*/
PORTD&=0b11111110;                 //拉低SDA线,启动总线
delay(2);                         //延时2微秒
/*本过程对应为Thd(sta),I2C协议规定为160ns(min),本器件规定为600ns(常规条件下)*/
PORTD&=0b11111101;                 //拉低SCK线
}

void i2c_rec (void)
/*本程序收取I2C总线上的一个字节到主机,并以全局变量data_rec
的形式返回给调用主函数,主函数必须在下次调用本函数前将该值取
走,否则将会造成该值被新的数据覆盖掉

硬件环境:AVR单片机对基于I2C协议的EEPROM芯片24LC256通讯

在调用本函数前,必须确定I2C总线所使用的端口口线,并且要求在调用
本函数前,已经用其他方式请求到总线通讯权,已经书写好控制字和
要读取的地址值

这里假设PD.0为SDA线,PD.1为SCK线。

注意:本程序对从器件所发送来的数据不给出应答信号,在调用本程序后,
应该立即终止总线传送过程
*/
{
unsigned char i,n,d_temp=0;

DDRD=0b00000010;                //为避免逻辑混乱,再次定义端口方向
PORTD|=0b00000001;                //打开内部弱上拉,以便接受数据
/*由于不给出应答信号,SDA线被始终设置为输入状态*/

data_rec=0;
/*由于是采用位运算的方式获得输入信号的,必须在新的数据输入前清空原来的数据*/

for (i=0;i<8;i++)
  {
   n=(7-i);                          //获取移位计数器的值
   delay(2);                      //延时2微秒,在本低电平其间,器件传送一个BIT
/*本过程对应为Tlow,协议规定为160ns(min),本器件规定为1300ns(常规条件下)*/
   PORTD|=0b00000010;            //拉高SCK,以便开始采样过程
   delay(1);                    //延时1微秒
/*本过程对应为Thd(dat),协议规定为0,但是考虑到器件的响应速度问题,做了1微秒的延时*/
   d_temp=(PIND&0b00000001);    //端口值采样
   data_rec|=(d_temp<<n);        //用右移运算组合数据
   delay(1);                    //分两次延时,产生高电平,在其间采样了SDA线
   PORTD&=0b11111101;            //拉低SCK,使得从器件开始传送下一个BIT
   }
/*上面的循环完成一个字节的接收过程,完成后总线的状态为:
SDA随从器件传输的数据而不同,SCK可以理解为一个低电平的前端*/
delay(2);                        //延时2微秒
/*上面的过程对应为Tlow,协议规定为160ns(min),本器件规定为1300ns(常规条件下)*/
PORTD|=0b00000010;                //拉高SCK线
delay(2);
/*本过程对应为Thigh,I2C协议规定为60ns(min),本器件规定为600ns(常规条件下)*/
/*由于单字节接收时,主器件不需要发送应答信号,则应答等待时钟被主器件产生,但是
在其间没有进行应答操作*/
PORTD&=0b11111101;                //拉低SCK结束应答等待周期

/*上面的过程完成了字节的收取,完成后总线的状态为:
SDA线随是否得到应答信号而不同,SCK线可以理解为一个时钟低电平的前端*/
}

void i2c_send (unsigned char data)
/*本程序发送一个字节到i2c总线

硬件环境:AVR单片机对基于I2C协议的EEPROM芯片24LC256通讯

在调用本函数前,必须确定I2C总线所使用的端口口线并且要求在调用
本函数前,已经用其他方式请求到总线通讯权,已经书写好控制字和
要写入的地址值

这里假设PD.0为SDA线,PD.1为SCK线。

根据I2C总线协议,每次发送的数只能是一个字节,
要发送的数据由形参"data"传输给本函数。

在字节传输完成后,本函数将等待从器件的应答信号,并调用函数
返回标志值,如果响应成功,将全局变量i2c_flag写为0,
如果响应失败,将全局变量i2c_flag写为1
*/
{
unsigned char i=0;

bit[7]=(data&0b00000001);       //数据准备,将输入的数据拆成8个变量
bit[6]=(data&0b00000010);
bit[5]=(data&0b00000100);
bit[4]=(data&0b00001000);
bit[3]=(data&0b00010000);
bit[2]=(data&0b00100000);
bit[1]=(data&0b01000000);
bit[0]=(data&0b10000000);

DDRD=0b00000011;                //为避免逻辑混乱,再次定义端口方向

for (i=0;i<8;i++)
  {
   PORTD&=0b11111101;             //拉低SCK
   PORTD&=0b11111110;           //将数据预置为0
/*由于协议规定Thd(dat)的最小值为0,所以在送出数据前没有做延迟*/

   if (bit[i]>0)               //如果分离得到的BIT位为1,就将SDA置1
    PORTD|=0b00000001;
   delay(1);                     //延迟1微秒
/*本过程对应为Tsu(dat),I2C协议规定为10ns(min),本器件规定为100ns(常规条件下)*/
   PORTD|=0b00000010;           //将SCK拉高,使从器件采样SDA线
   delay(2);                   //延迟2微秒
/*本过程对应为Thigh,I2C协议规定为60ns(min),本器件规定为600ns(常规条件下)*/
   }
   
/*上面的循环完成一个字节的发送过程,发送完成后总线的状态为:
SDA线随最后一位BIT位而不同,SCK线可以理解为一个时钟高电平的末端*/

PORTD&=0b11111101;               //拉低SCK,开始应答等待时钟周期
DDRD=0b00000010;               //将SDA线设置为输入端口,以便采样总线
PORTD|=0b00000001;               //用内部弱上拉将总线拉高,等待应答信号
PORTD|=0b00000010;               //拉高SCK,开始采样SDA线
delay(1);                       //延迟1微秒等待SDA稳定
i2c_flag=(PIND&0b00000001);   //采样SDA线,检测应答信号
delay(1);                       //延迟1微秒
/*本过程对应为Thigh,由两个delay函数组成,在其间采样了SCK线应答的状态
I2C协议规定为60ns(min),本器件规定为600ns(常规条件下)*/
PORTD&=0b11111101;               //拉低SCK结束应答等待周期

/*上面的过程完成了字节的传送和应答信号的采样,完成后总线的状态为:
SDA线随是否得到应答信号而不同,SCK线可以理解为一个时钟低电平的前端*/
}

void i2c_stop (void)
/*本程序停止I2C总线

硬件环境:AVR单片机对基于I2C协议的EEPROM芯片24LC256通讯

在调用本函数前,必须确定I2C总线所使用的端口口线
这里假设PD.0为SDA线,PD.1为SCK线。
*/
{
DDRD=0b00000011;            //为避免逻辑混乱,再次定义端口方向
delay(1);                    //延时1微秒
/*本过程对应为Tlow,I2C协议规定为160ns(min),本器件规定为1300ns(常规条件下)*/
PORTD&=11111100;            //拉低SDA线
delay(1);
/*分两次完成延迟过程,在其间将低SDA线拉低*/
PORTD|=0b00000010;            //拉高SCK
delay(2);                    //延时2微秒
/*本过程对应为Tsu(sto),I2C协议规定为160ns(min),本器件规定为600ns(常规条件下)*/
PORTD|=0b00000001;            //拉高SDA,停止总线
}

//           子函数段结束             //
/**************************************/

void main (void)
{
addr_h=0x00;
addr_l=0x00;

i2c_start();
data_send=0b10100000;
i2c_send(data_send);
i2c_send(addr_h);
i2c_send(addr_l);
i2c_start();
data_send=0b10100001;
i2c_send(data_send);
i2c_rec();
i2c_stop();
DDRC=0xFF;
PORTC=i2c_flag;
DDRB=0xFF;
PORTB=data_rec;
}

专家
2022-08-27 15:27:35     打赏
3楼

了解一下


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]