ifree64 发表于 2009-3-23 22:38:12

STM8固件库GPIO学习笔记

[如果转载,请注明原作者ifree64,谢谢]

1、STM8的寄存器映射
STM8 core采用了哈佛结构,有两条总线分别用于访问Flash和RAM,但Flash,RAM,GPIO and peripheral registers都被映射到了线性的16Mbyte(24位地址)的存储器空间中;stm8s208rb的GPIO and peripheral registers被映射到了0x00 5000 ~ 0x00 57FF地址空间。所以要在C语言中访问外围设备寄存器我们只需要指向这些地址空间的指针即可了。

2、STM8的寄存器的地址
在STM8中,与某个外围设备有关的寄存器在地址上都是顺序排列的;比如与GPIO有关的寄存器有ODR、IDR、DDR、CR1、CR2,与PA口有关的这五个寄存器就被安排在了0x00 5000~0x00 5004这5个地址空间中,它们有一个0x005000的基地址,分别偏移0,1,2,3,4。

3、”stm8s.h"中与GPIO有关的定义,以及固件库中访问外围设备寄存器的方法
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)

在结构体GPIO_TypeDef中,ODR,IDR,DDR,CR1,CR2的偏移分别是0,1,2,3,4正好与STM8S208RB对这几个安排一致,当我们将0x5000这个地址转换为指向GPIO_TypeDef的指针后,
我们就可以用类似GPIOA->ODR的方法访问寄存器了。非常巧妙,STM32中也是这种方法。

4、GPIO特性简述
STM8的每一个GPIO引脚都可以独立的作为输入/输出IO引脚使用,作为输入IO引脚使用时,每一个IO引脚都可以作为外部中断的触发输入端使用,输入有上拉和悬浮,输出有模拟开漏和推挽模式。
DDR用于设置方向,ODR用于输出,IDR用于输入,CR1、CR2用于控制,具体可参考数据手册,使用固件库时我们可以不关心具体值。

5、GPIO的初始化
固件库为我们提供了GPIO_Init这个函数,用于GPIO工作模式的初始化设置,它的原型为
void GPIO_Init(GPIO_TypeDef* GPIOx,GPIO_Pin_TypeDef GPIO_Pin, GPIO_Mode_TypeDef GPIO_Mode);
第一个参数是上面提到的GPIOA这样的指针,第二、三个参数都是枚举型变量(本质就是一些常数),用来制定要初始化的引脚和工作模式。枚举变量定义如下:
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;

我们可以如此使用这个函数:

#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的操作函数
void GPIO_Write(GPIO_TypeDef* GPIOx, u8 PortVal);             //写端口,8个脚一起设置
void GPIO_WriteHigh(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins); // 将指定脚设置为高
void GPIO_WriteLow(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins);// 讲指定脚设置为低
void GPIO_WriteReverse(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins);// 指定脚取反
u8 GPIO_ReadInputData(GPIO_TypeDef* GPIOx);// 读引脚
u8 GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);// 读端口,上次锁存到ODR中的数据
BitStatus GPIO_ReadInputPin(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin); // 读制定脚的状态,高电平返回非0,低返回0

// NewState取值为ENABLE或DISABLE,用于配置外部的上拉有效或无效?这个函数怎么用我不懂,还请懂的朋友告知,非常感谢!
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时,如输入则上拉,如输出则推挽
} else /* External Pull-Up Reset*/
{
    GPIOx->CR1 &= (u8)(~(GPIO_Pin));//CR1=0时,如输入则悬浮,如输出则开漏
}
}

my_avr 发表于 2009-3-23 23:37:34

沙发!

chen1986sl 发表于 2009-3-23 23:43:13

不 错 期待STM8   和STM32的好多设置一样。

我就奇怪了,为什么STM先出32位的,再出8位的? 是不是将来还出4位的??

xlswyf 发表于 2009-4-18 12:40:28

楼主你好,我安装的STVD环境里没有stm8s.h文件,请问到哪弄STM8的固件库,谢谢!!

ifree64 发表于 2009-4-18 20:22:41

到ST的网站下载STM8的固件函数库。

xlswyf 发表于 2009-4-21 09:04:47

