历史上的今天
返回首页

历史上的今天

今天是:2024年08月26日(星期一)

正在发生

2018年08月26日 | STM32学习笔记——GPIO之从库函数到寄存器

2018-08-26 来源:eefocus

例子为单片机的“Hello World”级的流水灯实验——虽然只有一个,其中并不是将完整的代码给出,只是给出关键部分来说明“如何调用ST公司的的库来完成对硬件的控制,以及对库文件代码进行跟踪和分析至寄存器级”。所以从第一段代码往下看就可以了,要用到的函数和变量大部分会说明,至于寄存器级的,那就只能翻手册了。

GPIO(General Purpose Input/Output) - 通用输入/输出

 main.c :此函数为主函数,控制LED,亮1s,灭1s


int main(void)

{

    //LED初始化 

    LED_Configuration();

    while(1)

    {

        GPIO_SetBits(GPIOB,GPIO_Pin_5);     //置为1  

        Systick_DelayMs(1000);              //延时1s,自己实现的,暂不说明  

        GPIO_ResetBits(GPIOB,GPIO_Pin_5);   //置为0  

        Systick_DelayMs(1000);              //延时1s  

    }

}


 stm32f10x_gpio.c GPIO_SetBits和GPIO_ResetBits


/**

  * @brief  Sets the selected data port bits.

  * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.

  * @param  GPIO_Pin: specifies the port bits to be written.

  *   This parameter can be any combination of GPIO_Pin_x where x can be (0..15).

  * @retval None

  */

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

{

  /* Check the parameters */

  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));

  assert_param(IS_GPIO_PIN(GPIO_Pin));

  

  GPIOx->BSRR = GPIO_Pin;

}


/**

  * @brief  Clears the selected data port bits.

  * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.

  * @param  GPIO_Pin: specifies the port bits to be written.

  *   This parameter can be any combination of GPIO_Pin_x where x can be (0..15).

  * @retval None

  */

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

{

  /* Check the parameters */

  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));

  assert_param(IS_GPIO_PIN(GPIO_Pin));

  

  GPIOx->BRR = GPIO_Pin;

}

 

 led.c  需要用到以下库文件:stm32f10x_rcc.c,stm32f10x_gpio.c-->STM32的I/O口初始化函数


void LED_Configuration(void)

{

    /*设置PB.5为输出模式,用于LED*/

    //定义一个GPIO数据结构,存放设置的参数

    GPIO_InitTypeDef  GPIO_InitStructure;

    //要使用一个I/O口时,需要先打开相应I/O口所在口的时钟,如使能PB端口时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    //先设置要配置的引脚,LED0-->PB.5 端口配置

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

    //配置为推挽输出模式

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    //配置I/O口速度为50MHz

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    //根据设定参数初始化GPIOB

    GPIO_Init(GPIOB, &GPIO_InitStructure);

}


下面为LED_Configuration中涉及到的结构体变量和一些其他变量的出处:

 stm32f10x_gpio.h


/**

  * @brief  GPIO Init structure definition

  */


typedef struct

{

    uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.

                                      This parameter can be any value of @ref GPIO_pins_define */


    GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.

                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */


    GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.

                                      This parameter can be a value of @ref GPIOMode_TypeDef */

} GPIO_InitTypeDef;


 stm32f10x_gpio.h :每个GPIO口有0x10个。


/** @defgroup GPIO_pins_define

  * @{

  */


#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */

#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */

#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */

#define GPIO_Pin_3                 ((uint16_t)0x0008)  /*!< Pin 3 selected */

#define GPIO_Pin_4                 ((uint16_t)0x0010)  /*!< Pin 4 selected */

#define GPIO_Pin_5                 ((uint16_t)0x0020)  /*!< Pin 5 selected */

#define GPIO_Pin_6                 ((uint16_t)0x0040)  /*!< Pin 6 selected */

#define GPIO_Pin_7                 ((uint16_t)0x0080)  /*!< Pin 7 selected */

#define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */

#define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */

#define GPIO_Pin_10                ((uint16_t)0x0400)  /*!< Pin 10 selected */

#define GPIO_Pin_11                ((uint16_t)0x0800)  /*!< Pin 11 selected */

#define GPIO_Pin_12                ((uint16_t)0x1000)  /*!< Pin 12 selected */

#define GPIO_Pin_13                ((uint16_t)0x2000)  /*!< Pin 13 selected */

#define GPIO_Pin_14                ((uint16_t)0x4000)  /*!< Pin 14 selected */

#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */

#define GPIO_Pin_All               ((uint16_t)0xFFFF)  /*!< All pins selected */


 stm32f10x_gpio.h : GPIO的模式,比51多多了


/**

  * @brief  Configuration Mode enumeration

  */


typedef enum

{

    GPIO_Mode_AIN = 0x0,             /* 模拟输入模式 */ 

    GPIO_Mode_IN_FLOATING = 0x04,    /* 浮空输入模式 */ 

    GPIO_Mode_IPD = 0x28,            /* 下拉输入模式 */ 

    GPIO_Mode_IPU = 0x48,            /* 上拉输入模式 */ 

    GPIO_Mode_Out_OD = 0x14,         /* 通用推挽输出模式 */  

    GPIO_Mode_Out_PP = 0x10,         /* 通用开漏输出模式 */ 

    GPIO_Mode_AF_OD = 0x1C,          /* 复用功能推挽输出模式 */ 

    GPIO_Mode_AF_PP = 0x18           /* 复用功能开漏输出模式 */ 

} GPIOMode_TypeDef;

    具体区别翻手册,也没记那么清楚~

  stm32f10x_gpio.h  : 赋予GPIO的运行频率


/**

  * @brief  Output Maximum frequency selection

  */


typedef enum

{

    GPIO_Speed_10MHz = 1,

    GPIO_Speed_2MHz,

    GPIO_Speed_50MHz

} GPIOSpeed_TypeDef;

枚举变量:GPIO_Speed_10MHz =1;GPIO_Speed_2MHz =2;GPIO_Speed_50MHz =3,速度写着呢,选一个就ok了~


 stm32f10x.h


#define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */


#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)


#define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)

#define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)

#define GPIOC_BASE            (APB2PERIPH_BASE + 0x1000)

#define GPIOD_BASE            (APB2PERIPH_BASE + 0x1400)

#define GPIOE_BASE            (APB2PERIPH_BASE + 0x1800)

#define GPIOF_BASE            (APB2PERIPH_BASE + 0x1C00)

#define GPIOG_BASE            (APB2PERIPH_BASE + 0x2000)


#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)

#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)

#define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)

#define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)

#define GPIOE               ((GPIO_TypeDef *) GPIOE_BASE)

#define GPIOF               ((GPIO_TypeDef *) GPIOF_BASE)

#define GPIOG               ((GPIO_TypeDef *) GPIOG_BASE)

GPIOA=GPIOA_BASE=0x40000000+0x10000+0x800

通过查询STM32微控制器开发手册可以得知,STM32的外设起始基地址为0x40000000,而APB2总线设备起始地址相对于外设基地址的偏移量为0x10000,GPIOA设备相对于APB2总线设备起始地址偏移量为0x800。

注意:以上只是很小的一部分定义,stm32f10x.h文件的代码行数有8000多行。



下面为LED_Configuration中再配置完参数之后,将结构体中的参数写入到寄存器中的GPIO_Init初始化函数:

 stm32f10x_gpio.c  


/**

  * @brief  Initializes the GPIOx peripheral according to the specified

  *         parameters in the GPIO_InitStruct.

  * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.

  * @param  GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that

  *         contains the configuration information for the specified GPIO peripheral.

  * @retval None

  */

void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)

