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流水灯

目录

一、stm32芯片寄存器及IO口简介

二、硬件设计

2.1 IO口选择

?2.2 其余硬件

2.3 连线

三、软件设计

3.1 配置寄存器

3.2 主函数编写

3.3 程序的烧录

3.4 成果展示

四、汇编实现流水灯

五、参考文献


? 本篇博客将介绍如何使用STM32F103系列芯片以寄存器的方式点亮LED流水灯,文章内容包括芯片IO口和寄存器的使用、硬件设计、软件设计、仿真与下载。希望本篇文章能够帮助你。

一、stm32芯片寄存器及IO口简介

注:本博客使用的芯片为正点原子STM32F103RC芯片,不同的32芯片在细节上也许会有不同之处。

? ?  本博客将要实现的是控制STM32开发板上的三个IO口实现一个类似流水灯的效果,该实验的关键在于如何控制STM32的IO口输出。了解了STM32的IO口如何输出的,就可以实现流水灯了。

  STM32 的 IO 口可以由软件配置成如下 8 种模式:

  1、输入浮空

  2、输入上拉

  3、输入下拉

  4、模拟输入

  5、开漏输出

  6、推挽输出

  7、推挽式复用功能

  8、开漏复用功能

  STM32的每个IO端口都有7个寄存器来控制。他们分别是:配置模式的2个32位的端口配置寄存器CRL和CRH;2个32位的数据寄存器 IDR 和 ODR;1个32位的置位/复位寄存器BSRR;一个16位的复位寄存器BRR;1个32位的锁存寄存器LCKR;这里我们仅介绍常用的几个寄存器,我们常用的IO端口寄存器只有4个:CRL、CRH、IDR、ODR

  其中CRLCRH控制着每个IO口的模式及输出速率。

 STM32 的 IO 口位配置表如表

 STM32 输出模式配置如表?

? 接下来我们看看端口低配置寄存器 CRL 的描述 

? ? 该寄存器的复位值为0X4444 4444,从上图可以看到,复位值其实就是配置端口为浮空输入模式。从上图还可以得出:STM32 的CRL控制着每组IO端口(A~G)的低8位的模式。 每个IO端口的位占用CRL的 4 个位,高两位为CNF,低两位为MODE。这里我们可以记住几个常用的配置,比如0X0表示模拟输入模式(ADC 用)、0X3表示推挽输出模式(做输出口用,50M速率)、0X8表示上/下拉输入模式(做输入口用)、0XB表示复用输出(使用IO口的第二功能,50M速率)。

? ?CRH的作用和CRL完全一样,只是CRL控制的是低8位输出口,而CRH控制的是高8位输出口。这里我们对CRH就不做详细介绍了。

? ?给个实例,比如我们要设置PORTA的8位为上拉输入,13位为复用输出。代码如下:

GPIOA->CRH&=0XFF0FFFF0; //清掉这 2 个位原来的设置,同时也不影响其他位的设置
GPIOA->CRH|=0X00B00008;  //PA8输入,PA13输出
GPIOA->ODR=1<<8;  //PA8 上拉

? ? 通过这3句话的配置,我们就设置了PA8为上拉输入,PA13复用输出。

? ?IDR是一个端口输入数据寄存器,只用了低16位。该寄存器为只读寄存器,并且只能以16位的形式读出。该寄存器各位的描述如图所示:

? ?要想知道某个IO口的状态,你只要读这个寄存器,再看某个位的状态就可以了。使用起来是比较简单的。

? ?ODR是一个端口输出数据寄存器,也只用了低16位。该寄存器为可读写,从该寄存器读出来的数据可以用于判断当前IO口的输出状态。而向该寄存器写数据,则可以控制某个IO口的输出电平。该寄存器的各位描述如图所示:

??

? ?了解了这几个寄存器,我们就可以开始流水灯实验的真正设计了。?

二、硬件设计

2.1 IO口选择

? ?本篇博客将分别使用GPIOB、GPIOC、GPIOD这3个端口控制LED灯,在stm32手册中我们选择PB6、PC6、PD2这三个IO口来作为本次实验的输出口。

