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
原文地址:https://www.cnblogs.com/fuzidage/p/15385819.html