基于寄存器地址&标准外设库的LED流水灯

一、基础准备

1.创建keil工程,并添加相应文件

(1)首先创建一个自己的keil工程,选择芯片STM32F103C8系列,打开创建的文件夹,新建三个文件“Start,Library、User”,然后打开固件库,找到启动文件,先全部复制粘贴到Start文件夹下
在这里插入图片描述
继续在固件库里找到“stm32f10x.h”,“system_stm3210x.c”,“system_stm3210x.h”三个文件,复制粘贴到文件夹下;再找到“core_cm3.c”和“core_cm3.h”的两个文件,复制粘贴到Start文件夹下,Start文件夹配置完成。
在这里插入图片描述
找到标准外设驱动的文件夹,打开src,全部复制粘贴到Library文件夹下,然后打开inc,全部复制到Library文件下,Library文件夹配置完成。
在这里插入图片描述
最后打开Project,打开STM32F10x_StdPeriph_ Template的文件,选择其中的main、conf还有两个it文件,复制粘贴到User文件夹下
在这里插入图片描述
至此“Start”,“Library”和“User”文件全部添加完毕。
(2)在keil中,点击“Manage Project Items”,删除默认组,新建“Stsrt”,“Library”和“User”,选中“Start”,点击“Add Files”,添加之前添加到“Start”文件夹里面的文件,先添加后.md的文件,然后再添加.c和.h的文件。
在这里插入图片描述
在这里插入图片描述
选中“Library”,点击“Add Files”,添加之前添加到“Library”文件夹里面的文件
在这里插入图片描述
选中“User”,点击“Add Files”,添加之前添加到“User”文件夹里面的文件
在这里插入图片描述
至此,文件添加成功。
(3)在keil中点击魔术棒选项,打开C/C++,在include paths栏中把添加的文件夹路径添加进来。
在这里插入图片描述在“Define“”栏写上“USE_STDPERIPH_DRIVER”
在这里插入图片描述
在Debug”选项中,调试器选择“ST-Link Debugger”
在这里插入图片描述
点击“Flash Download”,勾选“Reset and Run”
在这里插入图片描述
至此,工程选项配置完成。

2.STM32串口的烧录方法

我们这里主要介绍STLink烧录。
(1)首先安装STLink驱动程序(可以使用CH430)
(2)将STLink插入电脑USB,检查电脑是否已识别到STLink,在设备管理器中查看是否有STM32 STLink
(3)打开keil,点开魔术棒,找到debug,点开settings,进行识别,出现如下画面,
在这里插入图片描述

3.寄存器和GPIO相关知识

