APM32F103 CAN总线控制LED灯固件程序示例
由于没有具体的硬件平台和开发环境,以下是一个基于STM32CubeMX和Keil MDK的APM32F103固件程序示例。
- 初始化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();
}
}
- 初始化按键和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);
}
- 处理按键事件
在主函数中,需要不断扫描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);
}
}
}
}
}
- 处理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
原文地址: https://www.cveoy.top/t/topic/oWXC 著作权归作者所有。请勿转载和采集!