{

    uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;

    uint32_t tmpreg = 0x00, pinmask = 0x00;

    /* Check the parameters */

    //用断言来检查参数是否正确

    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));

    assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));

    assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));

    /*---------------------------- GPIO Mode Configuration -----------------------*/

    //将工作模式暂存至currentmode变量中

    currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);


    //如果欲设置为任意一种输出模式,则再检查“翻转速率”参数是否正确

    if((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)

    {

        /* Check the parameters */

        assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));

        /* Output mode */

        currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;

    }


    /*---------------------------- GPIO CRL Configuration ------------------------*/

    /* Configure the eight low port pins */

    //设置低8位引脚(即pin0~pin7)

    if(((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)

    {

        //独处当前配置字

        tmpreg = GPIOx->CRL;


        for(pinpos = 0x00; pinpos < 0x08; pinpos++)

        {

            pos = ((uint32_t)0x01) << pinpos;

            /* Get the port pins position */

            //获取将要配置的引脚号

            currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;


            if(currentpin == pos)

            {

                //先清除对应引脚的配置字

                pos = pinpos << 2;

                /* Clear the corresponding low control register bits */

                pinmask = ((uint32_t)0x0F) << pos;

                tmpreg &= ~pinmask;

                /* Write the mode configuration in the corresponding bits */

                //写入新的配置字

                tmpreg |= (currentmode << pos);


                /* Reset the corresponding ODR bit */

                //若欲配置为上拉/下拉输入,则需要配置BRR和BSRR寄存器

                if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)

                {

                    GPIOx->BRR = (((uint32_t)0x01) << pinpos);

                }


                else

                {

                    /* Set the corresponding ODR bit */

                    if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)

                    {

                        GPIOx->BSRR = (((uint32_t)0x01) << pinpos);

                    }

                }

            }

        }


        //写入低8位引脚配置字

        GPIOx->CRL = tmpreg;

    }


    /*---------------------------- GPIO CRH Configuration ------------------------*/

    /* Configure the eight high port pins */

    //设置高8位引脚(即pin8~pin15),流程和低8位引脚一致

    if(GPIO_InitStruct->GPIO_Pin > 0x00FF)

    {

        tmpreg = GPIOx->CRH;


        for(pinpos = 0x00; pinpos < 0x08; pinpos++)

        {

            pos = (((uint32_t)0x01) << (pinpos + 0x08));

            /* Get the port pins position */

            currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);


            if(currentpin == pos)

            {

                pos = pinpos << 2;

                /* Clear the corresponding high control register bits */

                pinmask = ((uint32_t)0x0F) << pos;

                tmpreg &= ~pinmask;

                /* Write the mode configuration in the corresponding bits */

                tmpreg |= (currentmode << pos);


                /* Reset the corresponding ODR bit */

                if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)

                {

                    GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));

                }


                /* Set the corresponding ODR bit */

                if(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)

                {

                    GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));

                }

            }

        }


        GPIOx->CRH = tmpreg;

    }

}

        这段程序的流程:首先检查由结构体变量GPIO_InitStructure所传入的参数是否正确,然后对GPIO寄存器进行“读出->修改->写入”操作,完成对GPIO设备的配置工作。

        总结起来就是:固件库首先将各个设备所有的寄存器的配置字进行预先定义在stm32f10x.h文件中,然后封装在结构或枚举变量中(存在相对应的stm32f10x_xxx.h,其中xxx代表gpio,spi,exti等外设模块),待用户调用对应的固件库函数时,会根据用户传入的参数从这些封装好的结构体或枚举变量中取出对应的配置字,最后写入寄存器中,完成对底层寄存器的配置。


 stdint.h 一些具有可移植性的变量重定义


/*

 * 'signed' is redundant below, except for 'signed char' and if

 * the typedef is used to declare a bitfield.

 * '__int64' is used instead of 'long long' so that this header

 * can be used in --strict mode.

 */


/* 7.18.1.1 */


/* exact-width signed integer types */

typedef   signed          char int8_t;

typedef   signed short     int int16_t;

typedef   signed           int int32_t;

typedef   signed       __int64 int64_t;


/* exact-width unsigned integer types */

typedef unsigned          char uint8_t;

typedef unsigned short     int uint16_t;

