2882|3

13

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

stm32 CANOpen [复制链接]

下面是CAN协议与OSI网络模型的一个对比。CAN的物理层分了三层分别是MDI,PMA和PLS,数据链路层分了两层:MAC与LLC。这五层就是最原始的CAN协议,标准是ISO11898。也就是说CAN协议一开始是没有应用层的。后来有一种叫CANOpen的基于CAN的应用层协议被开发出来,标准是CiA301。

在实际开发CAN器件的时候不一定要用CANOpen,你可以根据自己的需要定制自己的应用层协议。

CANOpen协议共有6种通讯对象,分别是:PDO、SDO、SYNC、TIME、EMCY、NMT。这6种通讯对象完成了CANOpen协议的所有通讯功能。其中我们只介绍使用较多的PDO、SDO、NMT(4.4)。

通信对象ID(COB-ID)
CANOpen协议的通讯对象主要利用了CAN协议中的数据帧和远程帧。为了区分不同的通讯对象,CANOpen协议利用数据帧/远程帧中的ID。其中第7位到第10位为功能代码。第0位到第6位为节点ID,用以区分不同节点的相同功能。这样就允许最多127个从节点与主节点通讯。


下面是预定义的各通讯对象的COB-ID

其中绿色部分为广播的通讯对象,蓝色部分为点对点的通讯对象。

COB-ID的大小也决定了通讯对象的优先级,其中NMT的优先级最高,PDO的优先级高于SDO。

 

CANOpen的网络管理使用了master/slave结构。Master通过模块控制服务,可以控制slave的状态:{STOPPED, PRE-OPERATIONAL, OPERATIONAL, INITIALISING}.模块控制服务可以只针对一个节点,也可以是所有节点同时改变。
 

 

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "SysTick/systick.h" 
#include "GeneralTim.h" 
#include "stmflash.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>


/* Private variables ---------------------------------------------------------*/
uint8_t CAN1_RxRdy,CAN2_RxRdy;
uint16_t CAN1_Val_Tx,CAN1_Val_Rx,CAN2_Val_Tx,CAN2_Val_Rx;
CanTxMsg Can1TxMessage;
CanTxMsg Can2TxMessage;
CanRxMsg Can1RxMessage;
CanRxMsg Can2RxMessage;
/* Private function prototypes -----------------------------------------------*/

void GPIO_Configuration(void);
void NVIC_Configuration(void);
void CAN_Configuration(void);
void CanWriteData( CAN_TypeDef* CANx ,CanTxMsg *TxMessage );

  

u8 CAN1_TX_data[128],CAN1_RX_data[128];
u16 CAN1_Tx_Counter,CAN1_Rx_Counter,CAN1_TX_flag,CAN1_RX_flag,CAN1_TX_status,CAN1_RX_status;
u8 CAN2_TX_data[128],CAN2_RX_data[128];
u16 CAN2_Tx_Counter,CAN2_Rx_Counter,CAN2_TX_flag,CAN2_RX_flag,CAN2_TX_status,CAN2_RX_status;


