新闻中心

EEPW首页>嵌入式系统>设计应用> 基于STM32的CAN总线通信程序

基于STM32的CAN总线通信程序

作者: 时间:2016-11-24 来源:网络 收藏
#include

#include "sys.h"
#include "delay.h"
#include "CAN.h"
CAN_msgCAN_TxMsg;//发送邮箱
CAN_msgCAN_RxMsg;//接收邮箱
u8 CAN_TxRdy=0;//发送就绪标志
u8 CAN_RxRdy=0;//接收就绪标志
u8CAN_TDTxR_DLC;//数据长度,最高为1111
/////////////////CAN设置/////////////////////////////////////
void CAN_setup(void)
{
u8 brp=20;//获取主时钟频率APB1ENR时钟频率为36M
RCC->APB1ENR|=1<<25;//RCC_APB1ENR_CANEN; //开启CAN使能时钟
RCC->APB2ENR|=1<<0;//RCC_APB2ENR_AFIOEN; //开启辅助时钟
AFIO->MAPR&=0XFFFF9FFF;//清除复用重映射配置寄存器13,14位,
AFIO->MAPR|=0X00004000;//配置为10;IO口重映射至PB8.PB9
RCC->APB2ENR|=1<<3;//RCC_APB2ENR_IOPBEN;//开启IO口B时钟
GPIOB->CRH&=~(0X0F<<0);//清除PB8状态寄存器~(1111<<0)
GPIOB->CRH|=(0X08<<0);//设定pb8上下拉输入1000
GPIOB->CRH&=~(0XF<<4);//清空pb9状态寄存器
GPIOB->CRH|=(0X0B<<4);//设定PB9推挽输出
MY_NVIC_Init(1,1,USB_HP_CAN_TX_IRQChannel,2);//发送中断使能
MY_NVIC_Init(1,1,USB_LP_CAN_RX0_IRQChannel,2);//接收中断使能
CAN->MCR|=1<<4;//置NART位为1,禁止自动重传403
CAN->MCR|=1<<0;//置INRQ位为1,请求初始化403 (CAN_MCR_NART|CAN_MCR_INRQ);//初始化模式,禁止重传
CAN->IER|=1<<0;//发送邮箱空中断允许409
CAN->IER|=1<<1;//FIFO0消息挂号中断允许409 (CAN_IER_FMPIE0|CAN_IER_TMEIE);
//brp=(brp/18)/500000;//波特率设置500Kb/s,计算波特率分频器值
CAN->BTR&=~(((0X03)<<24)|((0x07)<<20)|((0x0f)<<16)|(0x1ff)); //清空BTR寄存器相关位 410400
CAN->BTR|=(((1&0X03)<<24)|((7&0X07)<<20)|((8&0X0F)<<16)|(brp-1));//设置BTR寄存器410 400

}
//////////////从初始化模式进入正常工作模式/////////////////////////////////////////////
void CAN_start(void)
{
CAN->MCR&=0xfffffffe;
while(CAN->MSR&(0x01));
CAN->MCR&=0xfffffffd;//清零INRQ位,进入正常模式
//while(~(CAN->MSR&0x01));//等待硬件对INAK位清零,确认退出初始化
}
//////////////设置工作模式///////////////////////////////////////////
void CAN_testmode(void)
{
CAN->BTR&=0x3fffffff;//清空BTR 的SILM LBKM位410
CAN->BTR|=0XC0000000;//设置BTR 的LBKM位为高,环回模式410

}
///////////////检测发送邮箱为空////////////////////////////////////////////////
void CAN_waitReady(void)
{
while((CAN->TSR&(1<<26))==0);//检测发送邮箱0标志位,为1则为空,为0不为空
CAN_TxRdy=1;//置发送就绪标志位为1
}
///////////////发送数据//////////////////////////////////////
void CAN_wrMsg(CAN_msg *msg)
{
CAN->sTxMailBox[0].TIR=(u8)0;//发送邮箱标示符寄存器复位 清零
if(msg->format ==STANDARD_FORMAT)//如果是标准11位标示符帧
{msg->id=33 ;
CAN->sTxMailBox[0].TIR|=0x4200000;//(msg->id<<21)|CAN_ID_STD; //则标示符左移21位,高11位为标准标示符,标示符选择位置0411
}
else//如果是29位扩展标示符帧
{
CAN->sTxMailBox[0].TIR|=(u8)(msg->id<<3)|CAN_ID_EXT;//标示符左移3位,高29位为标示符(扩展标示符)标示符选择位置1411
}
if(msg->type==DATA_FRAME)//如果消息为数据帧
{
CAN->sTxMailBox[0].TIR|=CAN_RTR_DATA;//标示符寄存器RTR位置0,数据帧
}
else//如果为远程帧
{
CAN->sTxMailBox[0].TIR|=CAN_RTR_REMOTE;//标示符寄存器RTR置1,远程帧
}
CAN->sTxMailBox[0].TDLR=(((u8)msg->data[3]<<24)|((u8)msg->data[2]<<16)|((u8)msg->data[1]<<8)|((u8)msg->data[0]));//数据位低4字节写入发送邮箱0



CAN->sTxMailBox[0].TDHR=(((u8)msg->data[7]<<24)|((u8)msg->data[6]<<16)|((u8)msg->data[5]<<8)|((u8)msg->data[4]));//数据位高4字节写入发送邮箱0



CAN->sTxMailBox[0].TDTR&=0xfffffff0;//设置消息长度DLC清0
CAN->sTxMailBox[0].TDTR|=0x00000004;//设置消息长度为4个字节
CAN->IER|=1<<0;//发送邮箱空中断使能 409
CAN->sTxMailBox[0].TIR|=1<<0;//发送消息411

}
///////////////读取邮箱数据并释放//////////////////////////////////////////////////////////////
void CAN_rdMsg(CAN_msg *msg)
{
if((CAN->sFIFOMailBox[0].RIR&CAN_ID_EXT)==0) //如果是11位标准标识符
{
msg->format=STANDARD_FORMAT;//消息为标准格式
msg->id=(u32)0x000007ff&(CAN->sFIFOMailBox[0].RIR>>21); //标示符等于标示符位右移21位与0x7ff
}
else//如果是29位扩展标识符
{
msg->format=EXTENDED_FORMAT;//消息格式为扩展标示符格式
msg->id=(u32)0x0003ffff&(CAN->sFIFOMailBox[0].RIR>>3);//标示符等于标示符位右移3位与上0x3ffff
}
if((CAN->sFIFOMailBox[0].RIR&CAN_RTR_REMOTE)==0) //如果消息为数据帧
{
msg->type=DATA_FRAME;
}
else//数据位远程帧
{
msg->type=REMOTE_FRAME;
}
msg->len = (unsigned char)0x0000000F & CAN->sFIFOMailBox[0].RDTR;//读取数据长度

msg->data[0] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDLR);//读取数据低4字节
msg->data[1] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDLR >> 8);
msg->data[2] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDLR >> 16);
msg->data[3] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDLR >> 24);

