iT邦幫忙

2021 iThome 鐵人賽

DAY 5
1
Arm Platforms

基於ARM-M0架構MCU之落摔檢測韌體開發系列 第 5

[DAY 5] _stm32f103c8t6開發板暫存器開發_控制MCU的GPIO High、Low範例

  • 分享至 

  • xImage
  •  

想走嵌入式系統開發這行必經的路,直接了解最底層怎麼運作的,Arduino底層也是這樣運作的,只是Arduino把這些操作都包起來寫成一個函式給你使用,叫出那函式輸入對的值就能直接使用。

我在DAY3DAY4的時候有先教學如何安裝環境,在第四天的最後先創了兩個空檔(main.c、stm32f103.h),還有從標準庫複製了1個.s檔,這個.s檔是用組合語言所寫的,MCU一上電第1個執行的地方,是1個啟動的檔案。

首先,先打stm32f103.h,這裡面是要配置暫存器位置,如下圖
https://ithelp.ithome.com.tw/upload/images/20210918/20141979veKX2oPoek.png

stm32f103.h 程式碼:

//外設基本地址,在datasheet的Memory map(內存映射)裡看的到
#define PERIPA_BASE          ((unsigned int)0x40000000)   

//基本地址加上20000是因為所有GPIO口在這地址上,( APB2PERIPH_BASE=0x4000 0000+0x0001 0000=0x4001 0000)
#define APB2PERIPH_BASE		 (PERIPA_BASE + 0x00010000) 

//GPIOA這個IO口的地址,"A"的,專屬於A的!!
#define GPIOA_BASE           (APB2PERIPH_BASE+0x0800)

//這一部份是Reference manual(參考手冊)上的GPIO章節所介紹的所有能配置功能的暫存器
//全部基本位置加上偏移位置就到單1那個GPIO口的實際位置了
#define GPIOA_CRL			*(unsigned int*)(GPIOA_BASE+0x00)                                        
#define GPIOA_CRH			*(unsigned int*)(GPIOA_BASE+0x04)                                        
#define GPIOA_IDR			*(unsigned int*)(GPIOA_BASE+0x08)                                        
#define GPIOA_ODR			*(unsigned int*)(GPIOA_BASE+0x0C)                                        
#define GPIOA_BSRR			*(unsigned int*)(GPIOA_BASE+0x10)                                        
#define GPIOA_BRR			*(unsigned int*)(GPIOA_BASE+0x14)                                        
#define GPIOA_LCKR			*(unsigned int*)(GPIOA_BASE+0x18)                                        
	
//RCC外設基本地址
#define RCC_BASE            (0x40021000)

//RCC_控制GPIO口時鐘的實際地址
#define RCC_APB2ENR			*(unsigned int*)(RCC_BASE+0x18)

逐行解釋,#define是C語言的定義,我打左邊的暫存器名稱會等於右邊的指向地址
#define PERIPA_BASE,這是指我總線的地址,先來看看Reference manual裡提供的記憶體的地圖:
https://ithelp.ithome.com.tw/upload/images/20210918/20141979QzC8i8Z5ro.png
看到上土左半邊的位置範圍,對上右邊每個位置的名稱,這樣就可以查詢你要的功能在哪個範圍,將偏移位置加上去,來舉#define GPIOA_BSRR為例:
先開Reference manua找對應的暫存器位置說明:
https://ithelp.ithome.com.tw/upload/images/20210918/20141979Pu0QbKmRuK.png
看到左半邊的目錄位置,點選BSRR後會跳進來,在看右邊上方有個Address offser:0x10再去看看我的程式碼,這就是實際的位置啦~~
同理再來設置RCC時鐘,有時中GPIO口才會開始工作,可以先看我上上個記憶體地圖,我有框起來RCC的基本位置從0x4002 1000 開始
https://ithelp.ithome.com.tw/upload/images/20210918/20141979ccVOlBkcZL.png
再來是實際的位置,加上0x18

這樣都配置完地址了~~,這邊要花時間自己看一下,看懂就會發現其實這原理很簡單,但查位置真的挺花時間的。
再來就是要去main.c裡去賦予值給這些暫存器瞜,首先天上我的程式碼:

//main.c
#include "stm32f103.h" 
int main(void)
{	
	int i=0;
	RCC_APB2ENR |= (1<<2);//開GPIOA的時鐘
	
	GPIOA_CRL	&= ~( 0xf<< (4)); //對要使用位置清0
	GPIOA_CRL	|= ( 0x1<< (4));  //賦予值

	while(1)
	{
		GPIOA_BSRR	|= ( 1<< 1); //GPIOA Pin1_Hi,開發版上的A1腳位
		for(i=0;i<=480000;i++)
		{
		}	
		i=0;
		GPIOA_BSRR	|= ~( 1<< 1);//GPIOA Pin1_LOW,開發版上的A1腳位
		for(i=0;i<=480000;i++)
		{
		}	
	}
}
//打這個函式是為了讓編譯器不報錯,實際的原因是.s啟動檔那有宣告執行這函式
//,所以讓他實現空空的的函示就好
void SystemInit(void)
{	
}

我這邊就當作大家都懂c語言跟基本的數位邏輯觀念了,不懂的話再去搜尋一下吧。
首先RCC開啟時鐘的部份
https://ithelp.ithome.com.tw/upload/images/20210918/20141979ywSQwOvQx8.png
可以看到上圖我紅框部份,再去對應我main.c的開啟時鐘看,到這邊看懂的話你就會操作了~
RCC_APB2ENR |= (1<<2); 講解一下這行,1左移兩位(1 => 100)或上RCC_APB2ENR這個暫存器。就這樣,這個不會的話要去看一下基本數位邏輯喔

下面程式我就不解釋,一樣的道理,去查看CRL和BSRR暫存器就可以啦,CRL主要是在配置IO口模式,我用簡單計數來當delay,BSRR一邊控制HI,一邊控制LOW,完成啦
驗證過了可以動作~,這套查詢的方式套用到哪顆MCU都可以!,方法都一樣
講一下燒錄的方式
https://ithelp.ithome.com.tw/upload/images/20210918/20141979RnGINrQMx9.png
確定編譯沒錯才能燒錄喔,燒入後記得按Reset,把LED接到 A1 的腳位就會看到LED在閃爍了喔~

底層就是這樣動作了,有什麼問題可以在下面提出來~
我預計明天來講暫存器的查找方式吧


上一篇
[DAY 4] _ 用Keil5直接編寫暫存器操控MCU的GPIO口_(建Keil5環境)
下一篇
[DAY 6] _stm32f103c8t6_暫存器查找方法
系列文
基於ARM-M0架構MCU之落摔檢測韌體開發35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言