1、寄存器
(1)功能:寄存器在STM32中起着至关重要的作用。通过操作寄存器,可以对GPIO端口的配置、控制外设的输入输出状态、读取外设的状态信息和数据、配置内核的运行模式和中断处理等。
(2)分类:STM32的寄存器主要分为内核寄存器和外设寄存器。内核寄存器包括程序计数器(PC)、堆栈指针(SP)、链接寄存器(LR)和控制寄存器(CONTROL)等,用于控制CPU的运行。外设寄存器则包括GPIO寄存器、USART寄存器、TIM定时器寄存器、ADC寄存器等,用于控制和配置外设的工作模式和参数。
2、GPIO
STM32中的GPIO是通用输入输出端口的简称。它是STM32控制器中的一种重要的数字输入输出接口,具有广泛的应用,是STM32可控制的引脚。这些引脚与外部设备连接起来,能够实现与外部通讯、控制以及数据采集的功能。
STM32的GPIO引脚可以配置为八种不同的工作模式,以下是这些模式的详细介绍:
(1)模拟输入(GPIO_Mode_AIN):此模式用于检测外部输入的模拟电压,可以检测电压值,只要不高于Vcc即可。通常用于ADC(模数转换器)的输入。
(2)浮空输入(GPIO_Mode_IN_FLOATING):此模式下GPIO引脚不连接到任何内部电阻,处于高阻抗状态,可以接收外部的高低电平信号。但这种模式下引脚易受干扰,常用于检测按键等。
(3)下拉输入(GPIO_Mode_IPD):此模式下GPIO引脚内部连接下拉电阻,检测到的电平默认为低,可以检测到由低到高的电平变化。
(4)上拉输入(GPIO_Mode_IPU):此模式下GPIO引脚内部连接上拉电阻,检测到的电平默认为高,可以检测到由高到低的电平变化。
(5)开漏输出(GPIO_Mode_Out_OD):开漏输出模式下,GPIO引脚只能输出低电平,要输出高电平需要通过外部上拉电阻或其他方式。常用于与外部器件连接,例如与开漏输出的I2C总线器件进行通信。
(6)推挽输出(GPIO_Mode_Out_PP):推挽输出模式是最常见的GPIO输出模式。在该模式下,引脚可以输出高电平或低电平,同时具有一定的驱动能力。
(7)复用开漏输出(GPIO_Mode_AF_OD):复用开漏输出模式允许将GPIO引脚用作特定外设功能,同时只能输出低电平,要输出高电平需要通过外部上拉电阻或其他方式。
(8)复用推挽输出(GPIO_Mode_AF_PP):复用推挽输出模式允许将GPIO引脚用作特定外设功能,具有推挽输出的特性,可以输出高电平或低电平,并具有一定的驱动能力。
这些模式通过配置GPIO的模式寄存器(GPIOx_MODER)、输出类型寄存器(GPIOx_OTYPER)、上拉/下拉寄存器(GPIOx_PUPDR)以及复用功能寄存器(AF寄存器)来实现。

二、基于寄存器地址实现LED流水灯

任务要求:以 STM32最小系统核心板(STM32F103C8T6)+面板板+3只_(或更多)红绿蓝LED 搭建电路,使用GPIOA/GPIOB/GPIOC端口控制LED灯,轮流闪烁,间隔时长1秒。

1.选定引脚

这里用的是A0,B9,C15三个引脚,然后需要通过查手册找的对应的GPIO口以及对应的寄存器地址,然后需要开启时钟,让时钟可以开始工作,再对gpio进行初始化以后,就可以进行读写操作,实现低电平点亮
在这里插入图片描述
在这里插入图片描述

2.用C语言寄存器方式编程实现

(1)实现函数封装

//函数封装

void LED_GPIO_Config(void)
{
    
  //打开gpio A端口的时钟
    *(unsigned int *)0x40021018 |=(1<<2);
    //打开gpio B端口的时钟
    *(unsigned int *)0x40021018 |=(1<<3);
    //打开gpio C端口的时钟
    *(unsigned int *)0x40021018 |=(1<<4);
    
    
    //设置推挽输出的速度
    *(unsigned int *)0x40010800 &=0xFFFFFFF0;//设置位 清零
    *(unsigned int *)0x40010800 |=0x00000002;//PA0推挽输出2MHz
    
    *(unsigned int *)0x40010C04 &=0xFFFFFF0F;//设置位清零
    *(unsigned int *)0x40010C04 |=0x00000020;//PB9推挽输出2MHz
    
    *(unsigned int *)0x40011004 &=0xFF0FFFFF;//设置位清零
    *(unsigned int *)0x40011004 |=0x20000000;//PC15推挽输出2MHz
    
    
    //设置GPIO输出端口的模式
    *(unsigned int *)0x40010800 &=0xFFFFFFF0;//设置位 清零
    *(unsigned int *)0x40010800 |=0x00000002;//PA0推挽输出
    
    *(unsigned int *)0x40010C04 &=0xFFFFFF0F;//设置位清零
    *(unsigned int *)0x40010C04 |=0x00000020;//PB9推挽输出
    
    *(unsigned int *)0x40011004 &=0xFF0FFFFF;//设置位清零
    *(unsigned int *)0x40011004 |=0x20000000;//PC15推挽输出

}

(2)设置LEDA、LEDB、LEDC闪烁函数

