stm32实现流水灯-----寄存器


前言

在stm32的开发过程中,使用寄存器的方式自己去配置、去开发是开发效率十分低的方式,因为stm32的寄存器实在是太多了,现在都是使用hal库或者固件库开发stm32,在最大程度上提高了我们的开发效率和周期。当然,作为新手我们也应该尝试用寄存器开发,了解其开发基本流程和步骤,也有助于我们后面使用库开发的学习。


一、stm32的系统架构

stm32是已经封装好的成品,主要是由内核和片上的外设所组成。下面给一张stm32的系统结构图,通过这张图我们可以看到各个外设挂载在哪个总线上,以及stm32的运作流程。

在这里插入图片描述
1、五个驱动单元

  • Cortex™-M3内核DCode总线(D-bus),和系统总线(S-bus)
  • 通用DMA1和通用DMA2
  • 以太网DMA

2、三个被动单元

  • 内部SRAM
  • 内部闪存存储器
  • AHB到APB的桥(AHB2APBx),它所连接的所有的APB设备

二、什么是寄存器

1、寄存器的映射

在存储器Block2的这块区域,设计的是片上外设,它们以四个字节为一个单元,总共32bit,每个单元对应不同的功能, 当我们控制这些单元就可以驱动相应的外设进行工作。我们可以找到每个单元的起始地址,通过指针的方式来访问这些单元。我们可以根据每个单元功能的不同,给这个单元取一个别名,这个给已分配好的地址的有特定功能的内存单元取名的过程就是寄存器的映射

2、什么是寄存器

通过上诉的讲解我们已经了解了寄存器的映射。那么什么是寄存器呢?其实给特定单元取的别名就是寄存器,寄存器只是特定功能的单元的名字罢了,操作寄存器可以驱动相应外设进行工作

3、stm32的外设地址映射

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

在这里插入图片描述

下图列出了stm32F10系列中内置外设的起始地址,通过这张图我们也可以知道每条总线的基地址和外设的基地址

在这里插入图片描述

三、新建工程

  • new prj
    在这里插入图片描述
  • 选择芯片型号
    在这里插入图片描述
  • CORE勾上,点击ok
    在这里插入图片描述
  • 右击Target,点击Manage…
    在这里插入图片描述
  • 添加一个Startup来放启动文件,Code来放用户代码
    在这里插入图片描述
  • 在Code文件下添加一个.c文件和.h文件
    在这里插入图片描述

四、代码的编写

通过查看数据手册发现所有的GPIO外设都是挂载在APB2总线下的,通过查询数据手册可以知道相应寄存器的基地址和偏移地址,给不同寄存器取别名,提高程序的可读性和可移植性。

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

将GPIO端口配置为通用推挽输出模式,2MHZ

在这里插入图片描述

#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();
	}
	
}

五、软件仿真、逻辑分析仪分析

  • 对keil软件的一些默认配置进行修改
    在这里插入图片描述
  • 进行Debug仿真并用逻辑分析仪观察分析3个gpio输出
    在这里插入图片描述
  • 观察结果,输出波形
    在这里插入图片描述
    观察上面的波形可知,已经实现了一个流水灯的功能!

总结

通过学习stm32寄存器实现流水灯的实验,大致了解了单片机开发的流程,开时钟,配置相应寄存器单元,后面库函数的学习也是差不多的,只是它的寄存器的配置它封装成了一个函数,使操作更加的简单,使开发效率得到大幅度提高。

猜你喜欢

转载自blog.csdn.net/wer4567/article/details/127227743