?2.2 其余硬件

? ?除了选择三个IO口,我们还需要准备好红黄绿三色LED灯,导线若干,以及面包板一块。

? ??

2.3 连线

? ?连线方面,LED灯的短脚连接IO口,长脚连接3.3V(注:尽量不要连接5V的端口,5V的端口没有电阻保护,容易烧坏LED灯)

? ?在实际连线中,我们为了能更好的连线,常使用面包板来方便连线,本次实验的连线结果如下图所示:

三、软件设计

3.1 配置寄存器

? ?对于程序的设计,我们首先需要将LED灯需要用到的IO口进行配置,这里我们采用的配置方法是使用寄存器。通过配置寄存器的值,来改变IO口的值进行变化。

led.h

#ifndef __LED_H
#define __LED_H	 
#include "sys.h"
   
//LED端口定义
#define LED0 BIT_ADDR(GPIOB_ODR_Addr,6)   // PB6输出
#define LED1 BIT_ADDR(GPIOC_ODR_Addr,6)	  // PC6输出
#define LED2 BIT_ADDR(GPIOD_ODR_Addr,2)	  // PD2输出

void LED_Init(void);	//初始化		 				    
#endif

led.c?

#include "sys.h"   
#include "led.h"

//初始化PB6、PC6和PD2为输出口,并使能这3个口的时钟
//LEDIO初始化
void LED_Init(void)
{
	RCC->APB2ENR|=1<<3;    //使能PORTB时钟
	RCC->APB2ENR|=1<<4;    //使能PORTC时钟
	RCC->APB2ENR|=1<<5;    //使能PORTD时钟
	
	GPIOB->CRL&=0XF0FFFFFF; //PB6清零
	GPIOB->CRL|=0X03000000; //PB6推挽输出  	 
    GPIOB->ODR|=1<<6;       //PB6输出高
	
	GPIOC->CRL&=0XF0FFFFFF; //PC6清零
	GPIOC->CRL|=0X03000000; //PC6推挽输出
	GPIOC->ODR|=1<<6;      //PC6输出高
	
	GPIOD->CRL&=0XFFFFF0FF; //PD2清零
	GPIOD->CRL|=0X00000300;//PD2推挽输出	 
    GPIOD->ODR|=1<<2;      //PD2输出高
											  
}

3.2 主函数编写

? ? 对于主函数的编写,我们首先需要编写一个简单的延时函数delay,控制LED轮流电亮。在主函数中,我们用一个while死循环保证三个LED灯可以一直轮流交替亮。对于如何控制LED灯的亮灭,我们用到的是BIT_ADDR(GPIOX_ODR_Addr,n)函数来控制输出口的电平,从而达到控制LED的亮灭的功能。

test.c

#include "sys.h"		
#include "led.h" 

void delay(unsigned int i)   //简单延时函数
{
	unsigned char j;               
	unsigned char k;
	for(;i>0;i--)
		for(j=500; j>0; j--) 
	       for(k =200; k>0; k--);
}

int main(void)
{		 

	LED_Init();		  	 	//初始化与LED连接的硬件接口   
	while(1)
	{
		
		LED0=0;  //灯亮
		LED1=1;  //灯灭
		LED2=1;
		delay(20);  //延时
		LED0=1;
		LED1=0;
		LED2=1;
		delay(20);
	    LED0=1;
		LED1=1;
		LED2=0;
		delay(20);
		
	}	 
}

3.3 程序的烧录

? ?烧录程序的软件我使用的是FlyMcu,还有另一种软件mcuisp也可以完成烧录功能,大家可以任选其一。

? ?在烧录之前,我们要先选择串口,我这里的串口为COM3. 之后我们选择的DTR的低电平复位,RTS高电平进BootLoader,这个选择项选中,flymcu就会通过DTR和RTS信号来控制板载的一键下载功能电路,以实现一键下载功能。如果不选择,则无法实现一键下载功能。

? ?串口波特率则可以通过bps那里设置,对于STM32F103,可以设置为最高:460800,而如果是 F4,则建议最高设置为:76800 即可。

