STM32F103 CAN通讯实操
目的:学习使用STM32CubeIDE进行CAN通讯编程学习;
准备条件:STM32F103ZET6开发板,PA11 PA12用于CAN + TJA1040,USB-CAN适配器1个;
操作流程:
第一步:使用cubeIDE自动生成代码;
第二步: 编辑代码,loopback条件下工作,中断接收CAN消息;
第三步:连接USB-CAN适配器,进行通讯测试。
详细操作步骤如下:
Step1:cubeIDE 生成project;File\New\STM32 Project;
Step2: Part Number中输入 STM32F103ZE, 选择LQFP144 package;
Step3:配置晶振和调试方法(PinOUT&Configuration)
Step4:配置时钟Clock Configration,确认APB1 peripheral clocks(MHz) = 16
bxCAN 对应的时钟为:APB1外设时钟; 见《STM32F10xx中文参考手册》“2.3 存储器映像” page28/547;
Step5: 配置bxCAN的波特率为100K
Step6:配置bxCAN的接收中断
Step7:配置读取中断的优先级别为15; USB low priority or CAN RX0 interrupts, preemption Priority =15;
Step8:生成代码后,在main.c中添加bxCAN初始化代码:
static void MX_CAN_Init(void){/* USER CODE BEGIN CAN_Init 0 *//* USER CODE END CAN_Init 0 *//* USER CODE BEGIN CAN_Init 1 *//* USER CODE END CAN_Init 1 */hcan.Instance = CAN1;hcan.Init.Prescaler = 16;hcan.Init.Mode = CAN_MODE_NORMAL;hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;hcan.Init.TimeSeg1 = CAN_BS1_6TQ;hcan.Init.TimeSeg2 = CAN_BS2_3TQ;hcan.Init.TimeTriggeredMode = DISABLE;hcan.Init.AutoBusOff = DISABLE;hcan.Init.AutoWakeUp = DISABLE;hcan.Init.AutoRetransmission = DISABLE;hcan.Init.ReceiveFifoLocked = DISABLE;hcan.Init.TransmitFifoPriority = DISABLE;if (HAL_CAN_Init(&hcan) != HAL_OK){Error_Handler();}/* USER CODE BEGIN CAN_Init 2 */CAN_FilterTypeDef _CAN_FilterTypeDef;_CAN_FilterTypeDef.FilterBank = 0; // filter 0_CAN_FilterTypeDef.FilterMode = CAN_FILTERMODE_IDMASK; // mask mode_CAN_FilterTypeDef.FilterScale = CAN_FILTERSCALE_32BIT;_CAN_FilterTypeDef.FilterIdHigh = 0;_CAN_FilterTypeDef.FilterIdLow = 0;_CAN_FilterTypeDef.FilterMaskIdHigh = 0;_CAN_FilterTypeDef.FilterMaskIdLow = 0; // set mask 0 to receive all can id_CAN_FilterTypeDef.FilterFIFOAssignment = CAN_RX_FIFO0; // assign to fifo0_CAN_FilterTypeDef.FilterActivation = CAN_FILTER_ENABLE;// enable can filter_CAN_FilterTypeDef.SlaveStartFilterBank = 27;if(HAL_CAN_ConfigFilter(&hcan,&_CAN_FilterTypeDef) != HAL_OK)Error_Handler();if(HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)Error_Handler();if(HAL_CAN_Start(&hcan) != HAL_OK)Error_Handler();/* USER CODE END CAN_Init 2 */}
Step9:生成代码后,在main.c中添加bxCAN读、写、中断接收代码:
/* USER CODE BEGIN 0 */
#define Tx_Error 3
#define Rx_Error 2
#define Rx_OK 0
CAN_TxHeaderTypeDef Tx_pHeader;
/** @brief: CAN Send Message.* @param: "TxData[]" stored the message of ready to send, which length must between 0 and 8.* @param: "length" stored the number of the data (one data is 8 bit) of ready to send.* @retval: Tx_Error: send error; other: the mailbox which has been used, this parameter can be a CAN_TX_MAILBOX0,* CAN_TX_MAILBOX1,* CAN_TX_MAILBOX2.*/
uint32_t CAN_TX_Message(uint8_t TxData[], uint8_t length)
{uint32_t TxMailboxNumber = 0x00000000U; // 存储本次发所使用邮箱的邮箱号Tx_pHeader.StdId = 0x030; // 以此ID发Tx_pHeader.ExtId = 0x0000; // 扩展ID(此处无用)Tx_pHeader.IDE = CAN_ID_STD; // 标准Tx_pHeader.RTR = CAN_RTR_DATA; // 数据Tx_pHeader.DLC = length; // 发数据的长度Tx_pHeader.TransmitGlobalTime = DISABLE;if(HAL_CAN_AddTxMessage(&hcan, &Tx_pHeader, TxData, &TxMailboxNumber) != HAL_OK){return Tx_Error;}return TxMailboxNumber;
}CAN_RxHeaderTypeDef Rx_pHeader;
/** @brief: CAN Receive Message.* @param: "RxData[]" will store the message which has been received, which length must between 0 and 8.* @retval: receive status.*/
uint32_t CAN_RX_Message(uint8_t RxData[])
{uint8_t aData[8]; // 缓存接收到的信息Rx_pHeader.StdId = 0x000; // 接收ID(此处无用,can接收有的ID号)Rx_pHeader.ExtId = 0x0000;Rx_pHeader.IDE = CAN_ID_STD; // 接收标准Rx_pHeader.DLC = 8; // 接收8bit数据Rx_pHeader.RTR = CAN_RTR_DATA; // 接收数据Rx_pHeader.FilterMatchIndex = 0; // 使用0号过滤器Rx_pHeader.Timestamp = 0;if(HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &Rx_pHeader, aData) != HAL_OK){return Rx_Error;}else{// 取出接收到的信息for(uint8_t i = 0; i<Rx_pHeader.DLC; i++){RxData[i] = aData[i];}return Rx_OK;}
}uint8_t RxData[8] = {0}; // 缓存接收到的信息
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{// 判断是哪路的CAN发生了中if(hcan->Instance == CAN1){if(CAN_RX_Message(RxData) != Rx_OK){// 接收信息失败printf("MCU Received CAN Data ERROR!!!");printf("\n\r");printf("\n\r");}else{// 接受信息成功,处理数printf("MCU Received CAN Data: ");for(uint8_t i = 0; i<8; i++){printf("%d ", RxData[i]);}printf("\n\r");printf("\n\r");}}
}
uint8_t TxData[8] = {0}; // 缓存待发送的信息
uint8_t length = 0x00; // 待发送信息的长度
/* USER CODE END 0 */
Step10:生成代码后,在main.c中添加main函数中添加主代码:
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_CAN_Init();/* USER CODE BEGIN 2 */TxData[7] = 0x1a; // 给定待发送的信息TxData[6] = 0x1b;TxData[5] = 0x1c;TxData[4] = 0x1d;TxData[3] = 0x1e;TxData[2] = 0x1f;TxData[1] = 0x10;TxData[0] = 0x11;length = 0x08; // 更新待发送信息的数据长度/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */if (CAN_TX_Message(TxData, length) == Tx_Error) // 轮询方式发CAN信息{Error_Handler();}HAL_Delay(500); // 延时0.5}/* USER CODE END 3 */
}
结果:调试成功后,可以在usb can收到消息
使用注意事项:
stm32的bxCAN配置和使用流程在cubeide软件中如下:
Step1: ioc文件里图形化使能can并配置工作时钟、波特率、工作模式、中断优先级;
Step2:自动生成代码后,在can.c文件里添加滤波器的配置并使能FIFO中断;
Step3:在MX_CAN_Init初始化完毕后启动can,才能发送信息;
Step4:在main.c文件下的main()外用户自定义中断回调函数。
常见错误点总结:
- 没有启动can,can是无法发送信息、接收不到信息的。对应库函数HAL_CAN_Start。
- 没有使能FIFO中断,can是不会中断的。
- 回调函数的函数名使用错误(因为有多个用途不同的函数名),can中断后不调用该函数。对应函数名:HAL_CAN_RxFifo0MsgPendingCallback;
- CAN调试的时候,可以先使用loopback模式,进行发送接收测试,没问题后,再设置为normal模块,连接USB-CAN适配器,进行实际测试;
- 波特率设置中的 Time Quanta Bit Segmenet1 和Time Quanta Bit Segmenet 2,尽量大于2,否则会影响发送和接收的稳定性。
- 希望自己能记住,同时看到的人也有帮助。
本文的源代码下载链接:https://download.csdn.net/download/qq_23313467/86730136
STM32F103 CAN通讯实操相关推荐
- I2C总线通信协议及实操stm32通过I2C实现温湿度(AHT20)采集
I2C总线通信协议及实操stm32通过I2C实现温湿度(AHT20)采集 一实验要求 二.12C总线通信协议 1.12C介绍 2.I2C物理层 3.I2C协议层 4.软件IIC和硬件IIC 三.STM ...
- 微生物组入门必读+宏基因组实操课程=新老司机赶快上车
声明:本文转载自宏基因组公众号,原作者朱微金,己获作者授权. 写在前面 作为纯wet遗传学博士,转行微生物组领域已经有两年.目睹微生物组文章中分析所占比重之大,让我痛下决心苦学dry技能.目前感觉对宏 ...
- 场景欺诈的策略梳理、总结与实操
风控部门作为一个成本部门,其本身不创造业务,但却逐渐被市场上的公司所接受,并且地位越来越重要.虽然风险自宇宙诞生起,就伴随着万物而生,但真正将其量化且客观分析也就这几个世纪以来的事情.而且就目前的认知 ...
- stm32移植paho_如何在STM32上移植Linux?超详细的实操经验分享
原标题:如何在STM32上移植Linux?超详细的实操经验分享 刚从硬件跳槽为嵌软时,没有任何一丝的准备.一入职,领导就交代了一项特难的任务--在stm32上移植linux! 瞬间我就懵了,没办法硬着 ...
- RabbitMQ第五个实操小案例——主题交换机(TopicExchange)
文章目录 RabbitMQ第五个实操小案例--主题交换机(TopicExchange) RabbitMQ第五个实操小案例--主题交换机(TopicExchange) TopicExchange 和 D ...
- 【Linux】2. Linux实操命令
Linux实操命令 2. Linux实操 2.1 远程登陆Linux系统 2.2 Vi和Vim编辑器 2.3 开机.重启和用户登陆注销 2.4 用户管理 2.5 指定运行级别指令 2.6 重置root ...
- 2021年道路运输企业主要负责人模拟考试题库及道路运输企业主要负责人实操考试视频
题库来源:安全生产模拟考试一点通公众号小程序 安全生产模拟考试一点通:道路运输企业主要负责人模拟考试题库根据新道路运输企业主要负责人考试大纲要求,安全生产模拟考试一点通将道路运输企业主要负责人模拟考试 ...
- redis 集群 实操 (史上最全、5w字长文)
文章很长,建议收藏起来慢慢读! 总目录 博客园版 为大家准备了更多的好文章!!!! 推荐:尼恩Java面试宝典(持续更新 + 史上最全 + 面试必备)具体详情,请点击此链接 尼恩Java面试宝典,34 ...
- redis cluster 集群 HA 原理和实操(史上最全、面试必备)
文章很长,建议收藏起来慢慢读!疯狂创客圈总目录 语雀版 | 总目录 码云版| 总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 经典图书:<Java高并发核心编程(卷1)> 面试必备 ...
最新文章
- Java数据类型简单认识
- 程序员的杂想-不要只做一名程序员
- 2019春第一次课程设计实验报告
- 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 )
- jQuery UI Widget(1.8.1)工作原理--转载
- Python正则表达式之扩展语法(5)
- 手写简版spring --2--实现Bean的定义、注册、获取
- STM32F4 HAL库开发 -- NVIC 中断优先级管理
- D-hdu 1465 不容易系列之一(递推)
- python中re_Python中re(正则表达式)模块学习
- Mysql学习总结(72)——MySQL 开发者开发,设计规范再总结
- keyshot渲染玻璃打光_KeyShot新手的第一次打光,无脑三点打光塑造模型质感
- linux实现访问自动挂载
- seriespandas索引操作练习
- java开发微信公众号支付全流程
- Echarts柱状图上加图标
- 小程序图片底部留白问题
- 新项目筹划中。。。。
- python12306爬虫_爬虫12306返回数据怎么解析
- 内核——eCos内核概览
热门文章
- main和_main的区别
- 贝叶斯判别python_SPSS分析技术:判别分析
- 朗读评价语言集锦_转载‖语文课堂评价语集锦
- 怎样选择青少年护眼灯?推荐最好的青少年护眼灯品牌
- GVINS编译出现大量的error: ‘CV_CALIB_CB_ADAPTIVE_THRESH’ was not declared in this scope错误
- 计算机世界“粗口”事件:该骂的不只是腾讯
- linux 搭建/重启 java项目 复制文件命令
- java socket重连_Java客户端Socket在服务端重启后的异常情况处理
- C++定义Teacher类和Cadre类作为基类,创建Teacher_Cadre类
- JS 流行库(七):WOW