STM32的CAN開發注意事項整理收集

一、STM32的bxCAN控制器

bxCAN是基本擴展CAN(Basic Extended CAN)的縮寫,它支持CAN協議2.0A和2.0B。它的設計目標是,以最小的CPU負荷來高效處理大量收到的報文。它也支持報文發送的優先級要求(優先級特性可軟件配置)。對於安全緊要的應用, bxCAN提供所有支持時間觸發通信模式所需的硬件功能。

STM32至少配備一個bxCAN控制器,它具有如下幾個特點:

*  支持CAN協議2.0A和2.0B主動模式
*  波特率最高可達1Mbps
*  支持時間觸發通信功能
*  11位的標準幀格式和29位的擴展幀格式的接收和發送
發送
*  3個發送郵箱
*  發送報文的優先級特性可軟件配置
*  記錄發送SOF時刻的時間戳

接收
*  3級深度的2個接收FIFO,每個FIFO都可以放3個完整報文,它們由硬件管理
*  14個位寬可變的過濾器組-由整個CAN共享
*  標識符列表
*  FIFO溢出處理方式可配置
*  記錄接收SOF時刻的時間戳
可支持時間觸發通信模式
*  禁止自動重傳模式
*  16位自由運行定時器
*  定時器分辨率可配置
*  可在最後2個數據字節發送時間戳

管理
*  中斷可屏蔽
*  郵箱佔用單獨1塊地址空間,便於提高軟件效率

二、CAN通信實驗過程

CAN通信實驗流程圖

2.1 功能描述

2.1.1 發送處理

發送報文的流程爲:應用程序選擇1個空發送郵箱;設置標識符,數據長度和待發送數據;然後對CAN_TIxR寄存器的TXRQ位置1, 來請求發送。 TXRQ位置1後, 郵箱就不再是空郵箱;而一旦郵箱不再爲空,軟件對郵箱寄存器就不再有寫的權限。 TXRQ位置1後,郵箱馬上進入掛號狀態,並等待成爲最高優先級的郵箱,參見發送優先級。一旦郵箱成爲最高優先級的郵箱,其狀態就變爲預定發送狀態。一旦CAN總線進入空閒狀態,預定發送郵箱中的報文就馬上被髮送(進入發送狀態)。一旦郵箱中的報文被成功發送後,它馬上變爲空郵箱;硬件相應地對CAN_TSR寄存器的RQCP和TXOK位置1,來表明一次成功發送。

如果發送失敗,由於仲裁引起的就對CAN_TSR寄存器的ALST位置1,由於發送錯誤引起的就對TERR位置1。

郵箱發送狀態圖

2.1.2 時間觸發通信模式

在該模式下, CAN硬件的內部定時器被激活,並且被用於產生時間戳,分別存儲在CAN_RDTxR/CAN_TDTxR寄存器中。內部定時器在接收和發送的幀起始位的採樣點位置被採樣,並生成時間戳。

2.1.3 接收管理

接收到的報文,被存儲在3級郵箱深度的FIFO中。 FIFO完全由硬件來管理,從而節省了CPU的處理負荷,簡化了軟件並保證了數據的一致性。應用程序只能通過讀取FIFO輸出郵箱,來讀取FIFO中最先收到的報文。

有效報文

根據CAN協議, 當報文被正確接收(直到EOF域的最後1位都沒有錯誤), 且通過了標識符過濾,那麼該報文被認爲是有效報文。

FIFO的管理

FIFO從空狀態開始,在接收到第1個有效的報文後, FIFO狀態變爲掛號_1( pending_1),硬件相應地把FMP[1:0]設置爲01(二進制01b)。軟件可以讀取FIFO輸出郵箱來讀出郵箱中的報文,然後通過對CRFR寄存器的RFOM位設置1來釋放郵箱,這樣FIFO又變爲空狀態了。

如果在釋放郵箱的同時,又收到了1個有效的報文,那麼FIFO仍然保留在掛號_1狀態,軟件可以讀取FIFO輸出郵箱來讀出新收到的報文。

如 果 應 用 程 序 不 釋 放 郵 箱 , 在 接 收 到 下 1 個 有 效 的 報 文 後 , FIFO 狀 態 變 爲 掛 號 _2( pending_2),硬件相應地把FMP[1:0]設置爲10(二進制10b)。重複上面的過程,第3個有效的報文把FIFO變爲掛號_3狀態( FMP[1:0]=11b)。此時,軟件必須對RFOM位設置1來釋放郵箱,以便FIFO可以有空間來存放下1個有效的報文;否則,下1個有效的報文到來時就會導致1個報文的丟失。

FIFO接收狀態

溢出

當FIFO處於掛號_3狀態(即FIFO的3個郵箱都是滿的),下1個有效的報文就會導致溢出,並且1個報文會丟失。此時,硬件對CAN_RFxR寄存器的FOVR位進行置1來表明溢出情況。至於哪個報文會被丟棄,取決於對FIFO的設置:

* 如果禁用了FIFO鎖定功能( CAN_MCR寄存器的RFLM位被清0),那麼FIFO中最後收到的報文就被新報文所覆蓋。這樣,最新收到的報文不會被丟棄掉。

* 如果啓用了FIFO鎖定功能( CAN_MCR寄存器的RFLM位被置1),那麼新收到的報文就被丟棄,軟件可以讀到FIFO中最早收到的3個報文。

接收相關的中斷

一旦往FIFO存入1個報文,硬件就會更新FMP[1:0]位,並且如果CAN_IER寄存器的FMPIE位爲1,那麼就會產生一箇中斷請求。

當FIFO變滿時(即第3個報文被存入), CAN_RFxR寄存器的FULL位就被置1,並且如果CAN_IER寄存器的FFIE位爲1,那麼就會產生一個滿中斷請求。

在溢出的情況下, FOVR位被置1,並且如果CAN_IER寄存器的FOVIE位爲1,那麼就會產生一個溢出中斷請求。

2.2 bxCAN通信工作模式

bxCAN有3個主要的工作模式: 初始化、正常和睡眠模式。在硬件復位後, bxCAN工作在睡眠模式以節省電能,同時CANTX引腳的內部上拉電阻被激活。軟件通過對CAN_MCR寄存器的INRQ或SLEEP位置’1’,可以請求bxCAN進入初始化或睡眠模式。一旦進入了初始化或睡眠模式,bxCAN就對CAN_MSR寄存器的INAK或SLAK位置’1’來進行確認,同時內部上拉電阻被禁用。當INAK和SLAK位都爲’0’時,bxCAN就處於正常模式。在進入正常模式前,bxCAN必須跟CAN總線取得同步;爲取得同步,bxCAN要等待CAN總線達到空閒狀態,即在CANRX引腳上監測到11個連續的隱性位。以下只做三種模式介紹,具體請參考STM32中文參考手冊。

2.2.1 初始化模式

軟件初始化應該在硬件處於初始化模式時進行。設置CAN_MCR寄存器的INRQ位爲’1’,請求bxCAN進入初始化模式,然後等待硬件對CAN_MSR寄存器的INAK位置’1’來進行確認。清除CAN_MCR寄存器的INRQ位爲’0’,請求bxCAN退出初始化模式,當硬件對CAN_MSR寄存器的INAK位清’0’就確認了初始化模式的退出。

當bxCAN處於初始化模式時,禁止報文的接收和發送,並且CANTX引腳輸出隱性位(高電平)。初始化模式的進入,不會改變配置寄存器。軟件對bxCAN的初始化,至少包括位時間特性(CAN_BTR)和控制(CAN_MCR)這2個寄存器。

在對bxCAN的過濾器組(模式、位寬、FIFO關聯、激活和過濾器值)進行初始化前,軟件要對CAN_FMR寄存器的FINIT位設置’1’。對過濾器的初始化可以在非初始化模式下進行。

注: 當FINIT=1時,報文的接收被禁止。可以先對過濾器激活位清’0’(在CAN_FA1R中),然後修改相應過濾器的值。如果過濾器組沒有使用,那麼就應該讓它處於非激活狀態(保持其FACT位爲清’0’狀態)。

2.2.2 正常模式

在初始化完成後,軟件應該讓硬件進入正常模式,以便正常接收和發送報文。軟件可以通過對CAN_MCR寄存器的INRQ位清’0’,來請求從初始化模式進入正常模式,然後要等待硬件對CAN_MSR寄存器的INAK位置’1’的確認。在跟CAN總線取得同步,即在CANRX引腳上監測到11個連續的隱性位(等效於總線空閒)後, bxCAN才能正常接收和發送報文。

