国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

江科大自化協(xié)STM32學(xué)習(xí)筆記(部分C語(yǔ)言知識(shí)、STM32簡(jiǎn)介和GPIO口的使用)

這篇具有很好參考價(jià)值的文章主要介紹了江科大自化協(xié)STM32學(xué)習(xí)筆記(部分C語(yǔ)言知識(shí)、STM32簡(jiǎn)介和GPIO口的使用)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

本篇文章是根據(jù)B站UP主江科大自化協(xié)的教學(xué)視頻STM32入門教程-2023持續(xù)更新中,在了解、學(xué)習(xí)與實(shí)操后整理的學(xué)習(xí)筆記,內(nèi)容部分來(lái)自UP主的課程資料,并包含了一些個(gè)人的理解,如有謬誤歡迎指正,詳細(xì)知識(shí)點(diǎn)可以觀看UP主的視頻進(jìn)行了解。
希望大家都能早日掌握單片機(jī)。

一、前置知識(shí)(C語(yǔ)言)

1、指針

(1)基本概念

? 計(jì)算機(jī)的內(nèi)存中每個(gè)存儲(chǔ)單元都是有序的,且都是按字節(jié)編碼的,字節(jié)是最小的存儲(chǔ)單位。在程序中我們定義的變量存儲(chǔ)于類似的緩存中,不過(guò)緩存位于CPU內(nèi)部,且速度更快,同樣每個(gè)存儲(chǔ)單元也有對(duì)應(yīng)編碼,我們稱其為地址,而指針即為地址。

? 指針是一種數(shù)據(jù)類型,是地址,指針變量即為存儲(chǔ)地址的變量,其定義形式為:

//數(shù)據(jù)類型 *指針名
int *x;
float *f;
char *ch;
//如上,就分別定義了int、float和char類型的指針變量
  • 由上面的例子可以得到,指針變量也是有數(shù)據(jù)類型的,因?yàn)椴煌瑪?shù)據(jù)類型占的地址空間不同,所以指針變量的類型應(yīng)與它將指向的變量數(shù)據(jù)類型相同。
(2)指針變量的使用
Ⅰ、指針變量的聲明(初始化)

? 在聲明指針變量時(shí),如果不一開始就賦值的話,可能會(huì)導(dǎo)致較為嚴(yán)重的錯(cuò)誤:

int *p;
*p = 100;
//如上,因?yàn)橹羔樧兞繜o(wú)初值,“100”的值賦給的緩存地址是不確定(隨機(jī))的,這樣有可能導(dǎo)致一些重要的緩存位置的數(shù)據(jù)被替換導(dǎo)致數(shù)據(jù)丟失出錯(cuò)

? 因此建議聲明時(shí)賦空(“NULL”),避免出錯(cuò):

int *p = NULL;//等同于int *p = 0;
*p = 100;
  • 聲明指針變量時(shí)一定要先初始化,否則可能會(huì)導(dǎo)致出錯(cuò)。
Ⅱ、相關(guān)運(yùn)算符
  • 取地址運(yùn)算符&:?jiǎn)文窟\(yùn)算符&是用來(lái)取操作對(duì)象的地址。例:&i 為取變量 i 的地址。對(duì)于常量表達(dá)式、寄存器變量不能取地址(因?yàn)樗鼈兇鎯?chǔ)在存儲(chǔ)器中,沒(méi)有地址);
  • 指針運(yùn)算符*(間接尋址符):與&為逆運(yùn)算,作用是通過(guò)操作對(duì)象的地址,獲取存儲(chǔ)的內(nèi)容。例:x = &i,x 為 i 的地址,間接尋址x 則為通過(guò) i 的地址,獲取 i 的內(nèi)容;
  • 關(guān)系:*x = &x

代碼示例:

int a;//聲明了一個(gè)普通變量a
int *pa;//聲明一個(gè)指針變量,指向變量a的地址
pa = &a;//通過(guò)取地址符&,獲取a的地址,賦值給指針變量
printf("%d",*pa);//通過(guò)間接尋址符,獲取指針指向的內(nèi)容
  • 注意:聲明中的*符號(hào)和其他情況下使用的意義不同,聲明中的僅僅表示聲明的變量為指針變量,另起一行賦值時(shí)不需要帶上星號(hào);其他情況下為指針運(yùn)算符,通過(guò)操作對(duì)象的地址,獲取存儲(chǔ)的內(nèi)容;為符號(hào)的復(fù)用。
(3)指針與數(shù)組
Ⅰ、相同點(diǎn)
  • 數(shù)組名是數(shù)組第一個(gè)元素的地址,即
char str[6]={0,1,2,3,4,5};
char *P=str;
//輸入第一個(gè)元素,以下兩條語(yǔ)句功能相同
scanf("%s\n",str);
scanf("%s\n",p);
//打印第一個(gè)元素,以下兩條語(yǔ)句功能相同
printf("%s",*str);
printf("%s",*p);
Ⅱ、不同點(diǎn)
  • 數(shù)組名只是一個(gè)地址(常量,不可變),而指針是一個(gè)左值(可變)。

(C語(yǔ)言的術(shù)語(yǔ)lvalue左值指用于識(shí)別或定位一個(gè)存儲(chǔ)位置的標(biāo)識(shí)符,必須是可改變的。)

char str[6]={0,1,2,3,4,5};
char *P=str;
//輸入第二個(gè)元素
//scanf("%s\n",str+1);此為錯(cuò)誤的用法
scanf("%s\n",p+1);
//打印第二個(gè)元素
//printf("%s",*(str+1);此為錯(cuò)誤的用法
printf("%s",*(p+1));
  • 注意:p+1并不是簡(jiǎn)單地將地址加1,而是指向數(shù)組的下一個(gè)元素

2、結(jié)構(gòu)體

(1)基本概念

? 結(jié)構(gòu)體是一種構(gòu)造數(shù)據(jù)類型。數(shù)組是同種類型的數(shù)據(jù)的集合,那么結(jié)構(gòu)體就是不同類型的數(shù)據(jù)組合成的整體。其定義形式如下:

struct 結(jié)構(gòu)體名稱
{
    //結(jié)構(gòu)體成員可以是一種基本的數(shù)據(jù)類型,也可以是數(shù)組,或者另一個(gè)結(jié)構(gòu)體
    結(jié)構(gòu)體成員1;
    結(jié)構(gòu)體成員2;
    結(jié)構(gòu)體成員3;
    ……
}
  • 注意:大括號(hào)后面的分號(hào)不能少,這是一條完整的語(yǔ)句。
(2)定義結(jié)構(gòu)體變量