typedef unsigned           int uint32_t;

typedef unsigned       __int64 uint64_t;


/* 7.18.1.2 */


/* smallest type of at least n bits */

/* minimum-width signed integer types */

typedef   signed          char int_least8_t;

typedef   signed short     int int_least16_t;

typedef   signed           int int_least32_t;

typedef   signed       __int64 int_least64_t;


/* minimum-width unsigned integer types */

typedef unsigned          char uint_least8_t;

typedef unsigned short     int uint_least16_t;

typedef unsigned           int uint_least32_t;

typedef unsigned       __int64 uint_least64_t;


/* 7.18.1.3 */


/* fastest minimum-width signed integer types */

typedef   signed           int int_fast8_t;

typedef   signed           int int_fast16_t;

typedef   signed           int int_fast32_t;

typedef   signed       __int64 int_fast64_t;


/* fastest minimum-width unsigned integer types */

typedef unsigned           int uint_fast8_t;

typedef unsigned           int uint_fast16_t;

typedef unsigned           int uint_fast32_t;

typedef unsigned       __int64 uint_fast64_t;


/* 7.18.1.4 integer types capable of holding object pointers */

typedef   signed           int intptr_t;

typedef unsigned           int uintptr_t;


/* 7.18.1.5 greatest-width integer types */

typedef   signed       __int64 intmax_t;

typedef unsigned       __int64 uintmax_t;

推荐阅读

史海拾趣

Feller US公司的发展小趣事

菲斯克(FSR.US)作为一家新兴的电动汽车制造商,自创立之初便面临着巨大的挑战。资金紧张是公司面临的首要问题,为了维持运营和推进研发,公司不得不频繁地寻求融资。在一次次的融资尝试中,菲斯克展现了其坚定的决心和创新的理念,虽然过程充满艰辛,但公司最终通过不断努力,成功获得了一笔重要的投资,为公司的发展奠定了坚实的基础。

Hendon Semiconductors公司的发展小趣事

Hendon Semiconductors的起源可以追溯到上世纪90年代,当时它是Philips半导体在澳大利亚的一个分支机构。1997年,随着业务重组和战略调整,该分支机构转变为独立运营的公司,并更名为Integrated Electronic Solutions Pty. Ltd。这一转变标志着Hendon Semiconductors在电子设计与制造领域迈出了重要一步。通过继承Philips半导体的技术遗产和市场资源,Hendon Semiconductors迅速在行业内站稳脚跟,并开始了其自主发展的道路。

永丰盈(CST)公司的发展小趣事

在稳步发展国内市场的同时,CST积极拓展国际市场。公司建立了分布世界各地的销售渠道,与多家国际知名企业建立了长期稳定的合作关系。通过不断的市场拓展和品牌建设,CST在国际市场上树立了良好的企业形象和品牌形象。

EA Elektro-Automatik公司的发展小趣事

EA Elektro-Automatik深知持续创新是企业发展的重要动力。因此,公司始终将创新作为企业文化的核心价值观之一。公司鼓励员工积极提出创新想法和解决方案,并为他们提供充分的支持和资源。此外,EA Elektro-Automatik还积极参与各类科研项目和行业标准的制定工作,推动整个行业的创新和发展。这种企业文化不仅为公司带来了更多的机会和挑战,也为企业的长期发展奠定了坚实的基础。

以上是关于EA Elektro-Automatik公司在电子行业发展的5个相关故事。这些故事展示了公司从创立到成为全球知名电子测量品牌的发展历程和取得的成就。

Elcos AG公司的发展小趣事

随着国内市场的饱和,Elcos AG开始寻求国际化拓展的机会。公司首先在欧洲市场建立了销售网络,通过与当地合作伙伴的紧密合作,逐渐打开了欧洲市场的大门。随后,Elcos AG又将目光投向了亚洲和北美市场,通过设立海外办事处和参加国际展会等方式,积极推广公司品牌和产品。在国际市场的竞争中,Elcos AG凭借其卓越的产品品质和完善的售后服务体系,赢得了众多客户的信赖和支持。

AC Interface Inc公司的发展小趣事

ABC Electronics Inc. 深知人才是企业发展的核心动力。因此,公司高度重视人才培养和引进工作。一方面,公司建立了完善的人才培养机制,通过内部培训、轮岗锻炼等方式提升员工的技能和素质;另一方面,公司积极引进具有创新精神和国际视野的高端人才,为公司的技术创新和市场拓展提供了有力支撑。这些人才战略的实施,为公司的长远发展奠定了坚实基础。

这些故事虽然是以虚构的ABC Electronics Inc.为例,但其中的情节和策略在电子行业中是普遍存在的。如果AC Interface Inc是一个真实存在的公司,它的发展轨迹可能也会涉及这些方面。当然,具体的故事还需要根据公司的实际情况来创作。

问答坊 | AI 解惑

基于EASY嵌入式PLC芯片组构建现场总线ETS系统

TSI系统(汽轮机状态监视和保护系统)和ETS系统(汽轮机危机跳闸系统)是火力发电厂保证汽轮机和发电机正常运转的重要设备,在火力发电企业运用十分普遍。在当前的大部分应用中,这两套系统是互相独立的,一般由专业的TSI设备供应商提供TSI系统,而 ...…

查看全部问答>

vxworks资料

................ [ 本帖最后由 daicheng 于 2008-12-7 11:04 编辑 ]…

查看全部问答>

五个手指不一样齐正,说明了并不是所有人都这样看榜样做事。

如果这部分人不看榜样做事,工作完成不好,不符合领导要求。肯定就应该咔嚓了。否则影响整个团队了…

查看全部问答>

找兼职 多普达手机发短信和接受短信息,服务器接受并解析和向pda发短信息

找兼职 多普达手机发短信和接受短信息,服务器接受并解析和向pda发短信息,pda操作系统是wm ,服务器操作系统xp,是要求有成功案例或项目经验。 联系 msn djliu221@163.com qq 412925762 谢绝新手…

查看全部问答>

核心板不能从NOR启动UBOOT

我刚购买的核心板不能从NOR启动,NOR里已经烧写了UBOOT,在开发板上能从NOR正常启动,我的板子和开发板地板复位电路和JTAG电路都一样,在我板子上也不能用h-jtag烧写NOR flash,我的板子电源正常,能从NAND启动EBOOT,请帮忙分析一下 原因,谢谢先~…

查看全部问答>

关于:#pragma comment(lib, "ws2_32.lib ") 急————急

我修改一个实例程序:用到下面语句(在evc中) #pragma   comment(lib,   \"ws2_32.lib \"),但却出现下面错误。 cannot open file \'ws2_32.lib \' 我在setting->link->Object/library   modules:中填上:ws2_ ...…

查看全部问答>

串口通讯自发自收

你们好。我做了一个AT89S52;MAX232与PC通讯板子。 当我用11。12与单片机相连,13。14,GND与PC相连, 线路也对。能接收到单片机发到PC的数据。就是当我用调试助手发数据到单片机时。 调试助手一边发,它自已一边收,好像单片机没有还收不到 ...…

查看全部问答>

CroundButton

刚刚看了个CroundButton类,注释不够清楚,图像处理的函数一点都没头绪 在这里个大家贴出来,有心人给我理理来龙去脉哈   ____________________________________________________________________________________________________ ______ ...…

查看全部问答>

STM32的AD最高采样率跟USB时钟的冲突解决了没

103的中用USB的时候,AD不能工作在最高采样率 后来升级的105,107有没有解决这个问题,我的项目中就要用的1M的AD和USB啊,要是还没解决,我就要放弃stm32这鸡肋了 感觉ATMEL的也不错,高速USB,但貌似技术支持不太好,国内用的不很多,没有S ...…

查看全部问答>

高手们帮帮忙!关于坐标变换的方程组

带下划线的是已知量,a b w是未知量,高手们帮我解出 a= b= w= 的表达式吗?谢谢各位了!…

查看全部问答>