搜索
bottom↓
回复: 36

STM32 CAN模块使用方法

[复制链接]

出0入0汤圆

发表于 2011-10-6 10:25:01 | 显示全部楼层 |阅读模式
CAN 总线在控制领域使用的非常广泛,如今大多数CPU芯片外围都扩展CAN接口。本文重点介绍以STM32F103E系列芯片为基础介绍CAN 总线的使用方法。

1. 硬件基础

      CAN总线工作需要两根数据线,RX和TX,即为输入总线和输出总线。一般CPU与外界通信需要接一个驱动芯片(这点很像UART接口),常用的CAN芯片主要有:SN65VHD230、PCA82C250T等,本系统使用SN65VHD230作为CAN接口芯片。而CPU提供的CAN接口为CAN_L和CAN_H。

2. 软件设计

在进行软件设计时,我们首先来看这样的一个结构体:

typedef struct
{
  uint32_t StdId;  /*!< Specifies the standard identifier.
                        This parameter can be a value between 0 to 0x7FF. */

  uint32_t ExtId;  /*!< Specifies the extended identifier.
                        This parameter can be a value between 0 to 0x1FFFFFFF. */

  uint8_t IDE;     /*!< Specifies the type of identifier for the message that will be transmitted.
                        This parameter can be a value of @ref CAN_identifier_type */

  uint8_t RTR;     /*!< Specifies the type of frame for the message that will be transmitted.
                        This parameter can be a value of @ref CAN_remote_transmission_request */

  uint8_t DLC;     /*!< Specifies the length of the frame that will be transmitted.
                        This parameter can be a value between 0 to 8 */

  uint8_t Data[8];  /*!< Contains the data to be transmitted. It ranges from 0 to 0xFF. */
} CanTxMsg;

这是定义一个can数据包的结构体,即一个CAN数据包包含以上几个部分。

     现在我们思考一个问题:由于can可连接多个节点,如果一个系统为星形网络连接方式,那么主机应该怎样区别这些从机发送的信息呢?

    答案在上面那个结构体中,我们可以给每个分机定义一个ID,那么主机在接收到分机发送的数据后,通过ID号判别接收到的信息是那个从机发送的。

注意: DLC定义发送数据的长度,其范围为:0~8。

下面我们来编写CAN驱动:



对CAN模块初始化

void CAN_CfgInit(void)
{
    CAN_InitTypeDef        CAN_InitStructure;
    CAN_FilterInitTypeDef  CAN_FilterInitStructure;
   
    CAN_PortInit();
    CAN_DeInit(CAN1);
    CAN_StructInit(&CAN_InitStructure);
    /* CAN cell init */
    CAN_InitStructure.CAN_TTCM=DISABLE;
    CAN_InitStructure.CAN_ABOM=DISABLE;
    CAN_InitStructure.CAN_AWUM=DISABLE;
    CAN_InitStructure.CAN_NART=DISABLE;
    CAN_InitStructure.CAN_RFLM=DISABLE;
    CAN_InitStructure.CAN_TXFP=DISABLE;
    CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack;
    CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
    CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;
    CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
    CAN_InitStructure.CAN_Prescaler=5;
    CAN_Init(CAN1, &CAN_InitStructure);
    /* CAN filter init */
    CAN_FilterInitStructure.CAN_FilterNumber=0;
    CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
    CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
    CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;
    CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
  //  CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;
    CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
    CAN_FilterInit(&CAN_FilterInitStructure);
   
    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);      
}

这里为can 定义一个专门的结构体,便于数据处理:

typedef struct CAN_Socket CAN;
struct CAN_Socket {
   INT32U u32_StdId;
   INT32U u32_ExtId;
   INT8U  u8_IDE;
   INT8U  u8_RTR;
   INT8U  u8_DLC;
   INT8U  u8_FMI;
   INT8U  u8_data[8];
};

数据打包,并且发送

void CAN_TxSocket( CAN *can_Socket )
{
    INT8U i = 0;
    CanTxMsg TxMessage;
  
    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);      // CAN FIFO0 message pending interrupt enable
    // Transmit a message
    TxMessage.StdId=can_Socket->u32_StdId;      
    TxMessage.ExtId=can_Socket->u32_ExtId;
    TxMessage.IDE=can_Socket->u8_IDE;
    TxMessage.RTR= can_Socket->u8_RTR;
    TxMessage.DLC=can_Socket->u8_DLC;
    for( i =0; i<TxMessage.DLC; i++){
       TxMessage.Data = can_Socket->u8_data;
    }
    CAN_Transmit(CAN1, &TxMessage);
    CAN_ITConfig(CAN1, CAN_IT_FMP0, DISABLE);     // Disable interrupt handling
}



接收函数放在中断程序中处理:



void USB_LP_CAN1_RX0_IRQHandler(void)
{
    CanRxMsg RxMessage;
    INT8U i = 0;
    INT8U u8_RxLen = 0;
  
    RxMessage.StdId = 0x00;
    RxMessage.ExtId = 0x00;
    RxMessage.IDE = 0;
    RxMessage.RTR = 0;
    RxMessage.DLC = 0;
    RxMessage.FMI = 0;
    for( i=0;i<8;i++){
        RxMessage.Data=0x00;
    }
   
    CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
    u8_RxLen = RxMessage.DLC;
    if((RxMessage.ExtId==0x12) && (RxMessage.IDE==CAN_ID_EXT)){
        for( i=0;i<u8_RxLen; i++){
            CAN_ReceiveBuff = RxMessage.Data;
        }
    }
}



