/*****************************************************************
*
* 文件名: main.c
* 内容简述: 本实验测试开发板上的CAN接口是否正常(Normal方式)
*
*
******************************************************************/
#include "stm32f10x.h"
#include "systick.h"
#include <stdlib.h>
#include <stdio.h>
/* Private variables ---------------------------------------------------------*/
uint16_t CAN_ID;
uint8_t CAN_DATA0,CAN_DATA1,CAN_DATA2,CAN_DATA3,CAN_DATA4,CAN_DATA5,CAN_DATA6,CAN_DATA7;
uint8_t CanFlag,Display;
/*************************************************
函数: void RCC_Configuration(void)
功能: 复位和时钟控制 配置
参数: 无
返回: 无
**************************************************/
void RCC_Configuration(void)
{
ErrorStatus HSEStartUpStatus; //定义外部高速晶体启动状态枚举变量
RCC_DeInit(); //复位RCC外部设备寄存器到默认值
RCC_HSEConfig(RCC_HSE_ON); //打开外部高速晶振
HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部高速时钟准备好
if(HSEStartUpStatus == SUCCESS) //外部高速时钟已经准别好
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //开启FLASH预读缓冲功能,加速FLASH的读取。所有程序中必须的用法.位置:RCC初始化子函数里面,时钟起振之后
FLASH_SetLatency(FLASH_Latency_2); //flash操作的延时
RCC_HCLKConfig(RCC_SYSCLK_Div1); //配置AHB(HCLK)时钟等于==SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1); //配置APB2(PCLK2)钟==AHB时钟
RCC_PCLK1Config(RCC_HCLK_Div2); //配置APB1(PCLK1)钟==AHB1/2时钟
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //配置PLL时钟 == 外部高速晶体时钟 * 9 = 72MHz
RCC_PLLCmd(ENABLE); //使能PLL时钟
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) //等待PLL时钟就绪
{
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //配置系统时钟 = PLL时钟
while(RCC_GetSYSCLKSource() != 0x08) //检查PLL时钟是否作为系统时钟
{
}
}
}
/*******************************************************************************
* 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;
/* CAN Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_AFIO ,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap1_CAN1,ENABLE);
/* Configure CAN pin: RX */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure CAN pin: TX */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/**
* LED1 -> PE0 , LED2 -> PE1 , LED3 -> PE2 , LED4 -> PE3
*/
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
// GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_Init(GPIOF, &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;
/* Enable CAN1 RX0 interrupt IRQ channel */
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
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_StructInit(&CAN_InitStructure);
/* 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_Mode_LoopBack; /* 模式 */
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; /* 重新同步跳宽,只有can硬件处于初始化模式时才能访问这个寄存器 */
CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq; /* 时间段1 */
CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq; /* 时间段2 */
CAN_InitStructure.CAN_Prescaler = 9; /* 波特率预分频数 */
//(pclk1/((1+8+7)*9)) = 36Mhz/16/9 = 250Kbits设定了一个时间单位的长度9
/* 波特率计算方法 */
/* CANbps= Fpclk/((BRP+1)*((Tseg1+1)+(Tseg2+1)+1) 此处计算为 CANbps=36000000/(45*(4+3+1))=100kHz */ //此处Tseg1+1 = CAN_BS1_8tp
/* 配置大方向: Tseg1>=Tseg2 Tseg2>=tq; Tseg2>=2TSJW */
if (CAN_Init(CAN1,&CAN_InitStructure) == CANINITFAILED)
{
/* 初始化时先设置CAN_MCR的初始化位 */
/* 然后查看硬件是否真的设置了CAN_MSR的初始化位来确认是否进入了初始化模式 */
}
/* 配置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; /* 过滤器0 */
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; /* 能够通过该过滤器的报文存到fifo0中 */
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE); /* 挂号中断, 进入中断后读fifo的报文函数释放报文清中断标志 */
}
/*******************************************************************************
* Function Name : CanWriteData
* Description : Can Write Date to CAN-BUS
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
unsigned char CanWriteData(void)
{
CanTxMsg TxMessage;
u32 i = 0;
u8 TransmitMailbox = 0;
CAN_DATA0=rand()%0xff; CAN_DATA1=rand()%0xff;
CAN_DATA2=rand()%0xff; CAN_DATA3=rand()%0xff;
CAN_DATA4=rand()%0xff; CAN_DATA5=rand()%0xff;
CAN_DATA6=rand()%0xff; CAN_DATA7=rand()%0xff;
/* transmit */
TxMessage.StdId = 0x11; /* 设置标准id 注意标准id的最高7位不能全是隐性(1)。共11位 */
// TxMessage.ExtId = 0x1234; //设置扩展id 扩展id共18位
TxMessage.RTR = CAN_RTR_DATA; /* 设置为数据帧 */
TxMessage.IDE = CAN_ID_STD; /* 使用标准id */
TxMessage.DLC = 8; /* 数据长度, can报文规定最大的数据长度为8字节 */
TxMessage.Data[0] = CAN_DATA0;
TxMessage.Data[1] = CAN_DATA1;
TxMessage.Data[2] = CAN_DATA2;
TxMessage.Data[3] = CAN_DATA3;
TxMessage.Data[4] = CAN_DATA4;
TxMessage.Data[5] = CAN_DATA5;
TxMessage.Data[6] = CAN_DATA6;
TxMessage.Data[7] = CAN_DATA7;
// CAN_Transmit(CAN1,&TxMessage); /* 返回这个信息请求发送的邮箱号0,1,2或没有邮箱申请发送no_box */
TransmitMailbox = CAN_Transmit(CAN1,&TxMessage);//开始一个消息的传输
i = 0;
while(CAN_TransmitStatus(CAN1,TransmitMailbox) != CANTXOK)//通过检查CANTXOK位来确认发送是否成功
{
i++;
}
if(i==0xff)//发送超时,但发送不成功
{
return 0;
}else{
return 1;
}
}
/*******************************************************************************
* Function Name : USB_LP_CAN1_RX0_IRQHandler
* Description : This function handles USB Low Priority or CAN RX0 interrupts
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
void USB_LP_CAN1_RX0_IRQHandler(void)
{
CanRxMsg RxMessage;
CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); /* 此函数包含释放提出报文了的,在非必要时,不需要自己释放 */
CAN_ID=RxMessage.StdId;
CAN_DATA0=RxMessage.Data[0];
CAN_DATA1=RxMessage.Data[1];
CAN_DATA2=RxMessage.Data[2];
CAN_DATA3=RxMessage.Data[3];
CAN_DATA4=RxMessage.Data[4];
CAN_DATA5=RxMessage.Data[5];
CAN_DATA6=RxMessage.Data[6];
CAN_DATA7=RxMessage.Data[7];
CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0); /* 清除挂起中断 */
CanFlag = ENABLE;
}
/*************************************************
函数: int main(void)
功能: main主函数
参数: 无
返回: 无
**************************************************/
int main(void)
{
delay_init(); //初始化延迟函数
RCC_Configuration();
GPIO_Configuration();
CAN_Configuration();
/* Infinite loop */
while (1)
{
if( CanFlag == ENABLE )
{
CanFlag = DISABLE;
GPIO_SetBits(GPIOF , GPIO_Pin_7);
delay_ms(1000); /* delay 200ms */
}
GPIO_ResetBits(GPIOF , GPIO_Pin_7);
CanWriteData();
if( Display )
{
/*====LED-ON=======*/
GPIO_SetBits(GPIOF , GPIO_Pin_6);
}
else
{
/*====LED-OFF=======*/
GPIO_ResetBits(GPIOF , GPIO_Pin_6);
}
Display = ~Display;
delay_ms(500); /* delay 200ms */
}
}
/*******************************************************************************
* Function Name : fputc
* Description : Retargets the C library printf function to the USART.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
int fputc(int ch, FILE *f) //在源代码中添加fputc函数,可以用printf函数做为调试输出
{
/* 将Printf内容发往串口 */
USART_SendData(USART1, (u8) ch);
/* 循环,直到传送完成 */
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
{
}
return ch;
}
问题:CAN_Mode_LoopBack模式正常(单机),CAN_Mode_Normal模式时异常(两块CAN电路板连接),仿真单步执行发现CAN发送被“挂起”,无法发送数据。我在3块电路板上都测试得到相同结果。求高手帮忙。怀疑是硬件问题:连接问题或CAN芯片损坏。谁能帮我测试下软件!
程序换成战舰can的例子,问题依旧,发送不出,接收不到。确定一定是硬件问题。
仿真发送端,调出keil中的CAN:Controller中的Error Counter报ACK Error、stuff Error,总线异常,确定是接收端的硬件问题。拿了新做的板子做测试并将can芯片换成NXP的82c250,测试可以发送和接收。测试了第二块NXP芯片的板子,也可以收发。
买到次货了VP230。坑死了。。。。。。。买了3片都是坏的。
明天去买个can的协议分析器,没这东东,两眼黑呀!!!哪有问题都不知道。
|