溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

arm9 IIC接口有什么用

發(fā)布時(shí)間:2021-12-20 10:46:42 來(lái)源:億速云 閱讀:108 作者:iii 欄目:互聯(lián)網(wǎng)科技

本篇內(nèi)容主要講解“arm9 IIC接口有什么用”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“arm9 IIC接口有什么用”吧!

在2440的使用中其iic接口一般用來(lái)讀取外圍芯片的數(shù)據(jù), 這種情況下2440處于主機(jī)模式, 本例用中斷的方式來(lái)講述 主機(jī)發(fā)送/主機(jī)接收 模式.

主機(jī)發(fā)送模式使用流程:

arm9 IIC接口有什么用

    IICCON: 是否返回ack, 總線時(shí)鐘選擇, 中斷標(biāo)志

arm9 IIC接口有什么用

IICCON[7]  在發(fā)送模式該位沒(méi)有意義, 因?yàn)榘l(fā)送模式下主機(jī)只接收ACK信號(hào), 并不主動(dòng)發(fā)出ACK. 

                    在接收模式中當(dāng)從機(jī)返回了數(shù)據(jù)之后, 如果主機(jī)需要從機(jī)繼續(xù)返回?cái)?shù)據(jù)就必須發(fā)送一個(gè)ACK, 否則數(shù)據(jù)發(fā)送方不會(huì)繼續(xù)發(fā)送數(shù)據(jù). 

綜上: 無(wú)論是主/從, 只要接收數(shù)據(jù)的一方想要繼續(xù)通信就必須要發(fā)送一個(gè)ACK信號(hào), 所以ACK信號(hào)絕對(duì)是由接收數(shù)據(jù)的一方來(lái)發(fā)出的. 

IICCON[5] 必須為1, 否則IICCON[4]無(wú)法使用

IICCON[4] 0: 無(wú)中斷發(fā)生   1: 有中斷發(fā)生, 這時(shí)總線傳輸中止. 如果要繼續(xù)傳輸則需將該位清0

發(fā)生中斷的條件: 1. 總線仲裁失敗   2. 發(fā)送/接收完一個(gè)字節(jié)  3. 當(dāng)廣播或從地址匹配成功

    GPEUP  |= 0xc000;       // 禁止內(nèi)部上拉
    GPECON |= 0xa0000000;   // 選擇引腳功能:GPE15:IICSDA, GPE14:IICSCL

    INTMSK &= ~(BIT_IIC);	//清除IIC中斷屏蔽位

    /* bit[7] = 1, 使能ACK
     * bit[6] = 0, IICCLK = PCLK/16
     * bit[5] = 1, 使能中斷
     * bit[3:0] = 0xf, Tx clock = IICCLK/16
     * PCLK = 50MHz, IICCLK = 3.125MHz, Tx Clock = 0.195MHz
     */
    IICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);  // 0xaf

    IICSTAT = 0x10;     // IICSTAT[4]:I2C串行輸出使能(Rx/Tx), 這里可以不必配置該寄存器, 因?yàn)檎嬲_始發(fā)送/接收的時(shí)候會(huì)重新配置IICSTAT(見下邊的I2C_Write)

IICADD: 當(dāng)2440作為從機(jī)的時(shí)候, 本身的iic地址可以由該寄存器來(lái)設(shè)置. 

IICSTAT :  主從模式選擇,  S/P信號(hào)發(fā)送, 標(biāo)記各種狀態(tài)

arm9 IIC接口有什么用

IICSTAT[7:6] 主從模式選擇

IICSTAT[5] 讀取此位時(shí) 0 : 總線空閑,  1 : 總線忙 ;   寫入0: 發(fā)出 P 信號(hào),   寫入 1: 發(fā)出 S 信號(hào)

IICSTAT[4] 開啟收發(fā)

IICSTAT[3] 總線仲裁成功標(biāo)志位

IICSTAT[2]  當(dāng)2440作為從機(jī)時(shí), 接收到的地址和IICADD匹配則該位置一, 在檢測(cè)到 S/P 信號(hào)時(shí)自動(dòng)清0

IICSTAT[1] 當(dāng)接收到 0x00 地址時(shí)置一, 當(dāng)檢測(cè)到 S/P 信號(hào)時(shí)自動(dòng)清0