? 結(jié)構(gòu)體聲明僅是進(jìn)行一個(gè)框架的描繪,并不會(huì)為其分配存儲(chǔ)空間, 直到定義一個(gè)結(jié)構(gòu)體變量。

Ⅰ、基本方式

? 定義形式如下:

struct 結(jié)構(gòu)體名稱 結(jié)構(gòu)體變量名

? 示例如下:

#include <stdio.h>

struct Book
{
	char title[120];
    char author[40];
    float price;
    unsigned int date;
    char publisher[40];
}

int main(void)
{
    struct Book book;
    
    return 0;
}
  • 這樣定義的變量為局部變量
Ⅱ、在聲明的最后進(jìn)行定義

? 定義形式如下:

struct 結(jié)構(gòu)體名稱
{
    //結(jié)構(gòu)體成員可以是一種基本的數(shù)據(jù)類型,也可以是數(shù)組,或者另一個(gè)結(jié)構(gòu)體
    結(jié)構(gòu)體成員1;
    結(jié)構(gòu)體成員2;
    結(jié)構(gòu)體成員3;
    ……
} 結(jié)構(gòu)體變量名;
  • 這樣定義的變量為全局變量
Ⅲ、直接定義結(jié)構(gòu)體變量

定義形式如下:

struct 
{
    //結(jié)構(gòu)體成員可以是一種基本的數(shù)據(jù)類型,也可以是數(shù)組,或者另一個(gè)結(jié)構(gòu)體
    結(jié)構(gòu)體成員1;
    結(jié)構(gòu)體成員2;
    結(jié)構(gòu)體成員3;
    ……
} 結(jié)構(gòu)體變量名;
  • 只有關(guān)鍵字struct,沒(méi)有結(jié)構(gòu)體名稱。由于沒(méi)有結(jié)構(gòu)體名稱,在此定義語(yǔ)句后面無(wú)法再定義這個(gè)類型的其他結(jié)構(gòu)變量。一般情況下,除非變量不會(huì)再增加,還是建議采用前兩種結(jié)構(gòu)變量的定義形式
Ⅳ、利用typedef進(jìn)行簡(jiǎn)化

? 定義形式如下:

typedef struct 結(jié)構(gòu)體名稱
{
    //結(jié)構(gòu)體成員可以是一種基本的數(shù)據(jù)類型,也可以是數(shù)組,或者另一個(gè)結(jié)構(gòu)體
    結(jié)構(gòu)體成員1;
    結(jié)構(gòu)體成員2;
    結(jié)構(gòu)體成員3;
    ……
} 簡(jiǎn)化的結(jié)構(gòu)體變量定義格式("struct 結(jié)構(gòu)體名稱");
    
int main(void)
{
    簡(jiǎn)化的結(jié)構(gòu)體變量定義格式("struct 結(jié)構(gòu)體名稱") 結(jié)構(gòu)體變量名; 
}
  • 這樣定義的變量為全局變量

? 示例如下:

typedef struct Book
{
	char title[120];
    char author[40];
    float price;
    unsigned int date;
    char publisher[40];
} infor;
    

int main(void)
{
    infor book;
    
    return 0;
}
(3)訪問(wèn)結(jié)構(gòu)體變量
Ⅰ、使用點(diǎn)號(hào)運(yùn)算符

? 要訪問(wèn)結(jié)構(gòu)體成員,我們需要引入一個(gè)新的運(yùn)算符——點(diǎn)號(hào)(.)運(yùn)算符。比如book.title就是引用book結(jié)構(gòu)體的title成員,它是一個(gè)字符數(shù)組;而book.price則是引用book結(jié)構(gòu)體的price成員,它是一個(gè)浮點(diǎn)型的變量。示例如下:

typedef struct{
    char title[120];
    char author[40];
    float price;
    unsigned int date;
    char publisher[40];
} infor;
    
int main(void)
{
    infor book;
    book.title[120]="";
    book.author[40]="";
    book.price=;
    book.date=;
    book.publisher=;
}
Ⅱ、使用結(jié)構(gòu)體指針(使用運(yùn)算符)

? 要訪問(wèn)結(jié)構(gòu)體成員,我們需要引入一個(gè)新的運(yùn)算符——指針(->)運(yùn)算符。

? 訪問(wèn)形式如下:

結(jié)構(gòu)體指針(結(jié)構(gòu)體的首地址)->結(jié)構(gòu)體成員名=//意為將值賦給結(jié)構(gòu)體指針指向的結(jié)構(gòu)體成員
//等同于:
(*結(jié)構(gòu)體指針).結(jié)構(gòu)體成員名=;//注意:“.”號(hào)運(yùn)算符優(yōu)先級(jí)比“*”號(hào)運(yùn)算符高,因此要加括號(hào)

? 示例如下:

typedef struct{
    char title[120];
    char author[40];
    float price;
    unsigned int date;
    char publisher[40];
} infor;
    
int main(void)
{
    infor book;
    struct *pt;
    pt=&book;
    pt->title[120]="";
    pt->author[40]="";
    pt->price=;
    pt->date=;
    pt->publisher[40]=;
}

3、枚舉

(1)基本概念

? 枚舉是C語(yǔ)言中的一種基本數(shù)據(jù)類型,它的用途是:定義一個(gè)取值受限制的整形變量,用于限制變量取值范圍,讓數(shù)據(jù)更為簡(jiǎn)潔和易讀,提高可讀性。其定義格式如下:

enum 枚舉類型名稱{
    枚舉值名稱,
	枚舉值名稱,
    ……
};
  • 注意:大括號(hào)后面的分號(hào)不能少,這是一條完整的語(yǔ)句;每個(gè)成員名稱后的分隔符為“,”,這是與結(jié)構(gòu)體不同的地方。
  • 注意:第一個(gè)枚舉成員的默認(rèn)值為整型的 0,后續(xù)枚舉成員的值在前一個(gè)成員上加 1;若我們?cè)谶@個(gè)實(shí)例中把第一個(gè)枚舉成員的值定義為 1,第二個(gè)就為 2,以此類推。
(2)定義枚舉變量
Ⅰ、基本方式

? 定義形式如下:

enum 枚舉類型名稱 枚舉變量1,枚舉變量2;
Ⅱ、在聲明的最后進(jìn)行定義

? 定義形式如下:

enum 枚舉類型名稱{
    枚舉值名稱,
	枚舉值名稱,
    ……
} 枚舉變量名;
Ⅲ、直接定義枚舉變量

? 定義形式如下:

enum {枚舉值名稱,枚舉值名稱,……} 枚舉變量名;
  • 枚舉類型名稱可以省略;
  • 因?yàn)槊杜e變量類型較長(zhǎng),所以通常用typedef更改變量類型名。
(3)訪問(wèn)枚舉成員

? 示例如下:

