第三篇---STM32靈魂塑造之呱呱墜地

      之前我從宏觀上介紹了CM3架構和STM32的相關內容,現在我們就開始正式進行STM32的靈魂塑造---程序編寫。爲什麼說是塑造,因爲整個代碼是從無到有的而非利用官方庫的開發,就好像新生的嬰兒呱呱墜地。。。羅嗦止於此,切入正題!

      在我的一篇文章《ARM寄存器C操作探討》裏,我曾詳細的介紹了ARM通常採用的兩種寄存器C操作的方式,現在我們就實際應用一下第二種方法。爲了幫初學者形成ARM編程的一般思路和思想,我會從解讀Datasheet到實際編程都說明的非常詳細。

      首先,我們要讀Datasheet,這裏我選用的芯片是STM32F103RB,大家可以到ST的官網尋找下載,讀Datasheet讀什麼?就像物質是由原子組成,程序是由寄存器的配置組成,尤其對ARM來說,靈活的配置寄存器是基礎中的基礎,說來容易,可至此還是有種無從下手的感覺,下面我就從寄存器操作開始講講構建自己的ARM編程模式。

      打開KEIL,新建一個工程,device選擇STM32F103RB,詳細的我這裏不再展開,相信大家在51或其它微處理器的學習中都用的熟的不能再熟,不贅述,直奔核心---寄存器的操作。要操作一個寄存器我們得知道這個寄存器的地址,如何尋址?這就是重點。我們需要查看Datasheet來確定STM32F103RB這個芯片或者說STM32F103系列芯片的寄存器映射。依據這個內存映射,我們可以找到芯片外設的首地址,而這正是我們想要的、需要的。那麼具體怎麼寫?我們新建一個名爲MYstm32f10x_map.h的文件,內容可以這麼寫:

     

#ifndef MYstm32f10x_map_h_h_
#define MYstm32f10x_map_h_h_

//數據類型定義
typedef unsigned int  uint32;
typedef unsigned short int uint16;

//####################################################################################
//****RCC REGS******//
//####################################################################################

typedef struct tagRCC_REGS{
	uint32 CR;       //時鐘控制寄存器
	uint32 CFGR;     //時鐘配置寄存器
	uint32 CIR;      //時鐘中斷寄存器
	uint32 APB2RSTR; //APB2外設復位寄存器
	uint32 APB1RSTR; //APB1外設復位寄存器
	uint32 AHBENR;   //AHB外設時鐘使能寄存器
	uint32 APB2ENR;  //APB2外設時鐘使能寄存器
	uint32 APB1ENR;  //APB1外設時鐘使能寄存器
	uint32 BDCR;     //備份域控制寄存器
	uint32 CSR;      //控制/狀態寄存器
}RCC_REGS;

#define RCC ((volatile RCC_REGS *)0x40021000)    //RCC寄存器組首地址

//####################################################################################
//****GPIO REGS****//
//####################################################################################

typedef struct tagGPI0X_REGS{	 //X=A\B\C
	uint32 CRL;  //端口配置低寄存器
	uint32 CRH;  //端口配置高寄存器
	uint32 IDR;  //端口輸入數據寄存器
	uint32 ODR;  //端口輸出數據寄存器
	uint32 BSRR; //端口位設置/清除寄存器
	uint32 BRR;  //端口位清除寄存器
	uint32 LCKR; //端口配置鎖定寄存器
}GPIOX_REGS;

#define GPIOA ((volatile GPIOX_REGS *)0x40010800)	 //端口A寄存器組首地址
#define GPIOB ((volatile GPIOX_REGS *)0x40010C00)	 //端口B寄存器組首地址
#define GPIOC ((volatile GPIOX_REGS *)0x40011000)	 //端口C寄存器組首地址

//####################################################################################
//*****TIME REGS******//
//####################################################################################

typedef struct tagADVANCED_TIMX_REGS{		  //高級控制定時器(X)寄存器組
	uint32 CR1;      //控制寄存器1
	uint32 CR2;      //控制寄存器2
	uint32 SMCR;     //從模式控制寄存器
	uint32 DIER;     //中斷使能寄存器
	uint32 SR;       //狀態寄存器
	uint32 EGR;      //事件產生寄存器
	uint32 CCMR1;    //捕獲/比較模式寄存器1
	uint32 CCMR2;    //捕獲/比較模式寄存器2
	uint32 CCER;     //捕獲/比較使能寄存器
	uint32 CNT;      //計數器
	uint32 PSC;      //預分頻器
	uint32 ARR;      //自動裝載寄存器
	uint32 RCR;      //重複計數寄存器
	uint32 CCR1;     //捕獲/比較寄存器1
	uint32 CCR2;     //捕獲/比較寄存器2
	uint32 CCR3;     //捕獲/比較寄存器3
	uint32 CCR4;     //捕獲/比較寄存器4
	uint32 BDTR;     //剎車和死區寄存器
	uint32 DCR;      //DMA控制寄存器
	uint32 DMAR;     //連續模式的DMA地址
}ADVANCED_TIMX_REGS;

