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

stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口

這篇具有很好參考價值的文章主要介紹了stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

3 GPIO通用輸入輸出口

注:筆記主要參考B站 江科大自化協(xié) 教學(xué)視頻“STM32入門教程-2023持續(xù)更新中”。
注:工程及代碼文件放在了本人的Github倉庫。


3.1 GPIO輸入輸出原理

GPIO(General Purpose Input Output)通用輸入輸出口 可配置為8種輸入輸出模式。引腳電平范圍為0V~3.3V,部分引腳可容忍5V(圖1-6中IO口電平為FT標(biāo)識的)。輸出模式 下可控制端口輸出高低電平,用以驅(qū)動LED、控制蜂鳴器、模擬通信協(xié)議輸出時序等,當(dāng)然若驅(qū)動大功率設(shè)備還需要添加驅(qū)動電路。輸入模式 下可讀取端口的高低電平或電壓,用于讀取按鍵輸入、外接模塊電平信號輸入、ADC電壓采集、模擬通信協(xié)議接收數(shù)據(jù)等。

stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-1 GPIO基本結(jié)構(gòu)

上圖給出了GPIO的基本結(jié)構(gòu)圖。在STM32中,所有的GPIO都掛載在APB2外設(shè)總線上。命名方式采用GPIOA、GPIOB、GPIOC…的方式來命名。每個GPIO模塊內(nèi),主要包括寄存器、驅(qū)動器等。

  • 寄存器就是一段特殊的存儲器,內(nèi)核可以通過APB2總線對寄存器進(jìn)行讀寫,從而完成輸出電平和讀取電平的功能。該寄存器的每一位都對應(yīng)一個引腳,由于stm32是32位的單片機(jī),所以所有的寄存器都是32位的,也就是說只有寄存器的低16位對應(yīng)上了相應(yīng)的GPIO口。
  • 驅(qū)動器就是增加信號的驅(qū)動能力的。

注:stm32f103c8t6芯片上48個引腳,除了基本的電源和晶振等維持系統(tǒng)正常運(yùn)行的引腳外,分別包括PA0~PA15、PB0~PB15、PC13~PC15。

stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-2 GPIO位結(jié)構(gòu)

上圖就是將“GPIO的基本結(jié)構(gòu)”進(jìn)行放大,得到的實(shí)際的位結(jié)構(gòu)。

輸入部分:

  • 整體框架從左到右依次是寄存器、驅(qū)動器、IO引腳,從上到下分為“輸入”、“輸出”。
  • 最右側(cè)的IO引腳上兩個保護(hù)二極管,其作用是對IO引腳的輸出電壓進(jìn)行限幅在0~3.3V之間,進(jìn)而可以避免過高的IO引腳輸入電壓對電路內(nèi)部造成傷害。VDD=3.3V,VSS=0V。
  • 輸入驅(qū)動器的上、下拉電阻:相應(yīng)的兩個開關(guān)可以通過程序進(jìn)行配置,分別有上拉輸入模式(上開關(guān)導(dǎo)通&下開關(guān)斷開)、下拉輸入模式(下開關(guān)導(dǎo)通&上開關(guān)斷開)、浮空輸入模式(兩個開關(guān)都斷開)。上下拉電阻的作用就是給引腳輸入提供一個默認(rèn)的輸入電平,進(jìn)而避免引腳懸空導(dǎo)致的不確定。都屬于弱上拉、弱下拉。
  • 輸入驅(qū)動器的觸發(fā)器:這里是用肖特基管構(gòu)成的施密特觸發(fā)器。只有高于上限、低于下限電壓才進(jìn)行變化,作用是對輸入電壓進(jìn)行整形,可以消除電壓波紋、使電壓的上升沿/下降沿更加陡峭。也就是說,stm32的GPIO端口會自動對輸入的數(shù)字電壓進(jìn)行整形。
  • “模擬輸入”、“復(fù)用功能輸入”:都是連接到片上外設(shè)的一些端口,前者用于ADC等需要模擬輸入的外設(shè),后者用于串口輸入引腳等需要數(shù)字量的外設(shè)。

