• IIC


       

       s3c2440内部有一个IIC总线接口。它具有四种操作模式:主设备发送模式、主设备接收模式、从设备发送模式和从设备接收模式。

    IIC的具体时序:

     

    由此可知SCL为高位时SDA从高位跃迁到低位时表示开始、SCL为高位时SDA从低位跃迁到高位时表示结束。我们可以设置IICSTAT寄存器来发送开始或结束信号。在第九个时钟时主设备或从设备拉低SDA,表示应答ACK。应答后产出中断,此时可以将数据写入IICDS或读出,然后清除中断标志位IICCON[4]恢复操作

     

     主设备发送模式流程:首先配置IIC模式,然后把从设备地址写入接收发送数据移位寄存器IICDS中,再把0xF0写入控制状态寄存器IICSTAT中,这时等待从设备发送应答信号,如果想要继续发送数据,那么在接收到应答信号后,再把待发送的数据写入寄存器IICDS中,清除中断标志后,再次等待应答信号;如果不想再发送数据了,那么把0x90写入寄存器IICSTAT中,清除中断标志并等待停止条件后,即完成了一次主设备的发送。

     主设备接收模式流程:首先配置IIC模式,然后把从设备地址写入接收发送数据移位寄存器IICDS中,再把0xF0写入控制状态寄存器IICSTAT中,这时等待从设备发送应答信号,如果想要接收数据,那么在应答信号后,读取寄存器IICDS,清除中断标志;如果不想接收数据了,那么就向寄存器IICSTAT写入0x90,清除中断标志并等待停止条件后,即完成了一次主设备的接收。

     IICCON:[7]设置是否发出应答信号
                 [6]设置IIC的时钟频率

                         [5]用于是否使能发送和接收中断

                         [4]用于中断的标志,当接收或发送数据后一定要对该位进行清零,以清除中断标志。

            IICSTAT:[7:6]用于设置是哪种操作模式

                         [5]写0或写1时,则表示结束IIC或开始IIC通讯

                         [4]用于是否使能接收/发送数据。

          寄存器IICCON的第6位和低4位用于设置IIC的时钟频率,因为IIC的时钟线SCL都是由主设备提供的。s3c2440的IIC时钟源为PCLK,当系统的PCLK为50MHz,而从设备最高需要100kHz时,可以将IICCON的第6位置1,IICCON的低4位全为0即可。

    在这里,从设备是EEPROM——AT24C08A,要想让s3c2440能够正确地对AT24C08A读写,就必须让s3c2440的时序完全按照AT24C08A的时序。 

    AT24C08A的写操作有两种模式:字节写和页写。字节写是先接收带有写命令的设备地址信息,如果符合就应答,再接收设备内存地址信息,发出应答后,再接收要写入的数据,这样就完成了字节写过程。页写与字节写的区别就是,页写可以一次写多个数据,而字节写只能一次写一个数据。但由于AT24C08A的一页才8个字节,所以页写也最多写8个数据,而且只能在该页内写,不会发生一次页写同时写两页的情况。

    AT24C08A的读操作有三种模式:当前地址读、随机读和序列读。当前地址读是只能读取当前地址内的数据,它的时序是先接收带有读命令的设备地址信息,如果符合就应答,然后发送当前地址内的数据,在没有接收从主设备发来的应答信号的情况下终止该次操作。随机读的时序是,连续接收带有写命令的设备地址信息和设备内存地址信息,然后主设备重新开启IIC通信,AT24C08A再次接收到带有读命令的设备地址信息,在发出应答信号以后,发送该内存地址的数据,在没有接收到任何应答信号的情况下结束该次通信。当前地址读和随机读一次都只能读取一个数据,而序列读一次可以读取若干个数据,它的时序就是在当前地址读或随机读发出数据后,接收到了应答信号,那么AT24C08A会把下一个内存地址中的数据送出,除非AT24C08A接收不到任何应答信号,否则它会一直把下一个内存地址中的数据送出。序列读没有一页8个字节的限制。

     I2C设备并不只有一个设备地址。这一点往往被忽略,一般情况下认为在I2C启动信号之后的字节为I2C从机地址(7位)。对于AT24C04而言,内部具有4Kb存储位,合计512字节。若需要访问512字节内容,总共需要9根地址线(8位宽度),那么上图中的存储地址(8位长度)显然还差了一位,那么就需要从设备地址中“借”1位,这就使得AT24C04具有两个I2C地址,例如0x50和0x51

    ⑴清IIC中断标志语句rIICCON &= ~0x10;一定要在读写寄存器IICDS的后面,不能放到它的前面;

    ⑵在等待应答的死循环while内,一定要加上延时的程序;

    ⑶在读取AT24C02A数据时,当读到最后一个数据时,一定不能让s3c2440发送应答信号,否则以后会无法再读取AT24C02A数据,除非关电重启;

    ⑷在真正对AT24C02A进行读取数据时,在发送带有读命令的从设备地址后,AT24C02A会再返回一个从设备地址信息或从设备内存地址信息作为应答,所以一定要把该字节读取后抛弃,因为它不是我们所要读取的信息;

    ⑸按照AT24C02A的时序,在发送从设备地址字节时,它的最低位是0表示写,1表示读。但对于s3c2440来说,不用人为设置这一位,即是01都无所谓,因为这一位是由s3c2440根据是主设备发送模式还是主设备接收模式来自动设

    读写是站在主机的立场上定义的.

    ""是主机接收从机数据,""是主机发送数据给从机

    7I2C总线可以挂接127个不同地址的I2C设备,0"设备"作为群呼地址.

    10I2C总线可以挂接更多的10I2C设备

    常用IIC接口通用器件的器件地址是由种类型号,及寻址码组成的,共7位。
    如格式如下: 
      D7 D6 D5 D4 D3 D2 D1 D0
    1-
    器件类型由:D7-D4 4位决定的。这是由半导公司生产时就已固定此类型的了,也就是说这4位已是固定的。

    2-
    用户自定义地址码:D3-D13位。这是由用户自己设置的,通常的作法如EEPROM这些器件是由外部IC3个引脚所组合电平决定的(用常用的名字如A0,A1,A2)。这也就是寻址码。

    所以为什么同一IIC总线上同一型号的IC只能最多共挂8片同种类芯片的原因了。

    3-最低一位就是R/W位。

     

     

    mini2440-256M上面用的eeprom的型号为AT24C08B,这个eeprom的大小为1024*8(8k),这是什么意思呢?
        存储器芯片容量=存储单元数*数据位数
    用AT24C08B来具体解释就是,AT24C08B共有1024个存储单元,每个存储单元的大小事8位(bits),而我们知道8位为一个字节,所以mini2440开发板的eeprom的大小为1024个字节,即1K大小,那么括弧里面的8K是什么意思的,8K的意思是总共有8*1024个位,不要混淆了哦。所以mini2440用户手册上说eeprom的大小是256字节是错误的,256字节那是AT24C0A的大小。

    查数据手册可以其地址为0xa0或0xa1。最低位为读写标志。在s3c2440中根据IIC模式自动选择,所以地址我们只需填写0xa0即可。

    值得注意的是EEPROM读写速度不是很快,所以每次读写一个字节都要加一定延时,这点十分关键。这往往是程序读写失败的原因。当然我们也需要设置好SCL的频率。在IICCON里设置这里不多说。

    在接收模式下最后一个字节数据不发送ACK这点也需要注意。

    测试代码中我们采用将数据写入EEPROM中然后读取出来输出到串口来检验,程序可以采用中断或轮询,代码如下:

    mian.c部分

    1. #define  GLOBAL_CLK 1  
    2.  
    3. #include "def.h"  
    4. #include "option.h"  
    5. #include "2440addr.h"  
    6. #include "profile.h"  
    7. #include "mmu.h"  
    8.   
    9. typedef unsigned char uchar;  
    10. typedef unsigned int uint;  
    11.   
    12. extern void AT24C08_wirte(uchar waddr, uchar *dat,  int num);  
    13. extern void AT24C08_read(uchar waddr, uchar *rev,  int num);  
    14. extern void IIC_init(void);  
    15. extern void delay(int time);  
    16.   
    17. uchar dat[]={"0123456789abcdef"};  
    18. uchar rev[50]={0};  
    19.   
    20. void Main(void)  
    21. {  
    22.   
    23.     rGPBCON=(1<<0);//关闭蜂鸣器  
    24.     rGPBDAT=0x00;  
    25.       
    26.     IIC_init();  
    27.   
    28.     AT24C08_wirte(0x00, dat, 16);  
    29.     Uart_Printf(" ");  
    30.     AT24C08_read(0x00, rev, 10);  
    31.       
    32.     Uart_Printf(" %s ",rev);  

     IIC.c部分

    1. #include "def.h"  
    2. #include "option.h"  
    3. #include "2440addr.h"  
    4. #include "profile.h"  
    5. #include "mmu.h"  
    6.   
    7. typedef unsigned char uchar;  
    8. typedef unsigned int uint;  
    9. void __irq IIC_INT(void);  
    10.   
    11. int flag=1;//中断标志  
    12.   
    13. void delay(int time)  
    14. {  
    15.     int i,j,k;  
    16.     for(i=0;i<100;++i)  
    17.         for(k=0;k<100;++k)  
    18.             for(j=0;j<time;j++);  
    19. }  
    20.   
    21. //IIC初始化  
    22. void IIC_init(void)  
    23. {  
    24.     //设置GPE15、GPE14为SDA、SCL  
    25.     rGPECON |= (0x0a<<28);  
    26.       
    27.     //允许ACK、允许中断、发送频率Khz  
    28.     rINTMSK &= ~(1<<27);  
    29.     rIICCON |= (1<<7 | 0<<6 | 1<<5 | 0xf);  
    30.     rIICSTAT |= 1<<4;//IICDS可写  
    31.       
    32.     MMU_Init();//映射地址  
    33.     pISR_IIC = (unsigned)IIC_INT;//中断入口  
    34. }  
    35.   
    36. //AT24C08页写  
    37. void AT24C08_wirte(uchar waddr, uchar *dat, int num)  
    38. {  
    39.     int i=0;  
    40.   
    41.     rIICDS = 0xa0;//AT24C08地址  
    42.     rIICSTAT =0xf0;//发送模式、发送开始信号  
    43.     while(flag == 1)  
    44.         delay(100);//等待中断  (等待ACK应答发出的中断信号)
    45.     flag = 1;  
    46.       
    47.     rIICDS = waddr;//起始地址  
    48.     rIICCON = 0xaf;//清除中断标志位  
    49.     while(flag == 1)  
    50.         delay(100);//等待中断  
    51.     flag = 1;  
    52.           
    53.     for(i=0;i<num;++i){  
    54.         rIICDS = *(dat + i);  
    55.         rIICCON = 0xaf;//清除中断标志位  
    56.         while(flag == 1)  
    57.             delay(100);//等待中断  
    58.         flag = 1;  
    59.     }  
    60.       
    61.     rIICSTAT =0xd0;//发送停止位  
    62.     rIICCON = 0xaf;//清除中断标志位  
    63.     delay(100);  
    64. }  
    65.   
    66. //AT24C08连续读          
    67. void AT24C08_read(uchar waddr, uchar *rev, int num)  
    68. {  
    69.     int i=0;  
    70.       
    71.     rIICDS = 0xa0;  
    72.     rIICSTAT =0xf0;//发送从机地址  
    73.     while(flag == 1)  
    74.         delay(100);//等待中断  
    75.     flag = 1;  
    76.       
    77.     rIICDS = waddr;//初始地址  
    78.     rIICCON = 0xaf;//清除中断标志位  
    79.     while(flag == 1)  
    80.         delay(100);//等待中断  
    81.     flag = 1;  
    82.       
    83.     rIICDS = 0xa0;  
    84.     rIICSTAT =0xb0;//接收模式  
    85.     rIICCON = 0xaf;//清除中断标志位  
    86.     while(flag == 1)  
    87.         delay(100);//等待中断  
    88.     flag = 1;  
    89.       
    90.     for(i=0;i<num;++i){  
    91.         if(i == (num-1)) rIICCON = 0x2f;  
    92.         else rIICCON = 0xaf;  
    93.         while(flag == 1)  
    94.             delay(100);//等待中断  
    95.         flag = 1;  
    96.         *(rev + i) = rIICDS;  
    97.         delay(100);  
    98.     }  
    99.       
    100.     rIICSTAT =0x90;//发送停止位  
    101.     rIICCON = 0xaf;//清除中断标志位  
    102.     delay(100);  
    103. }  
    104.   
    105. //中断服务函数  
    106. void __irq IIC_INT(void)  
    107. {  
    108.     flag = 0;  
    109.     rSRCPND |= 1<<27;//先清除SRCPND  
    110.     rINTPND |= 1<<27;  
    111. }  
    112.   
    113.   
    114. /* 
    115. #include "2440addr.h" 
    116.  
    117. typedef unsigned char uchar; 
    118. typedef unsigned int uint; 
    119.  
    120. void delay(int time) 
    121. { 
    122.     int i,j,k; 
    123.     for(i=0;i<100;++i) 
    124.         for(k=0;k<100;++k) 
    125.             for(j=0;j<time;j++); 
    126. } 
    127.  
    128. //IIC初始化 
    129. void IIC_init(void) 
    130. { 
    131.     //设置GPE15、GPE14为SDA、SCL 
    132.     rGPECON |=  (0x0a<<28); 
    133.     //允许ACK、允许中断、发送频率Khz 
    134.     rIICCON |= (1<<7 | 0<<6 | 1<<5 | 0xf); 
    135.     rIICSTAT |= (1<<4);//IICDS可写 
    136. } 
    137.  
    138. //AT24C08页写 
    139. void AT24C08_wirte(uchar waddr, uchar *dat, int num) 
    140. { 
    141.     int i=0; 
    142.  
    143.     rIICDS = 0xa0;//AT24C08地址 
    144.     rIICSTAT =0xf0;//发送模式、发送开始信号 
    145.     while(!(rIICCON & 0x10)) 
    146.         delay(100);//等待中断 
    147.  
    148.     rIICDS = waddr;//起始地址 
    149.     rIICCON &= ~(1<<4);//清除中断标志位 
    150.     while(!(rIICCON & 0x10)) 
    151.         delay(100);//等待中断 
    152.      
    153.     for(i=0;i<num;++i){ 
    154.         rIICDS = *(dat + i); 
    155.         rIICCON &= ~(1<<4);//清除中断标志位 
    156.         while(!(rIICCON & 0x10)) 
    157.             delay(100);//等待中断 
    158.     } 
    159.      
    160.     rIICSTAT =0xd0;//发送停止位 
    161.     rIICCON &= ~(1<<4);//清除中断标志位 
    162.     delay(100); 
    163. } 
    164.  
    165. //AT24C08连续读         
    166. void AT24C08_read(uchar waddr, uchar *rev, int num) 
    167. { 
    168.     int i=0; 
    169.  
    170.     rIICDS = 0xa0; 
    171.     rIICSTAT =0xf0;//发送EEPROM地址 
    172.     while(!(rIICCON & 0x10)) 
    173.         delay(100);//等待中断 
    174.      
    175.     rIICDS = waddr;//初始地址 
    176.     rIICCON &= ~(1<<4);//清除中断标志位 
    177.     while(!(rIICCON & 0x10)) 
    178.         delay(100);//等待中断 
    179.          
    180.     rIICDS = 0xa0; 
    181.     rIICSTAT =0xb0;//接收模式 
    182.     rIICCON &= ~(1<<4);//清除中断标志位 
    183.     while(!(rIICCON & 0x10)) 
    184.             delay(100);//等待中断 
    185.      
    186.     for(i=0;i<num;++i){ 
    187.         if(i == (num-1)) rIICCON &= ~(1<<7 | 1<<4);//不发送ACK 
    188.         else rIICCON &= ~(1<<4);//清除中断标志位 
    189.         while(!(rIICCON & 0x10)) 
    190.             delay(100);//等待中断 
    191.         *(rev+i) = rIICDS; 
    192.         delay(100); 
    193.     } 
    194.  
    195.     rIICSTAT =0x90;//发送停止位 
    196.     rIICCON &= ~(1<<4);//清除中断标志位 
    197.     delay(100); 
    198. } 
    199. */
  • 相关阅读:
    Linux Cannot allocate memory问题
    Linux后台运行Jar方法
    盒模型:外边距叠加和外边距为负值
    HTML如何创建二级目录
    css3实现立方体,并且自转效果
    前台技术--页面跳转的几种用法
    JS实现网站内容的禁止复制和粘贴、另存为
    网络爬虫大白话解析
    HTML5 canvas绘制arcTo、translate和rotate的画法探索
    HTML5实战与剖析之原生拖拽(一拖拽历史概述)
  • 原文地址:https://www.cnblogs.com/liuchengchuxiao/p/4204516.html
Copyright © 2020-2023  润新知