不需要在初始化模式下進行過濾器初值的設置,但必須在它處在非激活狀態下完成(相應的FACT位爲0)。而過濾器的位寬和模式的設置,則必須在初始化模式中進入正常模式前完成。

2.2.3 環回模式

通過對CAN_BTR寄存器的LBKM位置’1’,來選擇環回模式。在環回模式下, bxCAN把發送的報文當作接收的報文並保存(如果可以通過接收過濾)在接收郵箱裏。環回模式可用於自測試。爲了避免外部的影響,在環回模式下CAN內核忽略確認錯誤(在數據/遠程幀的確認位時刻,不檢測是否有顯性位)。在環回模式下, bxCAN在內部把Tx輸出回饋到Rx輸入上,而完全忽略CANRX引腳的實際狀態。發送的報文可以在CANTX引腳上檢測到。

bxCAN工作在環回模式

2.3 代碼部分

2.3.1 初始化設置

初始化包括三個部分:

① 配置相關引腳複用功能,使用CAN時鐘
② 設置CAN工作模式和波特率
③ 設置濾波器
初始化RCC寄存器組,配置PLL輸出72MHz時鐘,APB1總線的頻率爲36MHz,分別打開CAN/GPIOA/USARIT的設備時鐘。

//時鐘配置
GPIO_InitTypeDef       GPIO_InitStructure;
CAN_InitTypeDef        CAN_InitStrucutre;
NVIC_InitTypeDef       NVIC_InitStructure;
CAN_FilterInitTypeDef  CAN_FilterInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

查看芯片手冊,發現STM32F103ZET6版本的CAN總線TX和RX引腳分別是PA12和PA11,TX採用複用推輓輸出,RX採用上拉輸入:

//串口配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);           //
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);

由於實驗採用中斷接收,所以需進行中斷初始化配置

//中斷配置
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     //   搶佔優先級1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 	  次優先級爲0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//CAN配置
CAN_InitStrucutre.CAN_TTCM = DISABLE;  //禁止時間觸發通信模式
CAN_InitStrucutre.CAN_ABOM = DISABLE;  //軟件對CAN_MCR寄存器的INRQ位置1
CAN_InitStrucutre.CAN_AWUM = DISABLE;  //睡眠模式通過清除CAN_MCR寄存器SLEEP位		  
CAN_InitStrucutre.CAN_NART = ENABLE;    //CAN報文只被發送一次	
CAN_InitStrucutre.CAN_RFLM = DISABLE;   //	報文不鎖定,新的覆蓋原有	 
CAN_InitStrucutre.CAN_TXFP = DISABLE;    //發送FIFO優先級由報文標識符決定	
CAN_InitStrucutre.CAN_Mode = CAN_Mode_LoopBack  ; //採用環回模式

//波特率設置
CAN_InitStrucutre.CAN_SJW = CAN_SJW_1tq;  //重新同步跳躍寬度1個時間單位
CAN_InitStrucutre.CAN_BS1 = CAN_BS1_9tq;  //時間段1爲8個時間單位
CAN_InitStrucutre.CAN_BS2 = CAN_BS2_8tq;  //	時間段2爲7個時間單位
CAN_InitStrucutre.CAN_Prescaler = 4;      //分頻係數
CAN_Init(CAN1, &CAN_InitStrucutre);      // 36M/((8+9+1)*4)=500kbps

//過濾器設置
CAN_FilterInitStructure.CAN_FilterNumber=0;
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;  // 屏蔽模式       
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //	過濾器寬度32位	 
CAN_FilterInitStructure.CAN_FilterIdHigh= 0x00AA<<3;  //	過濾器標識符0xAA	 
CAN_FilterInitStructure.CAN_FilterIdLow =0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x00FF<<3;  //屏蔽位標識符0x00FF    
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);

2.3.2 發送部分

2.3.3 接收部分

2.3.4 主函數接收反饋

三、CAN波特率計算

四、關於過濾器的設置

Typedef struct
{
    uint32_t StdId;  //標準幀ID,如果要發送擴展幀,可以不理
    uint32_t ExtId;  //擴展幀ID,如果要發送標準幀,可以不理
    uint8_t IDE;    //發送標準幀還是擴展幀
    uint8_t RTR;   //發送遠程幀還是數據幀
    uint8_t DLC;   //發送數據的長度
    uint8_t Data[8]; //想要發送的數據
}CanTxMsg;