IICSTAT[0] 0: 接收到ACK;   1: 沒(méi)有接收到ACK

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *以下為中斷方式操作I2C接口的主要代碼, 從機(jī)芯片為 m41t11* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

在啟動(dòng)文件中設(shè)定好I2C中斷的異常向量, 在ISR中清除異常標(biāo)志

//head.S中設(shè)置異常向量
@ 0x1c: 快中斷模式的向量地址
HandleFIQ:
    b   HandleFIQ
    
//interrupt.c中的ISR, 該ISR總查詢到了IIC中斷, 調(diào)取了IIC異常處理函數(shù)
void IRQ_Handle(void)
{
	unsigned long oft = INTOFFSET;

	//清中斷
	if (oft == 4)
        EINTPEND = 1<<7;    //EINT4-7合用IRQ4,注意EINTPEND[3:0]保留未用,向這些位寫入1可能導(dǎo)致未知結(jié)果

	SRCPND = 1<<oft;
	INTPND = INTPND;

    /* 調(diào)用中斷服務(wù)程序 */
    isr_handle_array[oft]();
}

以下為IIC的主要操作:

#define WRDATA      (1)
#define RDDATA      (2)

typedef struct tI2C {
    unsigned char *pData;   /* 數(shù)據(jù)緩沖區(qū) */
    volatile int DataCount; /* 等待傳輸?shù)臄?shù)據(jù)長(zhǎng)度 */
    volatile int Status;    /* 狀態(tài) */
    volatile int Mode;      /* 模式:讀/寫 */
    volatile int Pt;        /* pData中待傳輸數(shù)據(jù)的位置 */
}tS3C24xx_I2C, *ptS3C24xx_I2C;

static tS3C24xx_I2C g_tS3C24xx_I2C;

// I2C初始化
void i2c_init(void)
{
    GPEUP  |= 0xc000;       // 禁止內(nèi)部上拉
    GPECON |= 0xa0000000;   // 選擇引腳功能:GPE15:IICSDA, GPE14:IICSCL

    INTMSK &= ~(BIT_IIC);   //允許IIC中斷

    /* bit[7] = 1, 使能ACK
     * bit[6] = 0, IICCLK = PCLK/16
     * bit[5] = 1, 使能中斷
     * bit[3:0] = 0xf, Tx clock = IICCLK/16
     * PCLK = 50MHz, IICCLK = 3.125MHz, Tx Clock = 0.195MHz
     */
    IICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);  // 0xaf

    IICADD  = 0x10;     // S3C24xx slave address = [7:1]  這句可以不需要的, 該寄存器只在2440作為從機(jī)才有用
    IICSTAT = 0x10;     // I2C串行輸出使能(Rx/Tx)    這句也可以不用, 因?yàn)檎嬲龑懙臅r(shí)候又重新配置了IICSTAT
}

/*
 * 主機(jī)發(fā)送
 * slvAddr : 從機(jī)地址,buf : 數(shù)據(jù)存放的緩沖區(qū),len : 數(shù)據(jù)長(zhǎng)度 
 */
void i2c_write(unsigned int slvAddr, unsigned char *buf, int len)
{
    g_tS3C24xx_I2C.Mode = WRDATA;   // 寫操作
    g_tS3C24xx_I2C.Pt   = 0;        // 索引值初始為0
    g_tS3C24xx_I2C.pData = buf;     // 保存緩沖區(qū)地址
    g_tS3C24xx_I2C.DataCount = len; // 傳輸長(zhǎng)度
    
    IICDS   = slvAddr;
    IICSTAT = 0xf0;         // 主機(jī)發(fā)送,啟動(dòng)
    
    /* 等待直至數(shù)據(jù)傳輸完畢 */    
    while (g_tS3C24xx_I2C.DataCount != -1);
}
        
