這節主要是GPIO的應用 包括點亮led燈和數碼管使用。使用CubeMax進行配置使用keil5編寫代碼。
應用效果演示 鏈接
GPIO介紹
General Purpose Input Output (通用輸入/輸出)簡稱爲GPIO
許多設備或電路只要求有開/關兩種狀態就夠了,比如LED的亮與滅。對這些設備的控制,在嵌入式微處理器上通常提供了一種“通用可編程I/O端口”,也就是GPIO。
對GPIO的配置一般有
① 浮空輸入_IN_FLOATING
② 帶上拉輸入_IPU
③ 帶下拉輸入_IPD
④ 模擬輸入_AIN
⑤ 開漏輸出_OUT_OD
⑥ 推輓輸出_OUT_PP
⑦ 複用功能的推輓輸出_AF_PP
⑧ 複用功能的開漏輸出_AF_OD
通常有5種方式使用某個引腳功能,它們的配置方式如下:
1、作爲普通GPIO輸入:根據需要配置該引腳爲浮空輸入、帶弱上拉輸入或帶弱下拉輸入,同時不要使能該引腳對應的所有複用功能模塊。
2、作爲普通模擬輸入:配置該引腳爲模擬輸入模式,同時不要使能該引腳對應的所有複用功能模塊。
3、作爲內置外設的輸入:根據需要配置該引腳爲浮空輸入、帶弱上拉輸入或帶弱下拉輸入,同時使能該引腳對應的某個複用功能模塊。
4、作爲普通GPIO輸出:根據需要配置該引腳爲推輓輸出或開漏輸出,同時不要使能該引腳對應的所有複用功能模塊。
5、作爲內置外設的輸出:根據需要配置該引腳爲複用推輓輸出或複用開漏輸出,同時使能該引腳對應的所有複用功能模塊。
如果有多個複用功能模塊對應同一個引腳,只能使能其中之一,其它模塊保持非使能狀態。
GPIO使用的一些函數
重要函數:
1個初始化函數:
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
1個讀取輸入電平函數:
GPIO_PinStateHAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
1個設置輸出電平函數:
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin, GPIO_PinStatePinState);
1個電平翻轉函數:
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
1個引腳電平鎖定函數:
HAL_StatusTypeDefHAL_GPIO_LockPin(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
點亮led燈
led燈的原理很簡單,通電有電流通過就有亮,沒有電流就不亮。
-
首先 查看板子的原理圖,看led燈所在GPIO口對應的管腳
我所使用的板子 led部分對應管腳 C1 C2 C3 A0 A1 A2 A3 A4
-
打開cubemx 選擇板子對應的芯片 對相應管腳進行配置
這裏寫一個三個led燈點亮的項目 使用A0 A1 A2 三個管腳
選擇要控制的管腳 左鍵點擊 選擇GPIO_Output 輸出功能
選擇之後會變那個管腳顏色會變化
可以選擇配置時鐘或者跳過 (下一篇文章寫配置時鐘過程)
- 配置工程
添加工程名字 位置 以及 使用的IDE
然後點擊 GENRATE CODE 合成代碼
4.使用keil5 打開代碼
(打開代碼第一節中寫過)
打開main.c 找到主函數
一般添加的代碼都在while循環中執行
可以添加
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,0);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,0);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,0);
HAL_Delay(500);
(不用寫這些代碼 生成hex文件 並傳入板子 也會亮 ,因爲默認cubemx設置的低電平而led是低電平有效)
使用writepin函數給三個引腳低電平 ,0就是低電平 1是高電平 然後HAL_Delay延時函數裏面參數單位爲ms。
低電平有效是共陽極,意思就是陽極電平一直不變時高電平,加上低電平的話就有了電勢差就有電流通過。而加上高電平的話,沒有電勢差也就沒有了電流。
同理高電平有效就是共陰極。陰極電平一直不變是低電平。
MX_GPIO_Init函數 裏面是GPIO的初始化
(該圖片不是該項目截圖)
5 編譯程序 燒寫程序
將程序寫好進行編譯 編譯通過就會生成一個hex文件,將該文件找到並使用燒寫工具 寫入板子。
(第一節有詳細過程)
然後就會看到 三個led燈變亮
使用數碼管
讓數碼管顯示數字,並能夠從0到9999依次遞增
原理
數碼管的原理跟led很類似。可以理解爲很多的小的led燈
常見有一位數碼管和四位數碼管
先來看一位數碼管接線圖
a-g dp 八個引腳分別控制着相應的碼段,如果是共陰極 給g高電平其餘低電平 那就是隻有一道橫線,如果給g低電平其餘高電平,那呈現的就是0 加上右下角的點。
四位數碼管跟一位的類型,不過接線複雜了點,理解起來還是簡單的
a-g dp控制的依舊是跟單個數碼管一樣
但是 A1 A2 A3 A4 控制的分別是 四個數碼管
如果是共陰極 高電平有效。給A1 g高電平,其餘低電平 那樣顯示的就是第一個數碼管的一道橫線亮。
如果給A1 g低電平 其餘高電平,那顯示的就是第一個數碼管暗,其餘三個數碼管都顯示0和點
動態顯示
我們平常用到的數碼管幾乎都是動態顯示。意思就是一次顯示一個循環顯示,只要相差時間不是很大,人眼就分辨不出來是循環顯示的。人大腦有視覺暫留功能,所以有這種現象。同樣動態顯示能夠節省內存,耗電等。(顯示屏也是動態顯示的)所以程序設計的時候要參考這個。
看原理圖
打開該板子對應的原理圖
可以看到控制四個數碼管分別是 D2 B4 B6 B7
a-f 以及dp 爲 C6 C8 —A15 (圖上左邊一排)
配置cubemx
把使用到的引腳 共12個 都初始化爲GPIO_OUTPUT
這樣就配置完成了
然後可以配置項目名稱,位置,IDE,合成代碼
編寫代碼
如果直接編譯,燒寫hex文件,顯示的是四個數碼管全亮
我們還需要根據我們的需求更改代碼。
- 編寫GPIO口對應的數組 ,便於調用
struct GPIO_PACK{
GPIO_TypeDef * port;
uint16_t pin;
};
struct GPIO_PACK segs[8]= {
{GPIOA,GPIO_PIN_15},
{GPIOA,GPIO_PIN_11},
{GPIOC,GPIO_PIN_9},
{GPIOC,GPIO_PIN_7},
{GPIOC,GPIO_PIN_8},
{GPIOA,GPIO_PIN_12},
{GPIOA,GPIO_PIN_8},
{GPIOC,GPIO_PIN_6},
} ;
struct GPIO_PACK bits[4]={
{GPIOD,GPIO_PIN_2},
{GPIOB,GPIO_PIN_4},
{GPIOB,GPIO_PIN_6},
{GPIOB,GPIO_PIN_7},
};
- 編寫段碼
段碼指的是 講單個數碼管上dp a-g 高低電平用1和0代替,按照dp g f e d c b a組成的一串二進制數值,再轉換爲十六進制
比如 十六進制值 c0就是 1100 0000 代表的是dp 和g 高電平 滅 其他亮 形成的是數字0
同理 0-9 分別是 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e
寫入數組
uint8_t shuzu[]={
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,
0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e
};
3.將段碼轉換爲實際的對引腳控制
下面的這個函數實現的是 讓特定一個數碼管顯示特定的值
void DisplayOnebit(uint8_t digtal,uint8_t bit){
uint8_t i;
for(i=0;i<8;i++){
HAL_GPIO_WritePin(segs[i].port,segs[i].pin,(GPIO_PinState)(shuzu[digtal]&(0x01<<i)));
}
for(i=0;i<4;i++){
HAL_GPIO_WritePin(bits[i].port,bits[i].pin,(GPIO_PinState)(i!=bit));
}
}
使用writePin函數能夠給GPIO腳高低電位,使用了移位的方式來解析段碼。
傳入的參數 digtal 是要顯示的數字 。bit 是要顯示的是第幾位數碼管
調用 DisplayOnebit(9,1);
結果就會是 第二位數碼管顯示數字9 其他數碼管暗 。
控制多個數碼管顯示多位數
void DisplayDigtal(uint16_t digtal){
int a=0;
while(a<50)
{
a++;
DisplayOnebit(digtal%10,0);
HAL_Delay(5);
if (digtal>=10){
DisplayOnebit(digtal/10%10,1);
HAL_Delay(5);
if (digtal>=100){
DisplayOnebit(digtal/100%10,2);
HAL_Delay(5);
if (digtal>=1000){
DisplayOnebit(digtal/1000%10,3);
HAL_Delay(5);
}
}
}
}
}
傳入一個值 就會直接顯示 輸入的值 裏面調用的是DisplayOnbit 函數 只不過是分配了一個每個數碼管應該顯示的值 並加了延時。
調用 DisplayDigtal(999);
結果會有三個數碼管顯示9 另一個數碼管是暗的
4.控制數碼管顯示
前面上一步操作可以理解成前期準備條件。是放到主函數外面的,方便調用。
真正根據應用場景需求編寫的代碼 是在這裏的。
在main函數中
while循環裏 添加以下代碼
DisplayDigtal(displya_data++);
if(displya_data>9999)
displya_data=0;
這裏需要注意 需要前面對display_data 這個變量進行聲明
uint16_t displya_data=0;
上面代碼很簡單就是變量從0一直增加並依次顯示,當變量達到9999時需要重新賦值爲0.
然後編譯 運行,燒寫程序就可以了。
效果
完整工程鏈接。GitHub
更多STM32學習教程
- STM32 cubemx keil5搭建學習環境
- 使用STM32 cubemx keil5實現led燈與數碼管控制
- 基於STM32 CubeMx keil5實現鍵盤的應用
- 基於STM32 CubeMx keil5實現串口通信 I2C與GPIO綜合應用
- 基於STM32 CubeMx keil5實現AD轉換獲取溫度
- 基於STM32 CubeMx keil5 學習使用I2C
- 基於STM32 CubeMx keil5 學習使用串口通信
- 基於STM32 CubeMx keil5應用定時器
- 基於STM32 cubemx keil5學習使用中斷
- 基於STM32 cubemx keil5綜合應用實現溫度控制系統