单片机第三季-第五课:GPIO控制LED

2023-11-11 13:01

本文主要是介绍单片机第三季-第五课:GPIO控制LED,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1,GPIO数据手册

1.1,端口配置寄存器

​1.2,端口输入数据寄存器和端口输出数据寄存器 

​1.3,端口位设置/清除寄存器 

1.4,端口位清除寄存器 

2,原理图分析和MDK工程

3,写代码通过GPIO点亮LED 

4,STM32时钟设置函数移植 

5,STM32外设编程经验总结 


1,GPIO数据手册

每个GPI/O端口有两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH),两个32位数据寄存器(GPIOx_IDR和GPIOx_ODR),一个32位置位/复位寄存器(GPIOx_BSRR),一个16位复位寄存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR)。

GPIOx_CRL,GPIOx_CRH中的x代表端口编号,CR代表control register,L代表Low,H代表High;

GPIOx_IDR和GPIOx_ODR中的IDR代表input data register,ODR代表output data register;

GPIOx_LCKR是锁定寄存器,可以将输出锁定,提升安全性,也是STM32与51单片机的区别,STM32用于工业控制的一个特点; 

GPIO端口的每个位可以由软件分别配置成多种模式:

─ 输入浮空

─ 输入上拉

─ 输入下拉

─ 模拟输入

─ 开漏输出

─ 推挽式输出

─ 推挽式复用功能

─ 开漏复用功能 

前四种是输入模式,其中前三个是数字输入,第四个是模拟输入。

下图为IO端口的基本结构:

通过设置可将端口设置为输入或输出端口,图中上半部分为输入,下半部分为输出,输入模式是分为模拟输入以及通过TTL肖特基触发器转化为数字输入。输出模式中的P-MOS和N-MOS起到将输出增强的作用,在软件编程中重点是对图中寄存器的设置。

 输出模式位代表着输出端口可设置的信号输出频率。

1.1,端口配置寄存器

端口配置低寄存器(GPIOx_CRL) (x=A..E)对应端口0-7和端口配置高寄存器(GPIOx_CRH) (x=A..E)对应端口8-18。 

每个端口占四位,分别为CNFy[1:0]和MODEy[1:0],一个寄存器可以配置8个IO。

如果一个端口中的IO超过8个就需要用到配置高寄存器(GPIOx_CRH)。

1.2,端口输入数据寄存器和端口输出数据寄存器 

端口输入数据寄存器(GPIOx_IDR) (x=A..E):

端口输出数据寄存器(GPIOx_ODR) (x=A..E):

1.3,端口位设置/清除寄存器 

端口位设置/清除寄存器(GPIOx_BSRR) (x=A..E):

注:如果同时设置了BSy和BRy的对应位,BSy位起作用。也就是此时置位起作用。 

1.4,端口位清除寄存器 

端口位清除寄存器(GPIOx_BRR) (x=A..E):

 

其他寄存器不再一一列举,具体参考数据手册。

2,原理图分析和MDK工程

需要分析STM32核心板和转接插座的对应端口,以及通过转接插座的端口连接LED的插接口。 

选择PB8-PB15控制LED,也就是STM32的Port B。 

起始代码:

不同的CPU的起始代码一般是不同的;
起始代码是用汇编写的,一般不需要看懂,知道点就行了。 

3,写代码通过GPIO点亮LED 

第一步,寄存器信息确认,确认使用端口地址,Port B,0X4001 0C00 - 0x4001 0FFF。

第二步,找到Port B对应要操作的寄存器,即第一节中介绍的几个寄存器。

有可能涉及到的GPIO的寄存器地址:

寄存器名              偏移量          寄存器地址
GPIOB_CRL        0x00             0x40010C00
GPIOB_CRH       0x04             0x40010C04            
GPIOB_IDR        0x08              0x40010C08
GPIOB_ODR      0x0C             0x40010C0C            
GPIOB_BSRR    0x10             0x40010C10            
GPIOB_BRR      0x14              0x40010C14            

第三步,通过C语言编程操作寄存器。

需要注意的几点:

(1)ARM是内存与IO统一编址的,所以ARM中的所有外设都是通过寄存器的方式来操作的
(2)每个寄存器都有地址,C语言通过这些地址来操作这些寄存器位,用到的C语言技巧主要是C语言的位操作和C语言指针。
(3)常见面试题:用C语言向内存地址0x30000004写入16
    *(unsigned int *)0x30000004 = 16;                                                                                              或者:
    unsigned int *p = (unsigned int *)0x30000004;    *p = 16; 