輸出部分:

  • 輸出數(shù)據(jù):可以由輸出數(shù)據(jù)寄存器(普通的IO口輸出)、片上外設(shè)來指定,數(shù)據(jù)選擇器控制數(shù)據(jù)來源。
  • 位設(shè)置/清除寄存器:單獨(dú)操作輸出數(shù)據(jù)的某一位,而不影響其他位。
  • 驅(qū)動器中的MOS管:MOS管相當(dāng)于一種開關(guān),輸出信號來控制這兩個MOS管的開啟狀態(tài),進(jìn)而輸出信號。可以選擇推挽、開漏、關(guān)閉三種輸出方式。
  1. 推挽輸出模式:兩個MOS管均有效,stm32對IO口有絕對的控制權(quán),也稱為強(qiáng)推輸出模式。
  2. 開漏輸出模式:P-MOS無效。只有低電平有驅(qū)動能力,高電平輸出高阻。
  3. 關(guān)閉模式:兩個MOS管均無效,端口電平由外部信號控制。

額外補(bǔ)充:stm32如何將數(shù)據(jù)寫入寄存器?

  1. 通過軟件的方式。由于stm32的寄存器只能進(jìn)行整體讀寫,所以可以先將數(shù)據(jù)全部讀出,然后代碼中用&=清零|=置位的方式改變單獨(dú)某一位的數(shù)據(jù),再將改寫后的數(shù)據(jù)寫回寄存器。此方法比較麻煩、效率不高,對于IO口進(jìn)行操作不合適。
  2. 通過位設(shè)置/清除寄存器。若對某一位 置1,只需對位設(shè)置寄存器的相應(yīng)位 置1;若對某一位 清零,則對清除寄存器相應(yīng)位 清零。這種方式通過內(nèi)置電路完成操作,一步到位。
  3. 通過讀寫STM32中的“位帶”區(qū)域。在STM32中,專門分配有一段地址區(qū)域,該區(qū)域映射了RAM和外設(shè)寄存器所有的位。讀寫這段地址中的數(shù)據(jù),就相當(dāng)于讀寫所映射位置的某一位。整體流程與51單片機(jī)中的位尋址作用差不多。本教程不涉及。
表3-1 GPIO的8種模式
模式名稱 性質(zhì) 特征
浮空輸入 數(shù)字輸入 可讀取引腳電平,若引腳懸空則電平不確定,需要連續(xù)驅(qū)動源
上拉輸入 數(shù)字輸入 可讀取引腳電平,內(nèi)部連接上拉電阻,懸空時默認(rèn)高電平
下拉輸入 數(shù)字輸入 可讀取引腳電平,內(nèi)部連接下拉電阻,懸空時默認(rèn)低電平
模擬輸入 模擬輸入 GPIO無效,引腳直接接入內(nèi)部ADC(ADC專屬配置)
開漏輸出 數(shù)字輸出 可輸出引腳電平,高電平為高阻態(tài),低電平接VSS
推挽輸出 數(shù)字輸出 可輸出引腳電平,高電平接VDD,低電平接VSS
復(fù)用開漏輸出 數(shù)字輸出 由片上外設(shè)控制,高電平為高阻態(tài),低電平接VSS
復(fù)用推挽輸出 數(shù)字輸出 由片上外設(shè)控制,高電平接VDD,低電平接VSS

上表給出了GPIO的8種模式,通過配置GPIO的端口配置寄存器即可選擇相應(yīng)的模式。

  1. 每一個端口的模式由4位進(jìn)行控制,16個端口就需要64位,也就是兩個32位寄存器,即端口配置低寄存器、端口配置高寄存器。
  2. 輸入模式下,輸出無效;而輸出模式下,輸入有效。這是因?yàn)橐粋€IO口只能有一個輸出,但可以有多個輸入,所以直接將輸出信號輸入回去也沒問題。

3.2 硬件介紹-LED、蜂鳴器、面包板

