你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32 CAN总线调试的一点心得总结

[复制链接]
aimejia 发布时间:2018-6-1 13:47
本帖最后由 aimejia 于 2018-6-1 13:49 编辑

一. 开发平台与工具:

1. 平台: STM32F103C8T6  48PIN工控板和自己设计的STM32开发板

2. 软件: MDK5 UVision V5.14.0.0

3. PACK: STM32F1xx_DFP——1.0.5(2014-03-14)

4. 其它:USB转串口,ST-Link下载器,

USB-CAN Adapter用于直接监视CAN口发出的数据,上位机有两个,一个是EmbededConfig for USB2CAN 配置串口、串口波特率、CAN速率等,另一个是EmbededDebug V2.0监视CAN口数据;使用顺序是先配置后查看CAN数据。

二. CAN总线的介绍简略:

bxCAN 是基本扩展 CAN (Basic Extended CAN) 的缩写,它支持 CAN 协议 2.0A 和 2.0B 。它的设计目标是,以最小的 CPU 负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求(优先级特性可软件配置)。

对于安全紧要的应用,bxCAN 提供所有支持时间触发通信模式所需的硬件功能。

主要特点
· 支持 CAN 协议 2.0A 和 2.0B 主动模式
· 波特率最高可达 1 兆位 / 秒
· 支持时间触发通信功能

发送
· 3 个发送邮箱
· 发送报文的优先级特性可软件配置
· 记录发送 SOF 时刻的时间戳

接收
· 3 级深度的2个接收 FIFO
· 14 个位宽可变的过滤器组 - 由整个 CAN 共享
· 标识符列表
· FIFO 溢出处理方式可配置
· 记录接收 SOF 时刻的时间戳

可支持时间触发通信模式
· 禁止自动重传模式
· 16 位自由运行定时器
· 定时器分辨率可配置
· 可在最后 2 个数据字节发送时间戳

管理
· 中断可屏蔽
· 邮箱占用单独 1 块地址空间,便于提高软件效率

更多STM32 CAN总线介绍详见:STM32中文参考手册_V10.pdf 或 STM32F10XXX-RM0008 Reference Manual 英文版

三. 遇到的问题分析与解决:

手上有两块STM32的板子,一个是网上买的MINI STM32工控板,另一个是自己公司设计的板子。二者有所不同,大致有两点,第一是串口,工控板用的是USART1 且用的是GPIO PA9(TX)和PA10(RX),自设板用的是USART2 且用的是GPIO PA2(TX)和PA3(RX);第二是CAN口管脚不同,工控板用的是复用功能映射到PB8(RX)和PB9(TX),而自设板用的是PA11(RX)和PA12(TX)。下图所示,两块板子部分原理图:

工控板

1.jpg

自设板

2.jpg

现在我是在工控板测试代码基础上,用到自设板上,实现PC端串口与STM32 CAN双向通信,要做的是将USART和CAN口的GPIO配置对应到自设板上。

首先,串口GPIO配置:

工控板
  1. [objc] view plain copy
  2. void USART1_Config(void)  
  3. {  
  4.     GPIO_InitTypeDef GPIO_InitStructure;  
  5.     USART_InitTypeDef USART_InitStructure;  
  6.   
  7.     /* config USART1 clock */  
  8.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);  
  9.       
  10.     /* USART1 GPIO config */  
  11.    /* Configure USART1 Tx (PA.09) as alternate function push-pull */  
  12.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  
  13.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
  14.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  15.   GPIO_Init(GPIOA, &GPIO_InitStructure);      
  16.   /* Configure USART1 Rx (PA.10) as input floating */  
  17.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;  
  18.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
  19.   GPIO_Init(GPIOA, &GPIO_InitStructure);  
  20.         
  21.     /* USART1 mode config */  
  22.     USART_InitStructure.USART_BaudRate = 115200;  
  23.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;  
  24.     USART_InitStructure.USART_StopBits = USART_StopBits_1;  
  25.     USART_InitStructure.USART_Parity = USART_Parity_No ;  
  26.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
  27.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  
  28.     USART_Init(USART1, &USART_InitStructure);   
  29.   USART_Cmd(USART1, ENABLE);  
  30.       
  31.     /* Enable the EVAL_COM1 Transmit interrupt: this interrupt is generated when the  
  32.      EVAL_COM1 transmit data register is empty */   
  33.   //USART_ITConfig(USART1, USART_IT_TXE, ENABLE);  
  34.   
  35.   /* Enable the EVAL_COM1 Receive interrupt: this interrupt is generated when the  
  36.      EVAL_COM1 receive data register is not empty */  
  37.   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  
  38. }  
  39.   
  40. /***************USART1 ÅäÖÃÖжϷ½Ê½·¢ËͽÓÊÕÊý¾Ý******************************/  
  41. void USART1_NVIC_Configuration(void)  
  42. {  
  43.   NVIC_InitTypeDef NVIC_InitStructure;  
  44.   
  45.   /* Enable the USARTx Interrupt */  
  46.   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;  
  47.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
  48.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
  49.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
  50.   NVIC_Init(&NVIC_InitStructure);  
  51. }  
  52.   
  53. /****************USART1 ÖжϺ¯Êý***************************/  
  54. void USART1_IRQHandler(void)  
  55. {  
  56.     if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
  57.     {  
  58.         RxBuffer[RxCounter++] = (USART_ReceiveData(USART1));  
  59.     }  
  60. }  
