stm32f103c8t6学习1 控制IO口的输出(点灯)

本文详细介绍了STM32单片机中IO口的四种配置方式:推挽输出、开漏输出、复用推挽输出及复用开漏输出,并通过实例展示了如何使用推挽输出配置PB5和PE5两个IO口。

在stm32系列单片机中,如果我们想要控制一个IO口输出或者输入,我们都需要对这个IO口进行配置,根据我们需要的功能,将其配置成适合的输出方式或者输入方式。

所以当我们想要控制IO的输出时我们先要确定stm32的输出方式:

1.推挽输出

内部结构

根据数模电的知识我们可以了解到,Vout具有输出高低电平的能力。

当上面的PMOS管导通,下面的NMOS管截止的时候,Vout输出高电平;

当上面的PMOS管截止,下面的NMOS管导通的时候,Vout输出低电平;

优缺点

优点:输出电压基本与电源电压没有压差;

           IO口驱动能力强,输出电流最大可达20mA

           电平变化快

缺点:

         不支持线与(线与指的就是两个IO口连接在一起,输出电平是这两个IO口相与的结果,当这两个IO口都是推挽输出的时候,线与容易烧坏芯片

2.开漏输出

内部结构

 根据数模电的知识我们知道,Vout具有输出低电平的能力

当NMOS管导通的时候,Vout输出低电平;

当NMOS管关断的时候,Vout为高阻态;

所以我们知道开漏输出本身不具有输出高电平的功能,我们需要外部连接一个上拉电阻,这样其才有输出高电平的能力。

3.复用推挽输出

 与普通推挽输出口一样,不过这时IO口不在是简单的输出高低电平那么简单,而是可以将其复用成输出PWM等功能。

4.复用开漏输出

与普通开漏输出口一样,不过这时IO口不在是简单的输出高低电平那么简单,而是可以将其复用成输出PWM等功能。

根据上面的解释,我们可以根据我们的实际情况选择合适的输出方式,一般IO口都没有上拉电阻,IO口也不需要线与,所以我们一般选择推挽输出。

确定了IO口的输出方式,我们就可以开始写代码了

首先确定我们的IO口,一般是查看原理图

这里我们知道我们需要控制PB5和PE5两个IO口的输出来控制LED。所以我们需要对PB5和PE5两个IO口进行程序配置。代码如下 

这里的文件是led.c

void LED_Init(void)
{
 GPIO_InitTypeDef  GPIO_InitStructure;  //IO口配置结构体
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);	 //使能PB,PE端口时钟
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				 //LED0-->PB.5 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5
 GPIO_SetBits(GPIOB,GPIO_Pin_5);						 //PB.5 输出高

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	    		 //LED1-->PE.5 端口配置, 推挽输出
 GPIO_Init(GPIOE, &GPIO_InitStructure);	  				 //推挽输出 ,IO口速度为50MHz
 GPIO_SetBits(GPIOE,GPIO_Pin_5); 						 //PE.5 输出高 
}

重点语句程序解释:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);     //使能PB,PE端口时钟 

在APB2总线上开启PB,PE端口时钟,只有开启才会工作!!!

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

需要配置的具体引脚,如果是PBx,这里就是GPIO_Pin_x。

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   设置为推挽输出

配置好IO口后,我们需要在main函数中进行调用

这里的文件是main.c

#include "delay.h"
#include "sys.h"
#include "led.h"
#include "lcd_init.h"
#include "lcd.h"
#include "pic.h"
#include "pwm.h"
#include "key.h"

int main(void)
{
	delay_init();
	LED_Init();
	//KEY_Init();
	//TIM3_PWM_Init(59999,23);//设置频率为50Hz,公式为:溢出时间Tout(单位秒)=(arr+1)(psc+1)/Tclk	 20MS = (59999+1)*(23+1)/72000000
                          //Tclk为通用定时器的时钟,如果APB1没有分频,则就为系统时钟,72MHZ
                          //PWM时钟频率=72000000/(59999+1)*(23+1) = 50HZ (20ms),设置自动装载值60000,预分频系数24
	while(1)
	{
//		if(GPIO_ReadInputDataBit(KEYPORT,KEY1)==0)
//		{
//			delay_ms(20);//20ms消除抖动	
//			if(GPIO_ReadInputDataBit(KEYPORT,KEY1)==0)
//			{
//				LED0=!LED0;
//			}
//			while(GPIO_ReadInputDataBit(KEYPORT,KEY1)==0); //等待按键松开 
//		}
        LED1=0;
		delay_ms(500);
		LED0=!LED0;
		delay_ms(500);
	}
}