typedef struct tagGENERAL_TIMX_REGS{		  //X=2-4
	uint32 CR1;      //控制寄存器1
	uint32 CR2;      //控制寄存器2
	uint32 SMCR;     //從模式控制寄存器
	uint32 DIER;     //DMA/中斷使能寄存器
	uint32 SR;       //狀態寄存器
	uint32 EGR;      //事件產生寄存器
	uint32 CCMR1;    //捕獲/比較模式寄存器1
	uint32 CCMR2;    //捕獲/比較模式寄存器2
	uint32 CCER;     //捕獲/比較使能寄存器
	uint32 CNT;      //計數器
	uint32 PSC;      //預分頻器
	uint32 ARR;      //自動裝載寄存器
	uint32 CCR1;     //捕獲/比較寄存器1
	uint32 CCR2;     //捕獲/比較寄存器2
	uint32 CCR3;     //捕獲/比較寄存器3
	uint32 CCR4;     //捕獲/比較寄存器4
	uint32 DCR;      //DMA控制寄存器
	uint32 DMAR;     //連續模式的DMA地址
}GENERAL_TIMX_REGS;

#define TIM1 ((volatile ADVANCED_TIMX_REGS *) 0x40012C00) //高級控制定時器1寄存器組首地址
#define TIM2 ((volatile GENERAL_TIMX_REGS *) 0x40000000)  //通用控制定時器2寄存器組首地址
#define TIM3 ((volatile GENERAL_TIMX_REGS *) 0x40000400)  //通用控制定時器3寄存器組首地址
#define TIM4 ((volatile GENERAL_TIMX_REGS *) 0x40000800)  //通用控制定時器4寄存器組首地址

//####################################################################################
//*****ADC REGS******//
//####################################################################################

typedef struct tagADCX_REGS{
	uint32 SR;      //ADC狀態寄存器
	uint32 CR1;     //ADC控制寄存器1
	uint32 CR2;     //ADC控制寄存器2
	uint32 SMPR1;   //ADC採樣時間寄存器1
	uint32 SMPR2;   //ADC採樣時間寄存器2
	uint32 JOFR1;   //ADC注入通道數據偏移寄存器1
	uint32 JOFR2;   //ADC注入通道數據偏移寄存器2
	uint32 JOFR3;   //ADC注入通道數據偏移寄存器3
	uint32 JOFR4;   //ADC注入通道數據偏移寄存器4
	uint32 HTR;     //ADC看門狗高閥值寄存器
	uint32 LTR;     //ADC看門狗低閥值寄存器
	uint32 SQR1;    //ADC規則序列寄存器1
	uint32 SQR2;    //ADC規則序列寄存器2
	uint32 SQR3;    //ADC規則序列寄存器3
	uint32 JSQR;    //ADC注入序列寄存器
	uint32 JDR1;    //ADC 注入數據寄存器1
	uint32 JDR2;    //ADC 注入數據寄存器2
	uint32 JDR3;    //ADC 注入數據寄存器3
	uint32 JDR4;    //ADC 注入數據寄存器4
	uint32 DR;      //ADC規則數據寄存器	
}ADCX_REGS;

#define ADC1 ((volatile ADCX_REGS *) 0x40012400)	//ADC1寄存器組首地址
#define ADC2 ((volatile ADCX_REGS *) 0x40012800)	//ADC2寄存器組首地址


//等等。。。。。。


#endif

     

       如上,然後我們就可以在.c文件裏包含這個頭文件,並根據技術手冊裏的各外設的寄存器描述來讀寫相應的寄存器,完成想要實現的功能。

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

注意:

        可能你在編譯過程中會報錯,大體意思是說你沒有定義某結構體,可我們明明定義了,我想這可能是KEIL的一個BUG(當然也有可能是盜版的緣故~),經過幾次猜想驗證之後,我發現在typedef struct...這個結構體定義時,在最後的結構體名一定要是你一個字一個字敲進去的,而不是從tagXXX中拷貝而來的,如果是從tagXXX拷貝而來的話就會報上述的錯誤(真是什麼奇怪的事都可能存在~)。

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

     歡迎大家掃描下方二維碼關注我的個人微信公衆號,一起交流學習,謝謝。

      

     

     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章