多谢楼主指点,还有个问题就是,我在调用
GPIO_Init(LEDS_PORT, (LED1_PIN | LED2_PIN | LED3_PIN | LED4_PIN), GPIO_MODE_OUT_PP_LOW_FAST);
的时候总是报错
#error cpstm8 ..\..\main.c:46(14) incompatible argument type
不知如何解决,我还按照ST提供的GPIO例程重新建立一个工程,按照例程把需要的文件加进去,可是编译时,ST的例程成功,我的总报错,不知什么地方出了问题,还请楼主或其他高手指点,万分感谢!!!

hahacomcn 发表于 2009-4-21 10:51:24

LS,出错的意思是参数的类型不对,你看看函数传递的变量是否和原型声明的一样。

xlswyf 发表于 2009-4-23 15:31:30

谢谢指点,总算找出来了!

bioe 发表于 2010-3-21 20:46:57

xlswyf,你好,我现在也遇到下面弄问题,请问你是怎样找出来的?
我按照ST提供的GPIO例程重新建立一个工程,按照例程把需要的文件加进去,可是编译时,ST的例程成功,我的总报错,不知什么地方出了问题?
hahacomcn说,出错的意思是参数的类型不对,看看函数传递的变量是否和原型声明的一样。
我还是没有看明白,请指点,谢谢。

122402902 发表于 2010-4-2 17:25:40

我做GPIO中断实验的时候 老是一进入TL1就马上跳出来了 不知道为什么 请问LZ遇到过这样的问题吗

wyaozj 发表于 2010-4-20 16:59:51

GPIOB用作双向I/O口,该怎么初始化?GPIO_Write,GPIO_ReadInputData两个函数就可以直接应用。在读写RC500时候还是读写不起来、

fycom200 发表于 2010-6-11 09:53:41

回复【2楼】chen1986sl 动感超人
      不 错 期待stm8   和stm32的好多设置一样。
我就奇怪了,为什么stm先出32位的,再出8位的? 是不是将来还出4位的??
-----------------------------------------------------------------------

不用奇怪,32的是用的ARM公司的内核,当然比较快,8位的则是自己开发的,当然得慢点

newboymail00 发表于 2011-9-17 09:43:22

stm8的库还是小很多啊 ,呵呵 !比较容易上手些!

chrisnepher 发表于 2011-9-29 22:45:51

一看都这些头都大了哦,
配置的时候喜欢“裸”着配。

larrythanks 发表于 2011-11-3 10:08:55

回复【5楼】xlswyf
-----------------------------------------------------------------------

有些引用的东西。编译器不认。找找是不是定义了(缺少宏定义)。

larrythanks 发表于 2011-11-3 10:11:24

回复【5楼】xlswyf
-----------------------------------------------------------------------

在main.c中加#include“”
就ok

more 发表于 2011-11-5 16:57:13

学习

runningpudge 发表于 2012-1-13 10:14:12

请问哪里有stm8L的库下载......

wakhs 发表于 2012-2-1 15:51:13

mark

zike 发表于 2012-6-11 13:22:23

学习了。

lkdsp 发表于 2013-2-8 17:48:49

mark!准备学stm8

Raywang 发表于 2013-8-14 23:53:01

mark!! 支持技术交流

yanwuhen 发表于 2013-8-16 09:47:41

发送一个非常好用的STM8库文件调用的软件

yanwuhen 发表于 2013-8-16 09:48:08

中文的哦

NEXEN1106 发表于 2013-9-24 16:08:20

虽然有点晚,我也遇到了9楼的问题,我的原因如下
我用的芯片是003,例程中调用了GPIOH端口,但是003芯片中没有H端口,所以就报参数不匹配了,我把H端口改成A端口就OK了

猫哥 发表于 2013-9-27 11:56:53

哥,去哪里找的库...?能否给我发一份?

sj1125055001 发表于 2014-11-26 19:18:44

顶                     

bobo89 发表于 2014-11-26 20:30:56

这个最基础了!~

VegeBird 发表于 2020-6-23 15:10:12

GPIO操作非常便利啊
页: [1]
查看完整版本: STM8固件库GPIO学习笔记