首先,簡單介紹一下stm32芯片外圍的電路。

  • LED:發(fā)光二極管,正向通電點(diǎn)亮,反向通電不亮。
  • 有源蜂鳴器(本實(shí)驗(yàn)):內(nèi)部自帶振蕩源,將正負(fù)極接上直流電壓即可持續(xù)發(fā)聲,頻率固定。上圖所示的蜂鳴器模塊使用三極管作為開關(guān)。
  • 無源蜂鳴器:內(nèi)部不帶振蕩源,需要控制器提供振蕩脈沖才可發(fā)聲,調(diào)整提供振蕩脈沖的頻率,可發(fā)出不同頻率的聲音。
  • 下面是其實(shí)物圖:
    stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)

注:LED長腳為正極、燈內(nèi)部小頭為正極。本實(shí)驗(yàn)的蜂鳴器低電平驅(qū)動。

stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-3 LED和蜂鳴器驅(qū)動電路設(shè)計

上圖則是給出了LED和蜂鳴器的驅(qū)動電路圖。注意,三極管的發(fā)射極一定要直接接正電源/地,這是因?yàn)槿龢O管的開啟需要發(fā)射極和基極之間有一定的電壓,如果接在負(fù)載側(cè)有可能會導(dǎo)致三極管無法正常開啟。

stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-4 面包板實(shí)物圖

上圖給出了面包板的示意圖??梢钥闯觯姘逯虚g的金屬爪是豎著排列的,用于插各種元器件;上下四排金屬爪是橫著排列的,一般用于供電。注意,在使用面包板之前,一定要觀察孔位的連接情況。

3.3 實(shí)驗(yàn):LED閃爍、LED流水燈、蜂鳴器提示

需求1: 面包板上的LED以1s為周期進(jìn)行閃爍。亮0.5s、滅0.5s……

  • LED低電平驅(qū)動。
  • 需要用到延時函數(shù)Delay.hDelay.c,在UP注提供的“程序源碼”中,為了方便管理,應(yīng)在工程內(nèi)創(chuàng)建System文件夾,專門存放這些可以復(fù)用的代碼。
stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-5 LED閃爍-接線圖

注:實(shí)際上,應(yīng)該在LED和驅(qū)動電源之間接上保護(hù)電阻,但是由于本電路過于簡單,于是直接省略保護(hù)電阻。后面“LED流水燈”、“蜂鳴器提示”實(shí)驗(yàn)同樣省略保護(hù)電阻。

stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-6 LED閃爍-代碼調(diào)用(除庫函數(shù)之外)

代碼展示:
- main.c

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

int main(void){
    // 開啟APB2-GPIOA的外設(shè)時鐘RCC
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    // 初始化PA0端口:定義結(jié)構(gòu)體及參數(shù)
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //下面是對GPIO端口賦值的常用的四種方式
//    GPIO_ResetBits(GPIOA, GPIO_Pin_0);//復(fù)位PA0
//    GPIO_SetBits(GPIOA, GPIO_Pin_0);//將PA0置1
//    GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);//將PA0清零
//    GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);//此函數(shù)可以對16位端口同時操作
    while(1){
        //正常思路
        GPIO_ResetBits(GPIOA, GPIO_Pin_0);//復(fù)位PA0
        Delay_ms(500);
        GPIO_SetBits(GPIOA, GPIO_Pin_0);//將PA0置1
        Delay_ms(500);

        //使用GPIO_WriteBit函數(shù),且強(qiáng)制類型轉(zhuǎn)換
        GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);//把0類型轉(zhuǎn)換成BitAction枚舉類型
        Delay_ms(500);
        GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);
        Delay_ms(500);
    };
}

- Delay.h

#ifndef __DELAY_H
#define __DELAY_H

void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);

#endif

- Delay.c

#include "stm32f10x.h"

/**
  * @brief  微秒級延時
  * @param  xus 延時時長,范圍:0~233015
  * @retval 無
  */
