IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32F103寄存器方式点亮LED流水灯 -> 正文阅读

[嵌入式]STM32F103寄存器方式点亮LED流水灯


一、实验要求


1、学习和理解STM32F103系列芯片的地址映射和寄存器映射原理;了解GPIO端口的初始化设置三步骤(时钟配置、输入输出模式设置、最大速率设置)。

2、以 STM32最小系统核心板(STM32F103C8T6)+面板板+3只红绿蓝LED 搭建电路,使用GPIOB、GPIOC、GPIOD这3个端口控制LED灯,轮流闪烁,间隔时长1秒。
1)写出程序设计思路,包括GPIOx端口的各寄存器地址和详细参数
2)分别用汇编语言,C语言编程实现。


二、实验过程及结果


(一)任务1

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

在这里插入图片描述
1)地址映射
地址映射,也被称为存储器映射。存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程称为存储器映射,如果再分配一个地址就叫重映射。
在这里插入图片描述
ARM 将 4GB 的存储器空间,平均分成 8 块区域,每块区域的大小是 512MB,STM32 芯片只用其中一部分。ARM 对 4GB 容量分块是按照其功能划分,每块都有特殊的用途。
在这里插入图片描述
在 8 个 Block 里面,Block0、Block1 和 Block2包含了 STM32 芯片的内部 Flash、RAM 和片上外设。

存储器 Block0 内部区域功能划分

Block0 主要用于设计片内的 FLASH,STM32F103 系列芯片内部 FLASH 最大是 512KB。在芯片内部集成更大的 FLASH 或者 SRAM ,意味着芯片成本的增加,所以片内集成的FLASH 都不会太大。
在这里插入图片描述
存储器Block1内部区域功能划分

Block1用于设计片内的SRAM。
在这里插入图片描述
存储器Block2内部区域功能划分

Block2 用于设计片内外设,根据外设总线速度的不同,Block2 被划分为 AHB 和 APB 两部分,APB 又被分成 APB1 和 APB2 总线。
在这里插入图片描述
Block3/4/5中包含了FSMC扩展区域,可用于扩展外部存储器,比如 SRAM,NORFLASH 和 NANDFLASH 等。

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

2、GPIO端口的初始化设置

在这里插入图片描述
1)时钟
STM32的时钟是由内部或外部振荡器产生的“频率”,被称为“系统时钟”。最大为72MHz,换成周期T约为13.9ns。

2)GPIO工作模式

在这里插入图片描述

GPIO_Mode_AIN           模拟输入(应用ADC模拟输入,或者低功耗下省电)
GPIO_Mode_IN_FLOATING   浮空输入(浮空就是浮在半空,可以被其他物体拉上或者拉下,可以用于按键输入)
GPIO_Mode_IPD           下拉输入(IO内部下拉电阻输入)
GPIO_Mode_IPU           上拉输入(IO内部上拉电阻输入)
GPIO_Mode_Out_OD        开漏输出(开漏输出:输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行)
GPIO_Mode_Out_PP        推挽输出(推挽就是有推有拉电平都是确定的,不需要上拉和下拉,IO输出0-接GND, IO输出1 -接VCC,读输入值是未知的 )
GPIO_Mode_AF_OD         复用开漏输出(片内外设功能(I2C的SCL,SDA))
GPIO_Mode_AF_PP         复用推挽输出(片内外设功能TX1,MOSI,MISO.SCK.SS)

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

对于单个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); //输出高

(二)任务2

1、STM32F103C8T6芯片

在这里插入图片描述
核心板原理图:

在这里插入图片描述

2、寄存器详情

查看寄存器组起始地址表,发现:RCC地址范围、寄存器地址范围。

在这里插入图片描述

寄存器地址:端口起始地址+偏移地址

1)时钟

在这里插入图片描述
2)GPIOx端口
端口配置寄存器有两个,分别为端口配置低寄存器(CRL)和端口配置高寄存器(CRH),每四位配置一个端口。

在这里插入图片描述
在这里插入图片描述
端口输出寄存器(ORD)在相应的位赋值可以控制输出电压,0为低电压,1为高电压。

在这里插入图片描述

3、流水灯原理

将 GPIO 的引脚设置成推挽输出模式并且默认下拉,输出低电平, LED灯点亮。

4、C语言编程

1)源码

LED.c程序:

#include "stm32f10x.h"

#define RCC_APB2ENR	*((unsigned volatile int*)0x40021018)//APB2使能时钟寄存器

#define GPIOA_CRL	*((unsigned volatile int*)0x40010800)//GPIOA配置寄存器 
#define	GPIOA_ODR	*((unsigned volatile int*)0x4001080C)

#define GPIOB_CRH	*((unsigned volatile int*)0x40010C04)//GPIOB配置寄存器
#define	GPIOB_ODR	*((unsigned volatile int*)0x40010C0C)

#define GPIOC_CRH	*((unsigned volatile int*)0x40011004)//GPIOC配置寄存器
#define	GPIOC_ODR	*((unsigned volatile int*)0x4001100C)

void Delay(volatile unsigned int);

