📄 can.c
字号:
/*----------------------------------------------------------------------------
QQ: 958664258
21IC用户名:banhushui
交流平台:http://blog.21ic.com/user1/5817/index.html
淘宝店铺:http://shop58559908.taobao.com
旺旺:半壶水电子
编译器版本:MDK4.12
*---------------------------------------------------------------------------*/
#include <stm32f10x_lib.h> // STM32F10x Library Definitions
#include "STM32_Reg.h" // STM32 register and bit Definitions
#include "STM32_Init.h" // STM32 Initialization
#include "CAN.h" // STM32 CAN adaption layer
CAN_msg CAN_TxMsg; // CAN messge for sending
CAN_msg CAN_RxMsg; // CAN message for receiving
unsigned int CAN_TxRdy = 0; // CAN HW ready to transmit a message
unsigned int CAN_RxRdy = 0; // CAN HW received a message
/*----------------------------------------------------------------------------
setup CAN interface
*----------------------------------------------------------------------------*/
void CAN_setup(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
unsigned int brp = stm32_GetPCLK1();
//配置CAN使用的时钟
/* CAN Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN, ENABLE);
// enable clock for Alternate Function
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);
//CAN功能重新映射
// AFIO->MAPR &= 0xFFFF9FFF; // reset CAN remap
// AFIO->MAPR |= 0x00004000; // set CAN remap, use PB8, PB9
GPIO_PinRemapConfig(GPIO_Remap1_CAN, ENABLE);
//配置CAN使用的IO口
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* Configure CAN pin: RX */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
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);
// NVIC->ISER[0] |= (1 << (USB_HP_CAN_TX_IRQChannel & 0x1F));// enable interrupt
// NVIC->ISER[0] |= (1 << (USB_LP_CAN_RX0_IRQChannel & 0x1F));// enable interrupt
/* Enable CAN RX0 interrupt IRQ channel */
//配置CAN收发中断
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN_RX0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USB_HP_CAN_TX_IRQChannel;
NVIC_Init(&NVIC_InitStructure);
// CAN->MCR = (CAN_MCR_NART | CAN_MCR_INRQ); // init mode, disable auto. retransmission
// Note: only FIFO 0, transmit mailbox 0 used
//*
// CAN_DeInit();
//配置CAN工作模式,波特率
CAN_StructInit(&CAN_InitStructure);
// CAN cell init
//初始化CAN
CAN_InitStructure.CAN_TTCM = DISABLE;//禁止时间触发通讯模式
CAN_InitStructure.CAN_ABOM = DISABLE;//禁止自动离线管理
CAN_InitStructure.CAN_AWUM = DISABLE;//禁止自动唤醒模式
CAN_InitStructure.CAN_NART = ENABLE;//允许非自动重传输模式
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_4tq;//重新同步跳跃宽度 4 个时间单位
CAN_InitStructure.CAN_BS1 = CAN_BS1_12tq;//时间段1 为12 个时间单位
CAN_InitStructure.CAN_BS2 = CAN_BS2_5tq;//时间段2 为5 个时间单位
CAN_InitStructure.CAN_Prescaler = (brp / 18) / 500000; //设置波特率
CAN_Init(&CAN_InitStructure);
//*/
// Note: only FIFO 0, transmit mailbox 0 used
// FIFO 0 msg pending, Transmit mbx empty
//FIFO0发生溢出的情况,FIFO 0的FOVR位被置’1’时,产生中断。
//发送邮箱0变为空,RQCPx位被置’1’时,产生中断。
CAN_ITConfig(CAN_IT_FMP0 | CAN_IT_TME, ENABLE);
}
/*----------------------------------------------------------------------------
leave initialisation mode
*----------------------------------------------------------------------------*/
void CAN_start (void) {
// normal operating mode, reset INRQ
//使CAN从初始化模式进入正常工作模式
CAN->MCR &= ~CAN_MCR_INRQ;
while (CAN->MSR & CAN_MCR_INRQ);
}
/*----------------------------------------------------------------------------
set the testmode
*----------------------------------------------------------------------------*/
void CAN_testmode (unsigned int testmode) {
// set testmode
//设置CAN工作模式
CAN->BTR &= ~(CAN_BTR_SILM | CAN_BTR_LBKM);
CAN->BTR |= (testmode & (CAN_BTR_SILM | CAN_BTR_LBKM));
}
/*----------------------------------------------------------------------------
check if transmit mailbox is empty
*----------------------------------------------------------------------------*/
void CAN_waitReady (void) {
// Transmit mailbox 0 is empty
//发送邮箱空?
while ((CAN->TSR & CAN_TSR_TME0) == 0);
CAN_TxRdy = 1;
}
/*----------------------------------------------------------------------------
wite a message to CAN peripheral and transmit it
*----------------------------------------------------------------------------*/
void CAN_wrMsg (CAN_msg *msg) {
// Reset TIR register
//发送邮箱标识符寄存器复位
CAN->sTxMailBox[0].TIR = (unsigned int)0;
// Setup identifier information
//如果是标准帧,标准帧是11位ID(报文识别码)
if (msg->format == STANDARD_FORMAT)
{ // Standard ID
CAN->sTxMailBox[0].TIR |= (unsigned int)(msg->id << 21) | CAN_ID_STD;
}
else//如果是扩展帧,扩展帧是29位ID(报文识别码)
{ // Extended ID
CAN->sTxMailBox[0].TIR |= (unsigned int)(msg->id << 3) | CAN_ID_EXT;
}
// Setup type information
//如果消息为数据帧
if (msg->type == DATA_FRAME)
{ // DATA FRAME
CAN->sTxMailBox[0].TIR |= CAN_RTR_DATA;
}
else//数据为远程帧
{ // REMOTE FRAME
CAN->sTxMailBox[0].TIR |= CAN_RTR_REMOTE;
}
//发送邮箱填充数据 // Setup data bytes
CAN->sTxMailBox[0].TDLR = (((unsigned int)msg->data[3] << 24) |
((unsigned int)msg->data[2] << 16) |
((unsigned int)msg->data[1] << 8) |
((unsigned int)msg->data[0]) );
CAN->sTxMailBox[0].TDHR = (((unsigned int)msg->data[7] << 24) |
((unsigned int)msg->data[6] << 16) |
((unsigned int)msg->data[5] << 8) |
((unsigned int)msg->data[4]) );
// Setup length
//设置消息数据长度
CAN->sTxMailBox[0].TDTR &= ~CAN_TDTxR_DLC;
CAN->sTxMailBox[0].TDTR |= (msg->len & CAN_TDTxR_DLC);
// enable TME interrupt
//发送邮箱空中断使能
CAN->IER |= CAN_IER_TMEIE;
// transmit message
//发送消息
CAN->sTxMailBox[0].TIR |= CAN_TIxR_TXRQ;
}
/*----------------------------------------------------------------------------
read a message from CAN peripheral and release it
*----------------------------------------------------------------------------*/
void CAN_rdMsg (CAN_msg *msg) {
// Read identifier information
//标识信息
//如果是标准帧,标准帧是11位ID(报文识别码)
if ((CAN->sFIFOMailBox[0].RIR & CAN_ID_EXT) == 0)
{ // Standard ID
msg->format = STANDARD_FORMAT;
msg->id = (u32)0x000007FF & (CAN->sFIFOMailBox[0].RIR >> 21);
}
else//如果是扩展帧,扩展帧是29位ID(报文识别码)
{ // Extended ID
msg->format = EXTENDED_FORMAT;
msg->id = (u32)0x0003FFFF & (CAN->sFIFOMailBox[0].RIR >> 3);
}
// Read type information
//如果消息为数据帧
if ((CAN->sFIFOMailBox[0].RIR & CAN_RTR_REMOTE) == 0)
{
msg->type = DATA_FRAME; // DATA FRAME
}
else//数据为远程帧
{
msg->type = REMOTE_FRAME; // REMOTE FRAME
}
// Read length (number of received bytes)
//消息数据长度
msg->len = (unsigned char)0x0000000F & CAN->sFIFOMailBox[0].RDTR;
// Read data bytes
//从接收邮箱读数据
msg->data[0] = (unsigned int)0x000000FF & (CAN->sFIFOMailBox[0].RDLR);
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);
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);
// Release FIFO 0 output mailbox
//释放接收FIFO 0输出邮箱,由于FIFO的特点,软件需要释放输出邮箱才能访问第2个报文
CAN->RF0R |= CAN_RF0R_RFOM0;
}
void CAN_wrFilter (unsigned int id, unsigned char format) {
static unsigned short CAN_filterIdx = 0;
unsigned int CAN_msgId = 0;
// check if Filter Memory is full
//检查CAN过滤器是否已满
if (CAN_filterIdx > 13)
{
return;
}
// Setup identifier information
//如果是标准帧,标准帧是11位ID(报文识别码)
if (format == STANDARD_FORMAT)
{ // Standard ID
CAN_msgId |= (unsigned int)(id << 21) | CAN_ID_STD;
}
else//如果是扩展帧,扩展帧是29位ID(报文识别码)
{ // Extended ID
CAN_msgId |= (unsigned int)(id << 3) | CAN_ID_EXT;
}
// set Initialisation mode for filter banks
//CAN过滤器组工作在初始化模式
CAN->FMR |= CAN_FMR_FINIT;
// 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 &= ~CAN_FMR_FINIT;
// increase filter index
//设置的过滤器数量增加
CAN_filterIdx += 1;
}
/*----------------------------------------------------------------------------
CAN transmit interrupt handler
CAN发送中断
*----------------------------------------------------------------------------*/
void USB_HP_CAN_TX_IRQHandler (void) {
// request completed mbx 0
//邮箱0请求完成
if (CAN->TSR & CAN_TSR_RQCP0)
{
// reset request complete mbx 0
//复位邮箱0请求
CAN->TSR |= CAN_TSR_RQCP0;
// disable TME interrupt
//禁止发送邮箱空中断
CAN->IER &= ~CAN_IER_TMEIE;
CAN_TxRdy = 1;
}
}
/*----------------------------------------------------------------------------
CAN receive interrupt handler
CAN接收中断
*----------------------------------------------------------------------------*/
void USB_LP_CAN_RX0_IRQHandler (void) {
// message pending ?
//接收到CAN报文,通过判断报文数目判断是否有报文
if (CAN->RF0R & CAN_RF0R_FMP0)
{
// read the message
//接收报文
CAN_rdMsg (&CAN_RxMsg);
CAN_RxRdy = 1;// set receive flag
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -