• 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
  • 相关阅读:
    <EditText /> This text field does not specify an inputType or a hint
    phpmailer【PHP邮件】的用法
    IOS-Quartz2D(Paths元素)
    IOS-网络(网页开发-UIWebView,HTML,CSS,JavaScript,OC和JS代码互调)
    IOS学习路线图
    Android学习必备--java工具15个
    IOS-网络(ASI使用)
    IOS-网络(ASIHTTPRequest的使用简介)
    IOS-网络(AFNetworking)
    IOS-网络(文件压缩和解压缩)
  • 原文地址:https://www.cnblogs.com/fuzidage/p/15385819.html
Copyright © 2020-2023  润新知