198 lines
5.8 KiB
C
198 lines
5.8 KiB
C
#include "app_main.h"
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
|
||
// 地址 ID高3位 0x0-0x7
|
||
#define CAN_ADDRESS_HOST 0x7
|
||
#define CAN_ADDRESS_DEVICE 0x1
|
||
#define CAN_ADDRESS_MASK 0x7
|
||
// 指令 ID低8位 0x00-0xFF
|
||
#define CAN_COMMAND_LED_CONTROL 0x01
|
||
#define CAN_COMMAND_LED_STATUS 0x02
|
||
#define CAN_COMMAND_MASK 0xFF
|
||
|
||
static volatile uint8_t led_status[2] = { 0 };
|
||
static volatile uint8_t led_status_changed = 0;
|
||
|
||
void can_configure(void)
|
||
{
|
||
/**
|
||
* BYTE3 | BYTE2 | BYTE1 | BYTE0
|
||
* STID[10:3] | STID[2:0] EXID[17:13] | EXID[12:5] | EXID[4:0] IDE RTR 0
|
||
*
|
||
* STID[10:4] 标准ID,此处用作地址,Id置CAN_ADDRESS_HOST的值,MaskId置0x7F
|
||
* EXID[17:15] 扩展ID,未使用,Id置全0,Mask置全0
|
||
* RTR 1为遥控帧,0为数据帧,此处均接收,不需要过滤,Id任意,MaskId置0
|
||
* IDE 1为扩展ID格式,0为标准ID格式,此处只接收标准格式,需要过滤,Id置0,MaskId置1
|
||
*/
|
||
uint32_t filter_id = ((uint32_t)CAN_ADDRESS_DEVICE << 8) << 21;
|
||
uint32_t filter_id_mask = (((uint32_t)CAN_ADDRESS_MASK << 8) << 21) | ((uint32_t)0x01 << 3);
|
||
|
||
CAN_FilterTypeDef filter;
|
||
filter.FilterBank = 0;
|
||
filter.FilterMode = CAN_FILTERMODE_IDMASK; //过滤除主机发送的所有帧
|
||
filter.FilterScale = CAN_FILTERSCALE_32BIT; //标准ID格式,Id与Mask的High与Low分别代表两个过滤器
|
||
filter.FilterIdHigh = filter_id >> 16;
|
||
filter.FilterIdLow = (uint16_t)filter_id;
|
||
filter.FilterMaskIdHigh = filter_id_mask >> 16;
|
||
filter.FilterMaskIdLow = (uint16_t)filter_id_mask;
|
||
filter.FilterFIFOAssignment = CAN_RX_FIFO0;
|
||
filter.FilterActivation = ENABLE;
|
||
HAL_CAN_ConfigFilter(&hcan, &filter); //配置接收过滤器
|
||
|
||
HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_TX_MAILBOX_EMPTY | CAN_IT_ERROR); //使能接收与发送中断
|
||
HAL_CAN_ActivateNotification(&hcan, CAN_IT_ERROR | CAN_IT_RX_FIFO0_OVERRUN | CAN_IT_RX_FIFO0_FULL | CAN_IT_LAST_ERROR_CODE); //使能错误中断
|
||
|
||
HAL_CAN_Start(&hcan); //使能CAN外设
|
||
}
|
||
|
||
HAL_StatusTypeDef can_transmit(uint16_t id, const uint8_t *data, uint8_t length)
|
||
{
|
||
CAN_TxHeaderTypeDef header = {
|
||
.IDE = CAN_ID_STD, //标准ID格式
|
||
.RTR = CAN_RTR_DATA, //数据帧
|
||
.StdId = id,
|
||
.DLC = length
|
||
};
|
||
|
||
uint32_t mailbox;
|
||
return HAL_CAN_AddTxMessage(&hcan, &header, data, &mailbox);
|
||
}
|
||
|
||
void app_led_update(void)
|
||
{
|
||
if (led_status[0]) {
|
||
LED1_ON();
|
||
} else {
|
||
LED1_OFF();
|
||
}
|
||
|
||
if (led_status[1]) {
|
||
LED2_ON();
|
||
} else {
|
||
LED2_OFF();
|
||
}
|
||
}
|
||
|
||
void app_key_process(void)
|
||
{
|
||
if (KEY1_PRESSED()) {
|
||
led_status[0] = !led_status[0];
|
||
led_status_changed = 1;
|
||
HAL_Delay(100);
|
||
while (KEY1_PRESSED());
|
||
HAL_Delay(100);
|
||
}
|
||
|
||
if (KEY2_PRESSED()) {
|
||
led_status[1] = !led_status[1];
|
||
led_status_changed = 1;
|
||
HAL_Delay(100);
|
||
while (KEY2_PRESSED());
|
||
HAL_Delay(100);
|
||
}
|
||
}
|
||
|
||
void app_can_update(void)
|
||
{
|
||
if (led_status_changed) {
|
||
can_transmit((CAN_ADDRESS_HOST << 8) | CAN_COMMAND_LED_STATUS, (uint8_t*)led_status, sizeof(led_status));
|
||
led_status_changed = 0;
|
||
}
|
||
}
|
||
|
||
void app_main(void)
|
||
{
|
||
can_configure();
|
||
|
||
while (1) {
|
||
app_key_process();
|
||
|
||
app_led_update();
|
||
app_can_update();
|
||
}
|
||
}
|
||
|
||
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
|
||
{
|
||
CAN_RxHeaderTypeDef header;
|
||
uint8_t data[8];
|
||
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &header, data) != HAL_OK || header.DLC < 2) {
|
||
printf("wrong can message\r\n");
|
||
return;
|
||
}
|
||
|
||
if ((header.StdId & 0xFF) == CAN_COMMAND_LED_CONTROL) {
|
||
if (data[0] == 1) { //点亮
|
||
led_status[0] = 1;
|
||
} else if (data[0] == 2) { //熄灭
|
||
led_status[0] = 0;
|
||
} else if (data[0] == 3) { //切换
|
||
led_status[0] = !led_status[0];
|
||
}
|
||
|
||
if (data[1] == 1) { //点亮
|
||
led_status[1] = 1;
|
||
} else if (data[1] == 2) { //熄灭
|
||
led_status[1] = 0;
|
||
} else if (data[1] == 3) { //切换
|
||
led_status[1] = !led_status[1];
|
||
}
|
||
|
||
led_status_changed = 1;
|
||
} else {
|
||
printf("unhandled command: 0x%02X\r\n", (int)header.StdId & 0xFF);
|
||
}
|
||
}
|
||
|
||
void HAL_CAN_RxFifo0FullCallback(CAN_HandleTypeDef *hcan)
|
||
{
|
||
printf("rx fifo full!\r\n");
|
||
}
|
||
|
||
void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan)
|
||
{
|
||
printf("tx mailbox0 send ok\r\n");
|
||
}
|
||
|
||
void HAL_CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan)
|
||
{
|
||
printf("tx mailbox1 send ok\r\n");
|
||
}
|
||
|
||
void HAL_CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan)
|
||
{
|
||
printf("tx mailbox2 send ok\r\n");
|
||
}
|
||
|
||
void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan)
|
||
{
|
||
uint32_t error_code = HAL_CAN_GetError(hcan);
|
||
|
||
if (error_code & (HAL_CAN_ERROR_RX_FOV0 | HAL_CAN_ERROR_RX_FOV1)) {
|
||
printf("rx fifo overrun error");
|
||
}
|
||
|
||
if (error_code & (HAL_CAN_ERROR_TX_ALST0 | HAL_CAN_ERROR_TX_ALST1 | HAL_CAN_ERROR_TX_ALST2)) {
|
||
printf("tx mailbox arbitration failure"); //仲裁失败导致的发送错误
|
||
} else if (error_code & (HAL_CAN_ERROR_TX_TERR0 | HAL_CAN_ERROR_TX_TERR1 | HAL_CAN_ERROR_TX_TERR2)) {
|
||
printf("tx mailbox transmit error"); //发送失败导致的发送错误
|
||
}
|
||
|
||
if (error_code & HAL_CAN_ERROR_STF) {
|
||
printf(", reason: stuff error"); //位填充错误
|
||
} else if (error_code & HAL_CAN_ERROR_FOR) {
|
||
printf(", reason: form error"); //格式错误
|
||
} else if (error_code & HAL_CAN_ERROR_ACK) {
|
||
printf(", reason: acknowledgment error"); //ACK错误
|
||
} else if (error_code & HAL_CAN_ERROR_BR) {
|
||
printf(", reason: bit recessive error"); //显性位错误
|
||
} else if (error_code & HAL_CAN_ERROR_BD) {
|
||
printf(", reason: bit dominant error"); //隐性位错误
|
||
} else if (error_code & HAL_CAN_ERROR_CRC) {
|
||
printf(", reason: crc error"); //CRC校验错误
|
||
}
|
||
|
||
printf("\r\n");
|
||
}
|