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

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
谢谢分享!
KEY1 回答时间:2018-6-2 10:08:11
转载别人的文章 没有在标题注明 啥意思? 盗文吗?
飞鱼大炮 回答时间:2019-6-17 19:49:25
感谢分享实战例程学习学习
未来,我来 回答时间:2019-6-17 19:57:31
感谢分享实战例程学习学习

所属标签

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