사물 인터넷|버튼 실험 --- I/O 입력 및 인터럽트 프로그래밍 학습|함수 설명 형식|CMSIS 지연 사용 방법|외부 인터럽트를 통한 키 캡처 코드 구현 및 분석 읽기-연구 노트(14)

외부 인터럽트를 통한 키 캡처 코드 구현 및 분석

1 코드 흐름 분석
2 코드 구현
라이브러리 함수 HAL_Init(void) 분석:

HAL_StatusTypeDef HAL_Init(void)
{
  /* Configure Flash prefetch, Instruction cache, Data cache */
#if (INSTRUCTION_CACHE_ENABLE != 0U) //0U表示无符号整型 0 , 1U 表示无符号整型1 ~0U就是对无符号数0取反。
  __HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
#endif /* INSTRUCTION_CACHE_ENABLE  允许指令缓存*/

#if (DATA_CACHE_ENABLE != 0U)
  __HAL_FLASH_DATA_CACHE_ENABLE();
#endif /* DATA_CACHE_ENABLE */

#if (PREFETCH_ENABLE != 0U)
  __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#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();  //使用HAL_Delay延时

  /* Return function status */
  return HAL_OK;
}

Tip1: 함수 설명 형식

/****************
*函数名:main
*函数的描述:通过中断实现按键的捕获
*输入参教:
*输出参数:
*返回值:
*图数作者:
*创建时间:
*更改说明:
*****************/

Tip2: CMSIS 지연을 사용하는 방법

HAL_Delay() 시스템 지연 단계:
구현 단계는 다음과 같습니다.
1. 변수를 사용하여 시스템 클럭 소스 카운터의 값을 얻습니다
. 2. 지연 시간의 매개변수 값을 얻습니다
. 3. 두 크기를 비교합니다. 클럭 카운터가 실현될 값보다 큽니다. 지연된 값은 루프에 갇히게 됩니다. 그렇지 않으면 루프가 점프되어 지연이 완료됩니다.

/**
    * @brief此函数提供最小延迟(以毫秒为单位)对变量递增。
    * @note在默认实现中,SysTick计时器是基准时间的来源。
    *它用于在固定的时间间隔生成中断,其中uwTick是递增的。
    这个函数被声明为__weak,在其他情况下会被覆盖实现在用户文件。
    *@param Delay指定延迟时间长度,单位为毫秒。
    *@retval无
  */
__weak void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick(); //获得起始时钟
  uint32_t wait = Delay;

  /* Add a freq to guarantee minimum wait */
  if (wait < HAL_MAX_DELAY)   //#define HAL_MAX_DELAY      0xFFFFFFFFU=1111 1111 1111 1111 1111 1111 1111 1111
  {

    //  HAL_TICK_FREQ_1KHZ         = 1U,
    //  HAL_TICK_FREQ_DEFAULT      = HAL_TICK_FREQ_1KHZ

    wait += (uint32_t)(uwTickFreq);  //作用是给wait加1。HAL_TickFreqTypeDef uwTickFreq = HAL_TICK_FREQ_DEFAULT;  /* 1KHz */

  }

  while((HAL_GetTick() - tickstart) < wait) //当前时钟-起始时钟的值小于wait(delay)就重复操作,直到计时结束
  {
  }
}

GetTick 함수 프로토타입

/**
 调用这个函数是为了增加一个全局变量“uwTick”用作申请时基。
在默认实现中,这个变量每1ms增加一次在SysTick ISR。
这个函数被声明为__weak,在其他情况下会被覆盖实现在用户文件。
* @retval无
  */
__weak void HAL_IncTick(void)
{
  uwTick += uwTickFreq;
}

/**
* @brief提供以毫秒为单位的tick值。
这个函数被声明为__weak,在其他情况下会被覆盖实现在用户文件。
@retval tick value
  */
__weak uint32_t HAL_GetTick(void)
{
  return uwTick;
}

