端口復用功能
????????STM32 有很多的內置外設(比如:串口、ADC、DAC等是獨立的模塊和內核連接在一起),這些外設的外部引腳都是與 GPIO 復用的。也就是說,一個 GPIO如果可以復用為內置外設的功能引腳,那么當這個 GPIO 作為內置外設使用的時候,就叫做復用。
????????大家都知道,MCU 都有串口,STM32 有好幾個串口。比如說 STM32F103ZET6 有 5 個串口,我們可以查手冊知道,串口 1 的引腳對應的 IO 為 PA9,PA10.PA9,PA10 默認功能是 GPIO,所以當PA9,PA10 引腳作為串口 1 的 TX,RX 引腳使用的時候,那就是端口復用。查看芯片資料可知道那些口是復用端口。
復用端口初始化有幾個步驟:
- GPIO 端口時鐘使能。要使用到端口復用,當然要使能端口的時鐘了。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
- 復用的外設時鐘使能。比如你要將端口 PA9,PA10 復用為串口,所以要使能串口時鐘。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
- 端口模式配置。 在 IO 復用為內置外設功能引腳的時候,必須設置 GPIO 端口的模式,至于 在復用功能下 GPIO 的模式是怎么對應的,這個可以查看手冊《STM32 中文參考手冊 V10》 P110 的表格“8.1.11 外設的 GPIO 配置”。這里我們拿 Usart1 舉例:
從表格中可以看出,我們要配置全雙工的串口 1,那么 TX 管腳需要配置為推挽復用輸出,RX 管腳配置為浮空輸入或者帶上拉輸入。
代碼如下:
//USART1_TX PA.9 復用推挽輸出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART1_RX PA.10 浮空輸入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);
我們在使用復用功能的是時候,最少要使能 2 個時鐘:
- GPIO 時鐘使能
- 復用的外設時鐘使能同時要初始化 GPIO 以及復用外設功能
端口重映射
????????為了使不同器件封裝的外設 IO 功能數量達到最優,可以把一些復用功能重新映射到其他一些引腳上。STM32 中有很多內置外設的輸入輸出引腳都具有重映射(remap)的功能。我們知道每個內置外設都有若干個輸入輸出引腳,一般這些引腳的輸出端口都是固定不變的,為了讓設計工程師可以更好地安排引腳的走向和功能,在 STM32 中引入了外設引腳重映射的概念,即一個外設的引腳除了具有默認的端口外,還可以通過設置重映射寄存器的方式,把這個外設的引腳映射到其它的端口。
????????簡單的講就是把管腳的外設功能映射到另一個管腳,但不是可以隨便映射的,具體對應關系《STM32 中文參考手冊 V10》的 P116 頁“8.3 復用功能和調試配置”有講解。這里我們同樣拿串口 1 為例來講解。
????????上圖是截取的中文參考手冊中的重映射表,從表中可以看出,默認情況下,串口 1 復用的時候的引腳位 PA9,PA10,同時我們可以將 TX 和 RX 重新映射到管腳 PB6 和 PB7 上面去。
????????所以重映射我們同樣要使能復用功能的時候講解的 2 個時鐘外,還要使能 AFIO 功能時鐘,然后要調用重映射函數。詳細步驟為:
- 使能 GPIOB 時鐘:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
- 使能串口 1 時鐘:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
- 使能 AFIO 時鐘:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
PS: 在對寄存器AFIO_MARR,AFIO_EXTICRX和AFIO_EVCP進行讀寫操作前,應首先打開AFIO時鐘。
1、 AFIO_MARR:配置復用功能映射
2、 AFIO_EXTICRX:配置外部中斷線映射
3、 AFIO_EVCP:配置EVENTOUT事件輸出
- 開啟重映射:
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
這樣就將串口的 TX 和 RX 重映射到管腳 PB6 和 PB7 上面了。至于有哪些功能可以重映射,大家除了查看中文參考手冊之外,還可以從 GPIO_PinRemapConfig 函數入手查看第一個入口參數的取值范圍可以得知。在stm32f10x_gpio.h 文件中定義了取值范圍為下面宏定義的標識符,這里我們貼一小部分:
#define GPIO_Remap_SPI1 ((uint32_t)0x00000001)
#define GPIO_Remap_I2C1 ((uint32_t)0x00000002)
#define GPIO_Remap_USART1 ((uint32_t)0x00000004)
#define GPIO_Remap_USART2 ((uint32_t)0x00000008)
#define GPIO_PartialRemap_USART3 ((uint32_t)0x00140010)
#define GPIO_FullRemap_USART3 ((uint32_t)0x00140030)
從上面可以看出,USART1 只有一種重映射,而對于 USART3,存在部分重映射和完全重映射。所謂部分重映射就是部分管腳和默認的是一樣的,而部分管腳是重新映射到其他管腳。而完全重映射就是所有管腳都重新映射到其他管腳。看看手冊中的 USART3 重映射表:
部分重映射就是 PB10,PB11,PB12 重映射到 PC10,PC11,PC12 上。而 PB13 和 PB14 和沒有重映射情況是一樣的,都是 USART3_CTS 和 USART3_RTS 對應管腳。完全重映射就是將這兩個腳重新映射到 PD11 和 PD12 上去。我們要使用 USART3 的部分重映射,我們調用函數方法為:
GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, ENABLE);