void Delay_us(uint32_t xus)
{
	SysTick->LOAD = 72 * xus;            //設(shè)置定時器重裝值
	SysTick->VAL = 0x00;                 //清空當(dāng)前計數(shù)值
	SysTick->CTRL = 0x00000005;          //設(shè)置時鐘源為HCLK,啟動定時器
	while(!(SysTick->CTRL & 0x00010000));//等待計數(shù)到0
	SysTick->CTRL = 0x00000004;          //關(guān)閉定時器
}

/**
  * @brief  毫秒級延時
  * @param  xms 延時時長,范圍:0~4294967295
  * @retval 無
  */
void Delay_ms(uint32_t xms)
{
	while(xms--)
	{
		Delay_us(1000);
	}
}
 
/**
  * @brief  秒級延時
  * @param  xs 延時時長,范圍:0~4294967295
  * @retval 無
  */
void Delay_s(uint32_t xs)
{
	while(xs--)
	{
		Delay_ms(1000);
	}
} 

注:此后Delay.h、Delay.c將作為常用函數(shù)長期存放于System文件夾中,后續(xù)如果使用到將直接調(diào)用不會再在筆記中展示源代碼。

編程感想:

  1. Keil編譯過后,整個工程會比較大,不利于分享給別人??梢允褂肬P主提供的批處理程序,刪掉工程中的中間文件后再分享給別人,其他人使用的時候只需要重新編譯一下就行。
  2. 本教程用到了RCC和GPIO兩個外設(shè),這些外設(shè)的庫函數(shù)在Library中,一般存放在相應(yīng)的 .h 文件的最后。
  3. 將LED的短腳接負(fù)極,長腳接PA0口,就是高電平驅(qū)動方式,但是現(xiàn)象和低電平相同。
  4. 將GPIO設(shè)置成開漏輸出模式,可以發(fā)現(xiàn)高電平(高阻態(tài))無驅(qū)動能力,低電平有驅(qū)動能力。

需求2: 面包板上的8個LED以0.5s切換一個的速度,實(shí)現(xiàn)流水燈。低電平驅(qū)動。

stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-7 LED流水燈-接線圖

代碼調(diào)用關(guān)系與“LED閃爍”實(shí)驗(yàn)相同,下面是代碼展示:
- main.c

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

int main(void){
    // 開啟APB2-GPIOA的外設(shè)時鐘RCC
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    // 初始化PA的8個端口:定義結(jié)構(gòu)體及參數(shù)
    GPIO_InitTypeDef GPIO_InitStructure;
    //同時定義某幾個端口
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | 
                                  GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    while(1){
        //使用GPIO_SetBits、GPIO_ResetBits進(jìn)行賦值,這里僅用于演示“或操作”同時賦值
        GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | 
                            GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7);
        GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    //    //對指定的端口同時賦值
    //    GPIO_Write(GPIOA, ~0x01);
        Delay_ms(500);
        GPIO_Write(GPIOA, ~0x02);
        Delay_ms(500);
        GPIO_Write(GPIOA, ~0x04);
        Delay_ms(500);
        GPIO_Write(GPIOA, ~0x08);
        Delay_ms(500);
        GPIO_Write(GPIOA, ~0x10);
        Delay_ms(500);
        GPIO_Write(GPIOA, ~0x20);
        Delay_ms(500);
        GPIO_Write(GPIOA, ~0x40);
        Delay_ms(500);
        GPIO_Write(GPIOA, ~0x80);
        Delay_ms(500);
    };
}

編程感想:

  1. 使用或操作 |就可以實(shí)現(xiàn)只初始化定義某幾個GPIO,或者某幾個外設(shè)的時鐘。

需求3: 蜂鳴器不斷地發(fā)出滴滴、滴滴……的提示音。蜂鳴器低電平觸發(fā)。
注:蜂鳴器執(zhí)行四個動作為1個周期,分別是響0.1s、靜0.1s、響0.1s、靜0.7s。

stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-8 蜂鳴器提示-接線圖

代碼調(diào)用關(guān)系與“LED閃爍”實(shí)驗(yàn)相同,下面是代碼展示:
- main.c

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