msg->data[4] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDHR);//读取数据高4字节
msg->data[5] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDHR >> 8);
msg->data[6] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDHR >> 16);
msg->data[7] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDHR >> 24);

本文引用地址://m.amcfsurvey.com/article/201611/320933.htm

CAN->RF0R |= 1<<5;//释放接收邮箱0 407
}
////////////////////////设置标示符过滤器组/////////////////////////////////////////////////////////////////////////////

void CAN_wrFilter (unsigned int id, unsigned char format)
{
static unsigned short CAN_filterIdx = 0;//标示符设置数量索引
unsigned intCAN_msgId= 0;//变量用于存储需要设定的标示符

if (CAN_filterIdx > 13)//检查CAN过滤器是否已满,最高到13
{
return;//如果已满-返回
}
if (format == STANDARD_FORMAT)//如果是标准帧,标准帧是11位ID(报文识别码)
{// Standard ID
CAN_msgId|= (unsigned int)(id << 21) | CAN_ID_STD;//标示符左移21位并添加帧识别码,得到32位的标示符字
}
else//如果是扩展帧,扩展帧是29位ID(报文识别码)
{// Extended ID
CAN_msgId|= (unsigned int)(id <<3) | CAN_ID_EXT;//标示符左移3位并添加帧识别码,得到32位的标示符字
}
// set Initialisation mode for filter banks
//CAN过滤器组工作在初始化模式
CAN->FMR|=1<<0;
// deactivate filter
CAN->FA1R &=~(unsigned int)(1 << CAN_filterIdx);

// initialize filter
// set 32-bit scale configuration
//初始化过滤器
//过滤器位宽为单个32位
CAN->FS1R |= (unsigned int)(1 << CAN_filterIdx);
// set 2 32-bit identifier list mode
//过滤器组x的2个32位寄存器工作在标识符列表模式
CAN->FM1R |= (unsigned int)(1 << CAN_filterIdx);
//32-bit identifier
//32位标识符
CAN->sFilterRegister[CAN_filterIdx].FR1 = CAN_msgId;
//32-bit identifier
//32位标识符
CAN->sFilterRegister[CAN_filterIdx].FR2 = CAN_msgId;
// assign filter to FIFO 0
//过滤器被关联到FIFO0
CAN->FFA1R &= ~(unsigned int)(1 << CAN_filterIdx);
// activate filter
//过滤器被激活
CAN->FA1R|=(unsigned int)(1 << CAN_filterIdx);
// reset Initialisation mode for filter banks
//CAN过滤器组工作在正常模式
CAN->FMR &= ~(1<<0);// 该位置0为正常模式415
// increase filter index
//设置的过滤器数量增加
CAN_filterIdx += 1;
}


上一页 1 2 下一页

评论


技术专区

关闭