打印
[其他ST产品]

STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解

[复制链接]
1166|28
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
寄存器原理
1.什么是寄存器
寄存器是 CPU 内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。其实寄存器就是一种常用的 时序逻辑电路 ,但这种时序逻辑电路只包含存储电路。 寄存器的存储电路是由锁存器或触发器构成的,因为一个锁存器或触发器能存储1位二进制数,所以由N个 锁存器 或触发器可以构成N位寄存器。寄存器是 中央处理器 内的组成部分。寄存器是有限存储容量的高速存储部件,它们可用来暂存指令、数据和位址。在计算机领域,寄存器是CPU内部的元件,包括 通用寄存器 、专用寄存器和控制寄存器。寄存器拥有非常高的读写速度,所以在寄存器之间的数据传送非常快。

2.如何访问寄存器
存放数据的寄存器是最好理解的,如果你需要读取一个数据,直接到这个寄存器所在的地方来问问他,数据是多少就行了。问寄存器这个动作,叫做访问寄存器。不同的数据会存放在不同的寄存器,例如引脚PA2与PB8的高低电平数据(1或0)肯定放在不同的寄存器里,那么怎么区分不同的寄存器呢?通过地址,不同的寄存器有不同的地址
**所以需要找到其地址,怎么找到某个寄存器的地址?查看数据手册。**在简单了解寄存器后,我们开始配置

使用特权

评论回复
沙发
花间一壶酒sd|  楼主 | 2023-5-30 13:17 | 只看该作者
GPIO端口的初始化设置
1.时钟配置
想要配置时钟首先要访问其寄存器,找到地址。
(1)找到时钟使能寄存器映射基地址
时钟控制名字叫做RCC,属于AHB总线,查看数据手册如下:


得出复位和时钟控制RCC的地址从0x4002 1000开始

使用特权

评论回复
板凳
花间一壶酒sd|  楼主 | 2023-5-30 13:18 | 只看该作者
找到端口偏移地址以及对应端口所在位置

手册RCC_APB2ENR,位3是IOPBEN,名字是IO端口B时钟使能,就是我们想要的。把RCC_APB2ENR的位3赋值为1,就是开启GPIOB时钟

使用特权

评论回复
地板
花间一壶酒sd|  楼主 | 2023-5-30 13:19 | 只看该作者
使能对应端口时钟
//----------------APB2使能时钟寄存器 ---------------------
#define RCC_APB2ENR                *((unsigned volatile int*)0x40021018)

        RCC_APB2ENR|=1<<2|1<<3|1<<4;                        //APB2-GPIOA、GPIOB、GPIOC外设时钟使能       

使用特权

评论回复
5
花间一壶酒sd|  楼主 | 2023-5-30 13:19 | 只看该作者
.端口输出寄存器配置
本次实验使用GPIOA-5、GPIOB-9、GPIOC-14 这3个引脚控制LED灯,GPIO是属于APB2的。
同理,也要访问其地址。

使用特权

评论回复
6
花间一壶酒sd|  楼主 | 2023-5-30 13:20 | 只看该作者
找到找到GPIOX的基地址


结论是,
所有GPIOA相关的寄存器,都住在0x4001 0800到0x4001 0BFF范围内。
所有GPIOB相关的寄存器,都住在0x4001 0C00到0x4001 0FFF范围内。
所有GPIOC相关的寄存器,都住在0x4001 1000到0x4001 13FF范围内。

使用特权

评论回复
7
花间一壶酒sd|  楼主 | 2023-5-30 13:20 | 只看该作者
找到端口输入寄存器的地址偏移
分别用到A4、B5、C14三个引脚。其中A4、B5属于端口配置低寄存器偏移地址为0x00,C13属于端口配置高寄存器偏移地址为0x04。

使用特权

评论回复
8
花间一壶酒sd|  楼主 | 2023-5-30 13:21 | 只看该作者
对应引脚寄存器,基地址+偏移量
相应端口配置器GPIOA_CRL地址为GPIOA的基址+上偏移量

使用特权

评论回复
9
花间一壶酒sd|  楼主 | 2023-5-30 13:21 | 只看该作者
//----------------GPIOA配置寄存器 -----------------------
#define GPIOA_CRL                *((unsigned volatile int*)0x40010800)
//----------------GPIOB配置寄存器 -----------------------
#define GPIOB_CRL                *((unsigned volatile int*)0x40010C00)
//----------------GPIOC配置寄存器 -----------------------
#define GPIOC_CRH                *((unsigned volatile int*)0x40011004)


使用特权

评论回复
10
花间一壶酒sd|  楼主 | 2023-5-30 13:21 | 只看该作者
输入输出模式和输出速率设置
我们需要的是输出高低电平,所以要设置为输出。输出模式又有好几种输出:

使用特权

评论回复
11
花间一壶酒sd|  楼主 | 2023-5-30 13:21 | 只看该作者
推挽输出:可以输出高,低电平,连接数字器件;推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。
开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行,适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。
开漏是需要外接上拉电阻才可以输出高电平的,这里并不适合。所以需要设置为推挽输出,没有复用,输出速度按要求设置为2Mhz