int main(void){
    // 開啟APB2-GPIOB的外設(shè)時鐘RCC
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    // 初始化PB12端口:定義結(jié)構(gòu)體及參數(shù)
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    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(100);
        Delay_ms(600);
    };
}

編程感想:

  1. 控制蜂鳴器的IO端口可以隨便選,但是不要選擇三個JTAG調(diào)試端口:PA15、PB3、PB4。本實(shí)驗(yàn)選擇PB12端口進(jìn)行輸出。
  2. 關(guān)于調(diào)用庫函數(shù),有以下幾種方法:
  • 直接查看每一個外設(shè)的.h函數(shù),拖到最后就可以看到本外設(shè)的所有庫函數(shù),然后在對應(yīng)的.c文件中查看函數(shù)定義和調(diào)用方式即可。
  • 查看庫函數(shù)的用戶手冊——“STM32F103xx固件函數(shù)庫用戶手冊.pdf”,這個中文版比較老;新版本的用戶手冊可以在ST公司的幫助文檔中查看,但只有英文版。
  • 百度一下別人的代碼。

3.4 硬件介紹-按鍵開關(guān)、光敏電阻

stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-9 按鍵開關(guān)實(shí)物圖

按鍵是最常見的輸入設(shè)備,按下導(dǎo)通,松手?jǐn)嚅_。由于按鍵內(nèi)部使用的是機(jī)械式彈簧片來進(jìn)行通斷的,所以在按下和松手的瞬間會伴隨有一連串的抖動。
雖然前面已經(jīng)說過,GPIO端口有專門的肖特基觸發(fā)器對輸入信號進(jìn)行整形,但按鍵開關(guān)的抖動幅度大、時間長,所以還是 需要“軟件消抖”?;舅悸肪褪茄舆t5~10ms,跳過抖動時間范圍即可。

stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-10 按鍵開關(guān)硬件電路

上圖給出了按鍵開關(guān)的硬件電路設(shè)計圖。對于按鍵開關(guān)來說,常見以上四種設(shè)計方法,而行業(yè)規(guī)范中,單片機(jī)端口一般都有 上拉輸入模式(弱上拉),所有基本上就選擇 內(nèi)部上拉/外部上拉 的設(shè)計電路

  • 如果電路同時存在內(nèi)部上拉和外部上拉,那么其高電平的驅(qū)動能力更強(qiáng),但是低電平會更加耗電。兩個下拉電路則可以使低電平驅(qū)動能力更強(qiáng),而不會明顯增加損耗。
  • 浮空輸入模式下,每部沒有上下拉,此時必須在外部有上下拉電路。
  • 注意 內(nèi)部和外部的上下拉模式必須一致! 內(nèi)部有上下拉時,就可以不用配置外部上下拉。
stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-11 傳感器模塊實(shí)物圖

上面給出了傳感器模塊的實(shí)物圖,從左到右依次是光敏電阻傳感器、熱敏電阻傳感器、對射式紅外傳感器、反射式紅外傳感器。傳感器元件的電阻會隨外界模擬量的變化而變化,通過與定值電阻分壓即可得到模擬電壓輸出,再通過電壓比較器進(jìn)行二值化即可得到數(shù)字電壓輸出。

stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-12 傳感器模塊原理圖

上面所給出的原理圖則是一個比較通用的傳感器模塊格式:

  • 左起第三個模塊:下面的可變電阻就是各種傳感器模塊所對應(yīng)的阻值,與上面的分壓電阻R1進(jìn)行分壓,進(jìn)而輸出模擬電壓值A(chǔ)O。電容C2是濾波電容。
  • 左起第一個模塊:使用LM393模塊,通過運(yùn)算放大器實(shí)現(xiàn)“電壓比較器”的功能。IN- 是一個可以調(diào)節(jié)的閾值,IN+ 則直接連接傳感器的模擬分壓AO,當(dāng) AO > IN- 時,數(shù)字輸出DO拉高;當(dāng) AO < IN- 時,數(shù)字輸出DO拉低。
  • 左起第二個模塊:通過一個滑動變阻器實(shí)現(xiàn)比較電壓 IN- 的調(diào)整。
  • 左起第四個模塊:電源指示燈。
  • 左起第五個模塊:傳感器模塊的端口。LED2用于指示數(shù)字輸出DO的值。注意R5上拉電阻保證DO的默認(rèn)值為高。