LED0与LED1在led.h中配置

#ifndef __LED_H
#define __LED_H

#include "sys.h"

#define LED0 PBout(5)// PB5
#define LED1 PEout(5)// PE5	

void LED_Init(void);


#endif

这里我们的期望是LED1一直亮,LED0闪烁

效果如下

 视频地址

VID20220921171305_哔哩哔哩_bilibili

<think>首先,用户的问题是:“我想设置STM32F103C8T6IO在寄存器模式下的配置方法 请问如何通过寄存器配置STM32F103C8T6IO”。这是一个关于STM32F103C8T6控制器的寄存器级别配置的问题。 用户指定了“寄存器模式”,意思是直接操作寄存器,而不是使用库函数如HAL或标准外设库。引用提供了相关信息,特别是引用[1]、[2]、[3]、[4][5],这些都与STM32F103C8T6的寄存器操作相关。 关键点从引用中提取: - 引用[1]:描述了STM32点灯过程,涉及使能GPIO时钟、配置GPIO寄存器(如模式设置),然后控制IO。步骤包括时钟配置、输入输出模式设置、最大速率设置。 - 引用[2]:讨论了寄存器寻址,包括GPIOB基址(0x40010C00地址偏移。 - 引用[3]:提到时钟控制寄存器在RCC模块中,不同系列有不同的地址。 - 引用[4]:提供了一个代码示例,展示如何通过寄存器配置GPIOC端来点亮LED灯。包括打开时钟、配置CRH寄存器、控制ODR寄存器。 - 引用[5]:详细介绍了GPIO寄存器,如ODR、IDR、BSRR,以及位操作。 用户的问题是关于配置IO的一般方法,所以我需要提供一个结构化的、逐步的指南。 回答结构: 1. **介绍**:简要解释在寄存器模式下配置IO的基本步骤。 2. **步骤详解**:分解配置过程: - 使能GPIO时钟(通过RCC寄存器)。 - 配置GPIO模式(通过GPIOx_CRL或GPIOx_CRH寄存器)。 - 设置输出类型、速度等(如果适用)。 - 控制输出电平(通过GPIOx_ODR或GPIOx_BSRR寄存器)。 3. **示例代码**:提供C代码示例,使用寄存器操作来配置一个具体的IO(如PC13,因为引用[4]使用了它)。 4. **注意事项**:提醒用户关于地址、位操作等。 5. **相关问题**:生成相关问题作为结尾。 系统指令要求: - 行内数学表达式用$...$,但这里可能不涉及数学公式,主要是寄存器地址位操作。 - 独立公式用$$...$$,如果有必要。 - 使用中文回答。 - 生成相关问题。 - 在引用段落末尾添加引用标识,如[^1]。 - 回答结构清晰,逐步解决问题。 在回答中,我需要自然地引用提供的引用。例如,当提到时钟使能时,引用引用[1]或[3];当提到寄存器地址时,引用引用[2]或[4]。 STM32F103C8T6的具体细节: - 它是Cortex-M3内核。 - GPIO:PA, PB, PC等。 - 寄存器基址:例如,GPIOA基址是0x40010800,GPIOB是0x40010C00,GPIOC是0x40011000等(从引用[2][4]推断)。 - RCC基址:0x40021000(引用[4]提到0x40021018是RCC_APB2ENR)。 配置步骤: 1. **使能GPIO时钟**: - 使用RCC_APB2ENR寄存器。 - 地址:0x40021018(引用[4])。 - 设置相应位来使能端时钟(如IOPCEN位4用于GPIOC)。 2. **配置GPIO模式**: - 每个端有CRL(低8位引脚)CRH(8位引脚)寄存器。 - 地址:例如,GPIOC_CRL在0x40011000,GPIOC_CRH在0x40011004(引用[4])。 - 模式包括输入、输出(推挽、开漏)、模拟、复用。 - 设置CNFMODE位。 3. **设置输出电平类型**: - 使用ODR寄存器设置输出电平。 - 或使用BSRR寄存器原子操作。 - 地址:ODR在基址+0x0C,如0x4001100C(引用[4])。 示例代码:基于引用[4],但改进解释。 相关问题: - 例如: 1. 如何配置STM32F103C8T6的输入模式? 2. 什么是BSRR寄存器,如何使用它? 3. 如何优化寄存器操作以提效率? 确保回答真实可靠:基于引用STM32F103参考手册(虽然用户没有提供手册,但引用是基础)。 最终回答结构: - 标题:如何通过寄存器配置STM32F103C8T6IO - 步骤: 1. 使能GPIO时钟 2. 配置GPIO模式寄存器(CRL/CRH) 3. 设置输出电平(ODR/BSRR) - 代码示例 - 注意事项 - 相关问题</think>### 如何通过寄存器配置STM32F103C8T6IOSTM32F103C8T6中,通过寄存器直接配置IO(即“寄存器模式”)涉及直接操作内存映射的寄存器,而无需依赖库函数(如HAL库)。这种方法效且灵活,但需要对硬件寄存器有深入了解。以下是基于STM32F103参考手册引用资料的逐步配置方法。整个过程分为三个主要步骤:使能GPIO时钟、配置GPIO模式寄存器、控制输出电平。下面以配置GPIOC的PC13引脚为例(常用于LED控制),详细说明操作流程。 --- #### 1. **使能GPIO时钟** - STM32的所有外设(包括GPIO)在操作前必须先使能其时钟。时钟控制通过RCC(Reset and Clock Control)模块的寄存器实现。 - **关键寄存器**:`RCC_APB2ENR`(APB2外设时钟使能寄存器),地址为`0x40021018`[^1][^3][^4]。 - **操作步骤**: - 设置`RCC_APB2ENR`的相应位来使能目标GPIO。例如: - 使能GPIOC时钟:设置位4(`IOPCEN`)为1。 - 使能GPIOB时钟:设置位3(`IOPBEN`)为1。 - 使用位操作确保不影响其他位。通常用“或”操作(`|=`)设置位,用“与”操作(`&=`)清零位。 - **示例代码**: ```c // 使能GPIOC时钟 (设置RCC_APB2ENR的位4) *(volatile uint32_t *)0x40021018 |= (1 << 4); // 0x40021018是RCC_APB2ENR地址[^4] ``` - **注意事项**:STM32F103C8T6的GPIO时钟在APB2总线上,地址固定为`0x40021018`[^3][^4]。未使能时钟时,任何GPIO操作无效。 #### 2. **配置GPIO模式寄存器** - 每个GPIO有两个配置寄存器:`GPIOx_CRL`(控制低8位引脚,如PC0-PC7)`GPIOx_CRH`(控制8位引脚,如PC8-PC15)。这些寄存器设置引脚的模式(输入/输出)、输出类型(推挽/开漏)速度。 - **关键寄存器**: - `GPIOx_CRL`:地址为`GPIOx_BASE + 0x00`,例如GPIOC的`0x40011000`[^2][^4]。 - `GPIOx_CRH`:地址为`GPIOx_BASE + 0x04`,例如GPIOC的`0x40011004`[^4]。 - **寄存器结构**:每个引脚占用4位(CNF[1:0]MODE[1:0]),其中: - `CNF`位:配置输入/输出模式(如通用推挽输出、开漏输出)。 - `MODE`位:设置输出速度(如2MHz、10MHz)。 - 例如,配置PC13(8位引脚)为推挽输出、最大速度2MHz: - `CNF = 00`(通用推挽输出) - `MODE = 01`(输出模式,最大速度2MHz) - 对应4位值:`0001`(二进制)。 - **操作步骤**: - 先清零目标引脚的配置位(避免残留值),再设置新值。 - 使用位操作:计算引脚在寄存器中的偏移(每个引脚偏移4位)。 - **示例代码**(配置PC13为推挽输出): ```c // 配置PC13(使用CRH寄存器,PC13是第13位,对应CRH的(13-8)*4 = 20位偏移) volatile uint32_t *pGPIOC_CRH = (volatile uint32_t *)0x40011004; // GPIOC_CRH地址[^4] // 先清零PC13的配置位(CNFMODE共4位) *pGPIOC_CRH &= ~(0x0F << (4 * (13 - 8))); // 13-8=5, 所以偏移4*5=20位[^4] // 设置PC13为推挽输出、2MHz速度 (CNF=00, MODE=01 → 二进制0001) *pGPIOC_CRH |= (1 << (4 * (13 - 8))); // 设置MODE位为01(仅需设置最低位)[^4][^5] ``` - **注意事项**:引脚编号从0开始,低引脚(0-7)用CRL,引脚(8-15)用CRH。模式选择需参考数据手册,避免冲突。 #### 3. **控制输出电平** - 配置完成后,通过输出数据寄存器(`GPIOx_ODR`)或位设置/清除寄存器(`GPIOx_BSRR`)控制引脚电平。 - **关键寄存器**: - `GPIOx_ODR`:直接读写引脚电平,地址为`GPIOx_BASE + 0x0C`,例如GPIOC的`0x4001100C`[^4][^5]。 - `GPIOx_BSRR`:原子操作寄存器,可单独置位或清零,地址为`GPIOx_BASE + 0x10`,例如`0x40011010`[^5]。 - **操作步骤**: - 使用`ODR`时,直接设置位值(1=电平,0=低电平)。 - 使用`BSRR`时: - 低16位:设置位(置1),16位:清除位(置0)。 - 例如,设置PC13电平:`BSRR = 1 << 13`;清零:`BSRR = 1 << (13 + 16)`。 - **示例代码**(设置PC13输出低电平点亮LED): ```c // 使用ODR设置PC13输出低电平(位13) *(volatile uint32_t *)0x4001100C &= ~(1 << 13); // 清零位13[^4] // 或使用BSRR(更安全,原子操作) // *(volatile uint32_t *)0x40011010 = (1 << (13 + 16)); // 清零PC13[^5] ``` - **注意事项**:`BSRR`优于`ODR`,因为它避免读-改-写竞争。输入模式使用`GPIOx_IDR`读取电平[^5]。 #### 完整示例代码 以下是一个完整C代码示例,配置PC13为输出模式并点亮LED(基于寄存器操作): ```c #include "stm32f10x.h" // 包含寄存器定义(可选) int main(void) { // 1. 使能GPIOC时钟 (RCC_APB2ENR地址0x40021018) *(volatile uint32_t *)0x40021018 |= (1 << 4); // 设置位4 (IOPCEN)[^4] // 2. 配置PC13为推挽输出 (GPIOC_CRH地址0x40011004) volatile uint32_t *pCRH = (volatile uint32_t *)0x40011004; *pCRH &= ~(0x0F << (4 * 5)); // 清零PC13配置位 (偏移20)[^4] *pCRH |= (1 << (4 * 5)); // 设置MODE=01 (推挽输出)[^5] // 3. 设置PC13输出低电平 (点亮LED) *(volatile uint32_t *)0x4001100C &= ~(1 << 13); // ODR地址0x4001100C[^4] while (1) { // 主循环(可添加流水灯逻辑) } } // 空SystemInit函数,避免编译器错误 void SystemInit(void) {} ``` - **关键点**: - 使用`volatile`关键字防止编译器优化寄存器访问。 - 地址值基于STM32F103C8T6内存映射:GPIOB基址`0x40010C00`,GPIOC基址`0x40011000`等[^2][^4]。 - 实际应用中,建议定义寄存器地址宏以提可读性,例如: ```c #define RCC_APB2ENR (*(volatile uint32_t *)0x40021018) #define GPIOC_CRH (*(volatile uint32_t *)0x40011004) #define GPIOC_ODR (*(volatile uint32_t *)0x4001100C) ``` #### 注意事项 - **时钟先决条件**:系统时钟需默认启用(STM32F103上电后HSI时钟自动启用),否则需配置RCC[^3]。 - **错误排查**:如果LED不亮,检查: - 时钟是否使能(使用调试器查看`RCC_APB2ENR`值)。 - 引脚配置是否正确(避免冲突模式如模拟输入)。 - 硬件连接(如LED串联电)。 - **性能优化**:使用`BSRR`寄存器替代`ODR`,避免位操作冲突[^5]。 - **扩展性**:此方法适用于所有IO(如PA、PB),只需修改基址引脚偏移。 通过以上步骤,您可以效配置STM32F103C8T6IO。此方法在资源受限场景(如Bootloader)中尤其有用[^1][^4]。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值