StdId

StdId用來設定標準標識符。它的取值範圍爲0到0x7FF。

ExtId

ExtId用來設定擴展標識符。它的取值範圍爲0到0x1FFFFFFF。

IDE

IDE用來設定消息標識符的類型。

IDE值

RTR

RTR用來設定待傳輸消息的幀類型。它可以設置爲數據幀或者遠程幀。

RTR

DLC

DLC用來設定待傳輸消息的幀長度。它的取值範圍是0到0x8。

Data[8]

Data[8]包含了待傳輸數據,它的取值範圍爲0到0xFF

接下來了解它是如何接收的。

STM32參考手冊中提到: bxCAN控制器爲應用程序提供了14個位寬可變的、 可配置的過濾器組(13~0)。(互聯型有28個)。 每個過濾器組的位寬都可以獨立配置。可以配置成16位或者32位。過濾器組還可配置爲屏蔽位模式或標識符列表模式。

每個過濾器組x由2個32位寄存器, CAN_FxR1和CAN_FxR2組成。

這樣的話,就只能過濾出ID爲0x317(與CAN_FxR1必須一樣)和0x00F(與CAN_FxR2必須一樣)兩種標準數據幀了。

以上是32位模式下標識符屏蔽模式和標識符列表模式下的設置方法。

在16位模式下,只不過把兩個32位寄存器拆成了4個16位的而已,原理和32位模式下是一樣的。就不贅述了。

接收數據是通過指向CanRxMsg 結構體變量的指針傳遞的。直接調用 CAN_Receive 即可輕鬆完成。

typedef struct
{
    uint32_t StdId;
    uint32_t ExtId;
    uint8_t IDE;
    uint8_t RTR;
    uint8_t DLC;
    uint8_t Data[8];
    uint8_t FMI;
} CanRxMsg;

CanRxMsg結構與CanTxMsg差不多。只是多了一個FMI域。

FMI
FMI設定爲消息將要通過的過濾器索引, 這些消息存儲於郵箱中。該參數取值範圍0到0xFF。

五、硬件設計

STM32 與 TJA1050 連接電路圖

若採用正常工作模式,從上圖可以看出: STM32 的 CAN 通過 P13 的設置,連接到 TJA1050 收發芯片,然後通過接線端子( CAN)同外部的 CAN 總線連接。圖中可以看出,在戰艦 STM32 開發板上面是帶有120Ω的終端電阻的,如果我們的開發板不是作爲 CAN 的終端的話,需要把這個電阻去掉,以免影響通信。
這裏還要注意,我們要設置好開發板上 P13 排針的連接,通過跳線帽將 PA11 和 PA12 分別連接到 CRX( CAN_RX)和 CTX( CAN_TX)上面,最後,我們用 2 根導線將兩個開發板 CAN 端子的 CAN_L 和 CAN_L, CAN_H 和 CAN_H連接起來。這裏注意不要接反了( CAN_L 接 CAN_H), 接反了會導致通訊異常!

附,下面根據設置的參數不同來決定can總線can總線的配置情況:

1、對擴展數據幀進行過濾:(只接收擴展數據幀)

CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)slave_id<<3)&0xFFFF0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;

(注:標準幀數據幀、標準遠程幀和擴展遠程幀均被過濾)

2、對擴展遠程幀過濾:(只接收擴展遠程幀)

CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)slave_id<<3)&0xFFFF0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_REMOTE)&0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;

3、對標準遠程幀過濾:(只接收標準遠程幀)

CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)slave_id<<21)&0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_REMOTE)&0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;

4、對標準數據幀過濾:(只接收標準數據幀)

CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)slave_id<<21)&0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;

5、對擴展幀進行過濾:(擴展幀不會被過濾掉)

CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)slave_id<<3)&0xFFFF0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)slave_id<<3)|CAN_ID_EXT)&0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFC;

6、對標準幀進行過濾:(標準幀不會被過濾掉)

CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)slave_id<<21)&0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)slave_id<<21)|CAN_ID_STD)&0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFC;

注:slave_id爲要過濾的id號。

串口輸入輸出模式

