CAN_TxStatus_Pending报错问题

        最近用STM32F407最小电路板测试CAN通讯遇到点小问题:回环模式测试没有问题的基础上,两块相同的最小系统板之间也可以通讯。但把其中一块板子换成USB转CAN分析仪时(或者其他板子),怎么也调不通。

        思考良久,硬件测试正常,没找到问题。逼得没办法,将CANH和CANL接到滤波器(此时在两块STM32F407最小系统板之间正常收发信息),测试波特率,才找到根源:不知什么时候,将外部时钟的系统频率由336MHz调成了360MHz,结果就导致CAN一直发送失败...

详情如下:

CAN.h代码:

#ifndef __CAN1_H
#define __CAN1_H

#include "stm32f4xx.h"                  // Device header

void CAN1_Init(void);
void CAN1_SetMsg(CanTxMsg* Send_CAN1_Msg);
void CAN1_Send(CanTxMsg* TxMessage);
void CAN1_RX0_IRQHandler(void);

#endif

CAN.c代码

#include "CAN1.h"

//	CAN1_RX		PA11	
//	CAN1_TX		PA12		APB1总线	42MHz

extern CanRxMsg Recv_CAN1_Msg;
uint8_t t = 6;

void CAN1_Init(void)
{
	//开启CAN1和GPIO时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
	//引脚复用为CAN1
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_CAN1);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_CAN1);
	//配置GPIO引脚
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//CAN1初始化配置
	CAN_InitTypeDef CAN_InitStructure;
	CAN_DeInit(CAN1);
	CAN_StructInit(&CAN_InitStructure);
	//CAN最大频率为1MHz。APB1频率为42MHz,波特率 = 42M/预分频/(1+BS1+BS2)
	//在本案例中,波特率 = 42M/6/(1+4+2) = 1M
	//如果想让波特率 = 500k,可以设置预分频为12,或者增加BS1和BS2的值
	CAN_InitStructure.CAN_Prescaler = 12;		//预分频,APB1总线42MHz
	CAN_InitStructure.CAN_BS1 = CAN_BS1_4tq;
	CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
	CAN_InitStructure.CAN_SJW = CAN_SJW_2tq;
	CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;		//CAN模式选择
//	CAN_InitStructure.CAN_Mode = CAN_Mode_LoopBack;	
	CAN_InitStructure.CAN_ABOM = ENABLE;			//自动离线
	CAN_InitStructure.CAN_AWUM = ENABLE;			//自动唤醒
	CAN_InitStructure.CAN_NART = DISABLE;			//禁止自动重发送,消息只发送一次
	CAN_InitStructure.CAN_RFLM = DISABLE;			//FIFO满了后,覆盖前一条
	CAN_InitStructure.CAN_TTCM = DISABLE;			//时间戳。不需要时间戳
	CAN_InitStructure.CAN_TXFP = DISABLE;			//发送FIFO优先级。按照请求的时间,不是标识符
	CAN_Init(CAN1,&CAN_InitStructure);
	
	//CAN过滤器配置
	CAN_FilterInitTypeDef CAN_FilterInitStructure;
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;		//是否激活筛选器
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
	//参考CAN 发送邮箱标识符寄存器 (CAN_TIxR),最低三位是功能码,所以需要左移3bit
	CAN_FilterInitStructure.CAN_FilterIdHigh = ((((uint32_t)0x199 << 3 )| CAN_ID_STD | CAN_RTR_DATA)&0xFFFF0000)>>16;
	CAN_FilterInitStructure.CAN_FilterIdLow = (((uint32_t)0x199 << 3 )| CAN_ID_STD | CAN_RTR_DATA)&0xFFFF;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;		//工作在掩码模式
	CAN_FilterInitStructure.CAN_FilterNumber = 8;				//设置筛选器的编号,0~13
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;	//筛选器的尺寸
	CAN_FilterInit(&CAN_FilterInitStructure);
	
	//配置CAN中断
	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
	
	//中断配置
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
}

