日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【51单片机快速入门指南】4.5:I2C 与 TCA6416实现双向 IO 扩展

發布時間:2023/12/9 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【51单片机快速入门指南】4.5:I2C 与 TCA6416实现双向 IO 扩展 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • 硬知識
    • IO 擴展芯片 TCA6416A
      • TAC6416A 的寄存器
        • IO 輸入寄存器
        • IO 輸出寄存器
        • IO 反相寄存器
        • IO 方向寄存器
      • TCA6416A 的操作
        • TCA6416A 寫數據
        • TCA6416A 讀數據
        • TCA6416A 的 IO 輸入寄存器
    • 硬件布局
  • 示例程序
    • TCA6416A.c
    • TCA6416A.h
  • 測試程序
    • main.c
    • 實驗現象

普中51-單核-A2
STC89C52
MSP430G2553 Launchpad 擴展板
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0
上位機:Vofa+ 1.3.10


???????摘自《Launchpad口袋實驗平臺(指導書)》、《AY-G2PL KIT_用戶手冊》

硬知識

???????對于低速的 IO,可以通過串行轉并行的方法擴展。1 片 I2C 接口控制的 IO 擴展芯片 TCA6416A可為 單片機額外擴展出 16 個雙向 IO。
???????擴展輸出口的方法其實就是將串行數據轉為并行數據輸出,串入并出移位寄存器加一個鎖存器就可以將串行轉并行輸出(也就是擴展了 IO 口),比如 74 系列通用數字邏輯器件74HC595,可以任意級聯擴展輸出口。
???????串行轉并行的代價就是速度會變慢,理論上,1 串轉 16 并輸出,速度至少要降 16 倍。假如普通 IO 翻轉電平的速度是 1MHz,轉 16 并輸出后,速度將降為 62.5kHz。這個速度對于很多應用已綽綽有余,比如和人有關的輸入輸出設備(鍵盤、段式 LCD/LED 驅動、點陣LCD/LED 驅動等)。
???????擴展輸入口的方法類似,只不過使用的是并入串出的移位寄存器。

IO 擴展芯片 TCA6416A