char KEY1_up,KEY2_up,KEY3_up,KEY4_up,KEY5_up,KEY6_up;
char canopen_ID=0x01;
char canopen_start,canopen_reset,canopen_pretreatment;
char canopen_RSDO,canopen_RPDO;
/*******************************************************************************
* Function Name  : main
* Description    : Main program
* Input          : None
* Output         : None
* Return         : None
* Attention		 : None
*******************************************************************************/
int main(void)
{
	CAN_Configuration();
	
	CAN2_RxRdy = DISABLE;
	Can2TxMessage.StdId=0x0700+canopen_ID;            //地址
	Can2TxMessage.DLC=3;
	Can2TxMessage.RTR = CAN_RTR_DATA; /* 设置为数据帧 */
	Can2TxMessage.IDE = CAN_ID_STD;   /* 使用标准id	*/
	Can2TxMessage.Data[0] = 0x00;			
	CAN_Transmit(CAN2,&Can2TxMessage);
	
	while (1)
	{		
		
		if(canopen_pretreatment==1)                            //高压恢复
		{
			canopen_pretreatment=0;
			CAN2_RxRdy = DISABLE;
			Can2TxMessage.StdId=0x0180+canopen_ID;            //地址
			Can2TxMessage.DLC=8;
			Can2TxMessage.RTR = CAN_RTR_DATA; /* 设置为数据帧 */
			Can2TxMessage.IDE = CAN_ID_STD;   /* 使用标准id	*/
			Can2TxMessage.Data[0] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_0);
			Can2TxMessage.Data[1] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_1);       	
			Can2TxMessage.Data[2] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_2);
			Can2TxMessage.Data[3] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_3);
			Can2TxMessage.Data[4] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_4);
			Can2TxMessage.Data[5] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_5);       	
			Can2TxMessage.Data[6] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_6);
			Can2TxMessage.Data[7] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_7);
							
			CAN_Transmit(CAN2,&Can2TxMessage);	
		}
		if(CAN1_RX_flag==1)
		{
			CAN1_RX_flag=0;
			if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x10)&&(Can1RxMessage.Data[1]==0x00))
			{
				canopen_start=1;
			}
			if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x10)&&(Can1RxMessage.Data[1]==canopen_ID))
			{
				canopen_start=1;
			}
			if(canopen_start==1) 
			{
				if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x20)&&(Can1RxMessage.Data[1]==0x00))
				{
					canopen_start=0;
				}
				if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x20)&&(Can1RxMessage.Data[1]==canopen_ID))
				{
					canopen_start=0;
				}
				if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x82)&&(Can1RxMessage.Data[1]==0x00))
				{
					canopen_reset=1;
				}
				if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x81)&&(Can1RxMessage.Data[1]==canopen_ID))
				{
					canopen_reset=1;
				}
				if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x80)&&(Can1RxMessage.Data[1]==0x00))
				{
					canopen_pretreatment=1;
				}
				if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x80)&&(Can1RxMessage.Data[1]==canopen_ID))
				{
					canopen_pretreatment=1;
				}
				if((Can1RxMessage.StdId-0x0600)==canopen_ID)
				{
					canopen_RSDO=1;
					if(canopen_RSDO==1)
					{
						canopen_RSDO=0;
						if((Can1RxMessage.Data[0]==0x2F)&&(Can1RxMessage.Data[1]==0x00)&&(Can1RxMessage.Data[2]==0x20)&&(Can1RxMessage.Data[3]==0x00))
						{
							canopen_ID=Can1RxMessage.Data[4];
						}
					}
				}
				if((Can1RxMessage.StdId-0x0200)==canopen_ID)
				{
					canopen_RPDO=1;
					if(canopen_RPDO==1)
					{
						canopen_RPDO=0;
						if(Can1RxMessage.Data[0]==0x31)
						{
							GPIO_WriteBit(GPIOB,GPIO_Pin_0,1);
						}
						if(Can1RxMessage.Data[0]==0x30)
						{
							GPIO_WriteBit(GPIOB,GPIO_Pin_0,0);
						}
						if(Can1RxMessage.Data[1]==0x31)
						{
							GPIO_WriteBit(GPIOB,GPIO_Pin_1,1);
						}
						if(Can1RxMessage.Data[1]==0x30)
						{
							GPIO_WriteBit(GPIOB,GPIO_Pin_1,0);
						}
					}
				}
			}
		}	
	}
}

/*******************************************************************************
* Function Name  : GPIO_Configuration
* Description    : Configures the different GPIO ports.
* Input          : None
* Output         : None
* Return         : None
* Attention		 : None
*******************************************************************************/
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO ,ENABLE);
  /* CAN1 and CAN2 periph clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1 | RCC_APB1Periph_CAN2, ENABLE);						 
	 
  /* Configure CAN1 RX pin */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  /* Configure CAN1 pin: TX */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  /* Configure CAN2 RX pin */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  /* Configure CAN2 pin: TX */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);  

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure); 	

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOE, &GPIO_InitStructure);
}