//LEDA、LEDB、LEDC闪烁函数
void LEDA_LIGHT(){
    *(unsigned int *)0x4001080C=0x0<<0;        //PA0低电平
    *(unsigned int *)0x40010C0C=0x1<<9;        //PB9高电平
    *(unsigned int *)0x4001100C=0x1<<15;        //PC15高电平
}
void LEDB_LIGHT(){
    *(unsigned int *)0x4001080C=0x1<<0;        //PA0高电平
    *(unsigned int *)0x40010C0C=0x0<<9;        //PB9低电平
    *(unsigned int *)0x4001100C=0x1<<15;        //PC15高电平
}
void LEDC_LIGHT(){
    *(unsigned int *)0x4001080C=0x1<<0;        //PA0高电平
    *(unsigned int *)0x40010C0C=0x1<<9;        //PB9高电平
    *(unsigned int *)0x4001100C=0x0<<15;    //PC15低电平    
}

(3)主函数部分

int main(void)
{
    /* LED 端口初始化 */
    LED_GPIO_Config();
    
    while(1)
    {
        LEDA_LIGHT();
        Delay_ms(1000);
        LEDB_LIGHT();
        Delay_ms(1000);
        LEDC_LIGHT();
        Delay_ms(1000);
        
    }
    
}

3.实验结果

在这里插入图片描述

4.验证烧录的代码

由于STM32最小系统核心板子出厂时已经焊接好了1个led灯(标注了PC13处),一般可通过此灯的点亮让编程者验证自己烧录的代码是否正常运行了,将这个灯也用在流水灯中,重新编写程序

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
    RCC->APB2ENR = 0x0000001C;
    /*RCC->APB2ENR = 0x0000001C;
    GPIOC->CRH = 0x300000;
    GPIOC->ODR = 0x00000000;//pc13灯亮
    Delay_ms(500);
    GPIOC->ODR = 0x00002000;//pc13灯灭
    Delay_ms(500);*/
    while(1)
    {
        RCC->APB2ENR = 0x0000001C;
    GPIOC->CRH = 0x00300000;
    GPIOC->ODR = 0x00000000;//pc13灯亮
    Delay_ms(500);
    GPIOC->ODR = 0x00002000;//pc13灯灭
    Delay_ms(500);
        
        GPIOA->CRL = 0x00000003;
        
        GPIOA->ODR = 0x00000001;
        Delay_ms(500);
        GPIOA->ODR = 0x00000000;
        Delay_ms(500);
        
        
        GPIOB->CRL = 0x00000003;
        
        GPIOB->ODR = 0x00000001;
        Delay_ms(500);
        GPIOB->ODR = 0x00000000;
        Delay_ms(500);
        
        
        
    }
    
}

实验结果
在这里插入图片描述

2.标准外设库的LED流水灯

(1)使用RCC开启GPIO的时钟

	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟

(2)使用GPIO_Init函数初始化GPIO

/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;					//定义结构体变量
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		//GPIO模式,赋值为推挽输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;				//GPIO引脚,赋值为所有引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//GPIO速度,赋值为50MHz
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将赋值后的构体变量传递给GPIO_Init函数
															//函数内部会自动根据结构体的参数配置相应寄存器
															//实现GPIOA的初始化

(3)使用输出或者输入的函数控制GPIO口,6个灯轮流闪烁,间隔1s

使用输出或者输入的函数控制GPIO口,6个灯轮流闪烁,间隔1s