这里只介绍CAN使用方法和主要驱动程序,测试程序可自行设计。

本人的测试程序:

~INT8U SendBuff1[]="Hello";
INT8U SendBuff2[]="World";
INT8U SendBuff3[]="ADC= 255";
void main(void)
{
  System_HardwareInit();
  while (1)
  {
      CAN_Tx(SendBuff1);
      Disp_CanReceveData();
      CAN_Tx(SendBuff2);
       Disp_CanReceveData();
      CAN_Tx(SendBuff3);
      Disp_CanReceveData();
  }
}



接收数据,并在液晶上打印出来!

void Disp_CanReceveData( void )
{
  INT8U u8_CanRecBuff[64];
  
  if(CAN_ReceiveBuff[0] == 'H'){
      sprintf(( char *)u8_CanRecBuff,"CAN receve buff1 is : %s",CAN_ReceiveBuff);
      GCLDASC_PutChar16x16Str(10,30,u8_CanRecBuff, Red, Green, 1);
  }
  if(CAN_ReceiveBuff[0] == 'W'){
      sprintf(( char *)u8_CanRecBuff,"CAN receve buff2 is : %s",CAN_ReceiveBuff);
      GCLDASC_PutChar16x16Str(10,50,u8_CanRecBuff, Red, Green, 1);
  }
  if(CAN_ReceiveBuff[0] == 'A'){
      sprintf(( char *)u8_CanRecBuff,"CAN receve buff3 is : %s",CAN_ReceiveBuff);
      GCLDASC_PutChar16x16Str(10,70,u8_CanRecBuff, Red, Green, 1);
  }  
}

出0入0汤圆

发表于 2011-10-6 12:07:18 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-10-6 13:22:34 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-10-6 17:09:31 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-10-6 23:52:51 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-10-7 01:19:29 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-10-31 14:43:53 | 显示全部楼层
太抽象了!!

出0入0汤圆

 楼主| 发表于 2011-11-1 00:35:34 | 显示全部楼层
点击此处下载 ourdev_690464RG7Q7J.pdf(文件大小:66K) (原文件名:MSP430F149实验板原理图.pdf)

出0入0汤圆

发表于 2011-12-1 22:36:09 | 显示全部楼层
mark
楼上的,发个149的原理图为啥呢?
149不带CAN呀。

出0入0汤圆

 楼主| 发表于 2011-12-2 10:55:15 | 显示全部楼层
回复【8楼】derive01
-----------------------------------------------------------------------

个人备份的,不能老带个U盘吧!

出0入0汤圆

发表于 2011-12-9 09:17:39 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-12-15 22:55:30 | 显示全部楼层
感觉can还是比较复杂的,学习中

出0入0汤圆

发表于 2011-12-21 21:35:56 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-11-14 14:43:50 | 显示全部楼层
mark.........

出0入0汤圆

发表于 2012-11-23 21:08:44 来自手机 | 显示全部楼层
果断mark

出0入0汤圆

发表于 2013-2-21 10:11:31 | 显示全部楼层
can入门知识。感谢楼主

出0入0汤圆

发表于 2013-2-21 19:52:19 | 显示全部楼层
mark,留以后用

出0入0汤圆

发表于 2013-2-25 09:35:15 | 显示全部楼层
mark

出0入0汤圆

发表于 2013-3-3 18:54:55 | 显示全部楼层

出0入0汤圆

发表于 2013-4-13 11:02:07 | 显示全部楼层
MARK!真在研究这个,谢谢楼主!

出0入0汤圆

发表于 2013-4-16 17:48:29 | 显示全部楼层
一个例子搞定入门了,非常谢谢

出0入0汤圆

发表于 2013-8-13 22:25:28 来自手机 | 显示全部楼层
mark……
顶一个…

出10入0汤圆

发表于 2013-8-26 22:25:13 | 显示全部楼层
MARK                     

出0入0汤圆

发表于 2013-8-27 14:03:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2013-10-8 10:38:58 | 显示全部楼层
mark------------------------------

出0入0汤圆

发表于 2014-3-18 14:57:51 | 显示全部楼层

出0入0汤圆

发表于 2014-4-9 15:53:33 | 显示全部楼层
非常好 感谢楼主

出0入0汤圆

发表于 2014-4-9 16:38:33 | 显示全部楼层
stm32-can收发程序例子,mark,谢谢分享

出0入0汤圆

发表于 2014-4-14 12:53:22 | 显示全部楼层
   xue xi liao

出0入0汤圆

发表于 2014-6-4 10:21:27 | 显示全部楼层
感谢分享

出0入0汤圆

发表于 2014-6-12 12:03:22 | 显示全部楼层
看上去不错呀

出0入0汤圆

发表于 2014-6-23 09:44:32 | 显示全部楼层
谢谢分享!!!

出0入0汤圆

发表于 2014-8-19 14:40:03 | 显示全部楼层
mark一下,CAN

出0入0汤圆

发表于 2014-8-27 09:53:59 | 显示全部楼层
看看吧

出0入0汤圆

发表于 2014-10-20 19:14:25 | 显示全部楼层
路过!顶!

出0入0汤圆

发表于 2014-12-18 16:15:36 | 显示全部楼层
STM32的好东西呀。感谢感谢

出0入0汤圆

发表于 2014-12-18 16:17:28 | 显示全部楼层
哪儿朋友有STM32图形库开发资料呢。共享一下吧。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-19 07:39

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表