//  主機(jī)接收
//  slvAddr : 從機(jī)地址,buf : 數(shù)據(jù)存放的緩沖區(qū),len : 數(shù)據(jù)長(zhǎng)度 
void i2c_read(unsigned int slvAddr, unsigned char *buf, int len)
{
    g_tS3C24xx_I2C.Mode = RDDATA;   // 讀操作
    g_tS3C24xx_I2C.Pt   = -1;       // 索引值初始化為-1,表示第1個(gè)中斷時(shí)不接收數(shù)據(jù)(地址中斷)
    g_tS3C24xx_I2C.pData = buf;     // 保存緩沖區(qū)地址
    g_tS3C24xx_I2C.DataCount = len; // 傳輸長(zhǎng)度
    
    IICDS        = slvAddr;
    IICSTAT      = 0xb0;    // 主機(jī)接收,啟動(dòng)
    
    /* 等待直至數(shù)據(jù)傳輸完畢 */    
    while (g_tS3C24xx_I2C.DataCount != -1);
}

//  I2C中斷服務(wù)程序
//  根據(jù)剩余的數(shù)據(jù)長(zhǎng)度選擇繼續(xù)傳輸或者結(jié)束
void I2CIntHandle(void)
{
    unsigned int iicSt,i;

    // 清中斷
    SRCPND = BIT_IIC;
    INTPND = BIT_IIC;

    iicSt  = IICSTAT;

    //先判斷是不是仲裁失敗引起的中斷
    if(iicSt & 0x8){ printf("Bus arbitration failed\n\r"); }

    switch (g_tS3C24xx_I2C.Mode)
    {
        case WRDATA:
        {
            //檢測(cè)是否數(shù)據(jù)發(fā)送完畢, 若完畢: 發(fā)送P信號(hào), 數(shù)據(jù)長(zhǎng)度=-1
            if((g_tS3C24xx_I2C.DataCount--) == 0)
            {
                // 下面兩行用來(lái)恢復(fù)I2C操作,發(fā)出P信號(hào)
                IICSTAT = 0xd0;
                IICCON  = 0xaf;
                Delay(10000);  // 等待一段時(shí)間以便P信號(hào)已經(jīng)發(fā)出
                break;         //注意這里的break, 發(fā)送P信號(hào)完畢直接返回.
            }
            //若數(shù)據(jù)未發(fā)送完畢直接發(fā)送, 緩沖區(qū)索引值++
            IICDS = g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++];

            // 將數(shù)據(jù)寫入IICDS后,需要一段時(shí)間才能出現(xiàn)在SDA線上
            for (i = 0; i < 10; i++);

            IICCON = 0xaf;      // 恢復(fù)I2C傳輸
            break;
        }

        case RDDATA:
        {
            // 這次中斷是發(fā)送I2C設(shè)備地址后發(fā)生的,沒(méi)有數(shù)據(jù), 第一次發(fā)送完地址之后(發(fā)送完一個(gè)字節(jié)會(huì)產(chǎn)生中斷)產(chǎn)生的中斷, 接收數(shù)據(jù)之后2440是需要發(fā)出ACK信號(hào)的
            if (g_tS3C24xx_I2C.Pt == -1)
            {
                // 只接收一個(gè)數(shù)據(jù)時(shí),不要發(fā)出ACK信號(hào)
                g_tS3C24xx_I2C.Pt = 0;//準(zhǔn)備從數(shù)據(jù)緩存區(qū)的0開始發(fā)送數(shù)據(jù)
                if(g_tS3C24xx_I2C.DataCount == 1)
                   IICCON = 0x2f;   // 恢復(fù)I2C傳輸,開始接收數(shù)據(jù),關(guān)閉ACK, 接收到數(shù)據(jù)時(shí)不發(fā)出ACK, 最后一個(gè)數(shù)據(jù)要先關(guān)閉ack, 因?yàn)樽詈笠粋€(gè)數(shù)據(jù)要發(fā)送no ack, 其實(shí)就是不發(fā)送ack
                else
                   IICCON = 0xaf;   // 恢復(fù)I2C傳輸,開始接收數(shù)據(jù), 0x2f與0xaf的區(qū)別就是前者不開ack
                break;
            }

            if ((g_tS3C24xx_I2C.DataCount--) == 0)
            {
            	//如果要讀取的剩余數(shù)據(jù)長(zhǎng)度為0, 就發(fā)送P信號(hào)
                g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++] = IICDS;

                // 下面兩行恢復(fù)I2C操作,發(fā)出P信號(hào)
                IICSTAT = 0x90;
                IICCON  = 0xaf;
                Delay(10000);  // 等待一段時(shí)間以便P信號(hào)已經(jīng)發(fā)出
                break;
            }

           g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++] = IICDS;

           // 接收最后一個(gè)數(shù)據(jù)時(shí),不要發(fā)出ACK信號(hào)
           if(g_tS3C24xx_I2C.DataCount == 0)
               IICCON = 0x2f;   // 恢復(fù)I2C傳輸,接收到下一數(shù)據(jù)時(shí)無(wú)ACK
           else
               IICCON = 0xaf;   // 恢復(fù)I2C傳輸,接收到下一數(shù)據(jù)時(shí)發(fā)出ACK
           break;
        }

        default:
            break;
    }
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *以上為中斷方式操作I2C總線, 以下使用輪詢方式來(lái)操作* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

