TX2 核心板 GPIO、IO擴展器、撥碼開關、LED燈 使用總結

#PS:要轉載請註明出處,本人版權所有

#PS:這個只是 《 我自己 》理解,如果和你的

#原則相沖突,請諒解,勿噴

起因

我們有個項目,做了一個基於TX2核心板的硬件板卡,這個板卡除了做相關算法的檢測之外,還得提供一些控制LED啊、通過撥碼開關這些來設置一些內容的小功能,你說氣不氣,這些小功能還必須要實現。如果LED和撥碼開關直接掛載到tx2的gpio上的話,就沒有必要寫本文了,沒意義,因爲只要學過嵌入式的人,給他一個板子,再差勁,讀取和設置一個gpio的高低電平總會吧。如果不會,建議還多學學嵌入式基礎知識(從單片機玩起來,先裸奔,再上OS)。

這裏我們知道,其實對於芯片來說,引腳是非常珍貴的,如果芯片所需要實現的功能複雜,那麼通用的io管腳異常珍貴,這裏就出現了一個種器件,叫做IO擴展器(所實話,我都不知道這樣翻譯對不對),從名字可知,就是較少的引腳擴展出更多的引腳,本文就是用兩個引腳擴展出了16個引腳。

TX2上,由於使用了Linux,讀取和設置gpio也是非常簡單的,直接打開相關的gpio設備,讀寫即可。不要問我爲啥要用linux,不用其他os,或者直接裸機控制,我只能夠回答曰:我是想啊,可是我實力不允許啊,什麼caffe、opencv、ncnn、cuda等等堆到其他系統或者裸機下,我着實能力不夠,弄不過去,關鍵還麻煩。

IO擴展器

IO擴展器原理簡介

其實本文的核心就是IO擴展器,這個器件由於我玩的板子少,見識少,我是第一次見到這種器件。下圖就是這種器件在tx2手冊裏面的推薦使用方法。
在這裏插入圖片描述
這種器件就是通過某種總線,然後擴展出儘可能多的io口。這裏的這個器件通過I2C總線,擴展出16個io口。
這裏我們可以看到:
SCL和SDA是I2C通信總線,A0和A1是可編程配置I2C從器件地址。(這裏不懂也沒關係,就是這個器件的地址可以編程設置,至於爲啥要有這個地址,可以簡單理解爲一個總線掛載多個設備,某一時刻總線只能爲其中一個設備提供服務,這些設備的區分就是通過地址來完成的。)

P00-P17是擴展出來的IO口。

知道以上足夠了,沒學過的也足夠了。

這個器件的特性是:
通過I2C協議操作他的寄存器,他有8個8位寄存器,0-1寄存器是INPUT用,2-3寄存器是OUTPUT用,4-5好像是優先級裁決,6-7是配置寄存器,就是配置IO口是輸出還是輸入,如果接觸過單片機、stm32這種的GPIO程序的話,是很好理解的。(手動滑稽,我出了校門就沒接觸過了)
不要問下圖的是什麼器件(問就是不知道,手動滑稽),這只是舉個例子,這個io擴展器的寄存器分配以及功能就是這樣的。
在這裏插入圖片描述
在這裏插入圖片描述

IO擴展器編程操作—shell command

首先這個器件是通過I2C協議操作的,不用關心I2C是什麼,他們你可以類比爲HTTP。
那麼Linux上怎麼通過I2C操作這個器件呢?
首先,Linux上有一組工具:i2c-tool,它可以讀取所有芯片的i2c bus上掛載的芯片,設置和讀取寄存器等等,拿來做測試或者封裝一個程序都是不錯的。TX2的ubuntu16.04是自帶這個工具的,他的詳細用法大家去百度,我不造輪子了。
在Ubuntu裏面操作I2C是非常簡單的,你不需要關心I2C的具體傳輸規定,不用管時序這些煩人的事情。
首先我們先用工具來測試,美滋滋:
還記得上文我提了這個IO擴展器的從地址的事情嗎?由於我的A0和A1都是接的低電平,在這裏我的器件地址是0x74,怎麼來的,看下圖。
在這裏插入圖片描述
然後通過i2cdetect查看我們器件的位置(0x74)(注意,這個命令需要傳入一個I2C總線序號,我這裏是0,也就是說你要知道你這個IO擴展器掛載到哪個總線上的,這和SCL和SDL接線有關,有興趣的可以去翻一翻手冊就知道了,UU代表有人在佔用這個設備)

shell:>i2cdetect -y -r -a 0