使用特权

评论回复
12
花间一壶酒sd|  楼主 | 2023-5-30 13:22 | 只看该作者
GPIOA_CRL&=0xFFF0FFFF;                //设置位 清零        
GPIOA_CRL|=0x00020000;                //PA4推挽输出,把第19、18、17、16位变为0010

GPIOB_CRL&=0xFF0FFFFF;                //设置位 清零       
GPIOB_CRL|=0x00200000;                //PB5推挽输出,把第23、22、21、20变为0010

GPIOC_CRH&=0xFF0FFFFF;                //设置位 清零       
GPIOC_CRH|=0x00200000;                //PC14推挽输出,把第23、22、21、20变为0010

使用特权

评论回复
13
花间一壶酒sd|  楼主 | 2023-5-30 13:22 | 只看该作者
三、C语言实现流水灯
1.流水灯原理
本次实验采用三个灯实现,亮灯状态用1表示,灭灯状态用0表示。
初始状态为0 0 0,
状态一为1 0 0
状态二为0 1 0
状态三为0 0 1
状态三结束后继续进入状态一,一直循环达到流水灯效果。

使用特权

评论回复
14
花间一壶酒sd|  楼主 | 2023-5-30 13:22 | 只看该作者
2.c语言实现
(1)创建项目
点击【project】->[New…】

使用特权

评论回复
15
花间一壶酒sd|  楼主 | 2023-5-30 13:22 | 只看该作者

使用特权

评论回复
16
花间一壶酒sd|  楼主 | 2023-5-30 13:23 | 只看该作者
选择STM32F103C8开发板

使用特权

评论回复
17
花间一壶酒sd|  楼主 | 2023-5-30 13:23 | 只看该作者
创建项目出现弹窗,勾选setup项和core项

使用特权

评论回复
18
花间一壶酒sd|  楼主 | 2023-5-30 13:23 | 只看该作者
在source group里创建led.c,选择【Add New Item to Group… …】

使用特权

评论回复
19
花间一壶酒sd|  楼主 | 2023-5-30 13:24 | 只看该作者
(2)写入代码
注意项目结构,使用的引脚是PA7,PB9,PC15

代码如下:
#include "stm32f10x.h"
//----------------APB2使能时钟寄存器 ---------------------
#define RCC_APB2ENR                *((unsigned volatile int*)0x40021018)
//----------------GPIOA配置寄存器 -----------------------
#define GPIOA_CRL                *((unsigned volatile int*)0x40010800)
#define        GPIOA_ODR                *((unsigned volatile int*)0x4001080C)
//----------------GPIOB配置寄存器 -----------------------
#define GPIOB_CRL                *((unsigned volatile int*)0x40010C00)
#define        GPIOB_ODR                *((unsigned volatile int*)0x40010C0C)
//----------------GPIOC配置寄存器 -----------------------
#define GPIOC_CRH                *((unsigned volatile int*)0x40011004)
#define        GPIOC_ODR                *((unsigned volatile int*)0x4001100C)


//延时函数
void Delay()
{
   u32 i=0;
   for(;i<5000000;i++);
}
int main(void)
{       
        RCC_APB2ENR|=1<<2|1<<3|1<<4;                        //APB2-GPIOA、GPIOB、GPIOC外设时钟使能       
       
        GPIOA_CRL&=0xFFF0FFFF;                //设置位 清零       
        GPIOA_CRL|=0x00020000;                //PB5推挽输出
        GPIOA_ODR&=~(1<<4);                        //设置初始灯为灭
       
        GPIOB_CRL&=0xFF0FFFFF;                //设置位 清零       
        GPIOB_CRL|=0x00200000;                //PB5推挽输出
        GPIOB_ODR&=~(1<<5);                        //设置初始灯为灭
         
        GPIOC_CRH&=0xF0FFFFFF;                //设置位 清零       
        GPIOC_CRH|=0x02000000;                //PB5推挽输出
        GPIOC_ODR&=~(1<<14);                        //设置初始灯为灭               
         

         

        while(1){
                //A灯
                GPIOA_ODR|=1<<4;                //PB5高电平
                 Delay();
                GPIOA_ODR&=~(1<<4);                //PB5低电平,因为是置0,所以用按位与


               
                //B灯
                GPIOB_ODR|=1<<5;                //PB5高电平
                 Delay();
                GPIOB_ODR&=~(1<<5);                //PB5低电平,因为是置0,所以用按位与


               
               
                //C灯
                GPIOC_ODR|=1<<14;                //PB5高电平
                 Delay();
                GPIOC_ODR&=~(1<<14);                //PB5低电平,因为是置0,所以用按位与


               
                }
}

使用特权

评论回复
20
花间一壶酒sd|  楼主 | 2023-5-30 13:24 | 只看该作者
(3)编译运行
运行成功,要注意勾选[get hex file]

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

1129

帖子

2

粉丝