以下以 LM75(數(shù)字溫度傳感器) 來(lái)說(shuō)明 輪詢方式 讀取溫度值的方法. 

控制過(guò)程: 1. 讀取溫度值之前需要先指定 LM75 的寄存器, LM75 的寄存器 0x0 是溫度寄存器器(READ ONLY).  所以先發(fā)送S信號(hào)再發(fā)送 LM75 的地址, 然后發(fā)送 0x0 就可以選中溫度寄存器

                2. 選中溫度寄存器之后, LM75 會(huì)將 高/低 字節(jié)依次發(fā)送到I2C總線. 所以, 再次發(fā)送 LM75 地址, 讀取 高/低 字節(jié)  發(fā)送P信號(hào)結(jié)束傳輸.

int set_pointer_and_read_2byte(int mode)
{	
	//主機(jī)發(fā)送模式, 選中溫度寄存器
        I2C0.I2CDS0 = 0x90;                // 發(fā)送LM75地址 
	I2C0.I2CCON0 = 0xe0;                // 使能, PRESCALER:512 ,RX/TX 中斷使能
	I2C0.I2CSTAT0 =0xf0;                // 主發(fā)送模式, 啟動(dòng), 使能 RX/TX 
	while(!(I2C0.I2CCON0&(1<<4)));    // 等待直至發(fā)送完成 
	
	I2C0.I2CDS0 = mode;                // READ TEMPERATURE ONLY 讀取溫度寄存器
	I2C0.I2CCON0 &= ~(1<<4);            // 清除掛起標(biāo)志 & 恢復(fù)總線操作 
	while(!(I2C0.I2CCON0&(1<<4)));    // 等待直至發(fā)送完成 
	
        //主機(jī)接收模式, 開始接收溫度數(shù)據(jù)
	I2C0.I2CDS0 = 0x91;                // 重新發(fā)送LM75地址 
	I2C0.I2CSTAT0 =0xb0;                // 主機(jī)接收模式, 啟動(dòng), 使能 RX/TX 
	I2C0.I2CCON0  &= ~(1<<4);            // 清除掛起標(biāo)志 & 恢復(fù)總線操作 
	while(!(I2C0.I2CCON0&(1<<4)));        // 等待直至發(fā)送完成 

	I2C0.I2CCON0 &= ~(1<<4);             // 清除掛起標(biāo)志 & 恢復(fù)總線操作 
	while(!(I2C0.I2CCON0&(1<<4)));        // 等待直至讀取完成 
	high = I2C0.I2CDS0;                // 讀取低8位數(shù)據(jù) 

	I2C0.I2CCON0 &= ~((1<<7)|(1<<4));// 清除掛起標(biāo)志 & 恢復(fù)總線操作 & 禁止發(fā)送 ACK  
	while(!(I2C0.I2CCON0&(1<<4)));        // 等待直至讀取完成  
	low = I2C0.I2CDS0;                    // 讀取更低字節(jié)數(shù)據(jù)(小數(shù)部分 ?)  

	I2C0.I2CSTAT0 &= ~(1<<5);        // 發(fā)送 P信號(hào), 釋放總線  
	I2C0.I2CCON0 &= ~(1<<4);        // 清除中斷標(biāo)志位  
	return ((high << 8) | low);
}

到此,相信大家對(duì)“arm9 IIC接口有什么用”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI