一、如何控制單片機?
單片機的內存映射圖解析
這里以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庫組成說明
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; /*!< This member configures the UART communication baudrate.*/ uint32_t WordLength; /*!< Specifies the number of data bits transmitted or received in a frame.*/ uint32_t StopBits; /*!< Specifies the number of stop bits transmitted.*/ uint32_t Parity; /*!< Specifies the parity mode. */ uint32_t Mode; /*!< Specifies wether the Receive or Transmit mode is enabled or disabled.*/ uint32_t HwFlowCtl; /*!< Specifies wether the hardware flow control mode is enabled or disabled.*/ uint32_t OverSampling; /*!< Specifies wether the Over sampling 8 is enabled or disabled, to achieve higher speed (up to fPCLK/8).*/ }UART_InitTypeDef;? 特定的處理結構體(跟硬件有關): 比如:下面這個ADC處理處理結構體
typedef struct { uint32_t Channel; /*!< Specifies the channel to configure into ADC regular group. This parameter can be a value of @ref ADC_channels */ uint32_t Rank; /*!< Specifies the rank in the regular group sequencer. This parameter must be a number between Min_Data = 1 and Max_Data = 16 */ uint32_t SamplingTime; /*!< Sampling time value to be set for the selected channel. 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; /*!< Reserved for future use, can be set to 0 */ }ADC_ChannelConfTypeDef;?
?
?
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, /*!? 公共的宏定義:NULL 和 HAL_MAX_DELAY #ifndef NULL #define NULL (void *) 0 #endif #define HAL_MAX_DELAY 0xFFFFFFFF??
?
HAL庫中斷回調函數實現說明
(1)使用 __ weak 定義好回調函數。如果用戶自己重寫了回調函數,那么編譯器就會使用用戶重寫的這個回調函數。其中__ weak 這個關鍵字是編譯器定義的。 (2)使用函數指針。定義一個全局的函數指針變量,在初始化函數時將我們自定義的回調函數賦值給這個全局的函數指針變量(這一步也叫做:注冊)。然后在中斷函數中通過這個全局的函數指針變量來調用我們自定義的回調函數。
編輯:黃飛
?
評論
查看更多