int main(void)
{
    enum Week{Mon=1,Tue,Wed} day;
    day = Wed;
    return 0;
}
(4)實(shí)例
Ⅰ、常規(guī)用法
#include <stdio.h>

enum WeekDay{Mon=1,Tue,Wed,Thu,Fri,Sat,Sun};

int main(void)
{
    enum WeekDay day;
    day = Mon;			//day = 1;
    day = Tue;			//day = 2;
    printf("%d\n",day);
    return 0;
}
Ⅱ、遍歷枚舉類型
#include <stdio.h>
enum Week{Mon=1, Tue, Wed, Thu, Fri, Sat, Sun} day;
int main(){
    // 遍歷枚舉元素
    for (day = Mon; day <= Sun; day++)
    {
        printf("枚舉元素:%d\n", day);
    }
}
  • 僅當(dāng)枚舉類型值連續(xù)才可遍歷。
Ⅲ、STM32中與結(jié)構(gòu)體結(jié)合的用法
typedef enum
{ 
  GPIO_Speed_10MHz = 1,
  GPIO_Speed_2MHz, 
  GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;

typedef struct
{
  uint16_t GPIO_Pin; 
  GPIOSpeed_TypeDef GPIO_Speed; 	//定義枚舉變量
  GPIOMode_TypeDef GPIO_Mode;   
}GPIO_InitTypeDef;

int main(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;	//定義結(jié)構(gòu)體變量
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
}
//節(jié)選

二、STM32F103基本介紹

1、STM32簡(jiǎn)介

? STM32是ST公司基于ARM Cortex-M內(nèi)核開發(fā)的32位微控制器,常應(yīng)用在嵌入式領(lǐng)域,如智能車、無(wú)人機(jī)、機(jī)器人、無(wú)線通信、物聯(lián)網(wǎng)、工業(yè)控制、娛樂(lè)電子產(chǎn)品等。STM32功能強(qiáng)大、性能優(yōu)異、片上資源豐富、功耗低,是一款經(jīng)典的嵌入式微控制器。目前STM32共有四個(gè)系列,分別是高性能系列、主流系列、超低功耗系列和無(wú)線系列,對(duì)應(yīng)的都有不同的產(chǎn)品,如:

  • 高性能系列:STM32F2、F4、F7、H7等;
  • 主流系列:STM32F0、F1、F3、G0、G4等;
  • 超低功耗系列:STM32L0、L1、L4、L4+、L5、U5等;
  • 無(wú)線系列:STM32WL、WB等。

2、系統(tǒng)結(jié)構(gòu)

江科大自化協(xié)STM32學(xué)習(xí)筆記(部分C語(yǔ)言知識(shí)、STM32簡(jiǎn)介和GPIO口的使用)

3、STM32F103C8T6基本信息

江科大自化協(xié)STM32學(xué)習(xí)筆記(部分C語(yǔ)言知識(shí)、STM32簡(jiǎn)介和GPIO口的使用)

  • 系列:主流系列STM32F1

  • 內(nèi)核:ARM Cortex-M3

  • 主頻:72MHz

  • RAM:20K(SRAM)

  • ROM:64K(Flash)

  • 供電:2.0~3.6V(標(biāo)準(zhǔn)3.3V)

  • 封裝:LQFP48

4、STM32F103C8T6片上資源/外設(shè)(Peripheral)

江科大自化協(xié)STM32學(xué)習(xí)筆記(部分C語(yǔ)言知識(shí)、STM32簡(jiǎn)介和GPIO口的使用)

5、引腳定義

江科大自化協(xié)STM32學(xué)習(xí)筆記(部分C語(yǔ)言知識(shí)、STM32簡(jiǎn)介和GPIO口的使用)

6、最小系統(tǒng)電路

江科大自化協(xié)STM32學(xué)習(xí)筆記(部分C語(yǔ)言知識(shí)、STM32簡(jiǎn)介和GPIO口的使用)

三、GPIO通用IO口的使用

1、GPIO簡(jiǎn)介

? GPIO(General Purpose Input Output)通用輸入輸出口,可配置為8種輸入輸出模式,引腳電平:0V~3.3V,部分引腳可容忍5V。

? 輸出模式下可控制端口輸出高低電平,用以驅(qū)動(dòng)LED、控制蜂鳴器、模擬通信協(xié)議輸出時(shí)序等。

? 輸入模式下可讀取端口的高低電平或電壓,用于讀取按鍵輸入、外接模塊電平信號(hào)輸入、ADC電壓采集、模擬通信協(xié)議接收數(shù)據(jù)等。

2、GPIO位結(jié)構(gòu)和工作模式

江科大自化協(xié)STM32學(xué)習(xí)筆記(部分C語(yǔ)言知識(shí)、STM32簡(jiǎn)介和GPIO口的使用)

? GPIO位結(jié)構(gòu)由引腳端口、驅(qū)動(dòng)器和寄存器組成。由圖可以將結(jié)構(gòu)分為兩部分,一是上半部分,為輸入模式;二是下半部分,為輸出模式

  • 輸入模式:共四種輸入模式,上拉電阻和下拉電阻將其分為三種模式,分別為上拉輸入(連接上拉電阻)、下拉輸入(連接下拉電阻)和浮空輸入(上拉、下拉電阻均不連接);后通過(guò)施密特觸發(fā)器對(duì)電壓進(jìn)行整形然后輸入;不通過(guò)施密特觸發(fā)器的為模擬輸入,引腳直接接入內(nèi)部ADC

上拉電阻接通時(shí),保證引腳為高電平;

下拉電阻接通時(shí),保證引腳為低電平;

施密特觸發(fā)器執(zhí)行邏輯:如果輸入電壓大于某一閾值,輸入就會(huì)瞬間升為高電平;如果輸入電壓小于某一閾值,輸入就會(huì)瞬間降為低電平。

  • 輸出模式:共四種輸出模式,輸出可以由輸出數(shù)據(jù)寄存器或者片上外設(shè)控制(復(fù)用輸出);在輸出控制部分,由兩個(gè)MOS管將其分為三種模式,分別為推挽輸出(兩個(gè)MOS管都有效)、開漏模式(N—MOS管有效)關(guān)閉(配置為輸入模式時(shí),兩個(gè)MOS管都無(wú)效)。

MOS管相當(dāng)于一種電子開關(guān),通過(guò)信號(hào)來(lái)控制開關(guān)的導(dǎo)通和關(guān)閉,開關(guān)負(fù)責(zé)使IO口輸出高或低電平;

推挽輸出模式(強(qiáng)推輸出模式)下,高低電平均有較強(qiáng)的驅(qū)動(dòng)能力,STM32對(duì)IO口有絕對(duì)的控制權(quán);

開漏輸出模式下,只有低電平有驅(qū)動(dòng)能力,高電平?jīng)]有驅(qū)動(dòng)能力;常作為通信協(xié)議的驅(qū)動(dòng)方式,在多機(jī)通信的情況下,這個(gè)模式可以避免各個(gè)設(shè)備的相互干擾;還可用于輸出5V的電平信號(hào)

  • 一個(gè)端口只能有一個(gè)輸出,但可以有多個(gè)輸入。即在輸入模式下,輸出都是無(wú)效的;在輸出模式下,輸入模式也是有效的。