/*主循环,循环体内的代码会一直循环执行*/
	while (1)
	{
		/*使用GPIO_Write,同时设置GPIOA所有引脚的高低电平,实现LED流水灯*/
		GPIO_Write(GPIOA, ~0x0001);	//0000 0000 0000 0001,PA0引脚为低电平,其他引脚均为高电平,注意数据有按位取反
		Delay_ms(1000);				//延时1000ms
		GPIO_Write(GPIOA, ~0x0002);	//0000 0000 0000 0010,PA1引脚为低电平,其他引脚均为高电平
		Delay_ms(1000);				//延时1000ms
		GPIO_Write(GPIOA, ~0x0004);	//0000 0000 0000 0100,PA2引脚为低电平,其他引脚均为高电平
		Delay_ms(1000);				//延时1000ms
		GPIO_Write(GPIOA, ~0x0008);	//0000 0000 0000 1000,PA3引脚为低电平,其他引脚均为高电平
		Delay_ms(1000);				//延时1000ms
		GPIO_Write(GPIOA, ~0x0010);	//0000 0000 0001 0000,PA4引脚为低电平,其他引脚均为高电平
		Delay_ms(1000);				//延时1000ms
		GPIO_Write(GPIOA, ~0x0020);	//0000 0000 0010 0000,PA5引脚为低电平,其他引脚均为高电平
		Delay_ms(1000);				//延时1000ms
		GPIO_Write(GPIOA, ~0x0040);	//0000 0000 0100 0000,PA6引脚为低电平,其他引脚均为高电平
		Delay_ms(1000);				//延时1000ms
		GPIO_Write(GPIOA, ~0x0080);	//0000 0000 1000 0000,PA7引脚为低电平,其他引脚均为高电平
		Delay_ms(1000);				//延时1000ms
	}
}

(4)实验结果

在这里插入图片描述

三、使用Keil的软件仿真逻辑分析仪观察GPIO端口的输出波形

任务要求:使用Keil的软件仿真逻辑分析仪功能,观察GPIO端口的输出波形,并分析时序状态正确与否、高低电平转换周期(LED闪烁周期)实际为多少。

1、操作准备

点击魔术棒,进入Debug配置,选中Use Simulator,并修改Dialog DLL和Parameter
在这里插入图片描述
点击“Start Debug Session”,开始仿真
点击“Logic Analyzer”,添加端口引脚
在这里插入图片描述
修改“Display Type”为“Bit”

2、波形输出

点击“Run”,得到输出波形
在这里插入图片描述
在这里插入图片描述
计算出LED低电平周期约为0.667

计算LED高电平周期
输出波形如下
在这里插入图片描述
在这里插入图片描述
计算得出高电平持续时间约为4.667s

四、实验相关知识原理总结

1. STM32 GPIO编程

STM32的GPIO编程涉及到对GPIO端口的配置,包括模式设置、速度设置等。STM32提供了两种主要的编程方式:寄存器直接操作和库函数操作
寄存器直接操作:这种方式需要开发者直接对GPIO相关的寄存器进行配置,包括模式寄存器(CRL和CRH)、输出类型寄存器(OTYPER)、输出速度寄存器(OSPEEDR)、上下拉寄存器(PUPDR)和输出数据寄存器(ODR)。这种方式效率较高,但需要对STM32的寄存器有深入的了解,代码移植性较差。
库函数操作:STM32的标准外设库提供了一系列的函数,用于简化GPIO的配置和操作。这种方式通过结构体和函数调用来配置GPIO,提高了代码的可读性和移植性,但可能会牺牲一些执行速度。

2. 寄存器与库函数编程

寄存器编程:直接操作硬件寄存器,这种方式更接近硬件,执行效率高,但代码复杂,移植性差,对开发者的硬件知识要求高。
库函数编程:STM32库函数是对寄存器操作的封装,提供了更高层次的抽象,使得代码更加简洁、易于理解和维护。库函数通过宏定义和枚举常量来代表寄存器的各个位,简化了编程过程。

五、总结

本篇文章主要介绍了STM32的一些基础知识,包括基本的开发步骤以及如何熟悉和使用Keil软件。在实验中,我们通过两种方式(寄存器方式和标准库方式)进行了点亮流水灯的操作,帮助我们加深了对STM32开发过程的理解。
通过实际操作,我们可以发现寄存器方式虽然能提供更高的执行效率,但由于需要直接操作硬件寄存器,开发难度较大,且要求开发者对硬件的工作原理有深入的了解,因此在实际开发中,更多人选择使用标准库方式。标准库方式通过封装硬件细节,简化了开发过程,虽然执行效率略低,但代码更易于理解和维护,适合大部分初学者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值