1. 前言
本教程基于【N32WB03x SDK使用指南】的开发环境,前期结合官方教程开展的N32WB03xSTB开发板ADC实验,接下来开展GPIO的按键控制点灯实验和PWM输出实验两部分组成。
2. GPIO 和 AFIO
2.1 概述
GPIO(General purpose input/output)即通用型 I/O,AFIO(Alternate-function input/output)即复用功能 I/O。芯片最多支持 21 个 GPIO,共被分为 2 组(GPIOA/GPIOB),A 组 7 个端口,B 组共 14 个。GPIO 端口和其他的复用外设共用引脚,用户可以根据需求灵活配置。每个 GPIO 引脚都可以独立配置成输出、输入或复用的外设功能端口。除了模拟输入引脚外,其他的 GPIO 引脚都有大电流通过能力。
GPIO 端口具有以下特性:
- GPIO 端口可由软件分别配置成以下模式:
◆ 输入浮空
◆ 输入上拉
◆ 输入下拉
◆ 模拟功能
◆ 开漏输出及上/下拉可配
◆ 推挽式输出及上/下拉可配
◆ 推挽式复用功能及上/下拉可配
◆ 开漏复用功能及上/下拉可配
- 单独的位设置或位清除功能
- 所有 IO 支持外部中断功能
- 所有 IO 支持低功耗模式唤醒,上升或下降沿可配置
8 个 EXTI 可用于 Sleep 模式唤醒,所有 I/O 可复用为 EXTI
PB3(WAKEUP1)唤醒 IO 可用于 PD 模式唤醒,I/O 滤波时间最大 1μs
-
支持软件重新映射 I/O 复用功能
-
支持 GPIO 锁定机制,复位方式清除锁定状态
每个 I/O 端口位可以任意编程,但必须按照 32 位字访问 I/O 端口寄存器(不允许 16 位半字或 8 位字节访问)。下图给出了一个 I/O 端口的基本结构
2.2 IO 功能描述
2.2.1 IO 模式配置
IO 的模式控制由配置寄存器 GPIOx_PMODE,GPIOx_POTYPE 和 GPIOx_PUPD(x=A,B)来设置,不同的
操作模式下的配置如下表所示:
另外 GPIOx_DS 寄存器 DSy 位可用来配置高/低驱动强度,GPIOx_SR 寄存器 SRy 位可用来高/低 Slew rate的配置。
IO 在不同的配置下的输入输出特性如下表所示
2.2.1.1 输入模式
当 I/O 端口配置为输入模式时:
■ 输出缓冲器被禁止
■ 施密特触发输入被激活
■ 上拉和下拉电阻是否被连接,取决于 GPIOx_PUPD 寄存器的配置
■ 出现在 I/O 脚上的数据在每个 APB2 时钟被采样到输入数据寄存器
■ 通过对数据寄存器的读访问得到 I/O 状态
2.2.1.2 输出模式
当 I/O 端口配置为输出时:
- 施密特触发输入被激活
- 上拉和下拉电阻是否被连接,取决于 GPIO_PUPD 寄存器的配置
- 输出缓冲器被激活
开漏模式: 输出寄存器上的’0’激活 N-MOS,引脚输出低电平 输出寄存器上的’1’端口置于高阻状态(P-MOS 从不被激活)
推挽模式: 输出寄存器上的’0’激活 N-MOS,引脚输出低电平 输出寄存器上的’1’激活 P-MOS,引脚输出高电平
- 出现在 I/O 脚上的数据在每个 APB2 时钟被采样到输入数据寄存器
- 对输入数据寄存器的读访问可得到 I/O 状态
- 对输出数据寄存器的读访问得到最后一次写的值
2.2.1.3 复用功能模式
当 I/O 端口配置为复用功能时:
-
施密特触发输入被激活
-
弱上拉和下拉电阻被禁止,取决于 GPIOx_PUPD 寄存器的配置
-
在开漏或推挽式配置中,输出缓冲器由外设控制
-
内置外设的信号驱动输出缓冲器
-
在每个 APB2 时钟周期,出现在 I/O 脚上的数据被采样到输入数据寄存器
-
对输入数据寄存器的读访问可得到 I/O 状态
-
对输出数据寄存器的读访问得到最后一次写的值
2.2.1.4 模拟模式
当 I/O 端口被配置为模拟输入配置时:
-
弱上拉和下拉电阻被禁止
-
读取输入数据寄存器时数值为’0’
-
输出缓存器被禁止
-
施密特触发输入被禁止,输出值被强置为’0’( 实现了每个模拟 I/O 引脚上的零消耗
2.3 复位后状态
复位期间和刚复位后,复用功能未开启,I/O 端口被配置成模拟输入模式(PMODEx[1:0]=2’b11)。但有以
下几个例外的信号:
- RESET 默认无 GPIO 功能:
RESET 上拉输入
- 复位后,调试系统相关的引脚默认配置为 SWD 接口 I/O 配置:
PA4: SWCLK 置于输入下拉模式
PA5: SWDIO 置于输入上拉模式
2.4 单独的位设置和位清除
通过对“位设置/清除寄存器(GPIOx_PBSC)和位清除寄存器(GPIOx_PBC)”中想要更改的位写’1’来实现对数据寄存器(GPIOx_POD)的个别位操作,可以一个或多个位。写’1’的位被相应的置位或清除,没被写’1’的位将不被更改。软件不需要禁止中断,在单次 APB2 写操作里完成。
2.5 外部中断/唤醒线
所有端口都有外部中断能力,可以在 EXTI 模块中配置:
- 端口必须配置成输入模式
- 所有端口可配置用于 Idle,Standby 或 Sleep 模式唤醒,支持上升或下降沿可配
- PB3,可用于 PD 模式唤醒
- 通用 I/O 端口以图 6-2 的方式连接到 8 个外部中断/事件线上,由寄存器 AFIO_EXTI_CFGx 配置
2.6 连续转换模式
将 ADC_CTRL.ADC_MODE 置为“1”可以在连续模式下使用 ADC,在连续转换模式中,当前面 ADC 转
换一结束马上就启动另一次转换。设置 ADC_CTRL.ADC_CH_SEL 选择输入通道后,可通过设置ADC_CTRL 寄存器的 ADC_EN 位来触发第一次转换,但之后,将每个 adcclk 周期自动生成新的转换数据。支持过采样率设置,配置值 ADC_OVR_SAMP_CNT. OS_CNT_LD_CNT 需要>=2,OS_CNT_LD_CNT+1个数据采样一个数据。
每个转换后:
- 转换数据被储存在 16 位的 ADC_DAT 寄存器中
- 使能 DMA 模式,每次转换后会产生 DMA 请求
2.7 复用功能
当端口配置位 AFIO 时,端口引脚用作外设复用功能,使用前必须对端口位配置寄存器(GPIOx_AFL/
GPIOx_AFH,GPIOx_PMODE,GPIOx_POTYPE 和 GPIOx_PUPD),复用输入或输出由外设确定。
3. GPIO 实验
3.1 按键控制点灯实验
项目文件地址:N32WB03x_SDK V1.2.0\N32WB03x_SDK V1.2.0\projects\n32wb03x_EVAL\peripheral\EXTI\KeyInterrupt\MDK-ARM
3.1.1 打开工程
keil5 打开后查看相关程序函数
项目简介在readme.txt
1、功能说明
1、此例程展示通过外部触发中断,控制 LED 闪烁
2、使用环境
软件开发环境:KEIL MDK-ARM V5.26.2.0
硬件环境:
1、基于N32WB031_STB开发板
2、MCU:N32WB031
3、使用说明
/* 描述相关模块配置方法;例如:时钟,I/O等 */
SystemClock:64MHz
GPIO:PB2 选择作为外部中断入口,LED2 (PA6) 闪烁
/* 描述Demo的测试步骤和现象 */
1.编译后下载程序复位运行,LED1(PB0)点亮;
2.按下松开 Button2 (PB2) 按键,LED2 (PA6) 闪烁;
4、注意事项
无
LED和按键接口原理图
跳帽连接LED1和2
3.1.2 配置工程
主程序main.c
#include "main.h"
#include <stdio.h>
#include <stdint.h>
int main(void)
{
LedInit(LED1_PORT, LED1_PIN);
LedInit(LED2_PORT, LED2_PIN);
KeyInputExtiInit(KEY_INPUT_PORT, KEY_INPUT_PIN);
LedOn(LED1_PORT, LED1_PIN);
while (1)
{
}
}
void Delay(uint32_t count)
{
for (; count > 0; count--)
;
}
void KeyInputExtiInit(GPIO_Module* GPIOx, uint16_t Pin)
{
GPIO_InitType GPIO_InitStructure;
EXTI_InitType EXTI_InitStructure;
NVIC_InitType NVIC_InitStructure;
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
if (GPIOx == GPIOA)
{
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_AFIO, ENABLE);
}
else if (GPIOx == GPIOB)
{
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB | RCC_APB2_PERIPH_AFIO, ENABLE);
}
else
{
return;
}
if (Pin <= GPIO_PIN_ALL)
{
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = Pin;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_InitPeripheral(GPIOx, &GPIO_InitStructure);
}
GPIO_ConfigEXTILine(KEY_INPUT_PORT_SOURCE, KEY_INPUT_PIN_SOURCE);
EXTI_InitStructure.EXTI_Line = KEY_INPUT_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitPeripheral(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = KEY_INPUT_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void LedInit(GPIO_Module* GPIOx, uint16_t Pin)
{
GPIO_InitType GPIO_InitStructure;
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
if (GPIOx == GPIOA)
{
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
}
else if (GPIOx == GPIOB)
{
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);
}
else
{
return;
}
if (Pin <= GPIO_PIN_ALL)
{
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = Pin;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitPeripheral(GPIOx, &GPIO_InitStructure);
}
}
void LedOn(GPIO_Module* GPIOx, uint16_t Pin)
{
GPIO_SetBits(GPIOx, Pin);
}
void LedOff(GPIO_Module* GPIOx, uint16_t Pin)
{
GPIO_ResetBits(GPIOx, Pin);
}
void LedBlink(GPIO_Module* GPIOx, uint16_t Pin)
{
GPIO_TogglePin(GPIOx, Pin);
}
#ifdef USE_FULL_ASSERT
void assert_failed(const uint8_t* expr, const uint8_t* file, uint32_t line)
{
while (1)
{
}
}
#endif
此部分不修改
3.1.3 编译下载
N32WB03xSTB开发板自带下载器,官方已经配置好了,直接连接Type-C编译下载
3.1.4 调试验证
1.编译后下载程序复位运行,LED1(PB0)点亮;
2.按下松开 Button2 (PB2) 按键,LED2 (PA6) 闪烁;
3.2 PWM输出实验
项目文件地址:N32WB03x_SDK V1.2.0\N32WB03x_SDK V1.2.0\projects\n32wb03x_EVAL\peripheral\TIM\PWM_Output\MDK-ARM
3.2.1 打开工程
keil5 打开后查看相关程序函数
项目简介在readme.txt
1、功能说明
1、TIM3 CH1 CH2 CH3 CH4输出频率相同占空比不同的PWM
2、使用环境
软件开发环境:KEIL MDK-ARM V5.26.2.0
硬件环境:
1、基于N32WB031_STB开发板
2、MCU:N32WB031
3、使用说明
系统配置;
1、时钟源:
HSI=64M,AHB=64M,APB1=32M,APB2=64M,TIM3 CLK=64M
2、端口配置:
PB4选择为TIM3的CH1输出
PB5选择为TIM3的CH2输出
PB6选择为TIM3的CH3输出
PB7选择为TIM3的CH4输出
3、TIM:
TIM3 CH1 CH2 CH3 CH4周期相等,占空比不等
使用方法:
1、编译后打开调试模式,用示波器或者逻辑分析仪观察TIM3 CH2、CH3、CH4的波形
2、采用杜邦线连接PB4与IED2,可见呼吸灯
4、注意事项
注意必须断开J10上PB6和PB7与NS Link的连接,避免受到干扰
3.2.2 配置工程
修改主程序main.c
如下,添加呼吸灯案例
#include "main.h"
#define USE_HSI_64M
TIM_TimeBaseInitType TIM_TimeBaseStructure;
OCInitType TIM_OCInitStructure;
uint16_t CCR1_Val = 300;
uint16_t CCR2_Val = 200;
uint16_t CCR3_Val = 100;
uint16_t CCR4_Val = 50;
int i=0;
uint16_t PrescalerValue = 0;
void RCC_Configuration(void);
void GPIO_Configuration(void);
void Delay(uint32_t count);
void Delay(uint32_t count)
{
for (; count > 0; count--)
;
}
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
PrescalerValue = (uint16_t)(SystemCoreClock / 16000000) - 1;
TIM_TimeBaseStructure.Period = (400-1);
TIM_TimeBaseStructure.Prescaler = PrescalerValue;
TIM_TimeBaseStructure.ClkDiv = 0;
TIM_TimeBaseStructure.CntMode = TIM_CNT_MODE_UP;
TIM_InitTimeBase(TIM3, &TIM_TimeBaseStructure);
TIM_OCInitStructure.OcMode = TIM_OCMODE_PWM1;
TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
TIM_OCInitStructure.Pulse = CCR1_Val;
TIM_OCInitStructure.OcPolarity = TIM_OC_POLARITY_HIGH;
TIM_InitOc1(TIM3, &TIM_OCInitStructure);
TIM_EnableOc1Preload(TIM3, TIM_OC_PRE_LOAD_ENABLE);
TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
TIM_OCInitStructure.Pulse = CCR2_Val;
TIM_InitOc2(TIM3, &TIM_OCInitStructure);
TIM_ConfigOc2Preload(TIM3, TIM_OC_PRE_LOAD_ENABLE);
TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
TIM_OCInitStructure.Pulse = CCR3_Val;
TIM_InitOc3(TIM3, &TIM_OCInitStructure);
TIM_ConfigOc3Preload(TIM3, TIM_OC_PRE_LOAD_ENABLE);
TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
TIM_OCInitStructure.Pulse = CCR4_Val;
TIM_InitOc4(TIM3, &TIM_OCInitStructure);
TIM_ConfigOc4Preload(TIM3, TIM_OC_PRE_LOAD_ENABLE);
TIM_ConfigArPreload(TIM3, ENABLE);
TIM_Enable(TIM3, ENABLE);
while (1)
{
for(i=0;i < 400;i++)
{
TIM_OCInitStructure.Pulse = i;
TIM_OCInitStructure.OcPolarity = TIM_OC_POLARITY_HIGH;
TIM_InitOc1(TIM3, &TIM_OCInitStructure);
TIM_EnableOc1Preload(TIM3, TIM_OC_PRE_LOAD_ENABLE);
TIM_ConfigArPreload(TIM3, ENABLE);
Delay(100000);
}
if(i==400){
i=0;
}
}
}
void RCC_Configuration(void)
{
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM3, ENABLE);
RCC_EnableAPB2PeriphClk( RCC_APB2_PERIPH_GPIOB| RCC_APB2_PERIPH_AFIO, ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.GPIO_Current = GPIO_DC_LOW;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF2_TIM3;
GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
}
#ifdef USE_FULL_ASSERT
void assert_failed(const uint8_t* expr, const uint8_t* file, uint32_t line)
{
while (1)
{
}
}
#endif
此部分不修改
3.2.3 编译下载
N32WB03xSTB开发板自带下载器,官方已经配置好了,直接连接Type-C编译下载
3.2.4 调试验证
1、编译后打开调试模式,用示波器或者逻辑分析仪观察TIM3 CH2、CH3、CH4的波形
2、采用杜邦线连接PB4与IED2,可见呼吸灯
实验就结束啦!
4. 小结
0