1. can总线简介:
CAN(Controller Area Network)是 ISO 国际标准化的串行通信协议。早期源于汽车行业对安全性、舒适性、低成本等要求,各种各样的电子控制系统被开发了出来。各系统之间通信所用的数据类型及对可靠性的要求不尽相同,由多条总线构成的情况很多,线束的数量也随之增加。
为"减少线束的数量,通过多个LAN进行大量数据的高速通信"的需要,1986 年德国电气商Bosch 公司开发出面向汽车的CAN 通信协议。此后CAN 通过 ISO11898 及 ISO11519 进行了标准化。
CAN 总线的工作原理
CAN 总线使用串行数据传输方式,且总线协议支持多主控制器。当CAN 总线上的一个节点(站)发送数据时,它以报文形式广播给网络中所有节点。
每组报文开头的11位字符为标识符,定义了报文的优先级,这种报文格式称为面向内容的编址方案。在同一系统中标识符是唯一的,不可能有两个站发送具有相同标识符的报文。当几个站同时竞争总线读取时,这种配置十分重要。
当一个站要向其它站发送数据时,该站的CPU 将要发送的数据和自己的标识符传送给本站的CAN 芯片,并处于准备状态;当它收到总线分配时,转为发送报文状态。
CAN 芯片将数据根据协议组织成一定的报文格式发出,这时网上的其它站处于接收状态。每个处于接收状态的站对接收到的报文进行检测,判断这些报文是否是发给自己的,以确定是否接收它。
CAN 的主要特点
1、 数据通信没有主从之分,任意一个节点可以向任何其他(一个或多个)节点发起数据通信,靠各个节点信息优先级先后顺序来决定通信次序。
2、 支持时间触发通信功能, 发送报文的优先级可软件配置。多个节点同时发起通信时,优先级低的避让优先级高的,不会对通信线路造成拥塞。
3、 CAN 是一种多主总线,通信介质可以是双绞线、同轴电缆或光导纤维。通信距离最远可达10KM(速率低于5Kbps),速率可达到1Mbps(通信距离小于40M)。
4、 CAN 总线采用了多主竞争式总线结构,具有多主站运行和分散仲裁的串行总线以及广播通信的特点。
5、 FIFO(First Input First Output),即先进先出队列,溢出处理方式可配置......
CAN总线的拓扑结构