在串口設置過程中,有必要了解它的輸入輸出模式

1、普通推輓輸出(GPIO_Mode_Out_PP):

使用場合:一般用在0V和3.3V的場合。線路經過兩個P_MOS 和N_MOS 管,負責上拉和下拉電流。

使用方法:直接使用

輸出電平:推輓輸出的低電平是0V,高電平是3.3V。

2、普通開漏輸出(GPIO_Mode_Out_OD):

使用場合:一般用在電平不匹配的場合,如需要輸出5V的高電平。

使用方法:就需要再外部接一個上拉電阻,電源爲5V,把GPIO設置爲開漏模式, 當輸出高組態時,由上拉電阻和電源向外輸出5V的電壓。

輸出電平:在開漏輸出模式時,如果輸出爲0,低電平,則使N_MOS 導通,使輸出接地。若控制輸出爲1(無法直接輸出高電平),則既不輸出高電平 也不輸出低電平,爲高組態。爲正常使用,必須在外部接一個上拉電 阻。

特性: 它具“線與”特性,即很多個開漏模式 引腳連接到一起時,只有當所有 引腳都輸出高阻態,才由上拉電阻提供高電平,此高電平的電壓爲外部 上拉電阻所接的電源的電壓。若其中一個引腳爲低電平,那線路就相當 於短路接地,使得整條線路都爲低電平,0 伏。

3、複用推輓輸出(GPIO_Mode_AF_PP):

用作串口的輸出。

4、複用開漏輸出(GPIO_Mode_AF_OD):

用在IIC。

STM32中GPIO的8種工作模式

(1)GPIO_Mode_AIN 模擬輸入 
(2)GPIO_Mode_IN_FLOATING 浮空輸入
(3)GPIO_Mode_IPD 下拉輸入 
(4)GPIO_Mode_IPU 上拉輸入 
(5)GPIO_Mode_Out_OD 開漏輸出
(6)GPIO_Mode_Out_PP 推輓輸出
(7)GPIO_Mode_AF_OD 複用開漏輸出 
(8)GPIO_Mode_AF_PP 複用推輓輸出

推輓輸出:

可以輸出高,低電平,連接數字器件; 推輓結構一般是指兩個三極管分別受兩互補信號的控制,總是在一個三極管導通的時候另一個截止。高低電平由IC的電源低定。

推輓電路是兩個參數相同的三極管或MOSFET,以推輓方式存在於電路中,各負責正負半周的波形放大任務,電路工作時,兩隻對稱的功率開關管每次只有一個導通,所以導通損耗小、效率高。輸出既可以向負載灌電流,也可以從負載抽取電流。推拉式輸出級既提高電路的負載能力,又提高開關速度。

開漏輸出:

輸出端相當於三極管的集電極,要得到高電平狀態需要上拉電阻才行。適合於做電流型的驅動,其吸收電流的能力相對強(一般20ma以內)。

開漏形式的電路有以下幾個特點:

1、利用外部電路的驅動能力,減少IC內部的驅動。當IC內部MOSFET導通時,驅動電流是從外部的VCC流經上拉電阻、MOSFET到GND。IC內部僅需很小的柵極驅動電流。

2、一般來說,開漏是用來連接不同電平的器件,匹配電平用的,因爲開漏引腳不連接外部的上拉電阻時,只能輸出低電平,如果需要同時具備輸出高電平的功能,則需要接上拉電阻,很好的一個優點是通過改變上拉電源的電壓,便可以改變傳輸電平。比如加上上拉電阻就可以提供TTL/CMOS電平輸出等。(上拉電阻的阻值決定了邏輯電平轉換的速度。阻值越大,速度越低功耗越小,所以負載電阻的選擇要兼顧功耗和速度。)

3、開漏輸出提供了靈活的輸出方式,但是也有其弱點,就是帶來上升沿的延時。因爲上升沿是通過外接上拉無源電阻對負載充電,所以當電阻選擇小時延時就小,但功耗大;反之延時大功耗小。所以如果對延時有要求,則建議用下降沿輸出。

4、可以將多個開漏輸出連接到一條線上。通過一隻上拉電阻,在不增加任何器件的情況下,形成“與邏輯”關係,即“線與”。可以簡單的理解爲:在所有引腳連在一起時,外接一上拉電阻,如果有一個引腳輸出爲邏輯0,相當於接地,與之並聯的迴路“相當於被一根導線短路”,所以外電路邏輯電平便爲0,只有都爲高電平時,與的結果才爲邏輯1。