베어메탈 레벨의 경우 별다른 숨은 내용은 없으며, 직접 분석해보면 프로그램 동작의 세부사항과 타이밍 관계 등을 정리할 수 있다. 준수해야 할 원칙:
1. 메인 프로그램에서 데드 웨이트 지연을 사용하지 마십시오 2. 각 서브루틴(태스크라고도 함)의 쿼리 빈도는 메인 프로그램의 실행 시간보다 커야 합니다. 예를 들어 광고 샘플링, 100ms마다 한 번씩 샘플링하는 경우 기본 프로그램은 100ms 이내에 실행되어야 합니다.
대기 지연은 미국 수준일 수 있으며, 타이밍이 높은 경우에는 큰 지연을 위해 타이머가 사용됩니다.

stm32f407_intr_handle.c 분석

인터럽트 처리 함수: void EXTI4_IRQHandler

Startup_stm32f407xx.s의 핸들러 설명에 따라 해당 중단점 처리 함수를 작성합니다.

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     MemManage_Handler          ; MPU Fault Handler
                DCD     BusFault_Handler           ; Bus Fault Handler
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

실행 함수: HAL_GPIO_EXTI_IRQHandler(KEY0_PIN), stm32f4xx_hal_gpio.c에서 void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) 호출, 함수 정의는 다음과 같습니다.

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  //#define __HAL_GPIO_EXTI_GET_IT(__EXTI_LINE__) (EXTI->PR & (__EXTI_LINE__))
  //__EXTI_LINE__ specifies the EXTI line flag to check.
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET) // RESET = 0U(stm32f4xx.h),表明检测到了中断
  {
    /**
  * @brief  Clears the EXTI's line pending bits.
  * @param  __EXTI_LINE__ specifies the EXTI lines to clear.
  *          This parameter can be any combination of GPIO_PIN_x where x can be (0..15)
  * @retval None
  */
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);

    HAL_GPIO_EXTI_Callback(GPIO_Pin);
  }
}

HAL_GPIO_EXTI_Callback의 콜백 함수는 HAL(약한 선언)에서 명시적으로 구현되지 않으며 구현 함수를 직접 구성해야 합니다.
프로토타입은 다음과 같습니다.

/**
  * @brief  EXTI line detection callbacks.
  * @param  GPIO_Pin Specifies the pins connected EXTI line
  * @retval None
  */
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);
  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Callback could be implemented in the user file
   */
}

콜백 함수는 key.c에서 다시 작성되었습니다.

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == KEY0_PIN) // KEY0_PIN被按下
	{
		Led_Ctrl(LED0_PIN_ROW, LED0_PIN, LED_ON); //执行点灯操作
  }
}

uint16_t Detect_key(uint16_t key_pin)는 이 섹션에서 사용되지 않습니다.

디버깅 프로세스

디버깅을 위해 인터럽트 처리 기능 및 uwTick 자체 증가 작업 기능에서 인터럽트를 설정합니다.

void EXTI4_IRQHandler(void)
{
	HAL_GPIO_EXTI_IRQHandler(KEY0_PIN);
}


void SysTick_Handler(void)
{
		HAL_IncTick(); //uwTick自加操作 uwTick += uwTickFreq;

}

여기에 이미지 설명을 삽입하세요.
여기에 이미지 설명을 삽입하세요.

소프트웨어 시뮬레이션 디버깅

소프트웨어 시뮬레이션을 사용하여 메인 함수 아래의 LED0_Init() 함수에서 디버깅을 시작하고 중지합니다.

작업 중 오류가 발생했습니다: *** 오류 65: 0x40023830의 액세스 위반:
해당 CPU가 지정되지 않았기 때문에 '쓰기' 권한이 없습니다:
해결 방법:

  • 1 새 cpu.ini를 생성하고 다음을 작성합니다.
map 0x40000000,0x400FFFFF read write
  • 2 디버그할 cpu.ini를 추가합니다.
    여기에 이미지 설명을 삽입하세요.

두 코드 비교

인터럽트 모드는 CPU 점유율이 낮고, 대기 시간도 짧으며, CPU 점유율도 낮아집니다.

수업 후 숙제:

1: Bincheng 매뉴얼(30장)에서 USART 컨트롤러 설명을 미리 봅니다.
2: KEY1을 누른 후 중단을 통해 프로그램을 구현합니다. LED1을 0.5S 간격으로 깜박이고 5S 후에 끄고 코드를 구현하고 보드 디버깅

Supongo que te gusta

Origin blog.csdn.net/Medlar_CN/article/details/132098270
Recomendado
Clasificación