单片机can实验
单片机 STM32F407开发板DMF407电机开发板平台keil V5.31HSE 为8MHZHSI为16MHZ原理图主函数int main(void) { uint8_t key; uint8_t i 0, t 0; uint8_t cnt 0; uint8_t canbuf[8]; uint8_t rxlen 0; uint8_t res; uint8_t mode 1; /* CAN工作模式: 0,普通模式; 1,环回模式 */ HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */ delay_init(168); /* 延时初始化 */ usart_init(115200); /* 串口初始化为115200 */ usmart_dev.init(84); /* 初始化USMART */ led_init(); /* 初始化LED */ lcd_init(); /* 初始化LCD */ key_init(); /* 初始化按键 */ can_init(CAN_SJW_1TQ, CAN_BS2_6TQ, CAN_BS1_7TQ, 6, CAN_MODE_LOOPBACK); /* CAN初始化, 环回模式, 波特率500Kbps */ lcd_show_string(30, 50, 200, 16, 16, STM32, RED); lcd_show_string(30, 70, 200, 16, 16, CAN TEST, RED); lcd_show_string(30, 90, 200, 16, 16, ATOMALIENTEK, RED); lcd_show_string(30, 110, 200, 16, 16, LoopBack Mode, RED); lcd_show_string(30, 130, 200, 16, 16, KEY0:Send KEY2:Mode, RED); /* 显示提示信息 */ lcd_show_string(30, 150, 200, 16, 16, Count:, RED); /* 显示当前计数值 */ lcd_show_string(30, 170, 200, 16, 16, Send Data:, RED); /* 提示发送的数据 */ lcd_show_string(30, 230, 200, 16, 16, Receive Data:, RED); /* 提示接收到的数据 */ while (1) { key key_scan(0); if (key KEY0_PRES) /* KEY0按下,发送一次数据 */ { for (i 0; i 8; i) { canbuf[i] cnt i; /* 填充发送缓冲区 */ if (i 4) { lcd_show_xnum(30 i * 32, 190, canbuf[i], 3, 16, 0x80, BLUE); /* 显示数据 */ } else { lcd_show_xnum(30 (i - 4) * 32, 210, canbuf[i], 3, 16, 0x80, BLUE); /* 显示数据 */ } } res can_send_msg(0x12, canbuf, 8); /* ID 0x12, 发送8个字节 */ if (res) { lcd_show_string(30 80, 170, 200, 16, 16, Failed, BLUE); /* 提示发送失败 */ } else { lcd_show_string(30 80, 170, 200, 16, 16, OK , BLUE); /* 提示发送成功 */ } } else if (key KEY2_PRES) /* KEY2按下, 改变CAN的工作模式 */ { mode !mode; /* CAN初始化, 普通(0)/回环(1)模式, 波特率500Kbps */ can_init(CAN_SJW_1TQ, CAN_BS2_6TQ, CAN_BS1_7TQ, 6, mode ? CAN_MODE_LOOPBACK : CAN_MODE_NORMAL); if (mode 0) /* 普通模式需要2个开发板 */ { lcd_show_string(30, 110, 200, 16, 16, Normal Mode , RED); } else /* 回环模式, 一个开发板就可以测试了. */ { lcd_show_string(30, 110, 200, 16, 16, LoopBack Mode, RED); } } rxlen can_receive_msg(0x12, canbuf); /* CAN ID 0x12, 接收数据查询 */ if (rxlen) /* 接收到有数据 */ { lcd_fill(30, 270, 130, 310, WHITE); /* 清除之前的显示 */ for (i 0; i rxlen; i) { if (i 4) { lcd_show_xnum(30 i * 32, 250, canbuf[i], 3, 16, 0x80, BLUE); /* 显示数据 */ } else { lcd_show_xnum(30 (i - 4) * 32, 270, canbuf[i], 3, 16, 0x80, BLUE); /* 显示数据 */ } } } t; delay_ms(10); if (t 20) { LED0_TOGGLE(); /* 提示系统正在运行 */ t 0; cnt; lcd_show_xnum(30 48, 150, cnt, 3, 16, 0x80, BLUE); /* 显示数据 */ } } }配置/* CAN 引脚 定义 */ #define CAN_RX_GPIO_PORT GPIOI #define CAN_RX_GPIO_PIN GPIO_PIN_9 #define CAN_RX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOI_CLK_ENABLE(); }while(0) /* PI口时钟使能 */ #define CAN_TX_GPIO_PORT GPIOB #define CAN_TX_GPIO_PIN GPIO_PIN_9 #define CAN_TX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */ uint8_t can_init(uint32_t tsjw, uint32_t tbs2, uint32_t tbs1, uint16_t brp, uint32_t mode) { g_canx_handler.Instance CAN1; g_canx_handler.Init.Prescaler brp; /* 分频系数(Fdiv)为brp1 */ g_canx_handler.Init.Mode mode; /* 模式设置 */ g_canx_handler.Init.SyncJumpWidth tsjw; /* 重新同步跳跃宽度(Tsjw)为tsjw1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ */ g_canx_handler.Init.TimeSeg1 tbs1; /* tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ */ g_canx_handler.Init.TimeSeg2 tbs2; /* tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ */ g_canx_handler.Init.TimeTriggeredMode DISABLE; /* 非时间触发通信模式 */ g_canx_handler.Init.AutoBusOff DISABLE; /* 软件自动离线管理 */ g_canx_handler.Init.AutoWakeUp DISABLE; /* 睡眠模式通过软件唤醒(清除CAN-MCR的SLEEP位) */ g_canx_handler.Init.AutoRetransmission ENABLE; /* 禁止报文自动传送 */ g_canx_handler.Init.ReceiveFifoLocked DISABLE; /* 报文不锁定,新的覆盖旧的 */ g_canx_handler.Init.TransmitFifoPriority DISABLE; /* 优先级由报文标识符决定 */ if (HAL_CAN_Init(g_canx_handler) ! HAL_OK) { return 1; } #if CAN_RX0_INT_ENABLE /* 使用中断接收 */ __HAL_CAN_ENABLE_IT(g_canx_handler, CAN_IT_RX_FIFO0_MSG_PENDING); /* FIFO0消息挂号中断允许 */ HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn); /* 使能CAN中断 */ HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 1, 0); /* 抢占优先级1子优先级0 */ #endif CAN_FilterTypeDef sFilterConfig; /*配置CAN过滤器*/ sFilterConfig.FilterBank 0; /* 过滤器0 */ sFilterConfig.FilterMode CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh 0x0000; /* 32位ID */ sFilterConfig.FilterIdLow 0x0000; sFilterConfig.FilterMaskIdHigh 0x0000; /* 32位MASK */ sFilterConfig.FilterMaskIdLow 0x0000; sFilterConfig.FilterFIFOAssignment CAN_FILTER_FIFO0; /* 过滤器0关联到FIFO0 */ sFilterConfig.FilterActivation CAN_FILTER_ENABLE; /* 激活滤波器0 */ sFilterConfig.SlaveStartFilterBank 14; /* 过滤器配置 */ if (HAL_CAN_ConfigFilter(g_canx_handler, sFilterConfig) ! HAL_OK) { return 2; } /* 启动CAN外围设备 */ if (HAL_CAN_Start(g_canx_handler) ! HAL_OK) { return 3; } return 0; } void HAL_CAN_MspInit(CAN_HandleTypeDef *hcan) { if (CAN1 hcan-Instance) { CAN_RX_GPIO_CLK_ENABLE(); /* CAN_RX脚时钟使能 */ CAN_TX_GPIO_CLK_ENABLE(); /* CAN_TX脚时钟使能 */ __HAL_RCC_CAN1_CLK_ENABLE(); /* 使能CAN1时钟 */ GPIO_InitTypeDef gpio_init_struct; gpio_init_struct.Pin CAN_TX_GPIO_PIN; gpio_init_struct.Mode GPIO_MODE_AF_PP; gpio_init_struct.Pull GPIO_PULLUP; gpio_init_struct.Speed GPIO_SPEED_FREQ_HIGH; gpio_init_struct.Alternate GPIO_AF9_CAN1; HAL_GPIO_Init(CAN_TX_GPIO_PORT, gpio_init_struct); /* CAN_TX脚 模式设置 */ gpio_init_struct.Pin CAN_RX_GPIO_PIN; HAL_GPIO_Init(CAN_RX_GPIO_PORT, gpio_init_struct); /* CAN_RX脚 必须设置成输入模式 */ } } uint8_t can_send_msg(uint32_t id, uint8_t *msg, uint8_t len) { uint32_t TxMailbox CAN_TX_MAILBOX0; g_canx_txheader.StdId id; /* 标准标识符 */ g_canx_txheader.ExtId id; /* 扩展标识符(29位) */ g_canx_txheader.IDE CAN_ID_STD; /* 使用标准帧 */ g_canx_txheader.RTR CAN_RTR_DATA; /* 数据帧 */ g_canx_txheader.DLC len; if (HAL_CAN_AddTxMessage(g_canx_handler, g_canx_txheader, msg, TxMailbox) ! HAL_OK) /* 发送消息 */ { return 1; } while (HAL_CAN_GetTxMailboxesFreeLevel(g_canx_handler) ! 3); /* 等待发送完成,所有邮箱为空 */ return 0; } uint8_t can_receive_msg(uint32_t id, uint8_t *buf) { if (HAL_CAN_GetRxFifoFillLevel(g_canx_handler, CAN_RX_FIFO0) 0) /* 没有接收到数据 */ { return 0; } if (HAL_CAN_GetRxMessage(g_canx_handler, CAN_RX_FIFO0, g_canx_rxheader, buf) ! HAL_OK) /* 读取数据 */ { return 0; } if (g_canx_rxheader.StdId! id || g_canx_rxheader.IDE ! CAN_ID_STD || g_canx_rxheader.RTR ! CAN_RTR_DATA) /* 接收到的ID不对 / 不是标准帧 / 不是数据帧 */ { return 0; } return g_canx_rxheader.DLC; }测试结果