關於推輓輸出和開漏輸出,最後用一幅最簡單的圖形來概括:該圖中左邊的便是推輓輸出模式,其中比較器輸出高電平時下面的PNP三極管截止,而上面NPN三極管導通,輸出電平VS+;當比較器輸出低電平時則恰恰相反,PNP三極管導通,輸出和地相連,爲低電平。右邊的則可以理解爲開漏輸出形式,需要接上拉。

由於浮空輸入一般多用於外部按鍵輸入,結合圖上的輸入部分電路,我理解爲浮空輸入狀態下,IO的電平狀態是不確定的,完全由外部輸入決定,如果在該引腳懸空的情況下,讀取該端口的電平是不確定的。

上拉輸入/下拉輸入/模擬輸入:

這幾個概念很好理解,從字面便能輕易讀懂。

複用開漏輸出、複用推輓輸出:

可以理解爲GPIO口被用作第二功能時的配置情況(即並非作爲通用IO口使用)

總結在STM32中選用IO模式

1、浮空輸入GPIO_IN_FLOATING ——浮空輸入,可以做KEY識別,RX1
2、帶上拉輸入GPIO_IPU——IO內部上拉電阻輸入
3、帶下拉輸入GPIO_IPD—— IO內部下拉電阻輸入
4、模擬輸入GPIO_AIN ——應用ADC模擬輸入,或者低功耗下省電
5、開漏輸出GPIO_OUT_OD ——IO輸出0接GND,IO輸出1,懸空,需要外接上拉電阻,才能實現輸出高電平。當輸出爲1時,IO口的狀態由上拉電阻拉高電平,但由於是開漏輸出模 式,這樣IO口也就可以由外部電路改變爲低電平或不變。可以讀IO輸入電平變化,實現C51的IO雙向功能
6、推輓輸出GPIO_OUT_PP ——IO輸出0-接GND, IO輸出1 -接VCC,讀輸入值是未知的
7、複用功能的推輓輸出GPIO_AF_PP ——片內外設功能(I2C的SCL,SDA)
8、複用功能的開漏輸出GPIO_AF_OD——片內外設功能(TX1,MOSI,MISO.SCK.SS)

STM32設置實例:

 1、模擬I2C使用開漏輸出_OUT_OD,接上拉電阻,能夠正確輸出0和1;讀值時先GPIO_SetBits(GPIOB, GPIO_Pin_0);拉高,然後可以讀IO的值;使用GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0);
  2、如果是無上拉電阻,IO默認是高電平;需要讀取IO的值,可以使用帶上拉輸入_IPU和浮空輸入_IN_FLOATING和開漏輸出_OUT_OD;

通常有5種方式使用某個引腳功能,它們的配置方式如下:

1、作爲普通GPIO輸入:根據需要配置該引腳爲浮空輸入、帶弱上拉輸入或帶弱下拉輸入,同時不要使能該引腳對應的所有複用功能模塊。
2、作爲普通GPIO輸出:根據需要配置該引腳爲推輓輸出或開漏輸出,同時不要使能該引腳對應的所有複用功能模塊。
3、作爲普通模擬輸入:配置該引腳爲模擬輸入模式,同時不要使能該引腳對應的所有複用功能模塊。
4、作爲內置外設的輸入:根據需要配置該引腳爲浮空輸入、帶弱上拉輸入或帶弱下拉輸入,同時使能該引腳對應的某個複用功能模塊。
5、作爲內置外設的輸出:根據需要配置該引腳爲複用推輓輸出或複用開漏輸出,同時使能該引腳對應的所有複用功能模塊。
注意如果有多個複用功能模塊對應同一個引腳,只能使能其中之一,其它模塊保持非使能狀態。比如要使用STM32F103VBT6的47、48腳的USART3功能,則需要配置47腳爲複用推輓輸出或複用開漏輸出,配置48腳爲某種輸入模式,同時使能USART3並保持I2C2的非使能狀態。如果要使用STM32F103VBT6的47腳作爲TIM2_CH3,則需要對TIM2進行重映射,然後再按複用功能的方式配置對應引腳。
 

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