???????類似 74HC595 的串并轉換芯片雖然廉價,但是它只能擴展輸出口,不能同時擴展出雙向IO 口。而TCA6416A則是基于 I2C 控制的雙向 IO 擴展芯片。

  • TCA6416A 可以擴展出 16 個雙向 IO 口,為了與單片機原生的 IO 區別,圖中TCA6416A 擴展出的 IO 標注為 IO00-IO07,IO10-IO17。
  • ADDR 引腳是 I2C 設備的地址引腳,通過接地或 VCC 可設置為兩個不同的地址,換句話說,1 組 I2C 總線上可掛兩片 TCA6416A(ADDR 引腳分別接地和接 VCC)。
  • /INT 引腳是專門為擴展輸入引腳設計的,相當于單片機的外部中斷。當擴展 IO 設為輸入模式,且輸入電平變化時,/INT 引腳便會觸發下降沿中斷,單片機的 IO 再去檢測/INT 的下降沿,觸發真正的單片機中斷。單片機通過 I2C 協議查看 TCA6416A 的相關寄存器,便知曉是哪個 IO 被按下。
  • /RESET 引腳地位相當于單片機的復位引腳,為了節約單片機為數不多的 IO口,這里仿照單片機的上電復位電路用 R2 和 C6 給 TCA6416 也設計了上電復位電路。
  • SDA、SCL 和/INT 引腳必須外接上拉電阻(R31/32/33)。
  • 電源 VCC 和地 GND 之間接電容 C5(100nF,標柱為 104)進行去耦,起到“有病治病無病強身”的作用。
  • TAC6416A 的寄存器

    ???????首先我們把 TCA6416A 擴展出的 16 個普通 IO 口,理解為成單片機的 P0 和 P1 口,CPU對 IO 口的讀寫實際上都是通過寄存器這個中介進行的。其次,參考圖 12.3 的移位寄存器原理,擴展出的 IO 也是無法位操作的,讀寫都必須多位同時進行。TAC6416A 的寄存器設計其實很好理解,共 4 組寄存器,我們不妨先分析一下需要哪 4 組。

  • 需要 16 位的 Input Port Registers 來存儲 16 個 IO 的輸入狀態,相當于單片機中的PxIN。
  • 需要 16 位的 Output Port Registers 來存儲 16 個 IO 的輸入狀態,相當于單片機中的PxOUT。
  • 需要 16 位的 Configuration Registers 來存儲 IO 的輸入輸出方向,相當于單片機中的PxDIR。
  • 需要 16 位的 Polarity Inversion Registers 來存儲是否對 IO1/0 取反操作,這個功能在單片機中沒有。
  • ???????CPU 對于 IO 口的操作有置 1,置 0 和取反三種,單片機可以通過先讀出 IO 狀態,再做異或邏輯的辦法實現取反。但是在 TCA6416A 中,就必須先用 I2C 協議讀 Input Port Registers ,CPU 運算后,再用 I2C 寫 Output Port Registers ,這個時間非常長。所以TCA6416A 直接就集成了硬件 IO 電平翻轉電路,相當于“復雜指令集”了一回。
    ???????實際的 TCA6416A 寄存器,使用 TCA6416A 的過程就是配置這幾個寄存器。

    IO 輸入寄存器

    IO 輸出寄存器

    IO 反相寄存器

    IO 方向寄存器

    TCA6416A 的操作

    TCA6416A 寫數據

    ???????對 TCA6416A 來說,可能要寫 3 種數據,IO 輸出電平寄存器,IO 方向寄存器,IO 電平極性翻轉寄存器,3 個寄存器都影響實際的 IO 輸出,所以這 3 者的地位是完全平等的,寫的方法也一樣。
    ???????如圖 12.9 所示為 TCA6416A 的寫寄存器操作時序圖。原說明書中將寫 IO 與寫寄存器分開畫圖,其實這完全沒有必要,寫 IO 的本質還是寫寄存器。一次完整的寫寄存器分 4 部分:

  • 從機地址:從機地址的前 6 位固定為 010000,為什么不定成 000000 呢?這是因為如果每種類型的 I2C 從機設備都從 000000 起始的話,那地址就區分不開了,所以每種 I2C 設備都會跳開一段地址賦值。第 7 位是真正的地址,只有兩種可能。第 8 位用于表示讀操作還是寫操作。
  • 命令字:這 8 位實際就是選擇寫哪個寄存器。高 5 位固定,用低 3 位表示 8 種寄存器。
  • 寄存器 0:先寫寄存器 0,高位在前,低位在后。
  • 寄存器 1:后寫寄存器 1。
  • TCA6416A 讀數據

    ???????單片機在真正讀 TCA6416A 數據前,需要寫命令告訴 TCA6416A 是操作哪個寄存器。然后才是真正的讀數據。寫命令需要 2 字節,從機地址+命令。讀數據需要 3 個字節,從機地址+低位數據+高位數據。

    TCA6416A 的 IO 輸入寄存器

    ???????如圖 12.11 所示為讀 IO 輸入寄存器的“讀數據”操作時序圖部分(即為圖 12.10 的后半部分,不包括寫命令部分)。為了把個各種異常情況下的現象都描述清楚,圖 12.11 做的非常復雜。
    ???????只需注意,圖中 IO 電平共變化了 5 次,而實際被單片機讀到的卻是兩次鎖存 IO 電平時刻對應的數據 Data1 和數據 Data4。

    ???????為了模擬普通 IO 的輸入中斷,TAC6416A 啟用了一個類似的/INT 中斷來提示輸入 IO 有變化。但是由于 IO 輸入的變化速度可能遠高于讀 IO 輸入寄存器的速度,所以,TAC6416A的中斷和單片機的 IO 外部中斷還不太一樣。輸入 IO 的變化可以觸發/INT 產生下降沿變成低電平,但是/INT 要等 I2C 的應答位才能恢復高電平(重新具備中斷能力)。也就是說,TCA6416A 的/INT 中斷無法響應快速變化的輸入信號,當然我們也可以不用中斷的方法判斷IO 輸入,定時掃描的方法同樣適用于 TCA6416A。

    硬件布局


    如圖所示,擴展出 16 個 IO 口中,8 個作為輸出口用于控制 8 個 LED,4 個作為輸
    出口用于控制 LCD 驅動器(這個另行介紹),4 個作為輸入口用于識別 4 個機械按鍵。

    下圖所示為 8 個 LED 以及 4 個機械按鍵在擴展板中的位置

    示例程序

    ???????stdint.h見【51單片機快速入門指南】1:基礎知識和工程創建
    ???????軟件I2C程序見【51單片機快速入門指南】4: 軟件 I2C

    TCA6416A.c

    /** TCA6416A.c** Created on: 2013-4-6* Author: Administrator*/ #include "./Software_I2C/Software_I2C.h"#define TCA6416A_ADDR 0x20 /*從機TCA6416A的7位地址*///-----控制寄存器定義----- #define In_CMD0 0x00 //讀取管腳輸入狀態寄存器;只讀 #define In_CMD1 0x01 #define Out_CMD0 0x02 //控制管腳輸出狀態寄存器;R/W #define Out_CMD1 0x03 #define PIVS_CMD0 0x04 //反向控制管腳輸出狀態寄存器;R/W #define PIVS_CMD1 0x05 #define CFG_CMD0 0x06 //管腳方向控制:1:In;0::Out。 #define CFG_CMD1 0x07volatile unsigned int TCA6416A_InputBuffer=0; unsigned char pinW0 = 0xff; //用于緩存已寫入相應管腳的狀態信息,此操作避免讀回TCA6416A中當前寄存器的值 unsigned char pinW1 = 0xff; //用于緩存已寫入相應管腳的狀態信息,此操作避免讀回TCA6416A中當前寄存器的值void Delay_ms(int i);/******************************************************************************************************* 名 稱:TCA6416A_Init()******************************************************************************************************/ void TCA6416A_Init(void) {unsigned char conf;Delay_ms(5); //TCA6416的復位時間比單片機長,延遲確保可靠復位//----根據擴展板的引腳使用,將按鍵所在管腳初始化為輸入,其余管腳初始化為輸出conf = 0x00; // 0 0 0 0_0 0 0 0 (LED0~LED7)i2c_mem_write(TCA6416A_ADDR, CFG_CMD0, &conf, 1); conf = 0x0f; // 0 0 0 0_1 1 1 1 (按鍵)i2c_mem_write(TCA6416A_ADDR, CFG_CMD1, &conf, 1); //----上電先將管腳輸出為高(此操作對輸入管腳無效)conf = 0xff; // 某位置1,輸出為高,0為低i2c_mem_write(TCA6416A_ADDR, Out_CMD0, &conf, 1);conf = 0xff; i2c_mem_write(TCA6416A_ADDR, Out_CMD1, &conf, 1); }/******************************************************************************************************* 名 稱:PinOUT()******************************************************************************************************/ void PinOUT(unsigned char pin,unsigned char status) {if(pin<=7) //所選管腳為pin0~pin7 ,刷新所要操作的輸出緩存pinW0 狀態{if(status == 0)pinW0 &= ~(1<<pin);elsepinW0 |= 1<<pin; i2c_mem_write(TCA6416A_ADDR, Out_CMD0, &pinW0, 1); // 將更新后的數據包,寫入芯片寄存器}else if(pin>=10 && pin<=17) //所選管腳為pin10~pin17 ,刷新所要操作的輸出緩存pinW1 狀態{if(status == 0)pinW1 &= ~(1<<(pin%10));elsepinW1 |= 1<<(pin%10);i2c_mem_write(TCA6416A_ADDR, Out_CMD1, &pinW1, 1); // 將更新后的數據包,寫入芯片寄存器} }/******************************************************************************************************* 名 稱:PinIN()******************************************************************************************************/ unsigned char PinIN(unsigned char pin) {unsigned char temp[2];i2c_mem_read(TCA6416A_ADDR, In_CMD0, temp, 2); // 讀取按鍵所在管腳信息TCA6416A_InputBuffer = (((unsigned int)temp[1])<<8)|temp[0];if(pin<=7) {if(temp[0] & (1<<pin))return 1;elsereturn 0;}else if(pin>=10 && pin<=17) {if(temp[1] & (1<<(pin%10)))return 1;elsereturn 0;} }/******************************************************************************************************* 名 稱:PinToggle()******************************************************************************************************/ void PinToggle(unsigned char pin) {unsigned char status;if(pin<=7) //所選管腳為pin0~pin7 ,刷新所要操作的輸出緩存pinW0 狀態{status = !(pinW0 & (1<<pin));if(status)pinW0 |= 1<<pin;elsepinW0 &= ~(1<<pin);i2c_mem_write(TCA6416A_ADDR, Out_CMD0, &pinW0, 1); // 將更新后的數據包,寫入芯片寄存器}else if(pin>=10 && pin<=17) //所選管腳為pin10~pin17 ,刷新所要操作的輸出緩存pinW1 狀態{status = !(pinW1 & (1<<(pin%10)));if(status)pinW1 |= 1<<(pin%10);elsepinW1 &= ~(1<<(pin%10));i2c_mem_write(TCA6416A_ADDR, Out_CMD1, &pinW1, 1); // 將更新后的數據包,寫入芯片寄存器} }

    TCA6416A.h

    /** TCA6416A.h** Created on: 2013-4-6* Author: Administrator*/#ifndef TCA6416A_H_ #define TCA6416A_H_extern unsigned char PinIN(unsigned char pin); extern void PinOUT(unsigned char pin,unsigned char status); extern void PinToggle(unsigned char pin); extern void TCA6416A_Init(); extern volatile unsigned int TCA6416A_InputBuffer;#endif /* TCA6416A_H_ */

    測試程序

    一個LED閃爍,另一個LED由KEY控制翻轉。

    main.c

    #include <STC89C5xRC.H> #include "intrins.h" #include "stdint.h" #include "TCA6416A.h"void Delay1ms() //@11.0592MHz {unsigned char i, j;_nop_();i = 2;j = 199;do{while (--j);} while (--i); }void Delay_ms(int i) {while(i--)Delay1ms(); }void main(void) {uint16_t delay_count = 0;TCA6416A_Init();while(1){ if(!PinIN(10)){Delay_ms(20);if(!PinIN(10)){PinToggle(1);while(!PinIN(10));}}if(++delay_count == 500){PinToggle(7);delay_count = 0;}Delay_ms(1);} }

    實驗現象

    總結

    以上是生活随笔為你收集整理的【51单片机快速入门指南】4.5:I2C 与 TCA6416实现双向 IO 扩展的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。