【嵌入式】STM32F103寄存器方式点亮LED流水灯

一、实验题目

1、学习和理解STM32F103系列芯片的地址映射和寄存器映射原理;了解GPIO端口的初始化设置三步骤(时钟配置、输入输出模式设置、最大速率设置)。
参考网上资料加深理解。
(https://blog.csdn.net/geek_monkey/article/details/86291377

https://blog.csdn.net/geek_monkey/article/details/86293880)

2、以 STM32最小系统核心板(STM32F103C8T6)+面板板+3只红绿蓝LED 搭建电路,使用GPIOB、GPIOC、GPIOD这3个端口控制LED灯,轮流闪烁,间隔时长1秒。

1)写出程序设计思路,包括GPIOx端口的各寄存器地址和详细参数;

2)分别用汇编语言,C语言编程实现。

二、建立工程文件

1、修改工程模板

在基于STM32固件库的MDK5工程建立基础上,将STM32F103RCT6工程模板修改为STM32F103C8T6的工程模板。

修改点:

替换启动文件,将startup_stm32f10x_hd.s更换为startup_stm32f10x_md.s,startup_stm32f10x_md.s为中等容量产品使用的启动文件,对应FLASH的大小范围为:64K≤FLASH≤128K。
在这里插入图片描述

2、修改全局宏定义

将STM32F10X_HD修改为STM32F10X_MD。
在这里插入图片描述

3、更改使用的芯片型号

在这里插入图片描述

4、设置下载的Flash容量

在这里插入图片描述

三、点亮LED灯(软件部分)

1、代码实现

(1)设置PA5、PA6、PA7为输出

GPIO_InitTypeDef  GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

(2)初始化GPIO为高电平,高电平时LED灯灭

GPIO_SetBits(GPIOA,GPIO_Pin_5);
GPIO_SetBits(GPIOA,GPIO_Pin_6);
GPIO_SetBits(GPIOA,GPIO_Pin_7);

(3)流水灯代码具体实现

#include "stm32f10x.h"

void Delay(u32 count)
{
        u32 i=0;
        for(;i<count;i++);
}

int main(void)
{
        GPIO_InitTypeDef  GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        
        GPIO_SetBits(GPIOA,GPIO_Pin_5);
        GPIO_SetBits(GPIOA,GPIO_Pin_6);
        GPIO_SetBits(GPIOA,GPIO_Pin_7);
        
        while(1)
        {
                GPIO_ResetBits(GPIOA,GPIO_Pin_5);
                GPIO_SetBits(GPIOA,GPIO_Pin_6);
                GPIO_SetBits(GPIOA,GPIO_Pin_7);
                Delay(1000000);Delay(1000000);Delay(1000000);
                GPIO_SetBits(GPIOA,GPIO_Pin_5);
                GPIO_ResetBits(GPIOA,GPIO_Pin_6);
                GPIO_SetBits(GPIOA,GPIO_Pin_7);
                Delay(1000000);Delay(1000000);Delay(1000000);
                GPIO_SetBits(GPIOA,GPIO_Pin_5);
                GPIO_SetBits(GPIOA,GPIO_Pin_6);
                GPIO_ResetBits(GPIOA,GPIO_Pin_7);
                Delay(1000000);Delay(1000000);Delay(1000000);
        }
}

2、编译运行

编译成功
在这里插入图片描述
如果想更好的看编译的结果,可以在keil中观察仿真输出波形
在这里插入图片描述

四、点亮LED灯(实操部分)

1、搭建电路

按照如下原理图来搭建实验电路在这里插入图片描述
实际效果如图
在这里插入图片描述

2、烧录

(1)点击魔法棒—>Output,勾选Create HEX File
在这里插入图片描述
(2)点击Dedug,勾选use,然后选择ST-Link,点击settings,看一下st-link有没有连接到。
在这里插入图片描述
(3)正确连接st-link和芯片之间的四根杜邦线,安装好驱动

(4)点击load,显示烧录成功