//设置要发送的数据
void CAN1_SetMsg(CanTxMsg* Send_CAN1_Msg)
{
	if(t>9)
		t = 6;
	Send_CAN1_Msg->ExtId = 0;		//此处采用标准报文格式,因此不用给ExtId赋值
	Send_CAN1_Msg->IDE = CAN_ID_STD;
	Send_CAN1_Msg->RTR = CAN_RTR_DATA;
	Send_CAN1_Msg->StdId = 0x199;	//设置标准ID为0x1314
	Send_CAN1_Msg->DLC = 8;
	for(uint8_t i = 0;i<8;i++)
	{
		Send_CAN1_Msg->Data[i] = t+i;
	}
	t++;
}

void CAN1_RX0_IRQHandler(void)
{
	if(CAN_GetITStatus(CAN1,CAN_IT_FMP0) == SET)
	{
		//接收数据后,系统会自动清除中断标志位。
		//如果没有接收函数,中断标志位一直保持为1,导致程序卡死
		CAN_Receive(CAN1,CAN_FIFO0,&Recv_CAN1_Msg);
	}
	//不用单独清除标志位。CAN_ClearITPendingBit函数没有CAN_IT_FMP0这个变量
//	CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
}

main.c代码

#include "stm32f4xx.h"                  // Device header
#include "Delay.h"
#include "CAN1.h"

CanTxMsg Send_CAN1_Msg;
CanRxMsg Recv_CAN1_Msg;
uint8_t Mail_Box = 0;

int main(void)
{
	//NVIC为内核中断,函数在misc.c和misc.h文件中
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	
	CAN1_Init();
	CAN1_RX0_IRQHandler();
	
	while(1)
	{
		//设置要发送的数据
		CAN1_SetMsg(&Send_CAN1_Msg);
		//获取发送的邮箱号。如果没有空的邮箱,返回CAN_TxStatus_NoMailBox
		Mail_Box = CAN_Transmit(CAN1,&Send_CAN1_Msg);
		if(Mail_Box != CAN_TxStatus_NoMailBox)
		{
			//检测发送状态,一直等到发送成功
			while(CAN_TransmitStatus(CAN1,Mail_Box) != CAN_TxStatus_Ok);
			//此处延时是为了让CAN收发器将收到的数据转换为电平,传送到总线
			delay_ms(1000);
		}
		else 
			return 0;
		
		//此处延时只是单纯防止发送过快
		delay_ms(1000);
	}
}

起初,代码运行时出现的问题:每次运行,都会卡在

while(CAN_TransmitStatus(CAN1,Mail_Box) != CAN_TxStatus_Ok);这一行,经检测,CAN_TransmitStatus(CAN1,Mail_Box)函数的返回值是CAN_TxStatus_Pending,也就是发送不成功

于是怀疑是代码有问题。调成回环模式测试,正常,用两个相同的板子测试,也是正常的

但每次接到USB转CAN分析仪就卡住,差点以为是分析仪坏掉了。于是用STM32F107板子写了个代码测试,也会卡住。猜测是波特率对不上,导致发送错误,于是用示波器测试频率(方法:将CANH接到示波器探头,将CANL接到示波器地端。按自动检测按钮。注意需要把程序中的两个延时注释掉),果然和计算数值不对。按照上面的计算,波特率应该是500kHz,实测是541.6KHz。

查stm32f4xx.h文件,HSE_VALUE数值和实际晶振相同

于是逐个检查system_stm32f4xx.c文件中的各个参数,最终发现,PLL_N的数值不知什么时候被改成了360

(检查方法,双击选中,右键,点击Go To Definition Of "PLL_N",调到PLL_N定义处)

一时大意,搞得这么麻烦,吸取教训了...

(以上代码亲测有效,供大家参考。芯片是stm32f407zgt6,外部晶振8MHz)

整体接线

USB转CAN分析仪,通电后,红灯亮起,如果通讯成功,绿灯+红灯同时亮,如上图(红灯小,拍不出来)

USB转CAN分析仪的软件界面以及通讯结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值