/*******************************************************************************
* Function Name  : NVIC_Configuration
* Description    : Configures the nested vectored interrupt controller.
* Input          : None
* Output         : None
* Return         : None
* Attention		 : None
*******************************************************************************/
void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

  /* Enable CAN1 RX0 interrupt IRQ channel */
  NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* Enable CAN2 RX0 interrupt IRQ channel */
  NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

/*******************************************************************************
* Function Name  : CAN_Configuration
* Description    : Configures the CAN
* Input          : None
* Output         : None
* Return         : None
* Attention		 : None
*******************************************************************************/
void CAN_Configuration(void)
{
  CAN_InitTypeDef        CAN_InitStructure;
  CAN_FilterInitTypeDef  CAN_FilterInitStructure;

  NVIC_Configuration();
  GPIO_Configuration();
  /* CAN register init */
  CAN_DeInit(CAN1);
  CAN_DeInit(CAN2);
  CAN_StructInit(&CAN_InitStructure);

  CAN1_RxRdy = CAN2_RxRdy = DISABLE;
  CAN1_Val_Tx = CAN1_Val_Rx = CAN2_Val_Tx = CAN2_Val_Rx = 0;

  /* CAN cell init */
  CAN_InitStructure.CAN_TTCM = DISABLE; /* 时间触发禁止, 时间触发:CAN硬件的内部定时器被激活,并且被用于产生时间戳 */
  CAN_InitStructure.CAN_ABOM = DISABLE; /* 自动离线禁止,自动离线:一旦硬件监控到128次11个隐性位,就自动退出离线状态。在这里要软件设定后才能退出 */
  CAN_InitStructure.CAN_AWUM = DISABLE; /* 自动唤醒禁止,有报文来的时候自动退出休眠	*/
  CAN_InitStructure.CAN_NART = DISABLE; /* 报文重传, 如果错误一直传到成功止,否则只传一次 */
  CAN_InitStructure.CAN_RFLM = DISABLE; /* 接收FIFO锁定, 1--锁定后接收到新的报文摘不要,0--接收到新的报文则覆盖前一报文	*/
  CAN_InitStructure.CAN_TXFP = ENABLE;  /* 发送优先级  0---由标识符决定  1---由发送请求顺序决定	*/
  CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; /* 模式	*/
  CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;      /* 重新同步跳宽,只有can硬件处于初始化模式时才能访问这个寄存器 */
  CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;      /* 时间段1 */
  CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;      /* 时间段2 */
  CAN_InitStructure.CAN_Prescaler = 8;          /* 波特率预分频数 */  
 
  /* 波特率计算方法 */
  /* CANbps= Fpclk/((BRP+1)*((Tseg1+1)+(Tseg2+1)+1)  此处计算为  CANbps=36000000/(45*(4+3+1))=1200kHz */   														  //此处Tseg1+1 = CAN_BS1_8tp
  /* 配置大方向: Tseg1>=Tseg2  Tseg2>=tq; Tseg2>=2TSJW */						

  /*Initializes the CAN1  and CAN2 */
  CAN_Init(CAN1, &CAN_InitStructure);
  CAN_Init(CAN2, &CAN_InitStructure);

  /* CAN1 filter init */
  /* 配置CAN过滤器 */
  /* 32位对应的id */
  /* stdid[10:0],extid[17:0],ide,rtr	*/
  /* 16位对应的id */
  /* stdid[10:0],ide,rtr,extid[17:15] */
  /* 一般使用屏蔽模式	*/
  /* 要注意的是fifo接收存满了中断,还有就是fifo的概念,即取的一直是最早那一个数据, 要释放才能取下一个数据 */
  /* 常使用的中断有 */
  /* 1,有信息中断,即fifo挂号中断 */
  /* 2,fifo满中断	*/
  /* 3,fifo满之后又有信息来则中断,即fifo溢出中断	*/
  CAN_FilterInitStructure.CAN_FilterNumber = 0;     /* 过滤器1 */
  CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;  /* 屏敝模式 */
  CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; /* 32位 */
  CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;  /* 以下四个都为0, 表明不过滤任何id */
  CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;
  CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
  CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;  
  CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
  CAN_FilterInit(&CAN_FilterInitStructure);

  /* CAN2 filter init */
  CAN_FilterInitStructure.CAN_FilterNumber = 14;
  CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
  CAN_FilterInit(&CAN_FilterInitStructure);

  /* IT Configuration for CAN1 */  
  CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

  /* IT Configuration for CAN2 */  
  CAN_ITConfig(CAN2, CAN_IT_FMP0, ENABLE);
}