CAN应用领域
CAN总线适用于大数据量短距离通信或者长距离小数据量,实时性要求比较高,适合多主多从或者各个节点平等的现场中使用。目前被广泛应用于工业自动化、船舶、医疗设备、工业设备等行业领域。
现场总线是当今自动化领域技术发展的热点之一,被誉为自动化领域的计算机局域网。它的出现为分布式控制系统实现各节点之间实时、可靠的数据通信提供了强有力的技术支持。
最后,来贴上我的驱动代码:
#ifndef __BSP_CAN_H__
  • #define __BSP_CAN_H__
  • #include "can.h"
  • #include "gpio.h"
  • // 主频Pclk 与 波特率定义
  • #define CAN_CHIP_TJA1043
  • #define CAN_CONFIG_48MHZ_500K
  • #define EVB_CAN_RX_PORT     GpioPortB
  • #define EVB_CAN_RX_PIN      GpioPin8
  • #define EVB_CAN_TX_PORT     GpioPortB
  • #define EVB_CAN_TX_PIN      GpioPin9
  • #define EVB_CAN_STB_PORT    GpioPortA
  • #define EVB_CAN_STB_PIN     GpioPin3 /*IO_STB*/
  • #define CAN_ID_BACKLIGHT  0X3b3  /*背光*/
  • #define CAN_ID_ACC  0X263   /* ACC */
  • #define CAN_ID_GAIN  0X445   /*电子刹车增益*/
  • #define CAN_ID_KEEPALIVE  0X5C0   /*KEEPALIVE*/
  • #define CAN_ID_BRAKE_X  0X7d  /*脚踩刹车深度*/
  • #define CAN_ID_BRAKE_SIGNAL  0X242 /*刹车信号*/
  • typedef struct stc_can
  • {
  •         boolean_t RxFlag;
  •         boolean_t RxFlag_Break; /*接收到刹车深度数据*/
  •         boolean_t BusErrorFlag;
  •         boolean_t CANSendFlag;
  •         boolean_t CAN_keepalive_SendFlag;
  •         boolean_t brake_signal;
  •         uint16_t brake_value;
  •         int Rx_cnt; /* 中断空闲30s倒计时进入低功耗*/
  •         uint32_t brake_cnt; //刹车长踩8秒
  •         uint32_t key_cnt; //按键长按计时
  • }stc_can_t;
  • typedef enum ACC_Status
  • {
  •     Off = 0u,   
  •     On  = 1u,            
  • }en_ACC_Status;
  • extern stc_can_t APP_CAN;
  • extern en_ACC_Status ACC_Status;
  • extern stc_can_txframe_t   TxFrame_Gain;
  • extern stc_can_txframe_t   TxFrame_Keepalive;
  • void BSP_Can_Init(void);
  • void CAN_send_Frame(stc_can_txframe_t *TxFrame, uint8_t frame_len);
  • void TJA1043_Goto_Sleep(void);
  • #endif
  • 复制代码
    C文件:
    #include "bsp_can.h"
  • #include "bsp_led.h"
  • #include "bsp_timer.h"
  • stc_can_rxframe_t   stcRxFrame;
  • stc_can_txframe_t   TxFrame_Gain;
  • stc_can_txframe_t   TxFrame_Keepalive;
  • stc_can_t APP_CAN;
  • en_ACC_Status ACC_Status = Off;
  • extern void PWM_duty_adjust(uint16_t adc_value, uint16_t MAX_Value);
  • static void Can_Gpio_Init(void)
  • {
  •     stc_gpio_cfg_t stcGpioCfg;
  •     Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
  •     ///< 端口方向配置->输入
  •     stcGpioCfg.enDir = GpioDirIn;
  •     ///< 端口驱动能力配置->高驱动能力
  •     stcGpioCfg.enDrv = GpioDrvL;
  •     ///< 端口上下拉配置->无
  •     stcGpioCfg.enPu = GpioPuDisable;
  •     stcGpioCfg.enPd = GpioPdDisable;
  •     ///< 端口开漏输出配置->开漏输出关闭
  •     stcGpioCfg.enOD = GpioOdDisable;
  •     ///< 端口输入/输出值寄存器总线控制模式配置->AHB
  •     stcGpioCfg.enCtrlMode = GpioAHB;
  •     Gpio_Init(EVB_CAN_RX_PORT, EVB_CAN_RX_PIN, &stcGpioCfg);
  •     stcGpioCfg.enDir = GpioDirOut;
  •     Gpio_Init(EVB_CAN_TX_PORT, EVB_CAN_TX_PIN, &stcGpioCfg);
  •     Gpio_Init(EVB_CAN_STB_PORT, EVB_CAN_STB_PIN, &stcGpioCfg);
  •     ///<CAN RX\TX复用功能配置
  •     Gpio_SetAfMode(EVB_CAN_RX_PORT, EVB_CAN_RX_PIN, GpioAf3);
  •     Gpio_SetAfMode(EVB_CAN_TX_PORT, EVB_CAN_TX_PIN, GpioAf5);
  •     ///<STB 低-PHY有效
  •     Gpio_ClrIO(EVB_CAN_STB_PORT, EVB_CAN_STB_PIN);
  • }
  • #ifdef CAN_CHIP_TJA1043
  • /*
  • TJA1043 刚上电是出于激活状态的,如果CAN总线没有数据,30s左右会休眠
  • 3个IO需要配置:
  • IO_ERR 检测总线出错标志(可以忽略)
  • IO_EN 芯片使能
  • IO_INH 使能外部LDO +5V
  • IO_STB_N standby模式使能
  • */
  • static void TJA1043_Gpio_Init(void)
  • {
  •     stc_gpio_cfg_t stcGpioCfg;
  •     Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
  •     ///< 端口方向配置->输出
  •     stcGpioCfg.enDir = GpioDirOut;
  •     ///< 端口驱动能力配置->高驱动能力
  •     stcGpioCfg.enDrv = GpioDrvH;
  •     ///< 端口上下拉配置->无
  •     stcGpioCfg.enPu = GpioPuDisable;
  •     stcGpioCfg.enPd = GpioPdDisable;
  •     ///< 端口开漏输出配置->开漏输出关闭
  •     stcGpioCfg.enOD = GpioOdDisable;
  •     ///< 端口输入/输出值寄存器总线控制模式配置->AHB
  •     stcGpioCfg.enCtrlMode = GpioAHB;
  •        
  •     Gpio_Init(GpioPortA, GpioPin3, &stcGpioCfg); // STB_N
  •     Gpio_Init(GpioPortB, GpioPin3, &stcGpioCfg); //IO_INH  
  •     Gpio_Init(GpioPortB, GpioPin7, &stcGpioCfg); // IO_EN
  •        
  •         Gpio_ClrIO(GpioPortB, GpioPin3);  /* PB3 IO_INH*/
  •         delay1ms(10);
  •     Gpio_SetIO(EVB_CAN_STB_PORT, EVB_CAN_STB_PIN);
  •         Gpio_SetIO(GpioPortB, GpioPin7);// IO_EN
  •        
  • }
  • void TJA1043_Goto_Sleep(void)
  • {
  •         Gpio_ClrIO(EVB_CAN_STB_PORT, EVB_CAN_STB_PIN);
  •         Gpio_SetIO(GpioPortB, GpioPin7);// IO_EN
  • }
  • #endif
  • void BSP_Can_Init(void)
  • {
  •     stc_can_init_config_t   stcCanInitCfg;
  •     stc_can_filter_t        stcFilter;
  •         Can_Gpio_Init();
  • #ifdef CAN_CHIP_TJA1043
  •         TJA1043_Gpio_Init();       
  • #endif
  •        
  •     Sysctrl_SetPeripheralGate(SysctrlPeripheralCan, TRUE);
  •     //<<CAN 波特率配置
  •         // 手册page884.exp: bt = (PRESC+1)((SEG_1+2) + (SEG_2+1))*(1/8M) = 1us (1000k)
  • #ifdef CAN_CONFIG_48MHZ_500K         
  •        
  •         stcCanInitCfg.stcCanBt.PRESC = 6-1;
  •         stcCanInitCfg.stcCanBt.SEG_1 = 9-2;
  •         stcCanInitCfg.stcCanBt.SEG_2 = 7-1;       
  •         stcCanInitCfg.stcCanBt.SJW   = 3-1;       
  •        
  • //        stcCanInitCfg.stcCanBt.PRESC = 8-1;
  • //  stcCanInitCfg.stcCanBt.SEG_1 = 7-2;
  • //  stcCanInitCfg.stcCanBt.SEG_2 = 5-1;
  • //  stcCanInitCfg.stcCanBt.SJW   = 5-1;
  •        
  • #endif
  •     stcCanInitCfg.stcWarningLimit.CanErrorWarningLimitVal = 10;
  •     stcCanInitCfg.stcWarningLimit.CanWarningLimitVal = 16-1;
  •     stcCanInitCfg.enCanRxBufAll  = CanRxNormal;
  •     stcCanInitCfg.enCanRxBufMode = CanRxBufNotStored;
  •     stcCanInitCfg.enCanSTBMode   = CanSTBFifoMode;
  •     CAN_Init(&stcCanInitCfg);
  •     //<<CAN 滤波器配置 /*u32MASK = 0x1FFFFFFF is all received*/
  •   
  •         stcFilter.enAcfFormat = CanStdFrames;
  •     stcFilter.enFilterSel = CanFilterSel1;
  •     stcFilter.u32CODE     = CAN_ID_BACKLIGHT;
  •     stcFilter.u32MASK     = 0x1FFFFFFF& (~CAN_ID_BACKLIGHT);   
  •     CAN_FilterConfig(&stcFilter, TRUE);
  •         stcFilter.enFilterSel = CanFilterSel2;
  •     stcFilter.u32CODE     = CAN_ID_ACC;
  •     stcFilter.u32MASK     = 0x1FFFFFFF& (~CAN_ID_ACC);
  •         CAN_FilterConfig(&stcFilter, TRUE);
  •        
  •         stcFilter.enFilterSel = CanFilterSel3;
  •     stcFilter.u32CODE     = CAN_ID_BRAKE_X;
  •     stcFilter.u32MASK     = 0x1FFFFFFF& (~CAN_ID_BRAKE_X);
  •     CAN_FilterConfig(&stcFilter, TRUE);
  •         stcFilter.enFilterSel = CanFilterSel4;
  •         stcFilter.u32CODE     = CAN_ID_BRAKE_SIGNAL;
  •         stcFilter.u32MASK     = 0x1FFFFFFF& (~CAN_ID_BRAKE_SIGNAL);
  •         CAN_FilterConfig(&stcFilter, TRUE);
  •     CAN_IrqCmd(CanRxIrqEn, TRUE); /* 接收中断使能 */
  •         CAN_IrqCmd(CanBusErrorIrqEn, TRUE); /*总线错误中断使能*/
  •     EnableNvic(CAN_IRQn, IrqLevel0, TRUE);
  • }
  • /********************************************************************************************************
  • **函数信息 :void CAN_send_Frame()
  • **功能描述 :CAN发送一帧报文
  • **输入参数 :stcTxFrame
  • **输出参数 :None
  • **    备注  目前只考虑标准帧
  • ********************************************************************************************************/
  • void CAN_send_Frame(stc_can_txframe_t *TxFrame, uint8_t frame_len)
  • {
  •         TxFrame->Control_f.DLC = frame_len;
  •         TxFrame->Control_f.IDE = 0; /*标准帧 or 扩展帧*/
  •         TxFrame->Control_f.RTR = 0; /*数据帧 or 远程帧*/
  •         TxFrame->enBufferSel = (en_can_buffer_sel_t)0U; /*使用主缓冲器*/
  •         CAN_SetFrame(TxFrame); /*数据塞进fifo缓冲器*/       
  •         CAN_TransmitCmd(CanPTBTxCmd);
  • }
  •        
  • void Can_IRQHandler(void)
  • {
  •     if(TRUE == CAN_IrqFlgGet(CanBusErrorIrqFlg))  /*当总线短路时,进入此中断*/
  •         {          
  •                 CAN_IrqFlgClr(CanBusErrorIrqFlg);         
  •                 APP_CAN.BusErrorFlag = TRUE;
  •                 // M0P_CAN->CFG_STAT = 0x00; /* 清除由硬件置位的Reset 标志位,必须在中断外部执行*/                 
  •         }         
  •         if(TRUE == CAN_IrqFlgGet(CanRxIrqFlg))
  •     {
  •         CAN_IrqFlgClr(CanRxIrqFlg);
  •         CAN_Receive(&stcRxFrame);
  •                 APP_CAN.RxFlag = TRUE;
  •                 APP_CAN.Rx_cnt = 0;
  •                 /*总线上发送周期约500ms*/
  •                 if( CAN_ID_BACKLIGHT == stcRxFrame.StdID )
  •                 {
  •                 /*                       
  •                 led off  3b3 40 48 00 12 10 05 80 02
  •                 led on         3b3 44 48 10 12 10 05 80 02
  •                 */
  •                         if(stcRxFrame.Data[0] & 0x04)
  •                         {
  •                                 LED_ON;
  •                         }       
  •                         else
  •                         {
  •                                 LED_OFF;
  •                         }
  •                 }
  •                 /*
  •                 XX 00 00 20 52 FF FB 00
  •                 XX:02 (ON)  00(OFF)
  •                 */       
  •                 if (CAN_ID_ACC == stcRxFrame.StdID)
  •                 {
  •                         if(stcRxFrame.Data[0]&0x02)
  •                         {
  •                                 ACC_Status = On;
  •                         }
  •                         else
  •                         {                       
  •                                 ACC_Status = Off;  /* ACC off 后延时30s进入休眠*/                       
  •                         }
  •                 }
  •                 /*
  •                 ID:7D(刹车深度)  //20ms一次
  •                 XX YY 00 00 00 00 00 00
  •                 XX:刹车深度高位
  •                 YY:刹车深度低位
  •                 XX<<8+YY = 0000 表示无刹车,最大到0F00(超级用力)       
  •                 */
  •                 if (CAN_ID_BRAKE_X == stcRxFrame.StdID) /* 刹车深度,最后与滑动变阻器比较,谁力度大则执行pwm输出*/
  •                 {
  •                         APP_CAN.brake_value = (stcRxFrame.Data[0]<<8) + stcRxFrame.Data[1];               
  •                         // 按等比例换算,再和adc_value 比较,再执行
  •                         APP_CAN.RxFlag_Break = TRUE;
  •                        
  •                 }
  •                 /*
  •                 ID:242(刹车信号)   //40ms一次
  •                 00 00 xx 00 00 00 00 00
  •                 xx:80(有踩刹车) 00(无踩刹车)
  •                 */       
  •                 if (CAN_ID_BRAKE_SIGNAL == stcRxFrame.StdID)
  •                 {               
  •                         if( stcRxFrame.Data[2]&0x80)
  •                         {
  •                                 APP_CAN.brake_signal = TRUE;
  •                         }
  •                         else
  •                         {                       
  •                                 APP_CAN.brake_signal = FALSE;
  •                         }
  •                 }               
  •     }
  • }
  • 复制代码