在這裏插入圖片描述
i2cdump可以通過標準i2c協議探測出所有的寄存器的值,下圖8個寄存器的值就的出來了,分別對應上面的寄存器說明。XX代表沒有這個寄存器。
shell:>i2cdump -f -y 0 0x74
在這裏插入圖片描述
然後:
i2cset -f -y i2c_bus_num slave_addr reg_num value 設置寄存器值
i2cget -f -y i2c_bus_num slave_addr reg_num 獲取寄存器值

其實通過上面的操作就可以完成整個io擴展器的操作,我們可以通過程序執行shell命令的方式設置和操作值。

IO擴展器編程操作—syscall

實際上,linux做了很多東西,我們可以用標準的linux sys-api來完成以上內容,其實這些api就是i2ctool使用的部分。
下面不墨跡,直接給出led操作的接口,有需要的參考吧。

int open_led_device(const char * i2c_bus_num, int slave_addr){

    int fd = 0; 

    if ( 0 > (fd = open(i2c_bus_num, O_RDWR)) ){//打開i2c總線

        perror("open i2c bus error:");
        return -1;
    }

    if(ioctl(fd, I2C_SLAVE_FORCE, DEVICE_I2C_ADDR) < 0) {//設置從器件地址,這裏使用I2C_SLAVE_FORCE進行強行設置,那麼這個設備忙

        perror("set device slave addr error:"); 
        return -1; 
    }

    if ( 0 > write_led_register(fd, LED_REG1_CFG_ADDR, LED_REG1_CFG_VAL) ){//設置寫寄存器值,這兩個宏和你的硬件連線有關。這裏不給出。

        printf("init pin for output-mode failed.\n");
        close(fd);
        return -1;
    }

    return fd;

}

int read_led_register(int fd, char reg_addr, char *read_val){//讀寄存器

    if (write(fd, &reg_addr, 1) != 1){//write reg addr ,從器件地址通過open接口設置好後,先寫入要讀的reg地址

        perror("set reg addr error:"); 
        return -1; 
    }

    if ( read(fd, read_val, 1) != 1 ){//read data,等待i2c返回剛剛要查詢的reg值

        perror("read reg error:"); 
        return -1; 
    }
    return 0;
}

int write_led_register(int fd, char reg_addr, char data){//寫寄存器

    char tmp_buf[2];


    tmp_buf[0] =  reg_addr;//reg 地址
    tmp_buf[1] = data;//reg 值


    if (write(fd, tmp_buf, 2) != 2){//write data

        perror("write data error:"); 
        return -1; 
    }

    return 0;
}

void close_led_device(int fd){//關閉

    close(fd);
}

LED燈

此處省略XXX字。
相信每個人都知道,常規情況下,在LED燈的兩邊加電源正極和負極,燈就能亮。在電路設計上,一般來說,LED燈的一端都是和電源正極或者負極是連接好的,另一端和GPIO口接上。如果GPIO輸出的電壓和另一端電壓邏輯一致(比如都是高電平、都是低電平),燈就不亮,反之就亮。
注意:這段話是有毛病的,但是一般人這樣理解就行了(不瞭解電子電路的就看到這就行了)。對於懂的人,這裏多說一句,這裏還有一個三極管做開關作用,也是就說LED燈兩端都接在電源正負極,中間有個三極管開關。

撥碼開關

這種器件,又是另外一種新奇的東西了,感覺我這兩年寫的“祖傳屎山“太多了,現在看到各種硬件器件都是眼前一亮的感覺。
就是類似下圖這種。
在這裏插入圖片描述
在這裏插入圖片描述
其作用是:
你可以人爲的按這個±號按鈕,設置數字,這個數字會反應到電路上,從而芯片可以讀取你設置的數字。
說白了,你的系統中有個數字參數,你可以通過這種器件進行手動設置,通過驅動程序,就可以更改這個系統參數,是不是 so 簡單。

這裏簡單說明一下電路是怎麼反應出對應的數字的:
我就舉個栗子,下圖是個例子撥碼開關(手動滑稽,這裏多說一句,上圖的撥碼開關,是4個撥碼開關合在一起的,下圖的這個輸出編碼是一個撥碼開關的)
在這裏插入圖片描述
這裏可以簡單理解爲:
一個撥碼開關有5個引腳,一個引腳是C,接GND或者VCC,其他4個是編碼引腳,是需要接GPIO,並去取編碼的。
其實很簡單:
例如:C端我接VCC,1248默認值爲0,那麼數字1,1號引腳接通,那麼8421io口輸出二進制就是0001,轉換爲10進制,就是1.
然後寫個程序讀取這4個腳的值,轉換一下,就OK。
#PS:請尊重原創,不喜勿噴

#PS:要轉載請註明出處,本人版權所有.

有問題請留言,看到後我會第一時間回覆

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章