void Delay(volatile unsigned int t)//延时函数
{
     unsigned int i;
     while(t--)
         for(i=0;i<800;i++);
}

int main(void)
{	
	RCC_APB2ENR|=1<<2|1<<3|1<<4; //APB2-GPIOA、GPIOB、GPIOC外设时钟使能	
	
	GPIOA_CRL&=0x0FFFFFFF;		//设置位 清零	
	GPIOA_CRL|=0x20000000;		//PA7推挽输出:0010
	GPIOA_ODR|=(1<<7);			//设置初始灯 灭
	
	GPIOB_CRH&=0xFFFFFF0F;		//设置位 清零	
	GPIOB_CRH|=0x00000020;		//PB9推挽输出:0010
	GPIOB_ODR|=(1<<9);			//设置初始灯 灭
	 
	GPIOC_CRH&=0x0FFFFFFF;		//设置位 清零	
	GPIOC_CRH|=0x20000000;		//PC15推挽输出:0010
	GPIOC_ODR|=(1<<15);		    //设置初始灯 灭		

	while(1)
	{
	    GPIOA_ODR&=~(1<<7);		//PA7亮灯,低电平:置0,按位与
	 	Delay(1000000);
		GPIOA_ODR|=1<<7;		//PA7高电平

        GPIOB_ODR&=~(1<<9);		//PB9亮灯,低电平:置0,按位与
        Delay(1000000);
		GPIOB_ODR|=1<<9;		//PB9高电平

		GPIOC_ODR&=~(1<<15);	//PC15亮灯,低电平:置0,按位与
	    Delay(1000000);
		GPIOC_ODR|=1<<15;		//PC15高电平
	}
}

2)步骤

① 项目创建
点击 Project ——> Open Project,打开之前实验“STM32汇编语言编程与仿真调试”创建的工程。

配置环境如下:
 工程的目标环境设置为STM32F103C8;
 CMSIS下选择CORE,Device下选择Startup;
 Output 中勾选 Create HEX File 生成 hex 文件;
 Debug中选择“Use Simulator”,设置Dialog DLL项为“DARMSTM.DLL”,parameter项为“-pSTM32F103C8”。

在这里插入图片描述
右击 Source Group 1 ,点击 Add New Item to Group;点击 C Flie(.c)创建C语言文件LED.c。

在这里插入图片描述
② 编译调试
编译程序:

在这里插入图片描述
设置示波器:

在这里插入图片描述
观察波形图:

在这里插入图片描述
③ 硬件操作
使用USB-TTL直接进行串口下载,将USB-TTL的GND和3.3V接入STM32最新系统板的GND和3.3V,然后TXD和RXD分别接入A10和A9引脚。
在这里插入图片描述
接入后按照程序中GPIOx的引脚接上LED灯,将LED灯+极接入3.3V的电压,且最小核心板要利用跳线帽实现boot0置1,boot1置0。

在这里插入图片描述
安装 USB 转串口驱动—CH340 版本。

在这里插入图片描述
打开 mcuisp 软件,开始烧录。

配置如下:
搜索串口,设置波特率 115200(尽量不要设置太高) 
选择要下载的HEX文件 
校验、编程后执行DTR低电平复位,RTS高电平进入bootloader 
开始编程,如果出现一直连接的情况,按一下开发板的复位键RESET

在这里插入图片描述

5、汇编语言编程

LED.s程序:

RCC_APB2ENR EQU 0x40021018;配置RCC寄存器,时钟,0x40021018为时钟地址

GPIOB_BASE EQU 0x40010C00
GPIOC_BASE EQU 0x40011000
GPIOA_BASE EQU 0x40010800
	
GPIOB_CRL EQU 0x40010C00
GPIOC_CRH EQU 0x40011004
GPIOA_CRL EQU 0x40010800
	
GPIOB_ODR EQU 0x40010C0C
GPIOC_ODR EQU 0x4001100C
GPIOA_ODR EQU 0x4001080C

Stack_Size EQU  0x00000400;栈的大小
	
                AREA    STACK, NOINIT, READWRITE, ALIGN=3 
                ;NOINIT: = NO Init,不初始化。READWRITE : 可读,可写。ALIGN =3 : 2^3 对齐,即8字节对齐。
                
Stack_Mem       SPACE   Stack_Size
__initial_sp

                AREA    RESET, DATA, READONLY

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                    
                    
                AREA    |.text|, CODE, READONLY
                    
                THUMB
                REQUIRE8
                PRESERVE8
                    
                ENTRY
Reset_Handler 
				bl LED_Init;bl:带链接的跳转指令。当使用该指令跳转时,当前地址(PC)会自动送入LR寄存器
				
MainLoop        BL LED_ON_C
                BL Delay
                BL LED_OFF_C
                BL Delay
				BL LED_ON_A
                BL Delay
                BL LED_OFF_A
                BL Delay
				BL LED_ON_B
                BL Delay
                BL LED_OFF_B
                BL Delay
                
                B MainLoop;B:无条件跳转。