? ?配置完成后点击开始编程,程序就会自动烧录进板子中,成功烧录后,就会显示下图右方的文字。

3.4 成果展示

四、汇编实现流水灯

代码部分为:

RCC_APB2ENR EQU 0x40021018
 
GPIOA_CRH EQU   0x40010804
GPIOA_ODR EQU   0x4001080C
                                    
GPIOB_CRL EQU   0x40010C00    ;寄存器映射
GPIOB_ODR EQU   0x40010C0C	
	
GPIOC_CRH EQU   0x40011004
GPIOC_ODR EQU   0x4001100C	
	
	
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               
                DCD     Reset_Handler              
                    
                    
                AREA    |.text|, CODE, READONLY
                    
                THUMB
                REQUIRE8
                PRESERVE8
                    
                ENTRY
Reset_Handler 
		
                
MainLoop		BL LED2_Init
                BL LED2_ON
                BL Delay             ;LED2灯闪烁
                BL LED2_OFF
                BL Delay
				
				BL LED1_Init				
				BL LED1_ON
                BL Delay             ;LED1灯闪烁
                BL LED1_OFF
                BL Delay
				
                BL LED3_Init				
				BL LED3_ON
                BL Delay            ;LED3灯闪烁
                BL LED3_OFF
                BL Delay
				
                B MainLoop
				
             
LED1_Init
                PUSH {R0,R1, LR}        ;R0,R1,LR中的值放入堆栈
                
                LDR R0,=RCC_APB2ENR      ;LDR是把地址装载到寄存器中(比如R0)。
                ORR R0,R0,#0x08         ;开启端口GPIOB的时钟,ORR 按位或操作,01000将R0的第二位置1,其他位不变		
                LDR R1,=RCC_APB2ENR
                STR R0,[R1]             ;STR是把值存储到寄存器所指的地址中,将r0里存储的值给rcc寄存器
				;上面一部分汇编代码是控制时钟的
                
                
                LDR R0,=GPIOB_CRL
                ORR R0,R0,#0X00000020   ;GPIOB_Pin_1配置为通用推挽输出;开启的是pb1,所以是2,为0010,是推挽输出模式,最大速度为2mhz
                LDR R1,=GPIOB_CRL
                STR R0,[R1]
                
                LDR R0,=GPIOB_ODR   
                BIC R0,R0,#0X00000002      ;BIC 先把立即数取反,再按位与
                LDR R1,=GPIOB_ODR          ;GPIOB_Pin_1输出为0;由r1控制ord寄存器
                STR R0,[R1]                 ;将ord寄存器的值变为r0的值
             
                POP {R0,R1,PC}             ;将栈中之前存的R0,R1,LR的值返还给R0,R1,PC
 
 
             
LED1_OFF
                PUSH {R0,R1, LR}    
                
                LDR R0,=GPIOB_ODR
                BIC R0,R0,#0X00000002    ;因为是PB1所以对应二进制0010;GPIOB_Pin_1输出为0,LED1熄灭
			    LDR R1,=GPIOB_ODR
                STR R0,[R1]
             
                POP {R0,R1,PC}
             
LED1_ON
                PUSH {R0,R1, LR}    
                
                 LDR R0,=GPIOB_ODR
                ORR R0,R0,#0X00000002    ;GPIOB_Pin_1输出为1,LED1亮
                 LDR R1,=GPIOB_ODR
                STR R0,[R1]
                POP {R0,R1,PC}           
 
 
				
 
LED2_Init
                PUSH {R0,R1, LR};R0,R1,LR中的值放入堆栈
                
                LDR R0,=RCC_APB2ENR
                ORR R0,R0,#0x04		   ;打开GPIOA的时钟
                LDR R1,=RCC_APB2ENR
                STR R0,[R1]                
                
                LDR R0,=GPIOA_CRH
                ORR R0,R0,#0X00020000   ;GPIOA_Pin_12配置为通用推挽输出
                LDR R1,=GPIOA_CRH
                STR R0,[R1]
                
                LDR R0,=GPIOA_ODR
                BIC R0,R0,#0X00001000   
                LDR R1,=GPIOA_ODR            ;GPIOA_Pin_12输出为0
                STR R0,[R1]
             
                POP {R0,R1,PC}
				
