can

CAN的Loopback模式例程的设置及程序分析

该例程提供一个关于用CAN的Loopback模式进行交互设置的描述.
貌似官方这个例子是stm324xG_EVAL板的,当用于stm32f407discovery板卡的时候
不能直接烧写使用.
例程说明在175Kbps运用查询模式传输和接收一组数据,接收到数据后进行检查通过led指示状态
以下程序已经更改用于discovery板卡.
LED1接PF6,LED2接PF7,LED3接PF8脚,
设置以上三个管脚为输出,上拉,fast模式
开启CAN1的master,设置CAN1的相关管脚为AFPP,上拉,fast模式
PA11 ------> CAN1_RX
PA12 ------> CAN1_TX

GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
不开任何中断.......................
CAN设置如下图
无标题3.png

已邀请:

admin

赞同来自:

原例程中分频设置的是2,但是stm32cube软件设置为2的情况下提示出错.所以至少要是4.
然后打开生成的代码.
打开can.c文件
在USER CODE BEGIN 1 和USER CODE END 1之间添加下列代码:


HAL_StatusTypeDef CAN_Polling(void)
{
CAN_FilterConfTypeDef sFilterConfig;
static CanTxMsgTypeDef TxMessage;
static CanRxMsgTypeDef RxMessage;

hcan1.pTxMsg = &TxMessage;
hcan1.pRxMsg = &RxMessage;

/[i][size=16]-2- Configure the CAN Filter [/size]###################################[size=16]#[size=16]#[/i]/[/size][/size]
sFilterConfig.FilterNumber = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = 0;//定义准备使用的FIFO号,0或者1,此次使用的是FIFO0
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;

if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
/[i] Filter configuration Error [/i]/
// Error_Handler();
}

/[i][size=16]-3- Start the Transmission process [/size]#############################[size=16]#[size=16]#[/i]/[/size][/size]
hcan1.pTxMsg->StdId = 0x11; //指定标准标示符
hcan1.pTxMsg->RTR = CAN_RTR_DATA; //数据类型,由系统定义的,无需理会
hcan1.pTxMsg->IDE = CAN_ID_STD;//定义信息传输类型,系统内定,不予理会
hcan1.pTxMsg->DLC = 2;//指定即将传输的数据帧的长度,最大8字节长度
hcan1.pTxMsg->Data = 0xCA;//第一字节数据
hcan1.pTxMsg->Data = 0xFE;//第二字节数据
//因为演示就定义了两个字节数据
if(HAL_CAN_Transmit(&hcan1, 10) != HAL_OK)//那个10是超时时间单位ms
{
/[i] Transmition Error [/i]/
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_7,GPIO_PIN_RESET );
while(1);
}

if(HAL_CAN_GetState(&hcan1) != HAL_CAN_STATE_READY)
{
return HAL_ERROR;
}

/[i][size=16]-4- Start the Reception process [/size]################################[size=16]#[size=16]#[/i]/[/size][/size]
if(HAL_CAN_Receive(&hcan1, CAN_FIFO0,10) != HAL_OK)//上面定义了FIFO0
{
/[i] Reception Error [/i]/

HAL_GPIO_WritePin (GPIOF,GPIO_PIN_7,GPIO_PIN_RESET );
while(1);
}

if(HAL_CAN_GetState(&hcan1) != HAL_CAN_STATE_READY)
{
return HAL_ERROR;
}

if (hcan1.pRxMsg->StdId != 0x11)//接收到的数据标示符
{
return HAL_ERROR;
}

if (hcan1.pRxMsg->IDE != CAN_ID_STD)//接收到的传输数据类型
{
return HAL_ERROR;
}

if (hcan1.pRxMsg->DLC != 2)//接收到的数据长度
{
return HAL_ERROR;
}

if ((hcan1.pRxMsg->Data<<8|RxMessage.Data) != 0xCAFE)接收到的数据比对
{
return HAL_ERROR;
}

return HAL_OK; /[i] Test Passed [/i]/
}

admin

赞同来自:

打开can.h文件在void MX_CAN1_Init(void);下面添加代码
HAL_StatusTypeDef CAN_Polling(void);
打开main.c文件
在main()函数修改为如下代码


int main(void)
{

/[i] USER CODE BEGIN 1 [/i]/

/[i] USER CODE END 1 [/i]/

/[i] MCU Configuration----------------------------------------------------------[/i]/

/[i] Reset of all peripherals, Initializes the Flash interface and the Systick. [/i]/
HAL_Init();

/[i] Configure the system clock [/i]/
SystemClock_Config();

/[i] Initialize all configured peripherals [/i]/
MX_GPIO_Init();
MX_CAN1_Init();

/[i] USER CODE BEGIN 2 [/i]/
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_RESET );
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_7,GPIO_PIN_SET );
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_8,GPIO_PIN_SET );

