前言
這段時間又是期末考時期,之前沒有學懂的東西又雙叒叕忘記了~
我知道如果用庫函數來操控底層比較輕松,但是作為51單片機的過渡,還是想使用更符合之前習慣的方法來操控硬體!
建一個工程模闆
在上一篇最小系統的使用中已經建過了,就是建個檔案夾放三個檔案
main.c
stm32f10x.h
startup_stm32f10x_hd.s
第一個就是這篇部落格所需要操作的主函數所處的位置,第二個是放自定義的寄存器的位址。這兩個檔案都是空檔案。第三個是STM32F103單片機的啟動檔案,不同種類的單片機的啟動檔案不同。
記憶體映射
定時器
中斷
序列槽
DMA
總線
電源管理
…………
這些功能的操控都需要靠相應的寄存器單元的設定。幾百個寄存器,幾乎每個都是32位的,單單從bit上來考慮似乎不太現實!
在進行寄存器操作的時候,的确是需要按位來操控的,但是許多寄存器不是每一位都是獨特的,是以存在許多相似之處使得我們隻需要操控幾個bit進而操控整個寄存器!
\;
\;
以下是stm32f103相關功能寄存器在記憶體上的位址
block 0 Code
0x0000 0000 - 0x1FFF FFFF
Aliased to Flash or system memory depending on BOOT pins[0x0000 0000 - 0x0007 FFFF]
Reserved[0x0008 0000 - 0x07FF FFFF]
Flash[0x0800 0000 - 0x0807 FFFF]
Reserved[0x0808 0000 - 0x1FFF EFFF]
System memory[0x1FFF F000 - 0x1FFF F7FF]
Option Bytes[0x1FFF F800 - 0x1FFF F80F]
block 1 SRAM
0x2000 0000 - 0x3FFF FFFF
SRAM(64 kB aliased by bit-banding)[0x2000 0000 - 0x2000 FFFF]
Reserved[0x2001 0000 - 0x3FFF FFFF]
block 2 Peripherals
0x4000 0000 - 0x5FFF FFFF
APB1總線
TIM2[0x4000 0000 - 0x4000 03FF]
TIM3[0x4000 0400 - 0x4000 07FF]
TIM4[0x4000 0800 - 0x4000 0BFF]
TIM5[0x4000 0C00 - 0x4000 0FFF]
TIM6[0x4000 1000 - 0x4000 13FF]
TIM7[0x4000 1400 - 0x4000 17FF]
Reserved[0x4000 1800 - 0x4000 27FF]
RTC[0x4000 2800 - 0x4000 2BFF]
WWDG[0x4000 2C00 - 0x4000 2FFF]
IWDG[0x4000 3000 - 0x4000 33FF]
Reserved[0x4000 3400 - 0x4000 37FF]
SPI2/I2S2[0x4000 3800 - 0x4000 3BFF]
SPI3/I2S3[0x4000 3C00 - 0x4000 3FFF]
Reserved[0x4000 4000 - 0x4000 43FF]
USART2[0x4000 4400 - 0x4000 47FF]
USART3[0x4000 4800 - 0x4000 4BFF]
UART4[0x4000 4C00 - 0x4000 4FFF]
UART5[0x4000 5000 - 0x4000 53FF]
I2C1[0x4000 5400 - 0x4000 57FF]
I2C2[0x4000 5800 - 0x4000 5BFF]
USB register[0x4000 5C00 - 0x4000 5FFF]
Shared USB/CAN SRAM 512 bytes[0x4000 6000 - 0x4000 63FF]
BxCAN[0x4000 6400 - 0x4000 67FF]
Reserved[0x4000 6800 - 0x4000 6BFF]
BKP[0x4000 6C00 - 0x4000 6FFF]
PWR[0x4000 7000 - 0x4000 73FF]
DAC[0x4000 7400 - 0x4000 77FF]
Reserved[0x4000 7800 - 0x4000 FFFF]
APB2總線
AFIO[0x4001 0000 - 0x4001 03FF]
EXTI[0x4001 0400 - 0x4001 07FF]
PortA[0x4001 0800 - 0x4001 0BFF]
PortB[0x4001 0C00 - 0x4001 0FFF]
PortC[0x4001 1000 - 0x4001 13FF]
PortD[0x4001 1400 - 0x4001 17FF]
PortE[0x4001 1800 - 0x4001 1BFF]
PortF[0x4001 1C00 - 0x4001 1FFF]
PortG[0x4001 2000 - 0x4001 23FF]
ADC1[0x4001 2400 - 0x4001 27FF]
ADC2[0x4001 2800 - 0x4001 2BFF]
TIM1[0x4001 2C00 - 0x4001 2FFF]
SPI1[0x4001 3000 - 0x4001 33FF]
TIM8[0x4001 3400 - 0x4001 37FF]
USART1[0x4001 3800 - 0x4001 3BFF]
ADC3[0x4001 3C00 - 0x4001 3FFF]
Reserved[0x4001 4000 - 0x4001 7FFF]
SDIO[0x4001 8000 - 0x4001 83FF]
Reserved[0x4001 8400 - 0x4001 FFFF]
AHB總線
DMA1[0x4002 0000 - 0x4002 03FF]
DMA2[0x4002 0400 - 0x4002 07FF]
Reserved[0x4002 0400 - 0x4002 1FFF]
RCC[0x4002 1000 - 0x4002 13FF]
Reserved[0x4002 1400 - 0x4002 1FFF]
Flash interface[0x4002 2000 - 0x4002 23FF]
Reserved[0x4002 2400 - 0x4002 2FFF]
CRC[0x4002 3000 - 0x4002 33FF]
Reserved[0x4002 4400 - 0x5FFF FFFF]
block 3 FSMC bank1&bank2
06000 0000 - 0x7FFF FFFF
FSMC bank1 NOR/PSRAM 1[0x6000 0000 - 0x63FF FFFF]
FSMC bank1 NOR/PSRAM 2[0x6400 0000 - 0x67FF FFFF]
FSMC bank1 NOR/PSRAM 3[0x6800 0000 - 0x6BFF FFFF]
FSMC bank1 NOR/PSRAM 4[0x6C00 0000 - 0x6FFF FFFF]
FSMC bank2 NAND(NAND1)[0x7000 0000 - 0x7FFF FFFF]
block 4 FSMC bank3&bank4
0x8000 0000 - 0x9FFF FFFF
FSMC bank3 NAND(NAND2)[0x8000 0000 - 0x8FFF FFFF]
FSMC bank4 PCCARD[0x9000 0000 - 0x9FFF FFFF]
block 5 FSMC register
0xA000 0000 - 0xBFFF FFFF
FSMC register[0xA000 0000 - 0xA000 0FFF]
Reserved[0xA000 1000 - 0xBFFF FFFF]
block 6 Not used
0xC000 0000 - 0xDFFF FFFF
block 7 Cortex-M3's internal Peripherals
0xE000 0000 - 0xFFFF FFFF
block2區域的首位址就是外設的基位址。
GPIO結構和工作模式
根據輸入/輸入的差別、上下拉電阻的差別、開漏推挽的差別可以将GPIO的工作模式分為8類。
浮空輸入
模拟輸入(不經過施密特觸發器,也沒有上下拉電阻)
上拉輸入
下拉輸入
開漏輸出
開漏複用輸出
推挽輸出
推挽複用輸出
(輸出模式下,施密特觸發器都是開啟狀态)
GPIOx寄存器
每偏移0x04就是偏移一個32位!
x表示可選數0~15!
GPIOx位址
GPIOx_CRL[bias 0x00]設定0~7引腳模式
GPIOx_CRH[bias 0x04]設定8~15引腳模式
GPIOx_IDR[bias 0x08]設定輸入資料寄存器,高16位保留
GPIOx_ODR[bias 0x0C]設定輸出資料寄存器,高16位保留
GPIOx_BSRR[bias 0x10]設定/清除寄存器
GPIOx_BRR[bias 0x14]清除寄存器,高16位保留
GPIOx_LCKR[bias 0x18]設定鎖定寄存器,高15位保留
對于GPIOx_CRL和GPIOx_CRH來說,每四個位控制一個引腳的工作模式。四個位分别是 CNFx[1:0] 和 MODEx[1:0]
MODEx[1:0]
- 00 ——輸入模式(複位後的狀态)
- 01 ——輸出模式,最大速度10MHz
- 10 ——輸出模式,最大速度2MHz
- 11 ——輸出模式,最大速度50MHz
CNFx[1:0]
- 00 ——在MODEx[1:0]=00時,設定模拟輸入。否則,設定推挽輸出。
- 01 ——在MODEx[1:0]=00時,設定浮空輸入。否則,設定開漏輸出。
- 10 ——在MODEx[1:0]=00時,設定上下拉輸入。否則,設定複用推挽輸出。
- 11 ——在MODEx[1:0]=00時,保留。否則,設定複用開漏輸出。
\;
\;
\;
GPIOx_IDR是端口輸入寄存器,在低16位裡(高16位保留),其位對應的值就是對應引腳的值——在隻讀模式下。
GPIOx_ODR是端口輸出寄存器,在低16位裡(高16位保留),其位對應的值就是對應引腳的值——在可讀可寫模式下。
GPIOx_BSRR是設定端口值的寄存器,高16位對應引腳的零,低16位對應引腳的一。如果對應的位為一,那麼如果是高16位這表示置零,如果是低16位表示置一。
GPIOx_BRR是端口值清零寄存器。低16位(高16位保留)置一表示對應引腳清零。
GPIOx_LCKR是端口配置鎖定。 一般用不到這個。
時鐘
這裡寫的程式是控制GPIOC亮燈,而GPIOC是APB2總線上的外設,是以需要配置APB2外設時鐘的使能寄存器。
對應的位為一,即使對應的外設使能。
示例:循環左移跑馬燈
//stm32f10x.h
#define PERIPH_BASE ((unsigned int)0x40000000)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000)
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
#define GPIOC_CRL *(unsigned int*)(GPIOC_BASE+0x00)
#define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0x04)
#define GPIOC_IDR *(unsigned int*)(GPIOC_BASE+0x08)
#define GPIOC_ODR *(unsigned int*)(GPIOC_BASE+0x0C)
#define GPIOC_BSRR *(unsigned int*)(GPIOC_BASE+0x10)
#define GPIOC_BRR *(unsigned int*)(GPIOC_BASE+0x14)
#define GPIOC_LCKR *(unsigned int*)(GPIOC_BASE+0x18)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)
//main.c
#include "stm32f10x.h"
void delay(unsigned int i){
while(i--){
__nop();
__nop();
__nop();
__nop();
__nop();
__nop();
}
}
void SystemInit(){}
int main(){
int k=0;
//use APB2 External RCC
//open GPIO clock
RCC_APB2ENR|=1<<4;
//8 ports
//CNF>00 MODE>11
//GPIOC_CRL&=~(0x0f<<(4*0));
//GPIOC_CRL|=(3<<(4*0));
GPIOC_CRL = 0x33333333;
//use BSRR
//set right ODR be one
//GPIOC_BSRR=(1<<(16+0));
while(1){
GPIOC_BSRR=~(1<<k); //light the led
delay(0xf000);
GPIOC_BSRR=~(1<<(k+16)); //dark the led
delay(0xf000);
if(k--==0)
k=7;
}
}
顯示效果: