你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

《STM32库开发实战指南-基于STM32F103霸道》读书笔记--续3

[复制链接]
zhdzhd 发布时间:2018-12-29 12:43
本帖最后由 zhdzhd-174422 于 2018-12-31 21:24 编辑

第8章 使用寄存器点亮LED灯
本章实验点亮2组GPIO端口中的2个LED灯。

图片1.png

STM32F103ZET6
    -  一共有144脚
    -  一共有7组IO口
    - 每组IO口有16个IO
    - 一共16X7=112个IO,分别是GPIOA,GPIOB...GPIOG。


无标题.png

GPIO 有8 种工作模式,分为4种输入模式和4种输出模式,用代码表示如下:
-----------------------------------------------------------------------------------------------------
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;

----------------------------------------------------------------------------------------------------

有3种最高切换频率:
       -2MHZ
       -10MHz
       -50MHz

每组IO口包含7个寄存器,可以控制GPIO的16个IO口。

        - GPIOx_CRL      端口配置低寄存器
        - GPIOx_CRH     端口配置高寄存器
        - GPIOx_IDR      端口输入寄存器
        - GPIOx_ODR     端口输出寄存器
        - GPIOx_BSRR   端口位设置/清除寄存器
        - GPIOx_BRR     端口位清除寄存器
        - GPIOx_LCKR   端口配置锁存寄存器

用C语言把上面的寄存器地址转换成指针代码如下:(x代表A---G)
----------------------------------------------------------------------------------------------------------------------
#define GPIOx_CRL                     *(unsigned int*)(GPIOB_BASE+0x00)
#define GPIOx_CRH                    *(unsigned int*)(GPIOB_BASE+0x04)
#define GPIOx_IDR                     *(unsigned int*)(GPIOB_BASE+0x08)
#define GPIOx_ODR                    *(unsigned int*)(GPIOB_BASE+0x0C)
#define GPIOx_BSRR                   *(unsigned int*)(GPIOB_BASE+0x10)
#define GPIOx_BRR                     *(unsigned int*)(GPIOB_BASE+0x14)
#define GPIOx_LCKR                   *(unsigned int*)(GPIOB_BASE+0x18)

----------------------------------------------------------------------------------------------------------------------
GPIOB_BASE从前面一章的学习我们知道是GPIO的外设基地址,而GPIO都是挂载到APB2总线上的,故各端口的基地址代码如下:
----------------------------------------------------------------------------------------------------------------------
#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)

----------------------------------------------------------------------------------------------------------------------
我用的是原子的精英板,板载有2个LED,分别是LED0和LED1,对应芯片的PB5和PE5脚。
捕获2.PNG 捕获1.PNG 捕获.PNG


所有的 GPIO都挂载到 APB2 总线上,具体的时钟由 APB2外设时钟使能寄存器(RCC_APB2ENR)来控制,见下图:


无标题1.png


开启时钟端口的代码如下:

RCC_APB2ENR |= (1<<3);        //开启GPIOB端口的时钟

RCC_APB2ENR |= (1<<6);        //开启GPIOB端口的时钟

在输出模式时,对端口位设置/清除寄存器 BSRR 寄存器、端口位清除寄存器 BRR 和ODR 寄存器写入参数即可控制引脚的电平状态,其中操作 BSRR 和 BRR 最终影响的都是ODR 寄存器,然后再通过 ODR寄存器的输出来控制 GPIO,直接操作 ODR寄存器来控制 GPIO 的电平。代码如下:

GPIOB_ODR &= ~(1<<0);
GPIOE_ODR &= ~(1<<0);

无标题1.png

通过上面 配置引脚模式,开启时钟,控制引脚电平这三步,我们实现了控制2个 LED 的基本步骤和代码,另外有个需要注意的事项就是:

我们在 main中添加如下函数:
----------------------------------------------------------------------------------------------------------------------
// 函数为空,目的是为了骗过编译器不报错
void SystemInit(void)
{
}

----------------------------------------------------------------------------------------------------------------------
如果不添加上面的函数,编译时会出现如下错误:
“Error: L6218E: Undefined symbol SystemInit (referred from startup_stm32f10x.o)”
错误提示 SystemInit 没有定义。
从分析启动文件时我们知道,Reset_Handler 调用了该函数用来初始化 SMT32 系统时钟,为了简单起见,我们在 main 文件里面定义一个SystemInit 空函数,什么也不做,为的是骗过编译器,把这个错误去掉。关于配置系统时钟我们在后面再写。当我们不配置系统时钟时,STM32 会把 HSI 当作系统时钟,HSI=8M,由芯片内部的振荡器提供。这时再编译就没有错了,完美解决。

