寄存器实现流水灯

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一,stm的系统架构

`在这里插入图片描述
上面的架构图主要包含:

ARM公司提供的内核:cortex-M3

ARM公司提供的总线:Icode,Dcode,System总线

ST公司提供的总线矩阵,DMA控制器,AHB总线,APB总线,以及各个外设控制器

以上整体称之为片上系统(SOC),每个模块各司其职,存在竞争与合作。

二,了解寄存器

1,寄存器的映射以及什么是寄存器

寄存器映射是在存储器映射的基础上进行的。 以STM32为例,操作硬件本质上就是操作寄存器。 在存储器片上外设区域,四字节为一个单元,每个单元对应不同的功能。 当我们控制这些单元时就可以驱动外设工作,我们可以找到每个单元的起始地址,然后通过C 语言指针的操作方式来访问这些单元。 但若每次都是通过这种方式访问地址,不好记忆且易出错。 这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名实质上就是寄存器名字。 给已分配好地址 (通过存储器映射实现)的有特定功能的内存单元取别名的过程就叫寄存器映射 。
其实给特定单元取的别名就是寄存器,寄存器只是特定功能的单元的名字罢了,操作寄存器可以驱动相应外设进行工作。

2、stm的地址映射

片上的外设区分为三条总线,根据外设速度的不同,挂载着不同的外设,APB1挂载低速外设,APB2和AHB挂载着高速外设。

  1. 总线基地址
    在这里插入图片描述
  2. 外设基地址
    总线上挂载着各种外设,这些外设也有自己的地址范围,特定外设的首个地址称为“XX 外设基地址”,也叫XX 外设的边界地址。具体有关STM32F10xx 外设的边界地址请参考《STM32F10xx 参考手册》的2.3 小节的存储器映射的表1:STM32F10xx 寄存器边界地址。

这里面我们以GPIO 这个外设来讲解外设的基地址,GPIO 属于高速的外设 ,挂载到APB2 总线
在这里插入图片描述
3. 外设寄存器
在XX 外设的地址范围内,分布着的就是该外设的寄存器。以GPIO 外设为例,GPIO是通用输入输出端口的简称,简单来说就是STM32 可控制的引脚,基本功能是控制引脚输出高电平或者低电平。最简单的应用就是把GPIO 的引脚连接到LED 灯的阴极,LED 灯的阳极接电源,然后通过STM32 控制该引脚的电平,从而实现控制LED 灯的亮灭。

GPIO 有很多个寄存器,每一个都有特定的功能。每个寄存器为32bit,占四个字节,在该外设的基地址上按照顺序排列,寄存器的位置都以相对该外设基地址的偏移地址来描述。这里我们以GPIOB 端口为例,来说明GPIO都有哪些寄存器。
在这里插入图片描述

三,新建工程

在上方点击这里新建一个工程文件
在这里插入图片描述
然后选择芯片后点击ok
在这里插入图片描述
然后勾上CORE
在这里插入图片描述
如图点击manage project item
在这里插入图片描述
添加一个startup来启动文件,code来放用户代码:
在code文件创建一个.c和.h文件
在这里插入图片描述
在这里插入图片描述

四,编写代码

1,led.h

#ifndef __LED_H__
#define __LED_H__

//片上外设基地址  
#define PERIPH_BASE           ((unsigned int)0x40000000)
//APB1 总线基地址 	
#define APB1PERIPH_BASE       PERIPH_BASE 
//APB2 总线基地址 
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
//AHB总线基地址 
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)
//RCC外设基地址
#define RCC_BASE              (AHBPERIPH_BASE + 0x1000)
//GPIOA外设基地址
#define GPIOA_BASE			  (APB2PERIPH_BASE + 0x0800)
//GPIOB外设基地址
#define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)
//GPIOC外设基地址
#define GPIOC_BASE			  (APB2PERIPH_BASE + 0x1000)
//APB2使能时钟寄存器
#define RCC_APB2ENR			  *(unsigned int*)(RCC_BASE + 0x18)
//GPIOx的端口配置低寄存器
#define GPIOA_CRL			  *(unsigned int*)(GPIOA_BASE + 0x00)
#define GPIOB_CRL	   		  *(unsigned int*)(GPIOB_BASE + 0x00)
#define GPIOC_CRL			  *(unsigned int*)(GPIOC_BASE + 0x00)
//GPIOx的端口配置高寄存器
#define GPIOA_CRH		 	  *(unsigned int*)(GPIOA_BASE + 0x04)
#define GPIOB_CRH			  *(unsigned int*)(GPIOB_BASE + 0x04)
#define GPIOC_CRH			  *(unsigned int*)(GPIOC_BASE + 0x04)
//GPIOx的端口输出寄存器
#define GPIOA_ODR			  *(unsigned int*)(GPIOA_BASE + 0x0C)
#define GPIOB_ODR			  *(unsigned int*)(GPIOB_BASE + 0x0C)
#define GPIOC_ODR			  *(unsigned int*)(GPIOC_BASE + 0x0C)

#endif

2 led.c

#include "led.h"

//定义软件延时函数
void Delay()
{
	int i = 0;
	for(;i<6000000; i++);
}

int main()
{
	RCC_APB2ENR |= (1<<2|1<<3|1<<4);//使能GPIO端口时钟
	GPIOA_CRL |= (0X01<<20);//配置GPIOA_5引脚的模式
	GPIOB_CRH |= (0X01<<4);//配置GPIOB_9引脚的模式
	GPIOC_CRH |= (0X01<<20);//配置GPIOC_13引脚的模式
	GPIOA_ODR &= ~(0X01<<5);//设置几个引脚的初始状态
	GPIOB_ODR &= ~(0X01<<9);
	GPIOC_ODR &= ~(0X01<<13);
	while(1)
	{
		Delay();
		GPIOA_ODR |= 1<<5;
		GPIOB_ODR &= ~(0X01<<9);
		GPIOC_ODR &= ~(0X01<<13);
		Delay();
		GPIOA_ODR &= ~(0X01<<5);
		GPIOB_ODR |= (1<<9);
		GPIOC_ODR &= ~(0X01<<13);
		Delay();
		GPIOA_ODR &= ~(0X01<<5);
		GPIOB_ODR &= ~(0X01<<9);
		GPIOC_ODR |= (1<<13);
		Delay();
	}
	
}

五,仿真分析

修改 一些配置,如下
在这里插入图片描述
进行Debug仿真并用逻辑分析仪观察分析3个gpio输出
在这里插入图片描述
输出波形
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值