
來源:https://blog.csdn.net/twx11213030422
一、如何控制單片機?
單片機的內存映射圖解析
這里以STM32F429芯片為例,講解下單片機芯片內存映射圖。從此圖中可以看到芯片的外設被分配了512M的空間,然而真正的外設其實沒有使用到512M的內存空間。
然后我們操作外設時,只需要操作它對應的內存地址即可。更加詳細的外設內存地址,可以參考芯片的用戶手冊(不是數據手冊)的Memory map章節。
因為單片機是將外設映射到內存地址上,所以我們可以像操作內存一樣來操作外設(寫/讀)。
我們在操作內存時是通過地址來進行操作的,由于單片機已經將外設與內存進行了映射,所以我們在操作單片機外設時只需要操作外設映射的內存地址就行。
內存如何操作?
在C語言中操作內存,我們可以用指針來進行操作。在匯編語言中由于沒有指針這個概念,所以我們在操作地址時只能用一些內存讀寫指令來完成。比如:LDR,STR
結構體操作與宏定義操作的對比
C語言——宏定義形式
#define?GPIOA?(*(volatile?uint32_t?*)(0x000800E0))
#define?GPIOA_DR?(*(volatile?uint32_t?*)(0x000800E4))
#define?GPIOA_MR?(*(volatile?uint32_t?*)(0x00080108))
#define?GPIOA_TR?(*(volatile?uint32_t?*)(0x00080108))C語言——結構體操作
struct?GPIOA_Reg{
????volatile?uint32_t?dr;
????volatile?uint32_t?mr;
????volatile?uint32_t?tr;
}GPIOA_REG匯編語言操作內存
LDR?r0,?=0x00800010
MOV?r1,?#2
STR?r1,?[r0]二、寄存器方式操作單片機
代碼結構框架:
文件結構
一個芯片頭文件:外設的地址宏定義以及外設相關的結構體定義
查看芯片的用戶手冊(注意:不是數據手冊)中寄存器對應的相應地址。然后使用宏定義來將它們定義好,同時定義好結構體來更加方便的管理外設寄存器組。這里以STM32F1系列為例
??一個啟動文件:匯編編寫的、中斷向量表等
??用戶代碼文件:剩余就是用戶代碼文件了
??各個芯片的外設驅動函數編寫(讀/寫、控制)、以及用戶邏輯部分代碼。
三、使用HAL庫方式操作單片機
HAL庫與固件庫的區別
HAL全稱Hardware abstract layer(硬件抽象層),這是一個大家公認并且遵守的一種函數名稱命名、資源定義。因為是統一的命名規范,所以當用戶更換芯片平臺后由于函數命名與所使用的資源都與具體硬件沒有關系,這樣就不需要修改用戶層代碼了。
而所謂的標準庫其實就是芯片廠商公司內部自己命名與實現的庫并且各個廠商的命名規則不一樣,這樣就會導致可移植性變差。當用戶更換了芯片平臺后由于它們各自的API函數不一樣就會導致用戶需要修改應用層代碼。
HAL庫設計
1. HAL框架設計
2. HAL資源命名規則
HAL函數命名規則:
中斷與時鐘設置宏:
回調函數命名規則:
3. 文件結構:
一個芯片頭文件:外設的地址宏定義以及外設相關的結構體定義
查看芯片的用戶手冊(注意:不是數據手冊)中寄存器對應的相應地址。然后使用宏定義來將它們定義好,同時定義好結構體來更加方便的管理外設寄存器組。這里以STM32F1系列為例
一個啟動文件:匯編編寫的、中斷向量表等。
一個HAL庫全局頭文件:一些全局的宏定義以及包含其他外設頭文件
HAL庫文件:芯片外設的驅動函數
四、HAL庫組成說明
1. HAL庫的數據結構體
??外設句柄結構體
??初始化和配置結構體
??特定的處理結構體(讀寫/控制)
** 外設句柄結構體(跟硬件不相關):**
比如:下面這個串口結構體
typedef?struct
{
????USART_TypeDef?*Instance;?/*?USART?registers?base?address?*/
????USART_InitTypeDef?Init;?/*?Usart?communication?parameters?*/
????uint8_t?*pTxBuffPtr;/*?Pointer?to?Usart?Tx?transfer?Buffer?*/
????uint16_t?TxXferSize;?/*?Usart?Tx?Transfer?size?*/
????__IO?uint16_t?TxXferCount;/*?Usart?Tx?Transfer?Counter?*/
????uint8_t?*pRxBuffPtr;/*?Pointer?to?Usart?Rx?transfer?Buffer?*/
????uint16_t?RxXferSize;?/*?Usart?Rx?Transfer?size?*/
????__IO?uint16_t?RxXferCount;?/*?Usart?Rx?Transfer?Counter?*/
????DMA_HandleTypeDef?*hdmatx;?/*?Usart?Tx?DMA?Handle?parameters?*/
????DMA_HandleTypeDef?*hdmarx;?/*?Usart?Rx?DMA?Handle?parameters?*/
????HAL_LockTypeDef?Lock;?/*?Locking?object?*/
????__IO?HAL_USART_StateTypeDef?State;?/*?Usart?communication?state?*/
????__IO?HAL_USART_ErrorTypeDef?ErrorCode;/*?USART?Error?code?*/
}USART_HandleTypeDef;初始化結構體(跟硬件相關):
比如:下面這個串口硬件相關的結構體
typedef?struct
{
????uint32_t?BaudRate;?/*!
????uint32_t?WordLength;?/*!????in?a?frame.*/
????uint32_t?StopBits;?/*!
????uint32_t?Parity;?/*!
????uint32_t?Mode;?/*!????disabled.*/
????uint32_t?HwFlowCtl;?/*!????or?disabled.*/
????uint32_t?OverSampling;?/*!????disabled,
????to?achieve?higher?speed?(up?to?fPCLK/8).*/
}UART_InitTypeDef;特定的處理結構體(跟硬件有關):
比如:下面這個ADC處理處理結構體
typedef?struct?
{
??uint32_t?Channel;????????????????/*!????????????????????????????????????????This?parameter?can?be?a?value?of?@ref?ADC_channels?*/
??uint32_t?Rank;???????????????????/*!????????????????????????????????????????This?parameter?must?be?a?number?between?Min_Data?=?1?and?Max_Data?=?16?*/
??uint32_t?SamplingTime;???????????/*!????????????????????????????????????????Unit:?ADC?clock?cycles
????????????????????????????????????????Conversion?time?is?the?addition?of?sampling?time?and?processing?time?(12?ADC?clock?cycles?at?ADC?resolution?12?bits,?11?cycles?at?10?bits,?9?cycles?at?8?bits,?7?cycles?at?6?bits).
????????????????????????????????????????This?parameter?can?be?a?value?of?@ref?ADC_sampling_times
????????????????????????????????????????Caution:?This?parameter?updates?the?parameter?property?of?the?channel,?that?can?be?used?into?regular?and/or?injected?groups.
?????????????????????????????????????????????????If?this?same?channel?has?been?previously?configured?in?the?other?group?(regular/injected),?it?will?be?updated?to?last?setting.
????????????????????????????????????????Note:?In?case?of?usage?of?internal?measurement?channels?(VrefInt/Vbat/TempSensor),
??????????????????????????????????????????????sampling?time?constraints?must?be?respected?(sampling?time?can?be?adjusted?in?function?of?ADC?clock?frequency?and?sampling?time?setting)
??????????????????????????????????????????????Refer?to?device?datasheet?for?timings?values,?parameters?TS_vrefint,?TS_temp?(values?rough?order:?4us?min).?*/
??uint32_t?Offset;?????????????????/*!
}ADC_ChannelConfTypeDef;2. HAL庫公共資源
HAL Status:狀態枚舉
Typedef?enum
{
HAL_OK?=?0x00,
HAL_ERROR?=?0x01,
HAL_BUSY?=?0x02,
HAL_TIMEOUT?=?0x03
}?HAL_StatusTypeDef;HAL Locked:用于防止共享資源被意外訪問
typedef?enum
{
HAL_UNLOCKED?=?0x00,?/*!
HAL_LOCKED?=?0x01?/*!
}?HAL_LockTypeDef;公共的宏定義:NULL 和 HAL_MAX_DELAY
#ifndef?NULL
#define?NULL?(void?*)?0
#endif
#define?HAL_MAX_DELAY?0xFFFFFFFF3. HAL庫中斷回調函數實現說明
(1)使用 __ weak 定義好回調函數。如果用戶自己重寫了回調函數,那么編譯器就會使用用戶重寫的這個回調函數。其中__ weak這個關鍵字是編譯器定義的。
(2)使用函數指針。定義一個全局的函數指針變量,在初始化函數時將我們自定義的回調函數賦值給這個全局的函數指針變量(這一步也叫做:注冊)。然后再中斷函數中通過這個全局的函數指針變量來調用我們自定義的回調函數。
版權聲明:本文來源網絡,免費傳達知識,版權歸原作者所有。如涉及作品版權問題,請聯系我進行刪除。
???????????????? ?END ????????????????
關注我的微信公眾號,回復“加群”按規則加入技術交流群。
點擊“閱讀原文”查看更多分享,歡迎點分享、收藏、點贊、在看。