LED2_OFF
                PUSH {R0,R1, LR}   
                
               LDR R0,=GPIOA_ODR
               BIC R0,R0,#0X00001000        ;GPIOA_Pin_12输出为0,LED2熄灭
			    LDR R1,=GPIOA_ODR
                STR R0,[R1]
             
                POP {R0,R1,PC}
             
LED2_ON
                PUSH {R0,R1, LR}    
                
                LDR R0,=GPIOA_ODR
                ORR R0,R0,#0X00001000     ;GPIOA_Pin_12输出为1,LED2亮
				 LDR R1,=GPIOA_ODR
                STR R0,[R1]
				
				 POP {R0,R1,PC}
				 
 
LED3_Init
                PUSH {R0,R1, LR}
                
                LDR R0,=RCC_APB2ENR
                ORR R0,R0,#0x10		    ;打开GPIOC的时钟
                LDR R1,=RCC_APB2ENR
                STR R0,[R1]                
                
                LDR R0,=GPIOC_CRH
                ORR R0,R0,#0X02000000   ;GPIOC_Pin_14配置为通用推挽输出
                LDR R1,=GPIOC_CRH
                STR R0,[R1]
                
                LDR R0,=GPIOC_ODR
                BIC R0,R0,#0X00004000   ;GPIOC_Pin_14输出为0
                LDR R1,=GPIOC_ODR
                STR R0,[R1]
             
                POP {R0,R1,PC}
             
LED3_OFF
                PUSH {R0,R1, LR}    
                
                LDR R0,=GPIOC_ODR
                BIC R0,R0,#0X00004000  ;GPIOC_Pin_14输出为0,LED3熄灭
			    LDR R1,=GPIOC_ODR
                STR R0,[R1]
             
                POP {R0,R1,PC}
             
LED3_ON
                PUSH {R0,R1, LR}    
                
                 LDR R0,=GPIOC_ODR
                ORR R0,R0,#0X00004000   ;GPIOC_Pin_14输出为1,LED3亮
                 LDR R1,=GPIOC_ODR
                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,#300
                BCC DelayLoop0
                
                MOVS R0,#0
                ADDS R1,R1,#1
                CMP R1,#300
                BCC DelayLoop0
 
                MOVS R0,#0
                MOVS R1,#0
                ADDS R2,R2,#1
                CMP R2,#15
                BCC DelayLoop0
                
                POP {R0,R1,PC}    
 
                END

编译部分可以直接编译不用再进行其他设置。

烧录方法同上,最后结果就如下所示:

五、参考文献

STM32寄存器的简介、地址查找,与直接操作寄存器_geekYatao-CSDN博客_stm32寄存器什么是寄存器提到单片机,就不得不提到寄存器。根据百度百科介绍,寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。  简单来说,寄存器就是存放东西的东西。从名字来看,跟火车站寄存行李的地方好像是有关系的。只不过火车站行李寄存处,存放的行李;寄存器可能存放的是指令、数据或地址。  存放数据的寄存器是最好理解的,如果你需要读取一个数据,直接到这个...https://blog.csdn.net/geek_monkey/article/details/86291377推挽输出,开漏输出等8中IO模式的总结_不文东的博客-CSDN博客(1)GPIO_Mode_AIN 模拟输入?(2)GPIO_Mode_IN_FLOATING 浮空输入(3)GPIO_Mode_IPD 下拉输入(4)GPIO_Mode_IPU 上拉输入(5)GPIO_Mode_Out_OD 开漏输出(6)GPIO_Mode_Out_PP 推挽输出(7)GPIO_Mode_AF_OD 复用开漏输出(8)GPIO_Mode_AF_PP 复用推挽输出对于刚入门的新手,https://blog.csdn.net/u013488347/article/details/79105018

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-20 12:38:50  更:2021-10-20 12:39:56 
 
开发: 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:49:54-

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