補(bǔ)充情況:

  1. 對于對射式紅外傳感器來說,N1就是紅外接收管,并且額外還有一個點(diǎn)亮紅外發(fā)射管的電路,模擬電壓表示接收紅外信號的強(qiáng)度。并且該模塊常用于檢測通斷,所以用兩個電阻將閾值固定為1/2的參考電壓,而不是采用滑動變阻器。
  2. 對于反射式紅外傳感器,向下發(fā)射和接收紅外光,可以做尋跡小車。

而對于傳感器模塊的電路設(shè)計來說,由于采用模塊的方案,所以直接給傳感器接上VCC和GND,然后將模擬信號AO和數(shù)字信號DO接在stm32的對應(yīng)端口上即可。
本次實(shí)驗(yàn)采用數(shù)字信號DO接入,關(guān)于模擬信號接入的使用方法在后面AD/DA的實(shí)驗(yàn)中繼續(xù)講解。

3.5 實(shí)驗(yàn):按鍵控制LED、光敏傳感器控制蜂鳴器

需求1: 一個按鍵開關(guān)控制一個LED,每次按下按鍵,LED就改變自己的亮滅狀態(tài);兩套系統(tǒng)互不影響。

  • LED低電平驅(qū)動。
  • 按鍵B11控制LEDA2,按鍵B1控制LEDA1。
  • LED的狀態(tài)改變是“松開觸發(fā)”。
stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-13 按鍵控制LED-接線圖
stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-14 按鍵控制LED-代碼調(diào)用(非庫函數(shù))

代碼展示:
- main.c

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

int main(void){    
    LED_Init();
    Key_Init();
    
    while(1){
        if(Key_GetNum()==1){LED1_TURN();}
        else if(Key_GetNum()==2){LED2_TURN();}        
    };
}

- LED.h

#ifndef __LED_H
#define __LED_H

void LED_Init(void);
void LED1_TURN(void);
void LED2_TURN(void);

#endif

- LED.c

#include "stm32f10x.h"                  // Device header

/**
  * @brief  初始化PA2、PA1作為兩個LED的輸出端口
  * @param  無
  * @retvl  無
  */
void LED_Init(void){
    // 開啟APB2-GPIOA的外設(shè)時鐘RCC
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    // 初始化PA的輸出端口:定義結(jié)構(gòu)體及參數(shù)
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽輸出
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    //默認(rèn)輸出為低電平-LED初始不亮
    GPIO_SetBits(GPIOA, GPIO_Pin_2 | GPIO_Pin_1);
};

/**
  * @brief  LED1狀態(tài)翻轉(zhuǎn)
  * @param  無
  * @retvl  無
  */
void LED1_TURN(void){
    if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1)==1){
        GPIO_ResetBits(GPIOA, GPIO_Pin_1);
    }else{
        GPIO_SetBits(GPIOA, GPIO_Pin_1);
    }
}

/**
  * @brief  LED2狀態(tài)翻轉(zhuǎn)
  * @param  無
  * @retvl  無
  */
void LED2_TURN(void){
    if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2)==1){
        GPIO_ResetBits(GPIOA, GPIO_Pin_2);
    }else{
        GPIO_SetBits(GPIOA, GPIO_Pin_2);
    }
}

- Key.h

#ifndef __KEY_H
#define __KEY_H

void Key_Init(void);
uint8_t Key_GetNum(void);

#endif

- Key.c

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

/**
  * @brief  初始化B11、B1作為按鍵2、按鍵1
  * @param  無
  * @retvl  無
  */
void Key_Init(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉輸入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//只有輸出才有速度等級,但是這里也可以定義
    GPIO_Init(GPIOB, &GPIO_InitStructure);
};

