今日继续学习使用 STM32 F103C8T6开发板 点亮一个LED灯,文章提供源码,测试工程,实验效果图,希望我的归纳总结会对大家有帮助~
目录
GPIO的认识与分类 :
引脚安排整理:
定时器的引脚例举:
串口的引脚例举:
CAN串口通信:
SPI通信:
IIC通信:
其余引脚:
烧录引脚:
相关库函数:
拉高、拉低输出:
APB2外设RCC开启GPIO时钟:
GPIO初始化函数:
接线与GPIO的初始化:
选择引脚:
接线与创建文件、文件路径添加:
GPIO的初始化:
所有代码贴出:
测试效果展示:编辑
测试工程下载:
首先看下这张表:它定义说明了STM32C8T6上所有48个引脚
主功能、默认复用、以及重定义功能:
建议保存此表,以后备用:
其中有许多引脚,他们是不能被贸然设计使用为通用输入输出口的(并不是说不能,而是不推荐一上来就这么设计)
我们结合学习笔记1中的开发板原理图,归纳了以下一些引脚,不推荐最先设计被占用使用为通用输入输出口,当然,VCC和VDD是电源与地,也是不能的~
首先大致认识一下,有一共37个GPIO可以被配置,但 ADC \ TIMER定时器 \ 通信与串口相关 的引脚是不推荐最先设计被使用为通用输入输出口的:
内核 | Cortex-M3 |
Flash | 64K x 8bit |
SRAM | 20K x 8bit |
GPIO | 37个GPIO 分别为PA0-PA15、PB0-PB15、PC13-PC15、PD0-PD1 |
ADC | 2个12bit ADC合计12路通道(外部通道:PA0到PA7+PB0到PB1,内部通道:) |
Timers | 4个16bit定时器/计数器,分别为TIM1、TIM2、TIM3、TM4 其中TM1带死区插入,常用于产生PWM控制电机 |
通信串口 | 2 IIC,2 SPI,3 USART,1 CAN |
接下来的分类只讲主功能,复用重定义不考虑:
---------- | CH1 | CH2 | CH3 | CH4 | ETR | BKIN |
TIM1 上方是CH_xN |
PB13 | PB14 | PB15 | PA11 | PA12 | PB12 |
PA8 | PA9 | PA2 | PA3 | |||
TIM2 | PA0 | PA1 | PA2 | PA3 | ---------- | ---------- |
TIM3 | PA6 | PA7 | PB0 | PB1 | ---------- | ---------- |
TIM4 | PB6 | PB7 | PB8 | PB9 | ---------- | ---------- |
其中,需要说明的是:
TIM1 中 CH_xN与CH_x
表示两个通道互补输出,也就是,你在设置这两个通道输出的时候,要是开启了互补输出,那么这两个引脚的输出电平始终相反,也就是一个引脚输出低电平,另一个引脚自动输出高电平,反之亦然。这样的输出方式一般用于电机驱动控制。
TIM1_ETR 是外部触发输入管脚;
TIM1_BKIN 是故障信号,用来关闭TIM1的输出。
由此我们发现,定时器TIM1的引脚功能最多最强大
对于其余定时器引脚 :若是用不到这么多定时器模块,是可以考虑作为通用输入输出口使用的
TX | RX | CTS | RTS | CK | |
USART1 | PA9 | PA10 | PA11 | PA12 | PA8 |
USART2 | PA2 | PA3 | PA0 | PA1 | |
USART3 | PB10 | PB11 | PB13 | PB14 | PB12 |
其中,需要说明的是:
RX和TX这两个引脚的功能,这两个引脚是USART串行通信最常见和必不可少的两个引脚。但我们在手册中会发现关于USART的其他引脚:
USART_CK、USART_RTS、USART_CTS
在ARM处理器中的USART中,基本上都具有硬件流控的功能,也就是说一般都有RTS CTS引脚(注意:功能简单一点的处理器,如51、STM8等,很少有串口硬件流控功能)。
RTS:是模块的输入端,用于MCU通知模块,MCU是否准备好,模块是否可向MCU发送信息,RTS的有效电平为低。
CTS:是模块的输出端,用于模块通知MCU,模块是否准备好,MCU是否可向模块发送信息,CTS的有效电平为低
RTS (Require ToSend,发送请求)为输出信号,用于指示本设备准备好可接收数据,低电平有效,低电平说明本设备可以接收数据。
CTS (Clear ToSend,发送允许)为输入信号,用于判断是否可以向对方发送数据,低电平有效,低电平说明本设备可以向对方发送数据。
1 CD ← Carrier Detect 载波检测
2 RXD ← Receive Data 接收数据
3 TXD → Transmit Data 发送数据
4 DTR → Data Terminal Ready数据终端就绪
5 GND — System Ground 系统接地
6 DSR ← Data Set Ready 数据设备就绪
7 RTS → Request To Send 请求发送
8 CTS ← Clear To Send 允许发送
9 RI → 这个好像是什么提示信号
RX | TX | |
CAN | PA11 | PA12 |
CAN总线通信和串口通信是两种不同的通信协议。这两种协议都是用于在不同设备之间传输数据的。虽然它们的目标相同,但它们在数据传输的方式和速度方面有很大的不同。
此处不多介绍
NSS | SCK | MISO | MOSI | |
SPI 1 | PA4 | PA5 | PA6 | PA7 |
SPI 2 | PB12 | PB13 | PB14 | PB15 |
SPI包含4条总线,分别为NSS、SCK、MISO、MOSI,各信号线功能如下:
NSS为片选信号,当NSS信号为低电平时,片选有效,开始SPI主从模式通讯。
SCK为时钟信号线,由主通讯设备产生,不同的设备支持的时钟频率不一样,STM32的SPI时钟频率最大为fpclk/2.
MISO和MOSI为主设备和从设备通讯数据线。MISO为从主机到从机,MOSI为从从机到主机。
SCL | SDA | SMBA1 | |
IIC 1 | PB6 | PB7 | PB5 |
IIC 2 | PB10 | PB11 | PB12 |
主要有三个引脚,分别是SDA、SCL、SMBA。
最主要的通信引脚主要是SDA、SCL引脚。
I2C的所有硬件架构都是根据SCL线和 SDA线展开的,其中SMBA我们很少用到SMBA线主要用于SMBUS的
这部分例举出的引脚是不能被使用的,
不是像上面的那样,不建议被设计为通用输入输出口,而是不能使用:
PC13 单片机的侵入检测引脚(TAMPER-RTC)
PC14 OSC32_IN 低速外部时钟的输入
PC15 OSC32_OUT 低速外部时钟的输出
(一般在单片机上都有 OSCin 和 OSCout 两个晶振接入端口 ,我们可以用无源的晶振加上起震电容可以配合单片机是晶振起震,为系统提供时钟源。
低速外部时钟:一般指外接比较精确和稳定的32.768KHz晶振电路,主要是给RTC实时时钟和看门狗提供一个低功耗且精确的时钟源。)
OSC_IN 高速外部时钟输入 用于提供芯片的时钟信号
OSC_OUT 高速外部时钟输出 用于输出芯片的时钟信号
(高速外部时钟:一般是给芯片的内核供电,倍频后作为系统时钟。)
NRST STM32芯片的复位引脚
PB4 nJTRST 是仿真器调试时的JTAG对内核的调试复位信号,一般用于信号调试,建议不要用作他用。
PA13 SWDIO:JTAG:Test Mode State pin ; SWD: Data I/O pin 数据线PA14 SWCLK:JTAG: Test Clock pin ; SWD: Clock pin 时钟线
PB2 BOOT1
BOOT0 BOOT0
(
功能:在每个STM32的芯片上都有两个管脚BOOT0和BOOT1,这两个管脚在芯片复位时的电平状态决定了芯片复位后从哪个区域开始执行程序,见下表:BOOT1=x BOOT0=0 从用户闪存启动,这是正常的工作模式。
BOOT1=0 BOOT0=1 从系统存储器启动,这种模式启动的程序功能由厂家设置。
BOOT1=1 BOOT0=1 从内置SRAM启动,这种模式可以用于调试。
STM32三种启动模式对应的存储介质均是芯片内置的,它们是:
1)用户闪存 = 芯片内置的Flash。
2)SRAM = 芯片内置的RAM区,就是内存。
3)系统存储器 = 芯片内部一块特定的区域,芯片出厂时在这个区域预置了一段Bootloader,就是通常说的ISP程序。
这个区域的内容在芯片出厂后没有人能够修改或擦除,即它是一个ROM区。
扩展资料System memory:从系统存储器启动,这种模式启动的程序功能是由厂家设置的。
)
SWD接口的烧录引脚是不能使用的(PA13 PA14)
JTAG_Jlink接口:
使用Jlink向STM32烧录程序时需要六个引脚:但由于STM32 F103 C8T6引脚资源紧张,因此不建议使用Jlink下载程序,这里建议使用CMSIS_DMA仿真器 接单片机的SWD端口下载程序
所以Jlink相关的6个引脚中,以下三个可以作为普通IO口使用了,但需要配置:
PB4/JNTRST
PB3/JTDO
PA15/JTDI
这三个引脚默认的是JLink的复用功能,如果程序中还有其他GPIO口的配置,那这三个引脚的GPIO初始化一定要放在其他所有GPIO配置之后,否则依然无法作为普通IO使用。
#define GPIO_Remap_SWJ_JTAGDisable ((uint32_t)0x00300200)
/*!< JTAG-DP Disabled and SW-DP Enabled */
void GPIOInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
/* Disable JLink, enable SW */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 |
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/* Push-pill output, it can be other output types */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/* Push-pill output, it can be other output types */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
如果非要把这三个引脚的配置放在其他GPIO配置之前,那么在程序中每次使用这些引脚前,需要再添加一句 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); 例如:
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_ResetBits(GPIOB, GPIO_Pin_4); // PB4 is set to 0;
//拉高引脚输出电平
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
//拉低引脚输出电平
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
RCC(Reset and Clock Control)是STM32微控制器中的一个模块,用于控制和配置各种外设的时钟和复位信息。在初始化STM32引脚之前,需要先开启相应引脚所对应的GPIO外设的时钟。
开启GPIO外设的时钟是为了确保引脚能够正常工作。因为STM32中的GPIO引脚是通过GPIO外设来控制的,而GPIO外设需要时钟信号来运行。通过RCC开启GPIO外设的时钟后,才能正常地对引脚进行配置和操作。
函数RCC_APB2PeriphClockCmd需要传入两个参数:RCC_APB2Periph和NewState。
参数RCC_APB2Periph是一个32位的无符号整数,用于指定要配置的外设的时钟使能。
参数NewState是一个表示状态(即使能或禁用)的枚举类型(FunctionalState),用于指定要对外设进行的操作,可能的取值为ENABLE(使能)或DISABLE(禁用)。
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
这个函数用于初始化GPIO,需要传入俩个参数: GPIO端口 与GPIO初始化 的结构体
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
现在经过刚才的归纳总结,我们将目光锁定在PB8 PB9这俩个引脚,他们的复用功能只有TIM4的通道,在定时器资源如此丰富的条件下,他们便显得不那么重要了,于是我决定在这初始化PB9为通用输入输出口来点亮我们第一个灯~~
以下为我的接线方式:
需要接俩个设备在单片机:一个是CMSIS_DAP仿真器用于下载调试,还有一个LED灯模块,这里我购买的LED灯模块是高电平点亮的
首先还是新建 .c与.h文件,这个新建步骤就不多赘述了,需要注意的是魔棒添加文件路径,否则编译器找不到文件来编译:
添加头文件路径(这个路径是你新建的.c与.h文件的目录),添加完点OK
之前将这俩文件路径放在了\Project\RVMDK(uv5)
发现KEIL编译没出错但总打红叉说我fire not found
后来将文件放在别处: \User 之后就不这样了
这里需要注意一下
1.开启外设时钟:
2.定义一个GPIO_InitTypeDef类型的结构体:
3.结构体选择要控制的GPIO引脚
4.结构体选择设置引脚模式为通用推挽输出
5.结构体选择设置引脚速率为50MHz
6.调用库函数,初始化GPIO
//初始化LED引脚
void GPIO_init_LED(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure0;
/*开启LED相关的GPIO外设时钟*/
RCC_APB2PeriphClockCmd( LED0_GPIO_CLK,ENABLE);
/*选择要控制的GPIO引脚*/
GPIO_InitStructure0.GPIO_Pin = LED0_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure0.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure0.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化GPIO*/
GPIO_Init(LED0_GPIO_PORT, &GPIO_InitStructure0);
}
因为本节还未学到时钟树与时钟系统的配置,因此使用最低端的循环占用延时来达成LED闪烁的目的:
#include "stm32f10x.h"
//定义LED端口引脚
#define LED0_GPIO_PORT GPIOB /* GPIO端口 */
#define LED0_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */
#define LED0_GPIO_PIN GPIO_Pin_8 //引脚
/* 使用标准的固件库控制IO*/
#define LED(a) if (a) \
GPIO_SetBits(LED0_GPIO_PORT,LED0_GPIO_PIN);\
else \
GPIO_ResetBits(LED0_GPIO_PORT,LED0_GPIO_PIN)
//初始化LED引脚
void GPIO_init_LED(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure0;
/*开启LED相关的GPIO外设时钟*/
RCC_APB2PeriphClockCmd( LED0_GPIO_CLK,ENABLE);
/*选择要控制的GPIO引脚*/
GPIO_InitStructure0.GPIO_Pin = LED0_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure0.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure0.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化GPIO*/
GPIO_Init(LED0_GPIO_PORT, &GPIO_InitStructure0);
}
主函数:
int main(void)
{
uint32_t t;
GPIO_init_LED();
while(1)
{
LED(0); //开灯
t=9900000;
while(t!=0)
{t--;}
LED(1); //灭灯
t=9900000;
while(t!=0)
{t--;}
}
}
https://download.csdn.net/download/qq_64257614/88197742?spm=1001.2014.3001.5503