? 通過(guò)配置GPIO的端口配置寄存器,端口可以配置成以下8種模式:

江科大自化協(xié)STM32學(xué)習(xí)筆記(部分C語(yǔ)言知識(shí)、STM32簡(jiǎn)介和GPIO口的使用)

3、不同外設(shè)的GPIO配置

? 內(nèi)容較多,見(jiàn)STM32F10XXX參考手冊(cè)。

4、GPIO常用寄存器

(1)端口配置低\高寄存器(GPIOx_CRL/GPIOx_CRH)(x=A…E)

? 端口配置寄存器共16位,但每4位數(shù)據(jù)表示1位,共需要64位,而STM32中每個(gè)寄存器都為32位,因此分為端口配置低寄存器和端口配置高寄存器。通過(guò)端口配置寄存器可以配置GPIO工作模式端口輸出速度。

輸出速度可以限制輸出引腳的最大翻轉(zhuǎn)速度,作用是降低功耗、提高穩(wěn)定性,一般情況下配置為50MHz

(2)端口輸入數(shù)據(jù)寄存器(GPIOx_IDR)(x=A…E)

? 輸入數(shù)據(jù)共16位,但寄存器共32位,因此寄存器高16位為空。

(3)端口輸出數(shù)據(jù)寄存器(GPIOx_ODR)(x=A…E)

? 輸出數(shù)據(jù)共16位,但寄存器共32位,因此寄存器高16位為空。

(4)端口位設(shè)置/清除寄存器(GPIOx_BERR)(x=A…E)

? 高16位用于清除,低16位用于設(shè)置。

  • 高16位:為0不影響;為1清0;
  • 低16為:為0不影響;為1置1。
(5)端口位清除寄存器(GPIOx_BER)(x=A…E)

? 高16位為空,低16位用于清除,方法同上。

(5)端口位配置鎖定寄存器(GPIOx_LCKR)(x=A…E)

? 高15位為空,低17位用于鎖定,較少使用。

5、GPIO常用函數(shù)

(1)RCC常用函數(shù)

? 在RCC時(shí)鐘控制的函數(shù)庫(kù)中,我們最經(jīng)常用到的是以下三個(gè)函數(shù):

//AHB系統(tǒng)總線時(shí)鐘控制
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
//APB2總線時(shí)鐘控制
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
//APB1總線時(shí)鐘控制
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
/*第一個(gè)參數(shù)為外設(shè)選擇,與STM32互聯(lián)型的設(shè)備在下列列表中選擇:
 *	   @arg RCC_AHBPeriph_DMA1
 *     @arg RCC_AHBPeriph_DMA2
 *     @arg RCC_AHBPeriph_SRAM
 *     @arg RCC_AHBPeriph_FLITF
 *     @arg RCC_AHBPeriph_CRC
 *     @arg RCC_AHBPeriph_OTG_FS    
 *     @arg RCC_AHBPeriph_ETH_MAC   
 *     @arg RCC_AHBPeriph_ETH_MAC_Tx
 *     @arg RCC_AHBPeriph_ETH_MAC_Rx
 *
 *     @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB,
 *          RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,
 *          RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,
 *          RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,
 *          RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,
 *          RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,
 *          RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11  
 *
 *     @arg RCC_APB1Periph_TIM2, RCC_APB1Periph_TIM3, RCC_APB1Periph_TIM4,
 *          RCC_APB1Periph_TIM5, RCC_APB1Periph_TIM6, RCC_APB1Periph_TIM7,
 *          RCC_APB1Periph_WWDG, RCC_APB1Periph_SPI2, RCC_APB1Periph_SPI3,
 *          RCC_APB1Periph_USART2, RCC_APB1Periph_USART3, RCC_APB1Periph_USART4, 
 *          RCC_APB1Periph_USART5, RCC_APB1Periph_I2C1, RCC_APB1Periph_I2C2,
 *          RCC_APB1Periph_USB, RCC_APB1Periph_CAN1, RCC_APB1Periph_BKP,
 *          RCC_APB1Periph_PWR, RCC_APB1Periph_DAC, RCC_APB1Periph_CEC,
 *          RCC_APB1Periph_TIM12, RCC_APB1Periph_TIM13, RCC_APB1Periph_TIM14
 *
 *	   其他設(shè)備在下列列表中選擇:
 *     @arg RCC_AHBPeriph_DMA1
 *     @arg RCC_AHBPeriph_DMA2
 *     @arg RCC_AHBPeriph_SRAM
 *     @arg RCC_AHBPeriph_FLITF
 *     @arg RCC_AHBPeriph_CRC
 *     @arg RCC_AHBPeriph_FSMC
 *     @arg RCC_AHBPeriph_SDIO
 *
 *可用按位或(|)來(lái)選擇多個(gè)外設(shè)
 *
 *第二個(gè)參數(shù)為選擇使能或失能,選擇:ENABLE or DISABLE
 */

? GPIO連接在APB2總線上,且假定以PA0為接口,則使能GPIO的函數(shù)為:

void RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
(2)GPIO常用函數(shù)

? 在GPIO通用IO口的函數(shù)庫(kù)中,我們最經(jīng)常用到的是以下函數(shù):