/**
  * @brief  檢測哪個按鍵已經(jīng)按下-松開觸發(fā)
  * @param  無
  * @retvl  返回按下的按鍵編號
  *     @arg  0,1,2
  */
uint8_t Key_GetNum(void){
    uint8_t keynum = 0;
    if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)==0){
        Delay_ms(20);
        while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)==0);
        Delay_ms(20);
        keynum = 2;
    }
    if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)==0){
        Delay_ms(20);
        while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)==0);
        Delay_ms(20);
        keynum = 1;
    }
    return keynum;
};

編程感想:

  1. 代碼提示框如果不彈出,可以使用ctrl + space彈出代碼提示框。如果沒用的話,大概率是和輸入法中/英切換快捷鍵沖突,輸入法右鍵設(shè)置取消即可。
  2. GPIO配置好之后默認(rèn)就是低電平,所以配置好后LED會默認(rèn)是亮的狀態(tài)。
  3. 本工程創(chuàng)建了全新的驅(qū)動函數(shù)文件夾Hardware,專門用于存放程序中使用到的外設(shè)(如LED、按鍵、光敏傳感器等)的驅(qū)動函數(shù)。做好驅(qū)動代碼的提取是非常重要的,可以極大地方便程序梳理。
  4. 其實(shí)寫完之后發(fā)現(xiàn),這個按鍵開關(guān)非常不靈敏,經(jīng)常出現(xiàn)按鍵松手后LED沒有反應(yīng)的情況。大概這就是設(shè)置“光敏傳感器控制蜂鳴器”實(shí)驗(yàn)的原因吧。

需求2: 光敏電阻被遮擋,蜂鳴器長鳴,光敏電阻不被遮擋,蜂鳴器不響。

  • 蜂鳴器低電平驅(qū)動。
  • 光敏傳感器,光強(qiáng)越強(qiáng)阻值越小,分壓越??;DO的LED指示燈低電平驅(qū)動。
stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-15 光敏傳感器控制蜂鳴器-接線圖
stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖3-16 光敏傳感器控制蜂鳴器-代碼調(diào)用(非庫函數(shù))

代碼展示:
- main.c

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

int main(void){    
    Buzzer_Init();
    LightSensor_Init();
    while(1){
        if(LightSensor_Get()==1){Buzzer_ON();}
        else                    {Buzzer_OFF();}
    };
}

- Buzzer.h

#ifndef __BUZZER_H
#define __BUZZER_H

void Buzzer_Init(void);
void Buzzer_ON(void);
void Buzzer_OFF(void);

#endif

- Buzzer.c

#include "stm32f10x.h"                  // Device header

/**
  * @brief  蜂鳴器初始化-PB12推挽輸出
  */
void Buzzer_Init(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    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);
    
    GPIO_SetBits(GPIOB, GPIO_Pin_12);
}

/**
  * @brief  蜂鳴器開啟-低電平驅(qū)動
  */
void Buzzer_ON(void){
    GPIO_ResetBits(GPIOB, GPIO_Pin_12);
}

/**
  * @brief  蜂鳴器關(guān)閉-輸入高電平
  */
void Buzzer_OFF(void){
    GPIO_SetBits(GPIOB, GPIO_Pin_12);
}

- LightSensor.h

#ifndef __LIGHTSENSOR_H
#define __LIGHTSENSOR_H

void LightSensor_Init(void);
uint8_t LightSensor_Get(void);

#endif

- LightSensor.c

#include "stm32f10x.h"                  // Device header

/**
* @brief  光敏傳感器初始化-PB13上拉輸入
  */
void LightSensor_Init(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    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);
}

/**
  * @brief  讀取光敏傳感器的數(shù)字輸入信號-光強(qiáng)越強(qiáng)分壓越低
  * @retvl  讀取到的數(shù)字輸入信號0/1
  */
uint8_t LightSensor_Get(void){
    return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
}

編程感想:

  1. 模塊化編程真香??!每個模塊都寫一個專門的驅(qū)動函數(shù)存放在Hardware文件夾中,看似麻煩,但是會使得main函數(shù)極其簡單,幾乎就可以直接按照正常的功能邏輯書寫代碼。