还有一个方法就是在启动文件statrup_stm32f10x.hd.s中把有关SystemInit 的代码注释掉也可以(首先要把此文件的“只读”属性取消,在下面红色的语句前面增加“;”即可注释掉,绿色保留)。

; Reset handler
Reset_Handler   PROC
                       EXPORT  Reset_Handler             [WEAK]
                       IMPORT  __main
                       IMPORT  SystemInit
                       LDR     R0, =SystemInit
                       BLX     R0               
                       LDR     R0, =__main
                       BX      R0
                       ENDP

捕获7.PNG

如果是初学,还是建议在main.c中增加void SystemInit(void)函数比较方便,不要去动启动文件。

现在完整组织一下用 STM32 控制2个 LED 的代码:
--------------------------------------------------------------------------------------------------------------
int main(void)
                    {

                     RCC_APB2ENR |= (1<<3);                       //开启 GPIOB 端口时钟

                     RCC_APB2ENR |= (1<<6);                       //开启 GPIOE 端口时钟



                     GPIOB_CRL &= ~( 0x0F<< (4*5));           //清空控制 PB5 的端口位

                     GPIOB_CRL |= (1<<4*5);                        //配置 PB5 为通用推挽输出,速度为 10M
                     GPIOB_ODR |= (0<<0);                          //PB5 输出 低电平


                     GPIOE_CRL &= ~( 0x0F<< (4*5));           //清空控制 PE5 的端口位
                     GPIOE_CRL |= (1<<4*5);                        //配置 PE5 为通用推挽输出,速度为 10M
                     GPIOE_ODR |= (0<<0);                          //PE5 输出 低电平


                    while (1);
                   }                                                           //切记此处要加回车

void SystemInit(void)
{
}                                                                            //切记此处要加回车



----------------------------------------------------------------------------------------------------------------------
将上面的代码写入上章创建的空的main.c中。
捕获5.PNG

将上面配置GPIOB和GPIOE寄存器要使用的代码写入上次创建的空文件stm32f10x.h中:
----------------------------------------------------------------------------------------------------------------------


#define  PERIPH_BASE                  ((unsigned int)0x40000000)
#define  APB1PERIPH_BASE          PERIPH_BASE
#define  APB2PERIPH_BASE          (PERIPH_BASE + 0x10000)
#define  AHBPERIPH_BASE           (PERIPH_BASE + 0x20000)


#define  RCC_BASE                     (AHBPERIPH_BASE + 0x1000)
#define  RCC_APB2ENR              *(unsigned int*)(RCC_BASE + 0x18)


#define  GPIOB_BASE                 (APB2PERIPH_BASE + 0x0C00)
#define  GPIOE_BASE                 (APB2PERIPH_BASE + 0x1800)


#define  GPIOB_CRL                  *(unsigned int*)(GPIOB_BASE + 0x00)
#define  GPIOB_ODR                 *(unsigned int*)(GPIOB_BASE + 0x0C)


#define  GPIOE_CRL                 *(unsigned int*)(GPIOE_BASE + 0x00)
#define  GPIOE_ODR                *(unsigned int*)(GPIOE_BASE + 0x0C)        

----------------------------------------------------------------------------------------------------------------------
捕获.PNG

编译通过,见下图:

捕获8.PNG

下载测试,效果如下:

IMG_20181229_123856.jpg
       眼看2019年就要来了,2018马上要悄悄的离我们而去了,回想今年一年在论坛混的日子,感觉收获颇丰,感谢各位管管和坛友们的支持和帮助,祝大家2019年工作顺利,财运恒通,身体健康!祝论坛在2019年越办越旺,给广大坛友带来更多的福利!!谢谢!










收藏 评论5 发布时间:2018-12-29 12:43

举报

5个回答
STMCU-管管 回答时间:2018-12-29 14:23:57
谢谢分享
Kevin_G 回答时间:2018-12-29 14:36:00
基本讲解
STM1024 回答时间:2018-12-29 19:58:54
学得挺认真的嘛
wsadnm55 回答时间:2018-12-30 11:55:30
占个楼
stm32学习hpdj 回答时间:2019-1-1 08:34:08
学习学习

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版