复制代码
USART1_Config()用于USART1的GPIO配置,配置到
*          | PA9  - USART1(Tx)      |
*          | PA10 - USART1(Rx)      |
*           ------------------------
USART1_NVIC_Configuration() 用于USART1设置中断方式接受发送数据

USART1_IRQHandler()用于USART1中断接受函数

自设板
  1. [objc] view plain copy
  2. void USART2_Config(void)  
  3. {  
  4.     GPIO_InitTypeDef GPIO_InitStructure;  
  5.     USART_InitTypeDef USART_InitStructure;  
  6.   
  7.     /* config USART2 clock */  
  8.     //RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);  
  9.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 , ENABLE);  
  10.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  
  11.       
  12.     /* USART2 GPIO config */  
  13.    /* Configure USART2 Tx (PA.02) as alternate function push-pull */  
  14.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;  
  15.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
  16.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  17.   GPIO_Init(GPIOA, &GPIO_InitStructure);      
  18.   /* Configure USART2 Rx (PA.03) as input floating */  
  19.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;  
  20.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
  21.   GPIO_Init(GPIOA, &GPIO_InitStructure);  
  22.         
  23.     /* USART2 mode config */  
  24.     USART_InitStructure.USART_BaudRate = 115200;  
  25.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;  
  26.     USART_InitStructure.USART_StopBits = USART_StopBits_1;  
  27.     USART_InitStructure.USART_Parity = USART_Parity_No ;  
  28.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
  29.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  
  30.     USART_Init(USART2, &USART_InitStructure);  
  31.     USART_Cmd(USART2, ENABLE);  
  32.       
  33.     /* Enable the EVAL_COM1 Transmit interrupt: this interrupt is generated when the  
  34.      EVAL_COM1 transmit data register is empty */   
  35.   //USART_ITConfig(USART1, USART_IT_TXE, ENABLE);  
  36.   
  37.   /* Enable the EVAL_COM1 Receive interrupt: this interrupt is generated when the  
  38.      EVAL_COM1 receive data register is not empty */  
  39.   //USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  
  40.     USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);  
  41. }  
  42.   
  43.   
  44. /***************USART2 ÅäÖÃÖжϷ½Ê½·¢ËͽÓÊÕÊý¾Ý******************************/  
  45. void USART2_NVIC_Configuration(void)  
  46. {  
  47.   NVIC_InitTypeDef NVIC_InitStructure;  
  48.   
  49.   /* Enable the USARTx Interrupt */  
  50.   NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;  
  51.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
  52.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
  53.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
  54.   NVIC_Init(&NVIC_InitStructure);  
  55. }  
  56.   
  57. /****************USART2 ÖжϺ¯Êý***************************/  
  58. void USART2_IRQHandler(void)  
  59. {  
  60.     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
  61.     {  
  62.         RxBuffer[RxCounter++] = (USART_ReceiveData(USART2));  
  63.     }  
  64. }  
复制代码
USART2_Config()用于USART2的GPIO配置,配置到
*          | PA2  - USART2(Tx)      |
*          | PA3 - USART2(Rx)      |
*           ------------------------

USART2_NVIC_Configuration() 用于USART2设置中断方式接受发送数据

USART2_IRQHandler()用于USART2中断接受函数

然后,配置CAN口GPIO

工控板
  1. [objc] view plain copy
  2. /*CAN GPIO ºÍʱÖÓÅäÖà */  
  3. void CAN_GPIO_Config(void)  
  4. {  
  5.   GPIO_InitTypeDef GPIO_InitStructure;   
  6.   /* ¸´Óù¦ÄܺÍGPIOB¶Ë¿ÚʱÖÓʹÄÜ*/     
  7.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                          
  8.   
  9.   /* CAN1 Ä£¿éʱÖÓʹÄÜ */  
  10.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);   
  11.   
  12.   /* Configure CAN pin: RX */    // PB8  
  13.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;  
  14.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  15.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  // ÉÏÀ­ÊäÈë  
  16.   GPIO_Init(GPIOB, &GPIO_InitStructure);  
  17.    
  18.   /* Configure CAN pin: TX */   // PB9  
  19.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  
  20.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // ¸´ÓÃÍÆÍìÊä³ö  
  21.   GPIO_Init(GPIOB, &GPIO_InitStructure);  
  22.    
  23.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 ±¾ÊµÑéûÓÐÓõ½ÖØÓ³ÉäI/O  
  24.   GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);  
  25.   
  26.    
  27. }  