//復(fù)位函數(shù),調(diào)用這個(gè)函數(shù)后,所指定的GPIO外設(shè)就會(huì)被復(fù)位
void GPIO_DeInit(GPIO_TypeDef* GPIOx);
//復(fù)位函數(shù),可以復(fù)位AFIO外設(shè)
void GPIO_AFIODeInit(void);
//初始化函數(shù),功能:用結(jié)構(gòu)體的參數(shù)來(lái)初始化GPIO口
//初始化時(shí),我們需要先定義一個(gè)結(jié)構(gòu)體變量,然后給結(jié)構(gòu)體賦值,最后調(diào)用初始化函數(shù),函數(shù)內(nèi)部會(huì)自動(dòng)讀取結(jié)構(gòu)體的值,然后把外設(shè)的各個(gè)參數(shù)配置好。
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
//功能:把結(jié)構(gòu)體變量賦一個(gè)默認(rèn)值
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);
//以下四個(gè)函數(shù)為GPIO的讀取函數(shù),均有返回值
//功能:讀取輸入數(shù)據(jù)寄存器某一個(gè)端口的輸入值
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//功能:讀取整個(gè)輸入數(shù)據(jù)寄存器
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
//功能:讀取輸出數(shù)據(jù)寄存器的某一位,用于輸出模式下,查看輸入的值
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//功能:讀取整個(gè)輸出數(shù)據(jù)寄存器
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
//以下四個(gè)函數(shù)為GPIO的寫入函數(shù)
//功能:將指定端口引腳設(shè)置為高電平
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//功能:將指定端口引腳設(shè)置為低電平
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//功能:對(duì)指定端口進(jìn)行寫入操作
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
//功能:同時(shí)對(duì)16個(gè)端口進(jìn)行寫入操作
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
/*參數(shù)注釋:
 *①GPIO_TypeDef* GPIOx,GPIO端口選擇,值為GPIOx(x=A~G);
 *可用按位或(|)來(lái)選擇多個(gè)端口
 *
 *②uint16_t GPIO_Pin,IO口引腳選擇,一個(gè)GPIO端口有16個(gè)引腳,所以其值為GPIO_Pin_x(x=0~15)
 *可用按位或(|)來(lái)選擇多個(gè)引腳
 *
 *③BitAction BitVal,指定寫入的數(shù)據(jù)值,這個(gè)參數(shù)可以是BitAction枚舉中的一個(gè)值,值為:
 *	@arg Bit_RESET:清除端口值,即置低電平
 *  @arg Bit_SET:設(shè)置端口值,即置高電平
 *
 *④uint16_t PortVal,指定要寫入端口輸出數(shù)據(jù)寄存器的值
 *
 *⑤GPIO_InitTypeDef* GPIO_InitStruct,GPIO初始化結(jié)構(gòu)體的地址
 */

/*初始化結(jié)構(gòu)體定義:
 *①定義一個(gè)結(jié)構(gòu)體變量
 *GPIO_InitTypeDef GPIO_InitStructure;
 *結(jié)構(gòu)體如下:
 *typedef struct
 *{
 *  uint16_t GPIO_Pin;             
 *  GPIOSpeed_TypeDef GPIO_Speed;  
 *  GPIOMode_TypeDef GPIO_Mode;    
 *}GPIO_InitTypeDef;
 *由此可知該結(jié)構(gòu)體有三個(gè)成員,分別為GPIO_Pin、GPIO_Speed和GPIO_Mode,下一步就是分別賦值
 *
 *②給結(jié)構(gòu)體賦值:
 *GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //設(shè)置推挽輸出
 *GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		   //使用GPIO的0號(hào)引腳
 *GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度為50MHz
 *
 *GPIO_Mode,用于設(shè)置工作模式,其枚舉如下:
 *typedef enum
 *{ GPIO_Mode_AIN = 0x0,			//模擬輸入模式(Analog IN)
 *  GPIO_Mode_IN_FLOATING = 0x04,	//浮空輸入模式
 *  GPIO_Mode_IPD = 0x28,			//下拉輸入模式(In Pull Down)
 *  GPIO_Mode_IPU = 0x48,			//上拉輸入模式(In Pull Up)
 *  GPIO_Mode_Out_OD = 0x14,		//開漏輸出模式(Out Open Drain)
 *  GPIO_Mode_Out_PP = 0x10,		//推挽輸出模式(Out Push Pull)
 *  GPIO_Mode_AF_OD = 0x1C,			//復(fù)用開漏模式(Atl Open Drain)
 *  GPIO_Mode_AF_PP = 0x18			//復(fù)用推挽模式(Atl Push Pull)
 *}GPIOMode_TypeDef;
 *
 *GPIO_Pin,選擇引腳,值為GPIO_Pin_x(x=0~15和All)
 *
 *GPIO_Speed,選擇輸出速度,其枚舉如下:
 *typedef enum
 *{ 
 *  GPIO_Speed_10MHz = 1,
 *  GPIO_Speed_2MHz, 
 *  GPIO_Speed_50MHz
 *}GPIOSpeed_TypeDef;
 *常用速度為50MHz
 */

6、GPIO初始化

? 以用低電平驅(qū)動(dòng)的方式點(diǎn)亮一個(gè)接在PA0口的LED,并使其閃爍為例。

(1)使用RCC開啟GPIO的時(shí)鐘

? GPIO連接在APB2總線上,且以PA0為接口,則使能時(shí)鐘的函數(shù)為:

void RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
(2)使用GPIO_Init函數(shù)初始化GPIO

? 為了保證高低電平的強(qiáng)驅(qū)動(dòng)能力,選用推挽輸出,代碼如下:

//定義結(jié)構(gòu)體變量(局部變量)
GPIO_InitTypeDef GPIO_InitStructure;
//訪問(wèn)結(jié)構(gòu)體變量(引出結(jié)構(gòu)體成員)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //設(shè)置推挽輸出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		 //使用GPIO的0號(hào)引腳
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度為50MHz
(3)使用輸出或輸入的函數(shù)控制GPIO口

? 調(diào)用輸入的函數(shù),GPIO_SetBits()、GPIO_ResetBits()和GPIO_WriteBit()均可單獨(dú)設(shè)置引腳低電平,代碼如下:

GPIO_ResetBits(GPIOA,GPIO_Pin_0);
Delay_ms(250);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
Delay_ms(250);
		
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
Delay_ms(250);
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
Delay_ms(250);
//通過(guò)強(qiáng)制轉(zhuǎn)換為BitAction的枚舉類型來(lái)直接輸入高低電平
GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)0);
Delay_ms(250);
GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)1);
Delay_ms(250);

7、GPIO應(yīng)用實(shí)例

(1)LED閃爍

? LED有來(lái)兩種驅(qū)動(dòng)方式:高電平驅(qū)動(dòng)和低電平驅(qū)動(dòng),對(duì)STM32來(lái)說(shuō),兩種驅(qū)動(dòng)方式均可,但是因?yàn)楹芏鄦纹瑱C(jī)或者芯片,都使用了高電平弱驅(qū)動(dòng)、低電平強(qiáng)驅(qū)動(dòng)的規(guī)則,這樣可以在一定程度上避免高低電平?jīng)_突,所以常使用低電平驅(qū)動(dòng)方式。

開漏輸出模式下,只有低電平有驅(qū)動(dòng)能力,高電平?jīng)]有驅(qū)動(dòng)能力,因此無(wú)法進(jìn)行高電平驅(qū)動(dòng)。

? 代碼如下(LED連接PA0口):

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