在这里插入图片描述
(5)烧录可能遇到的问题
1.st-link可能需要升级,升级后可用
2.显示flash timeout 错误的可能是因为芯片有读保护,需下载st link utility来解决,用法自己百度。
3.显示flash download错误的是由于芯片flash容量选择错误点击debug,然后点击settings,然后flash修改(目录二、4)。

3、实验成果

连接好电源后成果如下:
在这里插入图片描述

五、地址映射和寄存器映射映射原理

1、地址映射和寄存器映射原理

一、寄存器
寄存器是中央处理器内的组成部分。 寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。
简单来说,寄存器就是存放东西的一个空间器物。寄存器可能存放的是指令、数据或地址。
  存放数据的寄存器是最好理解的,如果你需要读取一个数据,直接到这个寄存器所在的地方来问问他,数据是多少就行了。问寄存器这个动作,叫做访问寄存器。不同的数据会存放在不同的寄存器,例如引脚PA2与PB8的高低电平数据(1或0)肯定放在不同的寄存器里,那么怎么区分不同的寄存器呢?通过地址,不同的寄存器有不同的地址,就像老张行李寄存处在101号店铺,老王行李寄存处在258号店铺。
  指令、地址寄存器与数据寄存器类似,里边存放的都是0和1,毕竟单片机也只认识机器码,机器码都是0或1,只是特别的规定下,数据寄存器里面存放的0和1表示数据,指令寄存器里存放的表示指令。
二、地址映射和寄存器映射原理
(1)地址映射:由百度词条可知为了保证CPU执行指令时可正确访问存储单元,需将用户程序中的逻辑地址转换为运行时由机器直接寻址的物理地址,这一过程称为地址映射。
(2)寄存器映射:在存储器的区域单元中,每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。我们可以找到每个单元的起始地址,然后通过 C 语言指针的操作方式来访问这些单元,如果每次都是通过这种地址的方式来访问,不仅不好记忆还容易出错,这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。

2、GPIO端口初始化设置

(1)GPIO初始化步骤:
第一步:使能GPIOx口的时钟。
第二步:指明GPIOx口的哪一位,这一位的速度大小以及模式。
第三步:调用GPIOx初始化函数进行初始化。
第四步:调用GPIO-SetBits函数,进行相应位的置位。
(2)实例
单个GPIO端口

GPIO_InitTypeDef GPIO_InitStructure;
第一步:使能GPIOA的时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

第二步:设置GPIOA参数:输出OR输入,工作模式,端口翻转速率
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_6| GPIO_Pin_7| GPIO_Pin_8; //设定要操作的管脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz

第三步:调用GPIOA口初始化函数,进行初始化。
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA

第四步:调用GPIO-SetBits函数,进行相应为的置位。
GPIO_SetBits(GPIOA,GPIO_Pin_0); //输出高



多个GPIO端口

GPIO_InitTypeDef GPIO_InitStructure;
第一步:使能GPIOA,GPIOE的时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);

第二步:设置GPIOA,GPIOE参数:输出OR输入,工作模式,端口翻转速率
第三步:调用GPIOA口初始化函数,进行初始化。
第四步:调用GPIO-SetBits函数,进行相应为的置位。

把第二、三、四步合并分别设置GPIOA和GPIOE
先设置GPIOA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // 第四个口,PA4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz
GPIO_Init(GPIOA,&GPIO-InitST); //根据设定参数初始化GPIOA
GPIO_SetBits(GPIOA,GPIO_Pin_4); //输出高

再设置GPIOE
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // 第三个口,PE3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz
GPIO_Init(GPIOE,&GPIO-InitST); //根据设定参数初始化GPIOE
GPIO_SetBits(GPIOE,GPIO_Pin_3); //输出高



六、实验总结

动手能力很重要,实际操作的时候会和理论相互应证。会发现很多问题,解决起来也会很有意思。

七、参考博客

https://blog.csdn.net/qq_46467126/article/details/120791793?utm_source=app&app_version=4.16.0&code=app_1562916241&uLinkId=usr1mkqgl919blen

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值