复制代码
自设板
  1. [objc] view plain copy
  2. void CAN_GPIOA_Config(void)   
  3. {   
  4. GPIO_InitTypeDef GPIO_InitStructure;      
  5. /* CAN Periph clock enable */   
  6.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);   
  7. // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);   
  8.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);   
  9.    
  10.   /* Configure CAN pin: TX */   
  11.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;   
  12.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
  13.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   
  14.   GPIO_Init(GPIOA, &GPIO_InitStructure);      
  15. /* Configure CAN pin: RX */   
  16.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;  
  17.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     
  18.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;     
  19.   GPIO_Init(GPIOA, &GPIO_InitStructure);      
  20.   //GPIO_PinRemapConfig(GPIO_Remap1_CAN1 , ENABLE);   
  21. }   
复制代码
/******************************************************************************************/
就是这里!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
出现几个小问题,但是却是致命的问题!!!!!!!!!!!!!!!!!!!

/******************************************************************************************/

第一配置GPIO_Speed:

[objc] view plain copy
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //配置GPIO_Speed为50MHz  
如果配置GPIO时,省略这一步,会导致CAN口发送不出数据,工控板的配置是放在LED 的GPIO配置中,一开始忽略了这一点,之后用排除法试出来的;

第二配置复用功能和映射与否:
  1. [objc] view plain copy
  2. // RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //复用功能时钟使能  
复制代码
  1. [objc] view plain copy
  2. //GPIO_PinRemapConfig(GPIO_Remap1_CAN1 , ENABLE); //重映射I/O CAN使能
复制代码
  1. [objc] view plain copy
复制代码
  1. [objc] view plain copy
复制代码
  1. [objc] view plain copy
复制代码
上面两个被注释掉了,是由于:  
用PA11和PA12 用的是CAN的默认端口,而用PB8和PB9是用CAN的复用功能重映射端口。

  1. [objc] view plain copy
  2.   
复制代码

3.jpg

具体:
-------------------------------------------------------------------------

默认模式

   /* Configure CAN pin: RX */

GPIO

_InitStructure.GPIO_Pin = GPIO_Pin_11;

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

   GPIO_Init(GPIOA, &GPIO_InitStructure);

   /* Configure CAN pin: TX */

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

   GPIO_Init(GPIOA, &GPIO_InitStructure);
------------------------------------------------------------------------

重定义地址1模式

/* Configure CAN pin: RX */

   //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

   //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

   //GPIO_Init(GPIOB, &GPIO_InitStructure);

   /* Configure CAN pin: TX */  

   //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

   //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

   //GPIO_Init(GPIOB, &GPIO_InitStructure);

   /* Configure CAN Remap   重影射 */

   //GPIO_PinRemapConfig(GPIO_Remap1_CAN, ENABLE);

-------------------------------------------------------------------------  

重定义地址2模式

   /* Configure CAN pin: RX */

   //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

   //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

   //GPIO_Init(GPIOD, &GPIO_InitStructure);


   /* Configure CAN pin: TX */

   //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;

   //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

   //GPIO_Init(GPIOD, &GPIO_InitStructure);


   /* Configure CAN Remap   重影射 */

   //GPIO_PinRemapConfig(GPIO_Remap2_CAN, ENABLE);

-------------------------------------------------------------------------

设置完 CAN 的引脚之后还需要打开 CAN 的时钟:

/* CAN Periph clock enable */

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN, ENABLE);

第三CAN硬件部分:

一开始对CAN硬件部分没有过多的了解,后面经过一系列的试验,发现:

1. 如果STM32 CAN TX和RX没有和CAN收发器连接的情况下,STM32的CAN TX和RX是没用数据发出的;

2. STM32 CAN TX和RX必须要与CAN收发器的TX和RX对应,即TX接TX,RX接RX,否则CAN没有数据发出,说明:之所以说这个问题,不知道你们有没有注意到,我的自设板CAN收发器TX和RX是反接的;

3. STM32F103C8T6-LQFP48 的CAN口和USB口复用,即用CAN口是需要将USB口断开,防止有所影响;

4. 是我本身设备问题,我的自设板用的12V电源是我自己焊接的,不太可靠,电源12V时有时无的,所以最好烧写程序的时候点亮一个LED灯,可以显示板子的工作状态;

5. 工控板上CAN收发器是用TJA1050 是5V供电的,自设板用SN65HVD234 3.3-V CAN Bus Transceivers,之前有所顾虑,怕CAN收发器不一样会导致其它后果,之后发现没有问题。



以上为本人的一点心得,走了很多弯路。。。记录点滴,以此自励。





转载自sunnyhyh


评分

参与人数 2 ST金币 +3 收起 理由
STMCU + 5
50031185 -2 转载请注明出处

查看全部评分

收藏 评论4 发布时间:2018-6-1 13:47

举报

4个回答
samhong 回答时间:2018-6-2 06:56:45
谢谢分享!
50031185 回答时间:2018-6-2 10:08:11
转载别人的文章 没有在标题注明 啥意思? 盗文吗?
飞鱼大炮 回答时间:2019-6-17 19:49:25
感谢分享实战例程学习学习
未来,我来 回答时间:2019-6-17 19:57:31
感谢分享实战例程学习学习

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版