/*
 *第一步,使用RCC開啟GPIO的時(shí)鐘
 *第二步,使用GPIO_Init函數(shù)初始化GPIO
 *第三步,使用輸出或輸入的函數(shù)控制GPIO口
*/
int main(void)
{
	//第一步,開啟時(shí)鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//第二步,初始化GPIO
	//定義結(jié)構(gòu)體變量(局部變量)
	GPIO_InitTypeDef GPIO_InitStructure;
	//訪問(wèn)結(jié)構(gòu)體變量(引出結(jié)構(gòu)體成員)
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //設(shè)置推挽輸出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		 //使用GPIO的0號(hào)引腳
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度為50MHz
	//使用GPIO_Init函數(shù)初始化GPIO
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//第三步,控制GPIO口
	
	while(1)
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_0);
		Delay_ms(250);
		GPIO_SetBits(GPIOA,GPIO_Pin_0);
		Delay_ms(250);
		
		GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
		Delay_ms(250);
		GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
		Delay_ms(250);
		//通過(guò)強(qiáng)制轉(zhuǎn)換為BitAction的枚舉類型來(lái)直接輸入高低電平
		GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)0);
		Delay_ms(250);
		GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)1);
		Delay_ms(250);
	}
}

(2)LED流水燈

? 實(shí)現(xiàn)基本流水燈(LED連接PA0~PA6),代碼如下:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
	//第一步,開啟時(shí)鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//第二步,初始化GPIO
	//定義結(jié)構(gòu)體變量(局部變量)
	GPIO_InitTypeDef GPIO_InitStructure;
	//訪問(wèn)結(jié)構(gòu)體變量(引出結(jié)構(gòu)體成員)
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //設(shè)置推挽輸出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;		 //使用GPIO的所有引腳
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度為50MHz
	//使用GPIO_Init函數(shù)初始化GPIO
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	while(1)
	{
        //低電平驅(qū)動(dòng),因此需要取反
		GPIO_Write(GPIOA,~0x0001);	//0000 0000 0000 0001
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0002);	//0000 0000 0000 0010
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0004);	//0000 0000 0000 0100
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0008);	//0000 0000 0000 1000
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0010);	//0000 0000 0001 0000
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0020);	//0000 0000 0010 0000
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0040);	//0000 0000 0100 0000
		Delay_ms(500);
	}
}

? 實(shí)現(xiàn)往返流水燈,代碼如下:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
	//第一步,開啟時(shí)鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//第二步,初始化GPIO
	//定義結(jié)構(gòu)體變量(局部變量)
	GPIO_InitTypeDef GPIO_InitStructure;
	//訪問(wèn)結(jié)構(gòu)體變量(引出結(jié)構(gòu)體成員)
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //設(shè)置推挽輸出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;		 //使用GPIO的所有引腳
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度為50MHz
	//使用GPIO_Init函數(shù)初始化GPIO
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	while(1)
	{
		unsigned int i;
		for(i=0;i<7;i++)
		{
			GPIO_Write(GPIOA,~(0x0001<<i));
			Delay_ms(250);
		}
		for(i=0;i<7i++)
		{
			GPIO_Write(GPIOA,~(0x0040>>i));
			Delay_ms(250);
		}
	}
}

(3)GPIO控制有源蜂鳴器

?
? 有源蜂鳴器同樣使用低電平驅(qū)動(dòng),不過(guò)接口為PB12,代碼如下:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
	//第一步,開啟時(shí)鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	//第二步,初始化GPIO
	//定義結(jié)構(gòu)體變量(局部變量)
	GPIO_InitTypeDef GPIO_InitStructure;
	//訪問(wèn)結(jié)構(gòu)體變量(引出結(jié)構(gòu)體成員)
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //設(shè)置推挽輸出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;		 //使用GPIO的12號(hào)引腳
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度為50MHz
	//使用GPIO_Init函數(shù)初始化GPIO
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	//第三步,控制GPIO口
	
	while(1)
	{
		GPIO_ResetBits(GPIOB,GPIO_Pin_12);
		Delay_ms(100);
		GPIO_SetBits(GPIOB,GPIO_Pin_12);
		Delay_ms(100);
		GPIO_ResetBits(GPIOB,GPIO_Pin_12);
		Delay_ms(100);
		GPIO_SetBits(GPIOB,GPIO_Pin_12);
		Delay_ms(700);
	}
}

(4)按鍵控制LED
  • 實(shí)際效果:兩個(gè)按鍵對(duì)應(yīng)兩個(gè)LED,按一次亮,再按一次滅。

?

? 按鍵1連接PB1,按鍵2連接PB11;LED1連接PA1,LED2連接PA2,使用模塊化編程,代碼如下:

①LED.c
#include "stm32f10x.h"                  // Device header

void LED_Init(void)
{
	//RCC使能時(shí)鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//使兩個(gè)端口默認(rèn)高電平,使LED處于未點(diǎn)亮的狀態(tài)
	GPIO_SetBits(GPIOA,GPIO_Pin_1 | GPIO_Pin_2);
}

//點(diǎn)亮對(duì)應(yīng)的LED
void LED_ON(unsigned char i)
{
	if(i==1)
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_1);
	}
	if(i==2)
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_2);
	}
}

//熄滅對(duì)應(yīng)的LED
void LED_OFF(unsigned char i)
{
	if(i==1)
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_1);
	}
	if(i==2)
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_2);
	}
}

//通過(guò)檢測(cè)輸出數(shù)據(jù)寄存器的數(shù)據(jù),得到當(dāng)前的LED狀態(tài),再用相反作用的函數(shù)使其狀態(tài)變化
void LED_Turn(unsigned char i)
{
	if(i == 1)
	{
		if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1) == 0)//檢測(cè)輸出數(shù)據(jù)寄存器的數(shù)據(jù)是否為0
		{
			GPIO_SetBits(GPIOA,GPIO_Pin_1);				 //若為0,即LED點(diǎn)亮?xí)r,對(duì)應(yīng)數(shù)據(jù)位置1,即熄滅
		}
		else
		{
			GPIO_ResetBits(GPIOA,GPIO_Pin_1);
		}
	}
	if(i == 2)
	{
		if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_2) == 0)//檢測(cè)輸出數(shù)據(jù)寄存器的數(shù)據(jù)是否為0
		{
			GPIO_SetBits(GPIOA,GPIO_Pin_2);				 //若為0,即LED點(diǎn)亮?xí)r,對(duì)應(yīng)數(shù)據(jù)位置1,即熄滅
		}
		else
		{
			GPIO_ResetBits(GPIOA,GPIO_Pin_2);
		}
	}
}

  • 51單片機(jī)使用按鍵控制LED亮滅時(shí),是直接將數(shù)據(jù)取反,但32不是直接對(duì)寄存器進(jìn)行操作,而是調(diào)用已經(jīng)封裝好的庫(kù)函數(shù),因此不能直接取反。所以STM32通過(guò)函數(shù)檢測(cè)輸出數(shù)據(jù)寄存器的數(shù)據(jù),得到當(dāng)前的LED狀態(tài),再用相反作用的函數(shù)使其狀態(tài)變化以達(dá)到取反的效果,使用的函數(shù)為:
GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
②Key.c
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

void Key_Init(void)
{
	//RCC使能時(shí)鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}

//消除抖動(dòng)后返回對(duì)應(yīng)鍵碼
uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;
	
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0)
	{
		Delay_ms(20);
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0);
		Delay_ms(20);							//消除抖動(dòng)
		KeyNum = 1;
	}
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0)
	{
		Delay_ms(20);
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0);
		Delay_ms(20);							//消除抖動(dòng)
		KeyNum = 2;
	}
	
	return KeyNum;
}

③main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"

uint8_t KeyNum;

int main(void)
{
	LED_Init();		//LED端口初始化
	Key_Init();		//按鍵端口初始化
	while(1)
	{
		KeyNum = Key_GetNum();
		if(KeyNum == 1)
		{
			LED_Turn(1);
		}
		if(KeyNum == 2)
		{
			LED_Turn(2);
		}
	}
}

(5)光敏傳感器控制蜂鳴器
  • 實(shí)際效果:當(dāng)光敏傳感器被遮蔽時(shí),蜂鳴器鳴響。
  • 光敏傳感器:當(dāng)亮度高于閾值時(shí),輸出指示燈亮,表示輸出低電平;當(dāng)亮度低于閾值時(shí),輸出指示燈滅,表示輸出高電平;閾值可通過(guò)上面的電位器調(diào)節(jié)。
  • 光敏傳感器初始化時(shí),需要選擇上拉工作模式,因?yàn)楣饷魝鞲衅鞯墓ぷ髟砭褪?strong>將光敏電阻與上拉電阻串聯(lián),通過(guò)分壓來(lái)實(shí)現(xiàn)對(duì)亮度的感知。

? 蜂鳴器連接PB12口,光敏傳感器連接PB13口,使用模塊化編程,代碼如下:

①Buzzer.c

#include "stm32f10x.h"                  // Device header

void Buzzer_Init(void)
{
	//RCC使能時(shí)鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	//使蜂鳴器默認(rèn)靜默
	GPIO_SetBits(GPIOB,GPIO_Pin_12);
}

//蜂鳴器鳴響
void Buzzer_ON(void)
{
	GPIO_ResetBits(GPIOB,GPIO_Pin_12);
}

//蜂鳴器靜默
void Buzzer_OFF(void)
{
	GPIO_SetBits(GPIOB,GPIO_Pin_12);
}

//蜂鳴器狀態(tài)翻轉(zhuǎn)
//通過(guò)檢測(cè)輸出數(shù)據(jù)寄存器的數(shù)據(jù),得到當(dāng)前的蜂鳴器狀態(tài),后使用函數(shù)改變蜂鳴器當(dāng)前狀態(tài)
void Buzzer_Turn(void)
{
	if(GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_12) == 0)//檢測(cè)輸出數(shù)據(jù)寄存器的數(shù)據(jù)是否為0
	{
		GPIO_SetBits(GPIOB,GPIO_Pin_12);			  //若為0,即蜂鳴器鳴響,對(duì)應(yīng)數(shù)據(jù)位置1,即使蜂鳴器靜默
	}
	else
	{
		GPIO_ResetBits(GPIOB,GPIO_Pin_12);
	}
}

②LightSensor.c

#include "stm32f10x.h"                  // Device header

//光敏傳感器初始化
void LightSensor_Init(void)
{
	//RCC使能時(shí)鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		//使用上拉輸出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

//返回光敏傳感器的電平情況
uint8_t LightSensor_Get(void)
{
	return GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13);
}

③main.c文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-430091.html

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Buzzer.h"
#include "LightSensor.h"

int main(void)
{
	Buzzer_Init();			//蜂鳴器初始化
	LightSensor_Init();		//光敏傳感器初始化
	while(1)
	{	
		if(LightSensor_Get() ==1)//如果光敏傳感器接收的亮度低于閾值,則蜂鳴器鳴響
		{
			Buzzer_ON();
		}
		else
		{
			Buzzer_OFF();
		}
	}
}

到了這里,關(guān)于江科大自化協(xié)STM32學(xué)習(xí)筆記(部分C語(yǔ)言知識(shí)、STM32簡(jiǎn)介和GPIO口的使用)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 江科大STM32學(xué)習(xí)筆記(詳細(xì)版)——2023持續(xù)更新

    江科大STM32學(xué)習(xí)筆記(詳細(xì)版)——2023持續(xù)更新

    基礎(chǔ)篇 是到時(shí)候我自己找其它視頻補(bǔ)充(就比如寄存器影射,時(shí)鐘樹),到時(shí)候?qū)懺谄渌恼吕铩?主篇(外設(shè)篇)目前是跟著@江協(xié)科技的STM32入門教程-2023版 細(xì)致講解 中文字幕視頻來(lái)學(xué)習(xí)的,大家可以邊看視頻邊根據(jù)我的筆記做適合自己的筆記; 另外,因?yàn)槠L(zhǎng)了,我將

    2024年02月06日
    瀏覽(24)
  • 【STM32】學(xué)習(xí)筆記(TIM定時(shí)器)-江科大

    【STM32】學(xué)習(xí)筆記(TIM定時(shí)器)-江科大

    定時(shí)器可以對(duì)輸入的時(shí)鐘進(jìn)行計(jì)數(shù),并在計(jì)數(shù)值達(dá)到設(shè)定值時(shí)觸發(fā)中斷 16位計(jì)數(shù)器、預(yù)分頻器、自動(dòng)重裝寄存器的時(shí)基單元,在72MHz計(jì)數(shù)時(shí)鐘下可以實(shí)現(xiàn)最大59.65s的定時(shí) 不僅具備基本的定時(shí)中斷功能,而且還包含內(nèi)外時(shí)鐘源選擇、輸入捕獲、輸出比較、編碼器接口、主從觸發(fā)

    2024年02月10日
    瀏覽(26)
  • 5、江科大stm32視頻學(xué)習(xí)筆記——OLED顯示屏

    5、江科大stm32視頻學(xué)習(xí)筆記——OLED顯示屏

    目錄 1、OLED簡(jiǎn)介? 2、OLED硬件電路 3、OLED驅(qū)動(dòng)函函數(shù)簡(jiǎn)介和應(yīng)用 4、用keil進(jìn)行調(diào)試 4引腳OLED SCL和SDA是I2C通信引腳,需要接在I2C通信的引腳上 實(shí)驗(yàn)中用的模塊是GPIO口模擬的I2C通信,故SCL和SDA兩個(gè)端口可以接在任意的GPIO口上 7引腳OLED 右邊5個(gè)引腳是SPI通信協(xié)議的引腳 如果是GPI

    2024年02月14日
    瀏覽(25)
  • 【stm32】stm32學(xué)習(xí)筆記(江科大)-詳解stm32獲取Mpu6050陀螺儀和加速度

    【stm32】stm32學(xué)習(xí)筆記(江科大)-詳解stm32獲取Mpu6050陀螺儀和加速度

    目錄 I2C 起始條件: 終止條件: ?發(fā)送一個(gè)字節(jié) 接收一個(gè)字節(jié) ?接收發(fā)送應(yīng)答 ?代碼 I2C I2C.C I2C.h Mpu6050 Mpu6050.c Mpu6050.h Mpu6050Reg.h main.c 結(jié)果 ? 要想獲取Mpu6050陀螺儀和加速度那就需要了解一下Mpu6050。Mpu6050使用的是I2C通訊 先了解一下 起始條件: SCL高電平期間,SDA從高電平切換

    2024年02月16日
    瀏覽(19)
  • 【江科大】STM32:TIM輸入捕獲(理論部分)

    【江科大】STM32:TIM輸入捕獲(理論部分)

    輸入捕獲模式下,當(dāng)通道輸入引腳出現(xiàn)指定電平跳變(上升沿或者下降沿)時(shí),(控制)當(dāng)前CNT的值將被鎖存到CCR中,可用于測(cè)量PWM波形的頻率、占空比、脈沖間隔、電平持續(xù)時(shí)間等參數(shù) 每個(gè)高級(jí)定時(shí)器和通用定時(shí)器都擁有4個(gè)輸入捕獲通道 可配置為PWMI(input)模式,同時(shí)測(cè)

    2024年01月23日
    瀏覽(20)
  • 江科大stm32視頻學(xué)習(xí)筆記——TIM定時(shí)中斷&定時(shí)器外部時(shí)鐘

    江科大stm32視頻學(xué)習(xí)筆記——TIM定時(shí)中斷&定時(shí)器外部時(shí)鐘

    目錄 一、TIM(Timer)定時(shí)器簡(jiǎn)介 ?1.1 定時(shí)器類型 摘要 1.1.1 基本定時(shí)器 1.1.2 通用定時(shí)器 1.1.3 高級(jí)定時(shí)器? 1.2 定時(shí)中斷基本結(jié)構(gòu) 1.2.1 結(jié)構(gòu)框圖 1.2.2 時(shí)序圖 二、定時(shí)器定時(shí)中斷定時(shí)器外部時(shí)鐘 2.1 內(nèi)部時(shí)鐘鬧鐘代碼 2.1.1 Timer.c 2.1.2 Buzzer.c加入間隔發(fā)聲函數(shù) 2.1.3 main.c 2.1.4 實(shí)驗(yàn)視頻

    2024年01月23日
    瀏覽(55)
  • 18、江科大stm32視頻學(xué)習(xí)筆記——USART串口發(fā)送&串口發(fā)送和接收

    18、江科大stm32視頻學(xué)習(xí)筆記——USART串口發(fā)送&串口發(fā)送和接收

    目錄 一、USART串口發(fā)送? 1、電路圖 2、printf函數(shù)的移植方法 3、serial.c 4、main.c 5、解決直接寫漢字,編譯器報(bào)錯(cuò) 二 、USART串口發(fā)送和接收 1、查詢實(shí)現(xiàn) 2、中斷實(shí)現(xiàn)? (1)在Serial.c中添加的代碼 (2)主函數(shù)中調(diào)用 (3)思路 (4)完整的Serial.c代碼 (5)mian.c ?要交叉連接,所

    2023年04月08日
    瀏覽(20)
  • 26、江科大stm32視頻學(xué)習(xí)筆記——W25Q64簡(jiǎn)介

    26、江科大stm32視頻學(xué)習(xí)筆記——W25Q64簡(jiǎn)介

    一、W25Q64簡(jiǎn)介 1、W25Q64的內(nèi)存空間結(jié)構(gòu): ?一頁(yè)256字節(jié),4K(4096 字節(jié))為一個(gè)扇區(qū),16個(gè)扇區(qū)為1塊,容量為8M字節(jié),共有128個(gè)塊,2048 個(gè)扇區(qū)。 ? 2、W25Q64每頁(yè)大小由256字節(jié)組成,每頁(yè)的256字節(jié)用一次頁(yè)編程指令即可完成。 3、擦除指令分別支持: 16頁(yè)(1個(gè)扇區(qū))、128頁(yè)、256頁(yè)、全片

    2024年01月22日
    瀏覽(27)
  • 10、江科大stm32視頻學(xué)習(xí)筆記——PWM驅(qū)動(dòng)led呼吸燈、驅(qū)動(dòng)舵機(jī)、驅(qū)動(dòng)直流機(jī)

    10、江科大stm32視頻學(xué)習(xí)筆記——PWM驅(qū)動(dòng)led呼吸燈、驅(qū)動(dòng)舵機(jī)、驅(qū)動(dòng)直流機(jī)

    目錄 一、PWM驅(qū)動(dòng)LED呼吸燈(燈接在PA0) 1、PWM波和GPIO的對(duì)應(yīng)關(guān)系參考引腳定義表 2、計(jì)數(shù)器的計(jì)算 3、TIM輸出PWM波使用步驟?編輯 4、代碼 (1)輸出化比較單元 (2) PWM.c (3)main.c 5、重映射更換成PA15亮燈 二、PWM驅(qū)動(dòng)舵機(jī)(舵機(jī)接在PA1、按鍵在PB1)? 1、電路圖 2、參數(shù)計(jì)算

    2024年02月14日
    瀏覽(24)
  • 【江科大】STM32:串口HEX/文本數(shù)據(jù)接收和發(fā)送(代碼部分)(下)

    【江科大】STM32:串口HEX/文本數(shù)據(jù)接收和發(fā)送(代碼部分)(下)

    串口收發(fā)HEX數(shù)據(jù)包 2. 將跳線帽置在boot1 按復(fù)位鍵,點(diǎn)擊開始編程即可。 由于該單片機(jī)只有串口1支持串口燒錄。因此連接線連在串口1的所在的引腳上。 程序加載到bootloader完成后,再將跳線帽換到boot0,按復(fù)位鍵 為什么可以使用串口下載? 原理是實(shí)現(xiàn)程序的自我更新,即利用

    2024年04月22日
    瀏覽(20)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包