zoukankan      html  css  js  c++  java
  • s3c2440裸机-I2c编程-3.i2c中断服务程序

    Start信号之后,发出设备地址,在第9个时钟就会产生一个中断,我们根据i2c的流程图来编写中断程序。

    每传输完一个数据将产生一个中断,I2C操作的主体在中断服务程序,它可以分为两部分:写操作,读操作。

    完整code如下:

    static p_i2c_msg p_cur_msg;
     
    int isLastData(void)
    {
            if (p_cur_msg->cnt_transferred == p_cur_msg->len - 1)
                    return 1;  /* 正要开始传输最后一个数据 */
            else 
                    return 0;
    }
     
    void resume_iic_with_ack(void)
    {
            unsigned int iiccon = IICCON;
            iiccon |= (1<<7); /* 回应ACK */
            iiccon &= ~(1<<4); /* 恢复IIC操作 */
            IICCON =  iiccon;
    }
     
    void resume_iic_without_ack(void)
    {
            unsigned int iiccon = IICCON;
            iiccon &= ~((1<<7) | (1<<4)); /* 不回应ACK, 恢复IIC操作 */
            IICCON =  iiccon;
    }
     
    void i2c_interrupt_func(int irq)
    {
            int index;
            unsigned int iicstat = IICSTAT;
            unsigned int iiccon;
     
            //printf("i2c_interrupt_func! flags = %d
    
    ", p_cur_msg->flags);
     
            p_cur_msg->cnt_transferred++;
            
            /* 每传输完一个数据将产生一个中断 */
     
            /* 对于每次传输, 第1个中断是"已经发出了设备地址" */
     
            if (p_cur_msg->flags == 0)        /* write */
            {
                    /* 对于第1个中断, 它是发送出设备地址后产生的
                     * 需要判断是否有ACK
                     * 有ACK : 设备存在
                     * 无ACK : 无设备, 出错, 直接结束传输
                     */
                    if (p_cur_msg->cnt_transferred == 0)  /* 第1次中断 */
                    {
                            if (iicstat & (1<<0)) /*iicstat [0] == 1表示no ack*/
                            { /* no ack */
                                    /* 停止传输 */
                                    IICSTAT = 0xd0;
                                    IICCON &= ~(1<<4); //clear pending bit
                                    p_cur_msg->err = -1;
                                    printf("tx err, no ack
    
    ");
                                    delay(1000);
                                    return;
                            }
                    }
            if (p_cur_msg->cnt_transferred < p_cur_msg->len)
            {
                    /* 对于其他中断, 要继续发送下一个数据
                     */
                    IICDS = p_cur_msg->buf[p_cur_msg->cnt_transferred];
                    IICCON &= ~(1<<4);//clear pending bit
            }
            else
            {
                    /* 停止传输 */
                    IICSTAT = 0xd0;
                    IICCON &= ~(1<<4);
                    delay(1000);
            }
            }
            else /* read */
            {
                    /* 对于第1个中断, 它是发送出设备地址后产生的
                     * 需要判断是否有ACK
                     * 有ACK : 设备存在, 恢复I2C传输, 这样在下一个中断才可以得到第1个数据
                     * 无ACK : 无设备, 出错, 直接结束传输
                     */
                    if (p_cur_msg->cnt_transferred == 0)  /* 第1次中断 */
                    {
                            if (iicstat & (1<<0))
                            { /* no ack */
                                    /* 停止传输 */
                                    IICSTAT = 0x90;
                                    IICCON &= ~(1<<4); //clear pending bit
                                    p_cur_msg->err = -1;
                                    printf("rx err, no ack
    
    ");
                                    delay(1000);
                                    return;
                            }
                            else  /* ack */
                            {
                                    /* 如果是最后一个数据, 启动传输时要设置为不回应ACK */
                                    /* 恢复I2C传输 */
                                    if (isLastData())
                                    {
                                            resume_iic_without_ack();
                                    }
                                    else
                                    {
                                            resume_iic_with_ack();
                                    }
                                    return;
                            }
                    }
     
            /* 非第1个中断, 表示得到了一个新数据
             * 从IICDS读出、保存
             */
            if (p_cur_msg->cnt_transferred < p_cur_msg->len)
            {
                    index = p_cur_msg->cnt_transferred - 1;
                    p_cur_msg->buf[index] = IICDS;
     
            /* 如果是最后一个数据, 启动传输时要设置为不回应ACK */
            /* 恢复I2C传输 */
            if (isLastData())
            {
                    resume_iic_without_ack();
            }
            else
            {
                    resume_iic_with_ack();
            }
            }
            else
            {
                    /* 发出停止信号 */
                    IICSTAT = 0x90;
                    IICCON &= ~(1<<4);
                    delay(1000);
            }
    }

    View Code

    写操作:

            if (p_cur_msg->flags == 0)        /* write */
            {
                    /* 对于第1个中断, 它是发送出设备地址后产生的
                     * 需要判断是否有ACK
                     * 有ACK : 设备存在
                     * 无ACK : 无设备, 出错, 直接结束传输
                     */
                    if (p_cur_msg->cnt_transferred == 0)  /* 第1次中断 */
                    {
                            if (iicstat & (1<<0)) /*iicstat [0] == 1表示no ack*/
                            { /* no ack */
                                    /* 停止传输 */
                                    IICSTAT = 0xd0;
                                    IICCON &= ~(1<<4); //clear pending bit
                                    p_cur_msg->err = -1;
                                    printf("tx err, no ack
    
    ");
                                    delay(1000);
                                    return;
                            }
                    }
                    if (p_cur_msg->cnt_transferred < p_cur_msg->len)
                    {
                            /* 对于其他中断, 要继续发送下一个数据
                             */
                            IICDS = p_cur_msg->buf[p_cur_msg->cnt_transferred];
                            IICCON &= ~(1<<4);//clear pending bit
                    }
                    else
                    {
                            /* 停止传输 */
                            IICSTAT = 0xd0;
                            IICCON &= ~(1<<4);
                            delay(1000);
                    }
            }

    1).p_cur_msg->cnt_transferred初始值为-1(do_master_tx启动时设置)。

    2).p_cur_msg->cnt_transferred == 0表示是第一次传输数据完后产生的中断,即发送从设备地址产生的中断。

    3).iicstat & (1<<0)表示主机没有接受到ACK信号(即发出的设备地址不存在),需要停止传输。

    4).IICSTAT = 0xd0置IICSTAT寄存器的[5]写为0,产生P信号。但是由于这时IICCON[4]仍为1,P信号没有实际发出,当执行IICCON &= ~(1<<4);清除IICCON[4]后,P信号才真正发出。

    5).等待一段时间,确保P信号已经发送完毕。

    1).假如if (p_cur_msg->cnt_transferred < p_cur_msg->len)条件成立,表示数据还没有发送完毕,需要继续发送数据。

    2).执行IICDS = p_cur_msg->buf[p_cur_msg->cnt_transferred]把要发送的数据写入到IICDS寄存器中,经过执行IICCON &= ~(1<<4);清除中断标志后后,紧接着就自动把数据发送出去了,这将触发下一个中断。

    3).如果条件不成立表示数据传输完毕,发出P信号,停止数据的传输。

    读操作:

    else /* read */
    {
            /* 对于第1个中断, 它是发送出设备地址后产生的
             * 需要判断是否有ACK
             * 有ACK : 设备存在, 恢复I2C传输, 这样在下一个中断才可以得到第1个数据
             * 无ACK : 无设备, 出错, 直接结束传输
             */
            if (p_cur_msg->cnt_transferred == 0)  /* 第1次中断 */
            {
                    if (iicstat & (1<<0))
                    { /* no ack */
                            /* 停止传输 */
                            IICSTAT = 0x90;
                            IICCON &= ~(1<<4); //clear pending bit
                            p_cur_msg->err = -1;
                            printf("rx err, no ack
    
    ");
                            delay(1000);
                            return;
                    }
                    else  /* ack */
                    {
                            /* 如果是最后一个数据, 启动传输时要设置为不回应ACK */
                            /* 恢复I2C传输 */
                            if (isLastData())
                            {
                                    resume_iic_without_ack();
                            }
                            else
                            {
                                    resume_iic_with_ack();
                            }
                            return;
                    }
            }
    
            /* 非第1个中断, 表示得到了一个新数据
             * 从IICDS读出、保存
             */
            if (p_cur_msg->cnt_transferred < p_cur_msg->len)
            {
                    index = p_cur_msg->cnt_transferred - 1;
                    p_cur_msg->buf[index] = IICDS;
    
                    /* 如果是最后一个数据, 启动传输时要设置为不回应ACK */
                    /* 恢复I2C传输 */
                    if (isLastData())
                    {
                            resume_iic_without_ack();
                    }
                    else
                    {
                            resume_iic_with_ack();
                    }
            }
            else
            {
                    /* 发出停止信号 */
                    IICSTAT = 0x90;
                    IICCON &= ~(1<<4);
                    delay(1000);
            }
    }

    测试: 

    void do_write_at24cxx(void)
    {
        unsigned int addr;
        unsigned char str[100];
        int err;
        
        /* 获得地址 */
        printf("Enter the address of sector to write: ");
        addr = get_uint();
    
        if (addr > 256)
        {
            printf("address > 256, error!
    
    ");
            return;
        }
    
        printf("Enter the string to write: ");
        gets(str);
    
        printf("writing ...
    
    ");
        err = at24cxx_write(addr, str, strlen(str)+1);
        printf("at24cxx_write ret = %d
    
    ", err);
    }
    
    void do_read_at24cxx(void)
    {
        unsigned int addr;
        int i, j;
        unsigned char c;
        unsigned char data[100];
        unsigned char str[16];
        int len;
        int err;
        int cnt = 0;
        
        /* 获得地址 */
        printf("Enter the address to read: ");
        addr = get_uint();
    
        if (addr > 256)
        {
            printf("address > 256, error!
    
    ");
            return;
        }
    
        /* 获得长度 */
        printf("Enter the length to read: ");
        len = get_int();
    
        err = at24cxx_read(addr, data, len);
        printf("at24cxx_read ret = %d
    
    ", err);
    
        printf("Data : 
    
    ");
        /* 长度固定为64 */
        for (i = 0; i < 4; i++)
        {
            /* 每行打印16个数据 */
            for (j = 0; j < 16; j++)
            {
                /* 先打印数值 */
                c = data[cnt++];
                str[j] = c;
                printf("%02x ", c);
            }
    
        printf("   ; ");
    
        for (j = 0; j < 16; j++)
        {
            /* 后打印字符 */
            if (str[j] < 0x20 || str[j] > 0x7e)  /* 不可视字符 */
                putchar('.');
            else
                putchar(str[j]);
        }
        printf("
    
    ");
        }
    }
    
    
    void i2c_test(void)
    {
        char c;
    
        /* 初始化 */
        i2c_init();
    
        while (1)
        {
            /* 打印菜单, 供我们选择测试内容 */
            printf("[w] Write at24cxx
    
    ");
            printf("[r] Read at24cxx
    
    ");
            printf("[q] quit
    
    ");
            printf("Enter selection: ");
    
                c = getchar();
                printf("%c
    
    ", c);
            
                /* 测试内容:
                 * 3. 编写某个地址
                 * 4. 读某个地址
                 */
                switch (c)                 
                {
                    case 'q':
                    case 'Q':
                        return;
                        break;
                        
                    case 'w':
                    case 'W':
                        do_write_at24cxx();
                        break;
            
                case 'r':
                case 'R':
                    do_read_at24cxx();
                    break;
                default:
                    break;
                }
        }
    }
    View Code
  • 相关阅读:
    poj 3616 Milking Time
    poj 3176 Cow Bowling
    poj 2229 Sumsets
    poj 2385 Apple Catching
    poj 3280 Cheapest Palindrome
    hdu 1530 Maximum Clique
    hdu 1102 Constructing Roads
    codeforces 592B The Monster and the Squirrel
    CDOJ 1221 Ancient Go
    hdu 1151 Air Raid(二分图最小路径覆盖)
  • 原文地址:https://www.cnblogs.com/fuzidage/p/15385819.html
Copyright © 2011-2022 走看看