1.1 GPIO流水灯硬件电路分析
发光二极管是属于二极管的一种,具有二级管单向导电特性,即只有在正向电压(二极管的正极接正,负极接负)下才能导通发光。PB0引脚接发光二极管(LED1)的正极,所以PB0引脚输出高电平LED1亮,PB0引脚输出低电平LED1熄灭,,LED2,LED3同理。
在上一章,我们知道STM32的引脚有8中模式,我们要点亮LED,显然是输出模式,那么则要将PB0、PG6、PG7设置为普通输出模式,那么是是开漏输出,还是推挽输出呢?或者都可以。为了使得LED点亮,我们只需要将PB0、PG6、PG7输出为高电平,斌企鹅需要输出电流,则需要将其设置为推挽输出,因为如果是开漏输出,则不会有电流,LED就不会点亮。好了,就到这里吧,我们使用STM32Cube新建工程。
1.2 STM32Cube新建工程
关于如何使用使用STM32Cube新建工程在前文已经讲解过了,这里直说配置GPIO部分内容。本文要实现流水灯,其实输出为初始化设置为高电平还是低电平都可以,因为流水灯需要不断反转。
1.首先进行系统配置
Debug模式选择可以选择其他模式,默认选择No debug,Timebase Source选择SysTick,关于Timebase Source在后文会详细讲解。
2.时钟配置,外部高速时钟
配置系统时钟配置72MHz,APB1总线配置36MHz。默认高速时钟是使用内部(HSI),而且CPU时钟配置的比较低。以我选择的STM32F103,外部8M晶振为例(如下图)。
3.GPIO初始化配置
我们将PB0、PG6、PG7配置输出模式(高电平、低电平均可)、输出速率、上/下拉等,默认即可。
4.工程生成设置
其他默认即可。最后点击“生成代码”即可生成代码。
1.3 GPIO流水灯实现与代码分析
1.3.1 流水灯实现
我们要实现流水灯,需要在主函数添加一下代码。
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
1.3.2流水灯代码分析
在分析代码前,先看看流水灯编程流程:
1>使能GPIO端口时钟;
2>初始化GPIO引脚,即为GPIO初始化结构体赋值,并调用相应初始化函数完成初始化配置;
3>根据实际需求控制流水灯。
STM32采用固件库开发,代码比较多,因此,我们在看一个实际工程时,只需从主函数开始,好了,接下来,笔者就带领大家一步一步看看流水灯是怎么实现的。笔者先贴出主函数代码。
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
注释部分不用管,我们只看代码。
1.复位所有硬件
HAL_Init()函数为复位所有硬件,这个就不细说了。
HAL_StatusTypeDef HAL_Init(void)
{
/* Configure Flash prefetch */
#if (PREFETCH_ENABLE != 0)
#if defined(STM32F101x6) || defined(STM32F101xB) || defined(STM32F101xE) || defined(STM32F101xG) || \
defined(STM32F102x6) || defined(STM32F102xB) || \
defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) || \
defined(STM32F105xC) || defined(STM32F107xC)
/* Prefetch buffer is not available on value line devices */
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif
#endif /* PREFETCH_ENABLE */
/* Set Interrupt Group Priority */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
HAL_InitTick(TICK_INT_PRIORITY);
/* Init the low level hardware */
HAL_MspInit();
/* Return function status */
return HAL_OK;
}
2.时钟初始化函数
SystemClock_Config()函数用于时钟初始化,也就是通过STM32Cube实现。
时钟初始化函数如下:
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
RCC_OscInitTypeDef结构体类型定义时钟来源和系统时钟生成配置,就是图9中的配置,本例程使用外部8MHz晶振,通过PLL锁相环9倍频后得到72M系统时钟。
RCC_ClkInitTypeDef结构体类型定义总线时钟配置,一般选择使能系统时钟、AHB、APB1和APB2总线时钟,其中只有APB1总线时钟36MHz,其他都为72MHz。
HAL_RCC_ClockConfig函数就是HAL定义的一个系统滴答定时器初始化配置函数,通过这个函数得到延时效果。
2.GPIO初始化函数
MX_GPIO_Init()函数用于LED的GPIO初始化,代码如下:
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
/*Configure GPIO pin : PB0 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pins : PG6 PG7 */
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
}
以上就是LED的初始化函数,初始化GPIO有个重要的结构体GPIO_InitTypeDef,先看看该结构体。
typedef struct
{
uint32_t Pin; /*!< Specifies the GPIO pins to be configured.
This parameter can be any value of @ref GPIO_pins_define */
uint32_t Mode; /*!< Specifies the operating mode for the selected pins.
This parameter can be a value of @ref GPIO_mode_define */
uint32_t Pull; /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.
This parameter can be a value of @ref GPIO_pull_define */
uint32_t Speed; /*!< Specifies the speed for the selected pins.
This parameter can be a value of @ref GPIO_speed_define */
} GPIO_InitTypeDef;
Pin:引脚编号选择,一个GPIO有16个引脚可选,参数可选有:GPIO_PIN_0、….、GPIO_PIN_15和GPIO_PIN_ALL。很多时候我们可以使用或运算进行选择:GPIO_PIN_0| GPIO_PIN_4。
Mode:引脚模式选择,在前文笔者已经介绍了引脚有8中工作模式,根据外设选择相应模式。
Pull:上下拉,用于输入模式,可选:GPIO_NOPULL不上下拉;GPIO_PULLUP:使能下拉;GPIO_PULLDOWN使能下拉;
Speed:引脚速度,可选:GPIO_SPEED_FREQ_LOW:低速(2MHz);中速(10MHz);高速(50MHz)。
在初始化代码中,还有一个重要的函数HAL_GPIO_WritePin()。HAL_GPIO_WritePin()函数为3个LED灯时钟初始化状态,这里设置为低电平,所以初始化状态3个LED都是暗的。
4.流水灯实现
在前文已经贴出了流水灯的相应代码。
while (1)
{
/* USER CODE END WHILE */
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
/* USER CODE BEGIN 3 */
}
HAL_GPIO_TogglePin函数用于GPIO电平反转,HAL_Delay用于延时,单位是毫秒,以此不断将LED1、LED2、LED3关灭,这就是实现流水灯的效果。
1.4实验现象
将编译好的程序下载到板子中,可以看到三个LED灯不同地闪烁。
代码获取方式
1.关注公众号[嵌入式实验楼]
2.在公众号回复关键词[STM32F1]获取资料
欢迎访问我的网站:
BruceOu的哔哩哔哩
BruceOu的主页
BruceOu的博客
CSDN博客