由于没有具体的硬件平台和开发环境,以下是一个基于STM32CubeMX和Keil MDK的APM32F103固件程序示例。

  1. 初始化CAN总线

在初始化函数中,首先要对CAN总线进行初始化,并设置CAN通信的波特率和模式。

void MX_CAN_Init(void)
{
  hcan.Instance = CAN1;
  hcan.Init.Prescaler = 16;
  hcan.Init.Mode = CAN_MODE_NORMAL;
  hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan.Init.TimeSeg1 = CAN_BS1_13TQ;
  hcan.Init.TimeSeg2 = CAN_BS2_2TQ;
  hcan.Init.TimeTriggeredMode = DISABLE;
  hcan.Init.AutoBusOff = ENABLE;
  hcan.Init.AutoWakeUp = DISABLE;
  hcan.Init.AutoRetransmission = ENABLE;
  hcan.Init.ReceiveFifoLocked = DISABLE;
  hcan.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan) != HAL_OK)
  {
    Error_Handler();
  }
}
  1. 初始化按键和LED

在初始化函数中,还需要对4个按键和4个LED进行初始化,并设置对应的IO口方向和初始状态。

void MX_GPIO_Init(void)
{
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pins : PA0 PA1 PA2 PA3 */
  GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PC13 PC14 PC15 */
  GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15, GPIO_PIN_RESET);
}
  1. 处理按键事件

在主函数中,需要不断扫描4个按键的状态,并根据不同的触发方式处理按键事件。当按键被按下时,发送按键状态到CAN总线,并点亮对应的LED。当接收到CAN总线的控制消息时,改变对应LED的状态。

uint32_t last_tick[4] = {0};
uint8_t click_count[4] = {0};
uint8_t button_state[4] = {0};

int main(void)
{
  /* Initialize HAL */
  HAL_Init();

  /* Initialize peripherals */
  MX_GPIO_Init();
  MX_CAN_Init();

  /* Start CAN reception */
  if (HAL_CAN_Receive_IT(&hcan, CAN_FIFO0) != HAL_OK)
  {
    Error_Handler();
  }

  /* Main loop */
  while (1)
  {
    for (int i = 0; i < 4; i++)
    {
      /* Detect button press */
      if (HAL_GPIO_ReadPin(GPIOA, 1 << i) == GPIO_PIN_RESET)
      {
        uint32_t current_tick = HAL_GetTick();
        uint32_t elapsed = current_tick - last_tick[i];
        last_tick[i] = current_tick;

        if (elapsed > 2000)
        {
          /* Double click */
          if (click_count[i] == 1)
          {
            click_count[i] = 0;
            button_state[i] = BUTTON_DOUBLE_CLICK;
            HAL_GPIO_TogglePin(GPIOC, 1 << i);
            send_button_state(i, BUTTON_DOUBLE_CLICK);
          }
          /* Long press */
          else if (click_count[i] == 0)
          {
            click_count[i] = 2;
            button_state[i] = BUTTON_LONG_PRESS;
            HAL_GPIO_WritePin(GPIOC, 1 << i, GPIO_PIN_SET);
            send_button_state(i, BUTTON_LONG_PRESS);
          }
        }
        else if (elapsed > 1000)
        {
          /* Short press */
          if (click_count[i] == 0)
          {
            click_count[i] = 1;
            button_state[i] = BUTTON_SHORT_PRESS;
            HAL_GPIO_WritePin(GPIOC, 1 << i, GPIO_PIN_SET);
            send_button_state(i, BUTTON_SHORT_PRESS);
          }
          /* Double click */
          else if (click_count[i] == 1)
          {
            click_count[i] = 0;
            button_state[i] = BUTTON_DOUBLE_CLICK;
            HAL_GPIO_TogglePin(GPIOC, 1 << i);
            send_button_state(i, BUTTON_DOUBLE_CLICK);
          }
        }
      }
      /* Detect button release */
      else
      {
        if (click_count[i] == 2)
        {
          /* Long press release */
          click_count[i] = 0;
          button_state[i] = BUTTON_LONG_PRESS_RELEASE;
          HAL_GPIO_WritePin(GPIOC, 1 << i, GPIO_PIN_RESET);
          send_button_state(i, BUTTON_LONG_PRESS_RELEASE);
        }
      }
    }
  }
}
  1. 处理CAN总线消息

在CAN总线的回调函数中,需要处理接收到的CAN总线消息,并根据消息内容改变对应LED的状态。

void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan)
{
  /* Check for message ID */
  if (hcan->pRxMsg->StdId == 0x100)
  {
    /* Check message length */
    if (hcan->pRxMsg->DLC == 1)
    {
      /* Parse message data */
      uint8_t led_state = hcan->pRxMsg->Data[0];

      /* Update LED state */
      for (int i = 0; i < 4; i++)
      {
        if (led_state & (1 << i))
        {
          HAL_GPIO_WritePin(GPIOC, 1 << i, GPIO_PIN_SET);
        }
        else
        {
          HAL_GPIO_WritePin(GPIOC, 1 << i, GPIO_PIN_RESET);
        }
      }
    }
  }

  /* Restart CAN reception */
  if (HAL_CAN_Receive_IT(hcan, CAN_FIFO0) != HAL_OK)
  {
    Error_Handler();
  }
}

完整的代码可以参考以下GitHub链接:https://github.com/qingyuexi/APM32F103_CAN_Button_LED

APM32F103 CAN总线控制LED灯固件程序示例

原文地址: https://www.cveoy.top/t/topic/oWXC 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录