STM32F103五分钟入门系列(一)跑马灯(库函数+寄存器)+加编程模板+GPIO总结
摘自:STM32F103五分鐘入門系列(一)跑馬燈(庫(kù)函數(shù)+寄存器)+加編程模板+GPIO總結(jié)
作者:自信且愛笑‘
發(fā)布時(shí)間: 2021-04-28 21:17:40
網(wǎng)址:https://blog.csdn.net/Curnane0_0/article/details/116158776
學(xué)習(xí)板:STM32F103ZET6
跑馬燈實(shí)驗(yàn)
- 前言
- 一、GPIO
- 1、GPIO種類
- 2、GPIO輸入輸出的8種模式:
- 3、模式用途
- 二、點(diǎn)亮LED(庫(kù)函數(shù)版)
- 1、庫(kù)函數(shù)的由來(lái)
- 2、點(diǎn)亮LED庫(kù)函數(shù)版編寫順序
- 1、GPIO_Init()
- 2、RCC_APB2PeriphClockCmd()
- 3、將配置函數(shù)放在led.c和led.h文件
- 三、點(diǎn)亮LED(寄存器版本)
- 1、新建工程、添加led文件
- 2、配置時(shí)鐘
- 3、GPIO配置
- 4、主函數(shù)代碼編寫
- 附1 PXout()與PXin()
前言
本來(lái)準(zhǔn)備先總結(jié)一下GPIO、幾種輸入輸出模式以及配置方法、寄存器種類、時(shí)鐘及分頻等,但是想了想,還是算了,一步步的來(lái),到時(shí)候用到再總結(jié)吧 ,不然前面總結(jié)了,后面用到還得回顧。
至于前面的安裝庫(kù)、安裝軟件、Keil中添加文件等,就不在總結(jié)了,因?yàn)檫@些根本并不需要記的,新手可以去跟著視頻走一遍。學(xué)習(xí)過程中,不用每次都自己去新建工程,直接將官方給的模板拷過來(lái),修改一下文件夾名稱即可。
一、GPIO
1、GPIO種類
本博板子STM32F103ZET6共有7組IO口,每組16個(gè),共16×7=112個(gè),分別為:
GPIOA——>PA0、PA1、PA2…PA15
GPIOB——>PB0、PB1、PB2…PB15
.
.
.
GPIOG——>PG0、PG1、PG2、…PG15
2、GPIO輸入輸出的8種模式:
| GPIO_Mode_AIN | 模擬輸入 |
| GPIO_Mode_IN_FLOATING | 浮空輸入 |
| GPIO_Mode_IPD | 下拉輸入 |
| GPIO_Mode_IPU | 上拉輸入 |
| GPIO_Mode_Out_OD | 開漏輸出 |
| GPIO_Mode_Out_PP | 推挽輸出 |
| GPIO_Mode_AF_OD | 復(fù)用開漏輸出 |
| GPIO_Mode_AF_PP | 復(fù)用推挽輸出 |
3、模式用途
1、 GPIO_Mode_AIN :模擬輸入
一般用于ADC模擬輸入
2、GPIO_Mode_IN_FLOATING :浮空輸入
可用于按鍵KEY實(shí)驗(yàn)、發(fā)送接收信號(hào)RX、TX等,不過這些實(shí)驗(yàn)可以不用浮空輸入,如KEY用到上拉和下拉
3、GPIO_Mode_IPD:下拉輸入
4、GPIO_Mode_IPU:上拉輸入
IO內(nèi)部上拉電阻、下拉電組輸入,使情況而定,比如剛剛說的key按鍵實(shí)驗(yàn),原理圖如下:
可以看到KEY_UP按下后,IO口應(yīng)該是3V3電平輸入,未按下時(shí)為懸空狀態(tài),而懸空狀態(tài)IO輸入是未知的,所以為了防止程序跑飛,采用下拉輸入,在懸空狀態(tài)下,使IO輸入下拉到低電平。這樣,在懸空狀態(tài)下,IO檢測(cè)到的是低電平,不會(huì)去執(zhí)行key_up按下后的程序。
KEY0~2按下后,IO口是低電平輸入。按下時(shí)為懸空狀態(tài),而懸空狀態(tài)IO輸入是未知的,所以為了防止程序跑飛,采用上拉輸入,在懸空狀態(tài)下,使IO輸入上拉到高電平。這樣,在懸空狀態(tài)下,IO檢測(cè)到的是高電平,不會(huì)去執(zhí)行KEY0 ~2按下后的程序。
5、GPIO_Mode_Out_OD:開漏輸出
IO 輸出 0 接 GND,IO 輸出 1,懸空,需要外接上拉電阻,才能實(shí)現(xiàn)輸出 高電平。當(dāng)輸出為 1 時(shí),IO 口的狀態(tài)由上拉電阻拉高電平,但由于是開漏輸出模式,這樣 IO 口也就可以 由外部電路改變?yōu)榈碗娖交虿蛔?。該模式適合做電流型的驅(qū)動(dòng),吸收電流能力比較強(qiáng)。
6、GPIO_Mode_Out_PP:推挽輸出
可以輸出高、低電平。導(dǎo)通損耗小、效率高。既提高電路的負(fù)載能力,又提高開關(guān)速度。廣泛各種實(shí)驗(yàn),比如接下來(lái)要總結(jié)的LED。
7、GPIO_Mode_AF_OD:復(fù)用開漏輸出
當(dāng)GPIO為復(fù)用IO時(shí)的開漏輸出模式,一般用于外設(shè)功能,如TX1
8、GPIO_Mode_AF_PP:復(fù)用推挽輸出
當(dāng)GPIO為復(fù)用IO時(shí)的推挽輸出模式,一般用于外設(shè)功能,如I2C
二、點(diǎn)亮LED(庫(kù)函數(shù)版)
1、庫(kù)函數(shù)的由來(lái)
在學(xué)習(xí)庫(kù)函數(shù)之前,應(yīng)該明白,STM32F1用的是Cortex-M3芯片,是由ARM公司設(shè)計(jì)的。所以芯片的標(biāo)準(zhǔn)是由ARM公司制定的,芯片內(nèi)核架構(gòu)有ARM公司提供。而我們現(xiàn)在用的STM32由ST公司生產(chǎn),所以關(guān)系是:ARM制定內(nèi)核架構(gòu),ST等芯片公司根據(jù)ARM公司的標(biāo)準(zhǔn)設(shè)計(jì)了芯片。ST等公司設(shè)計(jì)的芯片,不同的是存儲(chǔ)容量、外設(shè)、串口數(shù)量等等。
以本博的學(xué)習(xí)板STM32F103ZET6為例,固件庫(kù)(庫(kù)函數(shù)的集合)是由官方提供的,這個(gè)官方是ST公司,而不是正點(diǎn)原子官方。也就是說不僅僅這一型號(hào)單片機(jī),ST系列其他型號(hào)的單片機(jī)庫(kù)函數(shù)依舊可以適用。所以不必?fù)?dān)心更換板子后不知如何去編程。
ST公司推出官方固件庫(kù),將底層寄存器操作都封裝起來(lái),形成一套接口(API)供我們使用,大多數(shù)情況下我們不必去考慮底層寄存器。比如本博的LED,只需調(diào)用GPIO配置函數(shù)、時(shí)鐘配置函數(shù),然后主函數(shù)初始化后,直接給引腳賦值就可以實(shí)現(xiàn)LED的亮滅,而不用去考慮寄存器如何工作的。當(dāng)然本博會(huì)把寄存器版的LED也總結(jié)一下。畢竟想要真正理解單片機(jī),還得去真正理解寄存器,庫(kù)函數(shù)版只是讓我們停留在“會(huì)使用”。當(dāng)然,對(duì)應(yīng)大多數(shù)人來(lái)講,“會(huì)使用”已經(jīng)完全足夠了。
2、點(diǎn)亮LED庫(kù)函數(shù)版編寫順序
1、設(shè)置時(shí)鐘
2、設(shè)置GPIO
只要這兩步的配置,再在主函數(shù)中給對(duì)應(yīng)引腳傳輸高低電平即可。
打開原理圖文件(下圖我打開了6個(gè)文件,都是需要的,而且大部分情況下,有這6個(gè)文件足以。都在板子附帶資料的文件夾里)
從原理圖中得到以下信息:
①DS0 LED0陽(yáng)極接+,陰極接PB5;DS1 LED1陽(yáng)極接+,陰極接PE5。
②SYS LED由名稱“PWR”顧名思義,為電源指示燈,所以單片機(jī)接通電源后,電源指示燈常亮。
③芯片的PB5引腳軟件置0后,LED0亮;PE5引腳軟件置0后,LED1亮。
所以要配置GPIOB(因?yàn)镻B5)和GPIOE(因?yàn)镻E5)。
然后是時(shí)鐘設(shè)置,只要是對(duì)GPIO操作,就必須進(jìn)行時(shí)鐘配置(而且時(shí)鐘配置在前)。GPIO是掛載在APB2總線上的外設(shè),所以在對(duì)GPIO的時(shí)鐘進(jìn)行設(shè)置時(shí),通過函數(shù)RCC_APB2PeriphClockCmd()來(lái)實(shí)現(xiàn)。
下面進(jìn)入實(shí)戰(zhàn):
打開模板文件:(時(shí)間久遠(yuǎn)了,不知道模板文件原來(lái)放哪個(gè)文件夾下,找不到的話可以把LED官方例程打開,關(guān)于LED的.c和.h文件刪掉,主函數(shù)清空,就可以當(dāng)以后的模板來(lái)用了,不用每次都創(chuàng)建工程)
首先查看GPIO配置函數(shù),既然是GPIO,那么先找一下頭文件,在main.c下找GPIO頭文件,并點(diǎn)擊進(jìn)入。
找到對(duì)應(yīng)函數(shù):(下一博客總結(jié)所有GPIO函數(shù)的用法、以及延時(shí)函數(shù))
上圖標(biāo)注,GPIO_Init()函數(shù)初始化,進(jìn)行設(shè)置GPIO,GPIO_SetBits()函數(shù)給對(duì)應(yīng)引腳置1,GPIO_ReSetBits()函數(shù)給對(duì)應(yīng)引腳置0。
1、GPIO_Init()
右鍵選中函數(shù),點(diǎn)擊【Go to Definition of …】,進(jìn)入函數(shù)詳細(xì)說明
可以看到,函數(shù)的形參有兩個(gè),而且都是指針。進(jìn)入第一個(gè)形參“類型”
看到GPIOx指針是指向上圖這個(gè)結(jié)構(gòu)體的,也就是每組GPIO都包含的7個(gè)寄存器。
比如LED實(shí)驗(yàn),傳遞GPIOB(PB5)過來(lái)后,*GPIOB就指向這七個(gè)寄存器,初始化函數(shù)就是對(duì)七個(gè)寄存器的操作,不過被庫(kù)函數(shù)封裝起來(lái)了,emmmm…說太多了,只要知道GPIO_Init()傳過來(lái)的第一個(gè)參數(shù)表示對(duì)該組GPIO配置就行了。
察看第二組形參“類型”
看到第二個(gè)形參也是結(jié)構(gòu)體指針,指向的結(jié)構(gòu)體含有三個(gè)參數(shù)GPIO_Pin、GPIO_Speed、GPIO_Mode
到這里就可以用C++語(yǔ)法來(lái)說明了。比如第二個(gè)形參是a(注意是指針),那么:
a.GPIO_Pin=…
a.GPIO_Speed=…
a.GPIO_Mode=…
就完成了對(duì)參數(shù)GPIO參數(shù)的設(shè)置。
接下來(lái)我們?cè)倏纯瓷厦嫒齻€(gè)賦值語(yǔ)句的右邊究竟是什么東西:
轉(zhuǎn)回到初始化函數(shù):
1表示第二個(gè)形參
2表示對(duì) GPIO_Init()的第一個(gè)形參的處理(就是那個(gè)結(jié)構(gòu)體里有7個(gè)寄存器的東西)
3表示mode的配置
4表示pin的配置
5表示速speed的配置。
點(diǎn)開GPIO_Mode設(shè)置函數(shù):
可以看到就是我們第一大部分總結(jié)的8中輸入輸出模式
點(diǎn)開pin設(shè)置函數(shù)
可以看到pin是我們第一大部分總結(jié)的一組GPIO的15個(gè)IO口
點(diǎn)開速度設(shè)置函數(shù)
可以看到速度可設(shè)置的值:
到這里,GPIO的設(shè)置函數(shù)應(yīng)該會(huì)寫了:
第一步:設(shè)置形參1和形參2
第二步:上面那三個(gè)賦值語(yǔ)句的設(shè)置
第三步:運(yùn)行GPIO_Init()函數(shù)
程序:(先在主函數(shù)中書寫,.c文件中書寫接下來(lái)會(huì)總結(jié))
GPIO_TypeDef GPIO_B;//形參1GPIO_InitTypeDef GPIO_InitStruct;//形參2GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//形參2.mode=推挽輸出GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//形參2.pin=5GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//形參2.speed=50MHZGPIO_Init(&GPIO_B,&GPIO_InitStruct);- 1
- 2
- 3
- 4
- 5
- 6
注意GPIO_Init()傳遞的是指針,所以應(yīng)該用取地址符“&”。
上面的程序還是有問題的,因?yàn)槎x了GPIO_B為第一個(gè)參數(shù),但是程序并不知道GPIO_B是對(duì)GPIOB的操作,所以在 GPIO_Init(&GPIO_B,&GPIO_InitStruct);語(yǔ)句中,“&GPIO_B”應(yīng)該是真正的、物理上的地址,而不能像參數(shù)2一樣,只是程序定義參數(shù)時(shí)分配的地址。
輸入“GPIOB”,并進(jìn)入
發(fā)現(xiàn)官方真的定義了GPIOB,而且還是真正的、物理層的地址
所以之前程序中的GPIO_B可以刪掉了,不是物理層的地址,定義了、傳遞給GPIO_Init()函數(shù)也沒用。
正確完整程序:
//GPIO_TypeDef GPIO_B;//形參1GPIO_InitTypeDef GPIO_InitStruct;//形參2GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//形參2.mode=推挽輸出GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//形參2.pin=5GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//形參2.speed=50MHZGPIO_Init(GPIOB,&GPIO_InitStruct);//注意GPIOB是地址!GPIO_InitStruct是指針,傳遞過去后的倆個(gè)實(shí)參數(shù)都是指針。- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
以上配置了GPIOB是為了點(diǎn)亮LED0,現(xiàn)配置LED1(PE5)的GPIO,參考上面的程序:
GPIO_InitTypeDef GPIO_InitStruct;//形參2GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//形參2.mode=推挽輸出GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//形參2.pin=5GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//形參2.speed=50MHZGPIO_Init(GPIOB,&GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;GPIO_Init(GPIOE,&GPIO_InitStruct);- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
因?yàn)橹霸O(shè)置了mode和speed,而實(shí)參2是沒有指向的,即并不能知道實(shí)參2屬于實(shí)參1,所以哪怕再重新定義一個(gè)GPIOE的實(shí)參2,重新定義mode和speed也沒有意義,所以就可以省略了。
接下來(lái)可以將LED引腳置高電平,熄滅LED。使初始狀態(tài)下LED是滅的。
int main(void){ GPIO_InitTypeDef GPIO_InitStruct;//形參2GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//形參2.mode=推挽輸出GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//形參2.pin=5GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//形參2.speed=50MHZGPIO_Init(GPIOB,&GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;GPIO_Init(GPIOE,&GPIO_InitStruct);GPIO_SetBits(GPIOB, GPIO_Pin_5);GPIO_SetBits(GPIOE, GPIO_Pin_5);}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
2、RCC_APB2PeriphClockCmd()
之前說過,GPIO是掛載在APB2總線上的外設(shè),所以在對(duì)GPIO的時(shí)鐘進(jìn)行設(shè)置時(shí),通過函數(shù)RCC_APB2PeriphClockCmd()來(lái)實(shí)現(xiàn)。打開RCC.h頭文件,找到時(shí)鐘函數(shù)
同樣的方法確定形參類型
形參1:
形參2:
所以程序:(注意時(shí)鐘配置函數(shù)應(yīng)該放在最前面)
GPIO_InitTypeDef GPIO_InitStruct;//形參2RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOE , ENABLE);GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//形參2.mode=推挽輸出GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//形參2.pin=5GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//形參2.speed=50MHZGPIO_Init(GPIOB,&GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;GPIO_Init(GPIOE,&GPIO_InitStruct);GPIO_SetBits(GPIOB, GPIO_Pin_5);GPIO_SetBits(GPIOE, GPIO_Pin_5);- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
加入延時(shí)函數(shù),形成流水燈:(只在Main.c文件編程)
其中GPIO_SetBits(GPIOB, GPIO_Pin_5)是將PB5引腳置1;GPIO_ReSetBits(GPIOB, GPIO_Pin_5)是將PB5引腳置0
(是通過庫(kù)函數(shù)對(duì)BSRR和BRR寄存器操作完成置0置1,下一博客會(huì)涉及到)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
3、將配置函數(shù)放在led.c和led.h文件
在LED使用的工程文件夾新建一個(gè)LED文件夾
進(jìn)行下一步驟:
創(chuàng)建一個(gè)text文件,命名為led.h,保存在LED group中
將頭文件添加進(jìn)來(lái)
同理。新建一個(gè)led.c文件,將.c文件也添加進(jìn)來(lái)
上述步驟是創(chuàng)建一個(gè)LED Group,現(xiàn)在將頭文件添加進(jìn)來(lái):
找到剛剛創(chuàng)建的文件夾并添加
上述步驟是為了之后調(diào)用里面生成的led.c和led.h
編輯頭文件:
固定格式:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
本實(shí)驗(yàn)led.h文件可這樣寫:
#ifndef __LED_H //led.h文件 #define __LED_H void LED_Init(void);//初始化 #endif- 1
- 2
- 3
- 4
接下來(lái)編輯led.c文件
需要有本.c文件用到的頭文件,如果要用到別的文件中定義的變量,可以采用外部聲明重新聲明該變量。在.c文件實(shí)現(xiàn).h文件聲明的函數(shù)
將我們之前main函數(shù)中關(guān)于GPIO配置和時(shí)鐘聲明的函數(shù)移植過來(lái)得到完整的LED程序:
/**led.h**/ #ifndef __LED_H //led.h文件 #define __LED_H void LED_Init(void);//初始化 #endif/**led.c**/ #include "led.h" #include "stm32f10x.h" void LED_Init(void) {GPIO_InitTypeDef GPIO_InitStruct;//形參2RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOE , ENABLE);GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//形參2.mode=推挽輸出GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//形參2.pin=5GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//形參2.speed=50MHZGPIO_Init(GPIOB,&GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;GPIO_Init(GPIOE,&GPIO_InitStruct);GPIO_SetBits(GPIOB, GPIO_Pin_5);GPIO_SetBits(GPIOE, GPIO_Pin_5); }/**main.c**/ #include "stm32f10x.h" #include "delay.h" #include "led.h"int main(void){ LED_Init();delay_init(); //延時(shí)函數(shù)初始化 while(1){GPIO_SetBits(GPIOB, GPIO_Pin_5);GPIO_SetBits(GPIOE, GPIO_Pin_5);delay_ms(1000); //注意包含頭文件delay.h,這個(gè)好像是正點(diǎn)原子官方寫的GPIO_ResetBits(GPIOB, GPIO_Pin_5);GPIO_ResetBits(GPIOE, GPIO_Pin_5);delay_ms(1000); }}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
三、點(diǎn)亮LED(寄存器版本)
1、新建工程、添加led文件
畢竟是32系列第一個(gè)博客,還是希望詳細(xì)一點(diǎn),之后的實(shí)驗(yàn)就會(huì)慢慢省略一部分東西,寄存器版本完整來(lái)一遍
打開模板文件,如果沒有,就把LED庫(kù)函數(shù)例程打開,刪掉led.c和led.h,當(dāng)做以后所有實(shí)驗(yàn)的模板就行了。
一般情況下,應(yīng)該【HARDWARE】中創(chuàng)建.c文件。也可以在文件【HARDWARE】之外建,看個(gè)人習(xí)慣。
如果懶得去搞模板,就用我這個(gè)吧
先將模板文件拷過來(lái),在HARDWARE文件夾下創(chuàng)建LED文件夾
打開模板文件
新建兩個(gè)text文件,保存在剛剛創(chuàng)建的LED文件夾下,并改名為led.c、led.h
將led.c文件添加進(jìn)工程
將LED文件目錄添加進(jìn)來(lái)
現(xiàn)在進(jìn)入實(shí)戰(zhàn)
led.h編輯,之前庫(kù)函數(shù)版本講過了,直接附代碼:
#ifndef LED_H //led.h文件 #define LED_H int LED_Init(void); #endif- 1
- 2
- 3
- 4
led.c文件編輯
開始還是老規(guī)矩:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
2、配置時(shí)鐘
打開《STM32中文參考手冊(cè)》7.3.7 APB2外設(shè)時(shí)鐘使能寄存器(RCC_APB2ENR)
寄存器下一博客總結(jié),現(xiàn)在只需知道,APB2外設(shè)時(shí)鐘使能寄存器的第3位和第6位分別對(duì)應(yīng)GPIOB(LED0、DS0)和GPIOE(LED1、DS1)
時(shí)鐘使能代碼如下:
RCC->APB2ENR|=1<<3; RCC->APB2ENR|=1<<6;- 1
- 2
解釋一下:
首先RCC->APB2ENR是對(duì)外設(shè)時(shí)鐘使能寄存器的訪問
RCC->APB2ENR|=1的意思是:RCC->APB2ENR=RCC->APB2ENR|0x00000001(32位寄存器),也就是說將該寄存器的第0位軟件置1,其它位保持不變。"<<3"是將剛剛設(shè)置的那個(gè)第0位的1左移3位,也就是此時(shí)第3位為1.同理“<<6”是將第6位設(shè)置為1;此時(shí)就使能了GPIOB和GPIOE的時(shí)鐘
3、GPIO配置
用到端口配置寄存器,由于是對(duì)PB5、PE5的配置,是低位IO口(Px0~Px7是低位、Px8 ~Px15是高位),所以用到端口配置低寄存器GPIOx_CRL
打開《STM332中文參考手冊(cè)》
看到第21、20位控制模式和速度,為50M輸出,所以這兩位是11;23 、22控制哪種輸出,為推挽輸出,所以這兩位為00,所以GPIOx_CRL的狀態(tài)值為:0x00300000;程序如下:
GPIOB->CRL&=0xff0fffff; //PB5GPIOB->CRL|=0x00300000;GPIOE->CRL&=0xff0fffff; //PE5GPIOE->CRL|=0x00300000;- 1
- 2
- 3
- 4
- 5
解釋一下:
GPIOB->CRL&=0xff0fffff 是將GPIOB的20、21、22、23這四位置0,其它位保持不變;
GPIOB->CRL|=0x00300000是將GPIOB的20、21、22、23這四位置1,其它位保持不變;
此時(shí)配置好了,然后可以給IO口賦初值,如開始時(shí)讓LED處于熄滅狀態(tài),則PB5、PE5均置1。用到的寄存器:端口輸出數(shù)據(jù)寄存器GPIOx_ODR
代碼:
GPIOB->ODR|=1<<5;GPIOE->ODR|=1<<5;- 1
- 2
led.c文件完整代碼:
#include "led.h" //led.c文件 #include "stm32F10x.h" int LED_Init(void) {RCC->APB2ENR|=1<<3;RCC->APB2ENR|=1<<6;GPIOB->CRL&=0xff0fffff; //PB5GPIOB->CRL|=0x00300000;GPIOE->CRL&=0xff0fffff; //PE5GPIOE->CRL|=0x00300000;GPIOB->ODR|=1<<5;GPIOE->ODR|=1<<5; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
4、主函數(shù)代碼編寫
進(jìn)入主函數(shù)后,首先應(yīng)調(diào)用剛剛寫的LED初始化函數(shù),完成GPIO配置;程序會(huì)用到延時(shí)函數(shù),將延時(shí)函數(shù)也初始化,代碼:(頭文件包含led.h)
#include "sys.h"#include "delay.h"#include "led.h"int main(void){ LED_Init();delay_init();}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
然后在死循環(huán)中,對(duì)PB5和PE5 IO口賦值就行了,還是用到端口輸出數(shù)據(jù)寄存器GPIOx_ODR
不過給IO口置0時(shí),需要注意,應(yīng)該和0xffffffdf進(jìn)行與運(yùn)算
- 1
- 2
或者移位運(yùn)算,將第0位置0再向左移5位
GPIOB->ODR&=0xfffffffe<<5;GPIOE->ODR&=0xfffffffe<<5;- 1
- 2
給IO口置1就和0x00000020進(jìn)行或運(yùn)算
GPIOB->ODR|=0x00000020;GPIOE->ODR|=0x00000020;- 1
- 2
或者直接位移運(yùn)算,先和0x00000001進(jìn)行或運(yùn)算,使第0位置1,再將第0位向左移動(dòng)5,代碼:
GPIOB->ODR|=1<<5;GPIOE->ODR|=1<<5;- 1
- 2
main.c文件完整程序:
#include "sys.h" //main.c文件 #include "delay.h" #include "led.h"int main(void){ LED_Init();delay_init();while(1){GPIOB->ODR&=0xffffffdf;//置0GPIOE->ODR&=0xffffffdf;//置0//GPIOB->ODR&=0xfffffffe<<5;//GPIOE->ODR&=0xfffffffe<<5;delay_ms(1000);GPIOB->ODR|=0x00000020;GPIOE->ODR|=0x00000020;//GPIOB->ODR|=1<<5;//GPIOE->ODR|=1<<5;delay_ms(1000);}}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
附1 PXout()與PXin()
打開sys.h頭文件
定義了PXout()與PXin()函數(shù),用法為:
點(diǎn)亮熄滅DS0、DS1,只需:
PBout(5)=0;//點(diǎn)亮 PEout(5)=0;//點(diǎn)亮 delay_ms(1000); PBout(5)=1;//熄滅 PEout(5)=1;//熄滅 delay_ms(1000);- 1
- 2
- 3
- 4
- 5
- 6
或者定義:
#define LED0 PBout(5) #define LED1 PEout(5)LED0=0;//點(diǎn)亮 LED1=0;//點(diǎn)亮 delay_ms(1000); LED0=1;//熄滅 LED1=1;//熄滅 delay_ms(1000);- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
總結(jié)
以上是生活随笔為你收集整理的STM32F103五分钟入门系列(一)跑马灯(库函数+寄存器)+加编程模板+GPIO总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 集合系列14之 Map总结(H
- 下一篇: Day22——十字链表