3.6 C語言的語法

1. 數(shù)據(jù)類型

表3-1 C語言數(shù)據(jù)類型
關(guān)鍵字 位數(shù) 表示范圍 stdint關(guān)鍵字 ST關(guān)鍵字
char 8 -128 ~ 127 int8_t s8
unsigned char 8 0 ~ 255 uint8_t u8
short 16 -32768 ~ 32767 int16_t s16
unsigned short 16 0 ~ 65535 uint16_t u16
int 32 -2147483648 ~ 2147483647 int32_t s32
unsigned int 32 0 ~ 4294967295 uint32_t u32
long 32 -2147483648 ~ 2147483647
unsigned long 32 0 ~ 4294967295
long long 64 -(2^64)/2 ~ (2^64)/2-1 int64_t
unsigned long long 64 0 ~ (2^64)-1 uint64_t
float 32 -3.4e38 ~ 3.4e38
double 64 -1.7e308 ~ 1.7e308
  • 51單片機(jī)中 int型 為16位;stm32中 int型 為32位。
  • 倒數(shù)第二列是C語言給這些類型提供的別名;最后一列是老版本ST公司庫函數(shù)給這些類型提供的別名,新版的庫函數(shù)已經(jīng)全部替換成倒數(shù)第二列。以后寫程序時盡量使用上表中加粗的關(guān)鍵字。

2. 宏定義#define
關(guān)鍵字 #define,主要用于:用一個字符串代替一個數(shù)字,便于理解,防止出錯;或者提取程序中經(jīng)常出現(xiàn)的參數(shù),便于快速修改。

//定義宏定義:
#define ABC 12345
//引用宏定義:
int a = ABC;  //等效于int a = 12345;

3. 關(guān)鍵字typedef
關(guān)鍵字 typedef,常用于將一個比較長的變量類型名換個名字,便于使用。

//定義typedef:
typedef unsigned char uint8_t;
//引用typedef:
uint8_t num1; //等效于unsigned char num1;

相比于#define來說,typedef在進(jìn)行改名時會進(jìn)行變量類型檢查,所以更加安全。

4. 結(jié)構(gòu)體
關(guān)鍵字 struct,用途:數(shù)據(jù)打包,將不同類型變量組成一個集合。

//在main函數(shù)中定義結(jié)構(gòu)體變量:
struct{
    char x;
    int y;
    float z;
} StructName;
//因?yàn)榻Y(jié)構(gòu)體變量類型較長,所以通常在main函數(shù)外用typedef更改變量類型名
typedef struct{
    char x;
    int y;
    float z;
} StructName;

//引用結(jié)構(gòu)體成員:方法一
StructName struct1;
struct1.x = 'A';
struct1.y = 66;
struct1.z = 1.23;
//引用結(jié)構(gòu)體成員:方法二
pStructName->x = 'A';   //pStructName為結(jié)構(gòu)體的地址
pStructName->y = 66;
pStructName->z = 1.23;

5. 枚舉類型
關(guān)鍵字 enum,用途:定義一個取值受限制的整型變量,用于限制變量取值范圍;枚舉也相當(dāng)于一個宏定義的集合,可以直接把里面的枚舉變量拿出來用。注意枚舉變量用逗號隔開,且最后一個枚舉變量不加逗號。文章來源地址http://www.zghlxwxcb.cn/news/detail-613906.html

//函數(shù)內(nèi)定義枚舉變量:
enum{
    FALSE = 0,
    TRUE  = 1
} EnumName;
//因?yàn)槊杜e變量類型較長,所以通常在函數(shù)外用typedef更改變量類型名
typedef enum{
    FALSE = 0,
    TRUE  = 1
} EnumName;

//引用枚舉成員:
EnumName emu1;
emu1 = FALSE;
emu1 = TRUE;

到了這里,關(guān)于stm32學(xué)習(xí)筆記-3GPIO通用輸入輸出口的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包