一. 了解并掌握STM32中断原理,HAL库函数开发方法。使用HAL库方式完成下列任务 二. 在没有示波器条件下,可以使用Keil的软件仿真逻辑分析仪功能等。

1、重做上一个LED流水灯作业,即用GPIO端口完成3只LED红绿灯的周期闪烁。

  1. 安装STM32CubeMX和Keil:首先在计算机上安装STM32CubeMX和Keil软件并配置好。

  2. 创建一个新的项目:打开STM32CubeMX,选择你使用的STM32系列芯片,然后创建一个新的工程。

  3. 配置GPIO:在Pinout & Configuration选项卡中,选择你要使用的GPIO引脚,并将它们配置为输出模式。

  4. 配置时钟和中断:在RCC选项卡中,配置系统时钟和外部中断使能。你可以选择内部时钟源或外部时钟源,取决于你的具体需求。

  5. 配置中断优先级和触发方式:在NVIC选项卡中,为外部中断通道分配优先级,并选择触发方式(上升沿触发、下降沿触发等)。

  6. 生成代码:点击"Project"选项卡,选择你的开发环境(Keil),然后点击"Generate Code"生成代码。

  7. 打开Keil并导入项目:打开Keil软件,然后导入由STM32CubeMX生成的项目。

  8. 编写代码:在Keil中,打开main.c文件,编写你的代码来控制LED的闪烁。你可以使用HAL库提供的函数来控制GPIO引脚的状态和切换。

  9. 构建和下载代码:在Keil中,点击构建按钮来编译你的代码,并将生成的hex或bin文件下载到STM32开发板上。

使用HAL库函数控制GPIO闪烁LED的如下代码,可以实现3只LED红绿灯的周期闪烁:

#include "main.h"
#include "stm32f1xx_hal.h"

void SystemClock_Config(void);
static void MX_GPIO_Init(void);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  
  while (1)
  {
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
    HAL_Delay(500);
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  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();
  }

  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000);

  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;

  __HAL_RCC_GPIOA_CLK_ENABLE();

  GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void Error_Handler(void)
{
  while (1)
  {
  }
}

#ifdef  USE_FULL_ASSERT

void assert_failed(uint8_t *file, uint32_t line)
{
}

#endif

2、用stm32F103核心板的GPIOA端某一管脚接一个开关(用杜邦线模拟代替)。采用中断模式编程,当开关接高电平时,LED流水灯工作;

接低电平时,LED流水灯停止工作。

基于STM32F103核心板的GPIO中断模式编程,代码如下:

#include "stm32f10x.h"

void GPIO_Configuration(void);
void EXTI_Configuration(void);
void LED_Flowing(void);

int main(void)
{
  GPIO_Configuration();
  EXTI_Configuration();

  while (1)
  {
    // 主循环中的其他任务
  }
}

void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);

  // 配置LED流水灯引脚
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  // 配置开关引脚
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;  // 假设开关接在GPIOA的Pin_0
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  // 上拉输入模式
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void EXTI_Configuration(void)
{
  EXTI_InitTypeDef EXTI_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  // 配置开关引脚触发中断
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

  EXTI_InitStructure.EXTI_Line = EXTI_Line0;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  // 下降沿触发
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  // 配置中断优先级
  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  // 抢占优先级为0
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  // 子优先级为0
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

void EXTI0_IRQHandler(void)
{
  if (EXTI_GetITStatus(EXTI_Line0) != RESET)
  {
    // 延时一段时间以消除抖动
    int delay = 100000;
    while(delay--);

    // 检查开关引脚电平
    if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_RESET)
    {
      // 低电平,停止LED流水灯
      GPIO_ResetBits(GPIOC, GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10);
    }
    else
    {
      // 高电平,启动LED流水灯
      LED_Flowing();
    }

    EXTI_ClearITPendingBit(EXTI_Line0);
  }
}

void LED_Flowing(void)
{
  // 实现LED的流水灯效果
  int i;
  for (i = 0; i < 3; i++)
  {
    GPIO_SetBits(GPIOC, GPIO_Pin_8 << i);
    DELAY_ms(500);
    GPIO_ResetBits(GPIOC, GPIO_Pin_8 << i);
  }
}

实验过程图:

二. 在没有示波器条件下,可以使用Keil的软件仿真逻辑分析仪功能观察管脚的时序波形,更方便动态跟踪调试和定位代码故障点。

 请用此功能观察第1题中3个GPIO端口流水灯的输出波形,并分析时序状态正确与否,高低电平转换周期(LED闪烁周期)实际为多少。

根据第1题的代码,LED流水灯的输出波形是在一个循环中依次亮起和熄灭。通过观察GPIOC的Pin_8、Pin_9和Pin_10的状态变化,您可以确定高低电平转换的周期。

LED闪烁周期取决于LED_Flowing()函数中延时的时间,该示例代码中设定为500毫秒。因此,LED闪烁周期实际上为0.5秒。

使用Keil软件仿真逻辑分析仪功能来验证时序状态的正确性和实时观察GPIO引脚的状态变化。通过观察波形,您可以确认LED流水灯按照预期的方式在不同的GPIO端口上闪烁,并且高低电平转换的频率是正确的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值