/*******************************************************************************
* Function Name  : CanWriteData
* Description    : Can Write Date to CAN-BUS
* Input          : None
* Output         : None
* Return         : None
* Attention		 : None
*******************************************************************************/
void CanWriteData( CAN_TypeDef* CANx ,CanTxMsg *TxMessage )
{
  /* transmit */
//  TxMessage->StdId = 0xA5A5;     /* 设置标准id  注意标准id的最高7位不能全是隐性(1)。共11位 */
//TxMessage->ExtId = 0x00;       //设置扩展id  扩展id共18位
  TxMessage->RTR = CAN_RTR_DATA; /* 设置为数据帧 */
  TxMessage->IDE = CAN_ID_STD;   /* 使用标准id	*/
//  TxMessage->DLC = 8;            /* 数据长度, can报文规定最大的数据长度为8字节 */
 
  CAN_Transmit(CANx,TxMessage);  /* 返回这个信息请求发送的邮箱号0,1,2或没有邮箱申请发送no_box */	
}

/*******************************************************************************
* Function Name  : CAN1_RX0_IRQHandler
* Description    : This function handles CAN1 RX0 interrupts 
* Input          : None
* Output         : None
* Return         : None
* Attention		 : None
*******************************************************************************/
void CAN1_RX0_IRQHandler(void)
{
  int i;
	CAN_Receive(CAN1,CAN_FIFO0, &Can1RxMessage);  /* 此函数包含释放提出报文了的,在非必要时,不需要自己释放 */
  CAN1_RxRdy = ENABLE;
	CAN1_RX_flag=1;
}

/*******************************************************************************
* Function Name  : CAN2_RX0_IRQHandler
* Description    : This function handles CAN2 RX0 interrupts
* Input          : None
* Output         : None
* Return         : None
* Attention		 : None
*******************************************************************************/
void CAN2_RX0_IRQHandler(void)
{
  CAN_Receive(CAN2,CAN_FIFO0, &Can2RxMessage);  /* 此函数包含释放提出报文了的,在非必要时,不需要自己释放 */
  CAN2_RxRdy = ENABLE;
	CAN2_RX_flag=1;
}

/*********************************************************************************************************
      END FILE
*********************************************************************************************************/

 

此帖出自stm32/stm8论坛

最新回复

楼主重新传下图片,我们管理员也加您qq了,随时可以论坛或 qq 沟通。   详情 回复 发表于 2020-7-27 13:29
点赞 关注
 

回复
举报

310

帖子

1

TA的资源

一粒金砂(中级)

沙发
 

图裂了,上传图片方式不对吧

此帖出自stm32/stm8论坛
 
 

回复

13

帖子

0

TA的资源

一粒金砂(中级)

板凳
 

怎么成这样了

 

此帖出自stm32/stm8论坛

点评

楼主重新传下图片,我们管理员也加您qq了,随时可以论坛或 qq 沟通。  详情 回复 发表于 2020-7-27 13:29
 
 

回复

2万

帖子

71

TA的资源

管理员

4
 
gandong 发表于 2020-7-25 08:58 怎么成这样了  

楼主重新传下图片,我们管理员也加您qq了,随时可以论坛或 qq 沟通。

此帖出自stm32/stm8论坛
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表