HAL_Delay (2000);

if (CAN_Polling() == HAL_OK)
{ /[i] OK [/i]/
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
/[i] Turn on LED1 [/i]/

}
else
{ /[i] KO [/i]/

/[i] Turn on LED2 [/i]/
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_7,GPIO_PIN_RESET );
}
/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{
if(addtime>=1000)
{
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_8);
addtime =0;
}
}
/[i] USER CODE END 3 [/i]/

}

其中的变量addtime为定义的一个uint16_t,此值在滴答时钟Callback函数中自加即可.

admin

赞同来自:

程序演示效果.运行2秒后,执行CAN_Polling函数.如果can通信正常,则led1亮,led3闪烁,led2灭
否则通信失败则led2常亮其他不亮.
本程序运行正常!

admin

赞同来自:

一大坨东西,眼花.....
用到的时候可以这样
如果发送,不修改发送数据长度,那么
hcan1.pTxMsg->Data = 0xCA;//第一字节数据
hcan1.pTxMsg->Data = 0xFE;//第二字节数据
HAL_CAN_Transmit(&hcan1, 10);
建议你可以封装为一个函数.....
接收的话用中断接收..HAL_CAN_Receive_IT(&hcan1, CAN_FIFO0) ;
开启接收中断
HAL_NVIC_SetPriority(CANx_RX_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(CANx_RX_IRQn);
然后调用can_callback
假如设置StdId == 0x321

void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* CanHandle)
{
if ((CanHandle->pRxMsg->StdId == 0x321)&&(CanHandle->pRxMsg->IDE == CAN_ID_STD) && (CanHandle->pRxMsg->DLC == 2))
{
LED_Display(CanHandle->pRxMsg->Data);//接收到的数据0
ubKeyNumber = CanHandle->pRxMsg->Data;
}

/[i] Receive [/i]/
if(HAL_CAN_Receive_IT(CanHandle, CAN_FIFO0) != HAL_OK)//再次开启接收中断
{
/[i] Reception Error [/i]/
Error_Handler();
}
}

好了,can差不多就这样了.

思考:如果好几个can设备连接了.我怎么控制其他的那些做不同的动作呢?
呵呵,提示跟辨识符有关,看到上面的这个中断你应该知道了吧

admin

赞同来自: tinyuns

下面是复制的一个程序里面的关于CAN的过滤器方面的注释
**不是本文中的程序啊。。。。。
只是注释下,且看且研究。。。**
CAN_DeInit(CAN1); //将外设CAN的全部寄存器重设为缺省值
CAN_StructInit(&CAN_InitStructure);//把CAN_InitStruct中的每一个参数按缺省值填入

/ 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;//没有使能接收FIFO锁定模式
CAN_InitStructure.CAN_TXFP=DISABLE;//没有使能发送FIFO优先级
CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;//CAN设置为正常模式
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳跃宽度1个时间单位
CAN_InitStructure.CAN_BS1=CAN_BS1_3tq; //时间段1为3个时间单位
CAN_InitStructure.CAN_BS2=CAN_BS2_2tq; //时间段2为2个时间单位
CAN_InitStructure.CAN_Prescaler=60; //时间单位长度为60
CAN_Init(CAN1,&CAN_InitStructure);
//波特率为:72M/2/60(1+3+2)=0.1 即100K

/ CAN filter init /
CAN_FilterInitStructure.CAN_FilterNumber=1;//指定过滤器为1
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//指定过滤器为标识符屏蔽位模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//过滤器位宽为32位
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;// 过滤器标识符的高16位值
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;// 过滤器标识符的低16位值
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//过滤器屏蔽标识符的高16位值
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;// 过滤器屏蔽标识符的低16位值
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;// 设定了指向过滤器的FIFO为0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;// 使能过滤器
CAN_FilterInit(&CAN_FilterInitStructure);// 按上面的参数初始化过滤器

/ CAN FIFO0 message pending interrupt enable /
CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE); //使能FIFO0消息挂号中断

GskFlD

赞同来自: tinyuns

HAL_CAN_Receive,HAL_CAN_Receive_IT函数的问题,按照官方历程,在每次Can接收的回调函数后都调用了这个函数实现Can的连续接受,但是当Can总线上搭载两个以上的设备时,发现接收一定时间后会出现收不到数据的问题,然后Debug后发现,发生错误时Can的hcan1.Instance->IER变成零了,正常应该是0x00008F02,感觉这是HAL_CAN_Receive函数存在问题,不知道你有没有碰到过这个问题。

虎扑最大的吊

赞同来自:

写的非常好


要回复问题请先登录注册