
文章目录1. 实验目的2. 硬件清单3. 硬件接线4. 构思环节1. 框架搭建2. CAN内容3. 主函数5. 出现的问题6. 代码展示CAN总线代码按键代码主函数7. 实验结果1. 实验目的使用环回模式实现自发自收两个CAN设备实现收发。2. 硬件清单TJA10502个上官二号2个ST-LinkUSB转TTL本实验上官二号一个也可以实现3. 硬件接线4. 构思环节1. 框架搭建在串口打印功能实验基础上做建立CAN收发实验BSP文件夹中有按键key文件夹、can文件夹并加载相关.c和.h文件。加入CAN的驱动文件voidcan_init(void){}voidHAL_CAN_MspInit(句柄){}voidcan_send_data(uint32_tid,uint8_t*buf,uint8_tlen){}// uint8_t *buf接收数据用指针接收voidcan_recvive_data(uint8_t*buf){}2. CAN内容voidcan_init(void){// 参数配置对象是CAN1 工作模式回环模式 预分频器4TS19Tq81 TS28Tq71 SyncJumpWidthCAN_SJW_1TQ 其它6个为DISABLEHAL_CAN_Init(句柄);// 过滤器配置// 参数配置工作模式掩码模式 配置开关位32位 FilterIdLow0;MaskIdHigh0;MaskIdLow0;FilterBack0;FiletrFIFOAssignmentCAN_FILTER_FIFO0;FilterActivationENABLE;SlaveStartFilterBank14;HAL_CAN_ConfigFiletr(句柄);// can开始工作HAL_CAN_Start(句柄);}voidHAL_CAN_MspInit(句柄){// 打开CAN1时钟// 打开GPIO时钟// 对GPIO初始化,看手册TX引脚PA12 复用推挽输出 上拉 高速HAL_GPIO_Init();RX引脚11复用输入}// 发送函数voidcan_send_data(uint32_tid,uint8_t*buf,uint8_tlen){// 定义邮箱uint32_ttx_mailCAN_TX_MAILBOX0;// 数据帧参数配置ExtIdid;// 拓展帧DLClen;IDECAN_ID_EXT;RTR数据帧HAL_CAN_AddTxMessage(句柄数据帧buf 指定邮箱);// 等待数据发完while(HAL_CAN_GetMailboxesFreeLevel(句柄)!3);// 三个邮箱都空数据就发完了// 打印发的buf数据内容uint8_ti0;printf(发送数据\r\n);for(i0;ilen;i)printf(%X,buf[i]);printf(\r\n);}// 接收函数// uint8_t *buf接收数据用指针接收uint8_tcan_recvive_data(uint8_t*buf){// 定义数据帧首位// 先看邮箱是否有数据if(HAL_CAN_GetRxFifoFillLevel(can句柄,CAN_RX_FIFO0)0)return0;HAL_CAN_GetRxMessage(can句柄,CAN_RX_FIFO0,数据头句柄,buf);uint8_ti0;printf(接收数据\r\n);for(i0;irx_header.DLC;i)printf(%X,buf[i]);printf(\r\n);returnrx_header.DLC;}3. 主函数main.c// 发送数据数组uint8_tdata_send[8]{0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};// 接收数据数组uint8_tdata_recv[8];can_init();key_init();uint8_ti0;// 按下按键1发送数据while(1){if(key_scan()1){for(i0;i8;i)data_send[i];can_send_data(0x12345678,指定发送的数据data_send,len8);}can_receive_data(data_recv);}如何接到总线上将工作模式从回环模式改为NORMAL再编译烧录。TJ1050板子一定要5V供电3.3V无法正常工作。5. 出现的问题问题解决can_handle.Init.TimeSeg1 CAN_BS1_9TQ;can_handle.Init.TimeSeg2 CAN_BS2_8TQ;6. 代码展示CAN总线代码can.c#includecan.h#includestdio.hCAN_HandleTypeDef can_handle{0};voidcan_init(void){can_handle.InstanceCAN1;can_handle.Init.ModeCAN_MODE_LOOPBACK;can_handle.Init.Prescaler4;can_handle.Init.TimeSeg1CAN_BS1_9TQ;can_handle.Init.TimeSeg2CAN_BS2_8TQ;can_handle.Init.SyncJumpWidthCAN_SJW_1TQ;can_handle.Init.AutoBusOffDISABLE;can_handle.Init.AutoRetransmissionDISABLE;can_handle.Init.AutoWakeUpDISABLE;can_handle.Init.ReceiveFifoLockedDISABLE;can_handle.Init.TimeTriggeredModeDISABLE;can_handle.Init.TransmitFifoPriorityDISABLE;HAL_CAN_Init(can_handle);// 配置过滤器CAN_FilterTypeDef filter_config{0};filter_config.FilterModeCAN_FILTERMODE_IDMASK;// 掩码模式filter_config.FilterScaleCAN_FILTERSCALE_32BIT;// 32位扩展帧filter_config.FilterIdLow0;// 期望ID// 过滤器的开关用来指定FilterId中哪些位必须精准匹配//置1必须匹配filter_config.FilterMaskIdHigh0;// 期望的掩码值filter_config.FilterMaskIdLow0;// 掩码值filter_config.FilterBank0;// 过滤器组编号filter_config.FilterFIFOAssignmentCAN_FILTER_FIFO0;// FIFO分配filter_config.FilterActivationCAN_FILTER_ENABLE;// 过滤器激活HAL_CAN_ConfigFilter(can_handle,filter_config);// 开始工作HAL_CAN_Start(can_handle);}voidHAL_CAN_MspInit(CAN_HandleTypeDef*hcan){GPIO_InitTypeDef gpio_initstruct;// 打开can和gpio时钟__HAL_RCC_CAN1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();// 使能GPIOB时钟// 调用GPIO初始化函数gpio_initstruct.PinGPIO_PIN_12;gpio_initstruct.ModeGPIO_MODE_AF_PP;gpio_initstruct.PullGPIO_PULLUP;gpio_initstruct.SpeedGPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,gpio_initstruct);gpio_initstruct.PinGPIO_PIN_11;gpio_initstruct.ModeGPIO_MODE_AF_INPUT;HAL_GPIO_Init(GPIOA,gpio_initstruct);}// 发送数据voidcan_send_data(uint32_tid,uint8_t*buf,uint8_tlen){// 定义邮箱uint32_ttx_mailCAN_TX_MAILBOX0;CAN_TxHeaderTypeDef pheader_handle{0};pheader_handle.ExtIdid;pheader_handle.DLClen;pheader_handle.IDECAN_ID_EXT;pheader_handle.RTRCAN_RTR_DATA;HAL_CAN_AddTxMessage(can_handle,pheader_handle,buf,tx_mail);// 发送// 等待数据发完,三个邮箱都空表示数据发完while(HAL_CAN_GetTxMailboxesFreeLevel(can_handle)!3);// 打印数据内容uint8_ti0;printf(发送数据\r\n);for(i0;ilen;i)printf(%X ,buf[i]);printf(\r\n);}// 接收数据uint8_tcan_recv_data(uint8_t*buf){CAN_RxHeaderTypeDef recv_header{0};// 先看邮箱是否有数据if(HAL_CAN_GetRxFifoFillLevel(can_handle,CAN_RX_FIFO0)0)return0;HAL_CAN_GetRxMessage(can_handle,CAN_RX_FIFO0,recv_header,buf);// 接收uint8_ti0;printf(接收数据\r\n);for(i0;irecv_header.DLC;i)printf(%X ,buf[i]);printf(\r\n);returnrecv_header.DLC;}can.h#ifndef__CAN_H__#define__CAN_H__#includesys.hvoidcan_init(void);voidcan_send_data(uint32_tid,uint8_t*buf,uint8_tlen);uint8_tcan_recv_data(uint8_t*buf);#endif按键代码key.c#includekey.h#includedelay.h// 初始化GPIOvoidkey_init(void){GPIO_InitTypeDef gpio_initstruct;// 打开时钟__HAL_RCC_GPIOA_CLK_ENABLE();// 使能GPIOB时钟// 调用GPIO初始化函数gpio_initstruct.PinGPIO_PIN_0|GPIO_PIN_1;// KEY对应的引脚gpio_initstruct.ModeGPIO_MODE_INPUT;// 浮空输入gpio_initstruct.PullGPIO_PULLUP;// 上拉gpio_initstruct.SpeedGPIO_SPEED_FREQ_HIGH;// 高速HAL_GPIO_Init(GPIOA,gpio_initstruct);}// 按键扫描uint8_tkey_scan(void){// 检测按键是否按下if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)GPIO_PIN_RESET){// 消抖delay_ms(10);// 再次检测按键是否被按下if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)GPIO_PIN_RESET){// 如果是按下状态等待按键松开while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)GPIO_PIN_RESET);// 返回按键值return1;}}// 检测按键是否按下if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)GPIO_PIN_RESET){// 消抖delay_ms(10);// 再次检测按键是否被按下if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)GPIO_PIN_RESET){// 如果是按下状态等待按键松开while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)GPIO_PIN_RESET);// 返回按键值return2;}}// 返回默认值return0;}key.h#ifndef_KEY_H#define_KEY_H#includesys.hvoidkey_init(void);uint8_tkey_scan(void);#endif主函数main.c#includesys.h#includedelay.h#includeled.h#includeuart1.h#includekey.h#includecan.huint8_tsend_data[8]{0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};uint8_trecv_data[8];intmain(void){HAL_Init();/* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9);/* 设置时钟, 72Mhz */led_init();uart1_init(115200);key_init();can_init();printf(hello world! \r\n);uint8_ti0;while(1){// 如果按下按键1发送数据if(key_scan()1){for(i0;i8;i)send_data[i];can_send_data(0x12345678,send_data,8);}can_recv_data(recv_data);}}7. 实验结果先按下复位键再按下按键1发送数据与接收数据内容相同。再按下按键1与前面的数据相比全部1。