LED_Init;LED初始化
                PUSH {R0,R1, LR};R0,R1,LR中的值放入堆栈
                ;控制时钟
                LDR R0,=RCC_APB2ENR;LDR是把地址装载到寄存器中(比如R0)。
                ORR R0,R0,#0x1c
                LDR R1,=RCC_APB2ENR
                STR R0,[R1]
				
				
                ;初始化GPIOA_CRL
                LDR R0,=GPIOA_CRL
                BIC R0,R0,#0x0fffffff;BIC 先把立即数取反,再按位与
                LDR R1,=GPIOA_CRL
                STR R0,[R1]
				
                LDR R0,=GPIOA_CRL
                ORR R0,#0x00000001
                LDR R1,=GPIOA_CRL
                STR R0,[R1]
                ;将PA0置1
                MOV R0,#0x01
                LDR R1,=GPIOA_ORD
                STR R0,[R1]
				
				
                ;初始化GPIOB_CRL
                LDR R0,=GPIOB_CRL
                BIC R0,R0,#0x0fffffff;BIC 先把立即数取反,再按位与
                LDR R1,=GPIOB_CRL
                STR R0,[R1]
				
                LDR R0,=GPIOB_CRL
                ORR R0,#0x00000001
                LDR R1,=GPIOB_CRL
                STR R0,[R1]
                ;将PB0置1
                MOV R0,#0x01
                LDR R1,=GPIOA_ORD
                STR R0,[R1]
				
				
				 ;初始化GPIOC
                LDR R0,=GPIOC_CRH
                BIC R0,R0,#0x0fffffff
                LDR R1,=GPIOC_CRH
                STR R0,[R1]
				
                LDR R0,=GPIOC_CRH
                ORR R0,#0x01000000
                LDR R1,=GPIOC_CRH
                STR R0,[R1]
                ;将PC15置1
                MOV R0,#0x8000
                LDR R1,=GPIOC_ORD
                STR R0,[R1]
             
                POP {R0,R1,PC};将栈中之前存的R0,R1,LR的值返还给R0,R1,PC
LED_ON_A
                PUSH {R0,R1, LR}    
                
                MOV R0,#0x00
                LDR R1,=GPIOA_ORD 
                STR R0,[R1]
             
                POP {R0,R1,PC}
             
LED_OFF_A
                PUSH {R0,R1, LR}    
                
                MOV R0,#0x01
                LDR R1,=GPIOA_ORD 
                STR R0,[R1]
             
                POP {R0,R1,PC}  
LED_ON_B;亮灯
                PUSH {R0,R1, LR}    
                
                MOV R0,#0x00
                LDR R1,=GPIOB_ORD
                STR R0,[R1]
             
                POP {R0,R1,PC}
             
LED_OFF_B;熄灯
                PUSH {R0,R1, LR}    
                
                MOV R0,#0x01
                LDR R1,=GPIOB_ORD
                STR R0,[R1]
             
                POP {R0,R1,PC}  
LED_ON_C;亮灯
                PUSH {R0,R1, LR}    
                
                MOV R0,#0x00
                LDR R1,=GPIOC_ORD
                STR R0,[R1]
             
                POP {R0,R1,PC}
             
LED_OFF_C;熄灯
                PUSH {R0,R1, LR}    
                
                MOV R0,#0x0100
                LDR R1,=GPIOC_ORD
                STR R0,[R1]
             
                POP {R0,R1,PC}             
             
Delay
                PUSH {R0,R1, LR}
                
                MOVS R0,#0
                MOVS R1,#0
                MOVS R2,#0
                
DelayLoop0        
                ADDS R0,R0,#1

                CMP R0,#330
                BCC DelayLoop0
                
                MOVS R0,#0
                ADDS R1,R1,#1
                CMP R1,#330
                BCC DelayLoop0

                MOVS R0,#0
                MOVS R1,#0
                ADDS R2,R2,#1
                CMP R2,#15
                BCC DelayLoop0
                
                
                POP {R0,R1,PC}    
                NOP
                
				END

硬件操作过程同C语言编程时相同。

6、实际效果

stm32流水灯


三、实验总结


通过完成本次STM32F103寄存器方式点亮LED流水灯实验,我了解了STM32F103系列芯片的地址映射和寄存器映射原理,更加深入地学习了GPIOx端口寄存器和GPIO端口初始化设置的知识,进一步知晓了stm32系列开发板和面包板等硬件的连接方式。在本次实验操作的过程中,我深刻认识到仿真操作和硬件操作存在着很大的区别,使用硬件操作不仅能学到更多与硬件相关的基础知识,同时还能锻炼我的动手操作能力。总而言之,硬件操作与仿真操作相结合的实验方式让我受益匪浅。


四、参考资料


1、零死角玩转STM32—F103指南者.pdf
2、STM32F10xxx参考手册.pdf
3、3 . 存储器映射 和 寄存器映射
4、STM32入门-GPIO初始化步骤
5、STM32寄存器点亮流水灯的三种方法
6、STM32F103寄存器方式点亮LED流水灯

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-23 12:39:15  更:2021-10-23 12:40:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:32:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码