|
1、STM8的寄存器映射
STM8 core采用了哈佛結(jié)構(gòu),有兩條總線分別用于訪問(wèn)Flash和RAM,但Flash,RAM,GPIO and peripheral registers都被映射到了線性的16Mbyte(24位地址)的存儲(chǔ)器空間中;stm8s208rb的GPIO and peripheral registers被映射到了0x00 5000 ~ 0x00 57FF地址空間。所以要在C語(yǔ)言中訪問(wèn)外圍設(shè)備寄存器我們只需要指向這些地址空間的指針即可了。
2、STM8的寄存器的地址
在STM8中,與某個(gè)外圍設(shè)備有關(guān)的寄存器在地址上都是順序排列的;比如與GPIO有關(guān)的寄存器有ODR、IDR、DDR、CR1、CR2,與PA口有關(guān)的這五個(gè)寄存器就被安排在了0x00 5000~0x00 5004這5個(gè)地址空間中,它們有一個(gè)0x005000的基地址,分別偏移0,1,2,3,4。
3、”stm8s.h"中與GPIO有關(guān)的定義,以及固件庫(kù)中訪問(wèn)外圍設(shè)備寄存器的方法
typedef struct GPIO_struct
{
vu8 ODR; /*!< Output Data Register */
vu8 IDR; /*!< Input Data Register */
vu8 DDR; /*!< Data Direction Register */
vu8 CR1; /*!< Configuration Register 1 */
vu8 CR2; /*!< Configuration Register 2 */
}
GPIO_TypeDef;
#define GPIOA_BaseAddress 0x5000
#define GPIOB_BaseAddress 0x5005
#define GPIOC_BaseAddress 0x500A
#define GPIOD_BaseAddress 0x500F
#define GPIOE_BaseAddress 0x5014
#define GPIOF_BaseAddress 0x5019
#define GPIOA ((GPIO_TypeDef *) GPIOA_BaseAddress)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BaseAddress)
#define GPIOC ((GPIO_TypeDef *) GPIOC_BaseAddress)
#define GPIOD ((GPIO_TypeDef *) GPIOD_BaseAddress)
#define GPIOE ((GPIO_TypeDef *) GPIOE_BaseAddress)
#define GPIOF ((GPIO_TypeDef *) GPIOF_BaseAddress)
在結(jié)構(gòu)體GPIO_TypeDef中,ODR,IDR,DDR,CR1,CR2的偏移分別是0,1,2,3,4正好與STM8S208RB對(duì)這幾個(gè)安排一致,當(dāng)我們將0x5000這個(gè)地址轉(zhuǎn)換為指向GPIO_TypeDef的指針后,
我們就可以用類似GPIOA->ODR的方法訪問(wèn)寄存器了。非常巧妙,STM32中也是這種方法。
4、GPIO特性簡(jiǎn)述
STM8的每一個(gè)GPIO引腳都可以獨(dú)立的作為輸入/輸出IO引腳使用,作為輸入IO引腳使用時(shí),每一個(gè)IO引腳都可以作為外部中斷的觸發(fā)輸入端使用,輸入有上拉和懸浮,輸出有模擬開(kāi)漏和推挽模式。
DDR用于設(shè)置方向,ODR用于輸出,IDR用于輸入,CR1、CR2用于控制,具體可參考數(shù)據(jù)手冊(cè),使用固件庫(kù)時(shí)我們可以不關(guān)心具體值。
5、GPIO的初始化
固件庫(kù)為我們提供了GPIO_Init這個(gè)函數(shù),用于GPIO工作模式的初始化設(shè)置,它的原型為
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, GPIO_Mode_TypeDef GPIO_Mode);
第一個(gè)參數(shù)是上面提到的GPIOA這樣的指針,第二、三個(gè)參數(shù)都是枚舉型變量(本質(zhì)就是一些常數(shù)),用來(lái)制定要初始化的引腳和工作模式。枚舉變量定義如下:
typedef enum
{
GPIO_MODE_IN_FL_NO_IT = (u8)0b00000000, /*!< Input floating, no external interrupt */
GPIO_MODE_IN_PU_NO_IT = (u8)0b01000000, /*!< Input pull-up, no external interrupt */
GPIO_MODE_IN_FL_IT = (u8)0b00100000, /*!< Input floating, external interrupt */
GPIO_MODE_IN_PU_IT = (u8)0b01100000, /*!< Input pull-up, external interrupt */
GPIO_MODE_OUT_OD_LOW_FAST = (u8)0b10000000, /*!< Output open-drain, low level, no slope control */
GPIO_MODE_OUT_PP_LOW_FAST = (u8)0b11000000, /*!< Output push-pull, low level, no slope control */
GPIO_MODE_OUT_OD_LOW_SLOW = (u8)0b10100000, /*!< Output open-drain, low level, slow slope */
GPIO_MODE_OUT_PP_LOW_SLOW = (u8)0b11100000, /*!< Output push-pull, low level, slow slope */
GPIO_MODE_OUT_OD_HIZ_FAST = (u8)0b10010000, /*!< Output open-drain, high-impedance level, no slope control */
GPIO_MODE_OUT_PP_HIGH_FAST = (u8)0b11010000, /*!< Output push-pull, high level, no slope control */
GPIO_MODE_OUT_OD_HIZ_SLOW = (u8)0b10110000, /*!< Output open-drain, high-impedance level, slow slope */
GPIO_MODE_OUT_PP_HIGH_SLOW = (u8)0b11110000 /*!< Output push-pull, high level, slow slope */
}GPIO_Mode_TypeDef;
typedef enum
{
GPIO_PIN_0 = ((u8)0x01), /*!< Pin 0 selected */
GPIO_PIN_1 = ((u8)0x02), /*!< Pin 1 selected */
GPIO_PIN_2 = ((u8)0x04), /*!< Pin 2 selected */
GPIO_PIN_3 = ((u8)0x08), /*!< Pin 3 selected */
GPIO_PIN_4 = ((u8)0x10), /*!< Pin 4 selected */
GPIO_PIN_5 = ((u8)0x20), /*!< Pin 5 selected */
GPIO_PIN_6 = ((u8)0x40), /*!< Pin 6 selected */
GPIO_PIN_7 = ((u8)0x80), /*!< Pin 7 selected */
GPIO_PIN_LNIB = ((u8)0x0F), /*!< Low nibble pins selected */
GPIO_PIN_HNIB = ((u8)0xF0), /*!< High nibble pins selected */
GPIO_PIN_ALL = ((u8)0xFF) /*!< All pins selected */
}GPIO_Pin_TypeDef;
我們可以如此使用這個(gè)函數(shù):
#define LEDS_PORT (GPIOH)
#define LED1_PIN (GPIO_PIN_3)
#define LED2_PIN (GPIO_PIN_2)
#define LED3_PIN (GPIO_PIN_1)
#define LED4_PIN (GPIO_PIN_0)
#define BUTTON_PORT (GPIOC)
#define BUTTON_PIN (GPIO_PIN_0)
/* Initialize I/Os in Output Mode */
GPIO_Init(LEDS_PORT, (LED1_PIN | LED2_PIN | LED3_PIN | LED4_PIN), GPIO_MODE_OUT_PP_LOW_FAST);
/* Initialize I/O in Input Mode with Interrupt */
GPIO_Init(BUTTON_PORT, BUTTON_PIN, GPIO_MODE_IN_FL_IT);
6、GPIO的操作函數(shù)
void GPIO_Write(GPIO_TypeDef* GPIOx, u8 PortVal); //寫端口,8個(gè)腳一起設(shè)置
void GPIO_WriteHigh(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins); // 將指定腳設(shè)置為高
void GPIO_WriteLow(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins); // 講指定腳設(shè)置為低
void GPIO_WriteReverse(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins); // 指定腳取反
u8 GPIO_ReadInputData(GPIO_TypeDef* GPIOx); // 讀引腳
u8 GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); // 讀端口,上次鎖存到ODR中的數(shù)據(jù)
BitStatus GPIO_ReadInputPin(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin); // 讀制定腳的狀態(tài),高電平返回非0,低返回0
// NewState取值為ENABLE或DISABLE,用于配置外部的上拉有效或無(wú)效?這個(gè)函數(shù)怎么用我不懂,還請(qǐng)懂的朋友告知,非常感謝!
void GPIO_ExternalPullUpConfig(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_GPIO_PIN_OK(GPIO_Pin));
assert_param(IS_FUNCTIONALSTATE_OK(NewState));
if (NewState != DISABLE) /* External Pull-Up Set*/
{
GPIOx->CR1 |= (u8)GPIO_Pin; // CR1=1時(shí),如輸入則上拉,如輸出則推挽
} else /* External Pull-Up Reset*/
{
GPIOx->CR1 &= (u8)(~(GPIO_Pin)); //CR1=0時(shí),如輸入則懸浮,如輸出則開(kāi)漏
}
}
|
|