下边的代码中直接通过操作寄存器的地址控制LED: 

#define GPIOB_CRH 0x40010C04
#define GPIOB_ODR 0x40010C0Cvoid main()
{//将 port B端口的8-15设置为输出模式,最大速度50MHz,通用推挽输出模式*((unsigned int *)GPIOB_CRH) = 0x3333 3333;//输出1将8个LED灯全部点亮*((unsigned int *)GPIOB_ODR) = 0x0000 ffff;while(1)}

4,STM32时钟设置函数移植 

需要配置时钟的时钟控制寄存器(RCC_CR),时钟配置寄存器(RCC_CFGR)

第一步,时钟控制寄存器(RCC_CR)打开HSE ON(使用外部晶振),检测是否ready(HSE RDY)。

第二部,时钟配置寄存器(RCC_CFGR)配置HPRE(AHB)、PPRE1(APB1)、PPRE2(APB2)、PLLSRC、PLLXTPRE、PLLMUL。

第三步,配置时钟控制寄存器(RCC_CR) ,PLL ON,并检测PLL RDY。

 第四步,配置时钟配置寄存器(RCC_CFGR)中的SW,选择时钟源,并检测SWS状态。

时钟设置时需注意对flash相关寄存器的操作 。

另外需要注意各端口时钟的使能是独立的:

时钟函数代码:

头文件: 

#ifndef __CLOCK_H__
#define __CLOCK_H__#include "gpio.h"// 寄存器宏定义
// RCC寄存器基地址0x40021000
#define RCC_BASE	0x40021000			// RCC部分寄存器的基地址·
#define RCC_CR		(RCC_BASE + 0x00)	// RCC_CR的地址·
#define RCC_CFGR	(RCC_BASE + 0x04)#define FLASH_ACR	0x40022000// 用C语言来访问寄存器的宏定义
#define rRCC_CR		(*((volatile unsigned int *)RCC_CR))
#define rRCC_CFGR	(*((volatile unsigned int *)RCC_CFGR))
#define rFLASH_ACR	(*((volatile unsigned int *)FLASH_ACR))// 时钟源切换到HSE并使能PLL,将主频设置为12MHz
void Set_SysClockTo72M(void);#endif

源文件: 

#include "clock.h"void Set_SysClockTo72M(void)
{unsigned int rccCrHserdy = 0;unsigned int rccCrPllrdy = 0;unsigned int rccCfrSwsPll = 0;unsigned int faultTime = 0;rRCC_CR = 0x00000083;rRCC_CR &= ~(1<<16);	  	// 关闭HSEONrRCC_CR |= (1<<16);			//打开HSEON,让HSEON工作do{rccCrHserdy = rRCC_CR & (1<<17);	//检测第17位是否为1faultTime++;//检测时间}while ((faultTime<0x0FFFFFFF) && (rccCrHserdy==0));if ((rRCC_CR & (1<<17)) != 0){rFLASH_ACR |= 0x10;rFLASH_ACR &= (~0x03);rFLASH_ACR |= (0x02);// HSE ready,下面配置PLL并且等待readyrRCC_CFGR &= (~((0x0f<<4) | (0x07<<8) | (0x07<<11)));//rRCC_CFGR &= (~(0x3ff<<4));// AHB和APB2未分频,APB1被2分频,所以,AHB和APB2都是72MHz,APB是36MHzrRCC_CFGR |= ((0x0<<4) | (0x04<<8) | (0x0<<11));// 选择HSE作为PLL输入并且HSE不分频,所以PLL输入为8MHzrRCC_CFGR &= (~((1<<16) | (1<<17)));   	// 清零bit17和bit16rRCC_CFGR |= ((1<<16) | (0<<17));		//bit16置1// 设置PLL倍频系数为9rRCC_CFGR &= (~(0x0f<<18));   			// 清零bit18-21rRCC_CFGR |= (0x07<<18);				// 9倍频// 打开PLL开关rRCC_CR |= (1<<24);// do while 循环等待PLL时钟稳定faultTime = 0;do{rccCrPllrdy = rRCC_CR & (1<<25);	//检测25为是否为1faultTime++;//检测时间}while ((faultTime<0x0FFFFFFF) && (rccCrPllrdy==0));//while (rccCrPllrdy==0);if ((rRCC_CR & (1<<25)) == (1<<25)){// 到这里说明PLL已经稳定了,可以用了,下面就可以切了// 切换PLL输出为SYSCLKrRCC_CFGR &= (~(0x03<<0));   rRCC_CFGR |= (0x02<<0);	faultTime = 0;do{rccCfrSwsPll = rRCC_CFGR & (0x03<<2);	//检测第25位是否为1faultTime++;//检测时间}while ((faultTime<0x0FFFFFFF) && (rccCfrSwsPll!=(0x02<<2)));if ((rRCC_CFGR & (0x03<<2))== (0x02<<2)){//到这里时钟就设置好了}else{// 到这里说明PLL输出作为SYSCLK不成功while (1);}}else{// 到这里说明PLL启动时出错了,PLL不能稳定工作while (1);}}else{// HSE配置超时,说明HSE不可用,一般硬件存在问题while (1);}
}

5,STM32外设编程经验总结 

STM32和51或其他简单单片机的相同:
(1)开发环境都是Keil;
(2)都是看原理图和数据手册;
(3)都是用C语言;
STM32和51或其他简单单片机的不同:
(1)工程会更复杂,会用到Keil的一些高级设置;
(2)原理图和数据手册比简单单片机更复杂(复杂不是难);
(3)STM32会用到C语言的更多高级特性 ;

这篇关于单片机第三季-第五课:GPIO控制LED的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/390240

相关文章

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机

控制反转 的种类

之前对控制反转的定义和解释都不是很清晰。最近翻书发现在《Pro Spring 5》(免费电子版在文章最后)有一段非常不错的解释。记录一下,有道翻译贴出来方便查看。如有请直接跳过中文,看后面的原文。 控制反转的类型 控制反转的类型您可能想知道为什么有两种类型的IoC,以及为什么这些类型被进一步划分为不同的实现。这个问题似乎没有明确的答案;当然,不同的类型提供了一定程度的灵活性,但

单片机毕业设计基于单片机的智能门禁系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍程序代码部分参考 设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订

深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理

深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理 秒杀系统是应对高并发、高压力下的典型业务场景,涉及到并发控制、库存管理、事务管理等多个关键技术点。本文将深入剖析秒杀商品业务中常见的几个核心问题,包括 AOP 事务管理、同步锁机制、乐观锁、CAS 操作,以及用户限购策略。通过这些技术的结合,确保秒杀系统在高并发场景下的稳定性和一致性。 1. AOP 代理对象与事务管理 在秒杀商品

PostgreSQL中的多版本并发控制(MVCC)深入解析

引言 PostgreSQL作为一款强大的开源关系数据库管理系统,以其高性能、高可靠性和丰富的功能特性而广受欢迎。在并发控制方面,PostgreSQL采用了多版本并发控制(MVCC)机制,该机制为数据库提供了高效的数据访问和更新能力,同时保证了数据的一致性和隔离性。本文将深入解析PostgreSQL中的MVCC功能,探讨其工作原理、使用场景,并通过具体SQL示例来展示其在实际应用中的表现。 一、

vue2实践:el-table实现由用户自己控制行数的动态表格

需求 项目中需要提供一个动态表单,如图: 当我点击添加时,便添加一行;点击右边的删除时,便删除这一行。 至少要有一行数据,但是没有上限。 思路 这种每一行的数据固定,但是不定行数的,很容易想到使用el-table来实现,它可以循环读取:data所绑定的数组,来生成行数据,不同的是: 1、table里面的每一个cell,需要放置一个input来支持用户编辑。 2、最后一列放置两个b

【电机控制】数字滤波算法(持续更新)

文章目录 前言1. 数字低通滤波 前言 各种数字滤波原理,离散化公式及代码。 1. 数字低通滤波 滤波器公式 一阶低通滤波器的输出 y [ n ] y[n] y[n] 可以通过以下公式计算得到: y [ n ] = α x [ n ] + ( 1 − α ) y [ n − 1 ] y[n] = \alpha x[n] + (1 - \alpha) y[n-1]

物联网之流水LED灯、正常流水灯、反复流水灯、移动流水灯

MENU 硬件电路设计软件程序设计正常流水LED灯反复流水LED灯移动流水LED灯 硬件电路设计 材料名称数量直插式LED1kΩ电阻杜邦线(跳线)若干面包板1 每一个LED的正极与开发板一个GPIO引脚相连,并串联一个电阻,负极接GND。 当然也可以选择只使用一个电阻。 软件程序设计 正常流水LED灯 因为要用到多个GPIO引脚,所以最好把所有的GPI

A20 操作GPIO口

例如:先在 Sys_config.fex文件中 [1302_para] 1302_used      = 1 1302_clk             = port:PD05<1><default><default><0> 1302_dat             = port:PD06<1><default><default><0> 1302_rs