📄 can.c
字号:
/****************************************************************/
/* 项目名称 : R8C/23 CAN/LIN Demo Board */
/* : 样例程序2 */
/* : CAN收发 */
/* 硬件环境 : R0K521237C000BB */
/* MCU型号 : R5F21237JFP */
/* C编译器 : NC30WA,版本5.30.r02及以上 */
/* 文件名 : CAN.c */
/* 版本 : 1.0 */
/* 作者 : wangsy */
/* 修订历史 : */
/* 修订者 时间 版本 说明 */
/* wangsy 2006/9/11 1.0 初版发行 */
/* */
/****************************************************************/
/* Copyright, 2006 RENESAS TECHNOLOGY CORPORATION & */
/* RENESAS SOLUTIONS CORPORATION */
/****************************************************************/
/*------------包含的头文件--------------*/
#include "..\inc\Comdef_r823.h"
#include "..\inc\CAN.h"
/*-------------变量定义-----------------*/
// CAN 接受帧
can_std_data_def ReceiveData = {0x00U, 0x08, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
// CAN 发送帧
can_std_data_def TransmitData = {SND_FRM_ID, 0x08, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
uchar8 ucFlag_CAN0_RE = NO; // CAN接收,事件触发标志
uchar8 re_slot = RCV_SLOT; // 接收信箱
uchar8 tr_slot = SND_SLOT; // 发送信箱
/*-------------函数声明-----------------*/
void config_can0(void); // CAN0初始设置
void can0_receive(void); // CAN0接收入口函数
void can0_transmit(void); // CAN0发送入口函数
void set_bitrate_can0(void); // CAN0波特率设置
// 移位(左移)函数 MISRA中不允许移位的位数为变量
uint16 left_shift(uint16 oprnd_obj, uchar8 left_bit);
// 设置CAN0标准数据帧的发送
void set_trm_std_dataframe_can0(uchar8 in_slot, can_std_data_def * in_trm_data);
// 设置CAN0标准数据帧的接收
void set_rcv_std_dataframe_can0(uchar8 in_slot, uint16 in_sid);
/*-----------中断处理函数---------------*/
void int_can0_receive(void);
/*------------函数定义------------------*/
/*------------------------------------------------------
名称 : config_can0
功能 : CAN0初始设置
入口 : 无
出口 : 无
调用 : 调用void set_bitrate_can0(void)
寄存器 : c0ctlr, c0str,c0recic,c0gmr,c0lmar,c0lmbr
------------------------------------------------------*/
void config_can0(void)
{
// canI/O 设置
pd6_1 = 1;
pd6_2 = 0;
c0ctlr_addr.b.reset = 1; // 进入初始化模式
c0ctlr_addr.b.sleep = 0; // 结束休眠模式
while(c0str_addr.b.state_reset == 0) // 等待处理器进入初始化模式
{
}
c0ctlr_addr.b.porten = 1; // CAN端口使能
c0ctlr_addr.b.loopback = 0; // 不采用自环模式
c0ctlr_addr.b.msgorder = 1; // 消息顺序:字节访问
c0ctlr_addr.b.basiccan = 0; // 不采用Basic CAN模式
c0ctlr_addr.b.buserren = 0; // 禁止总线错误中断
c0ctlr_addr.b.tsprescale = 0; // 时间戳预分频器:"period of 1bit time"
set_bitrate_can0(); // 调用比特率设置函数
c0ctlr_addr.b.reset = 0; // 跳出初始化模式
while(c0str_addr.b.state_reset != 0) // 确认跳出初始化模式
{
}
c0recic_addr.byte = CAN0_RCV_PRIORITY; // CAN0接收中断优先级5
//设置屏蔽寄存器为可以接收所有的ID
c0gmr.ba.sidh = 0x0;
c0gmr.ba.sidl = 0x0;
c0lmar.ba.sidh = 0x0;
c0lmar.ba.sidl= 0x0;
c0lmbr.ba.sidh = 0x0;
c0lmbr.ba.sidl= 0x0;
}
/*------------------------------------------------------
名称 : set_bitrate_can0
功能 : CAN0波特率设置
入口 : 无
出口 : 无
调用 : 无
寄存器 : prc0,cclkr,c0conr
------------------------------------------------------*/
void set_bitrate_can0(void)
{
// clock = 20MHz
prc0 = 1; // 打开保护寄存器
cclkr &= ~(uchar8)0x00; // 清零 CAN0 时钟寄存器
prc0 = 0; // 关闭保护寄存器
c0conr_addr.b.brp = CAN0_BRP - 1U; // CAN 时钟预分频器 = 10 125kbps
// 设置位时序
c0conr_addr.b.sam = BT_SAM - 1U; // SS = 1 Tq
c0conr_addr.b.pts = BT_PTS - 1U; // PTS = 1 Tq
c0conr_addr.b.pbs1 = BT_PBS1 - 1U; // PBS1 = 3 Tq
c0conr_addr.b.pbs2 = BT_PBS2 - 1U; // PBS2 = 3 Tq
c0conr_addr.b.sjw = BT_SJW - 1U; // SJW = 1 Tq
}
/*------------------------------------------------------
名称 : left_shift
功能 : 移位(左移)函数
入口 : 要求左移的位数
出口 : 被移位的变量
调用 : 无
寄存器 : 无
------------------------------------------------------*/
uint16 left_shift(uint16 oprnd_obj, uchar8 left_bit)
{
switch(left_bit)
{
case 0:
break;
case 1:
oprnd_obj = oprnd_obj << 1;
break;
case 2:
oprnd_obj = oprnd_obj << 2;
break;
case 3:
oprnd_obj = oprnd_obj << 3;
break;
case 4:
oprnd_obj = oprnd_obj << 4;
break;
case 5:
oprnd_obj = oprnd_obj << 5;
break;
case 6:
oprnd_obj = oprnd_obj << 6;
break;
case 7:
oprnd_obj = oprnd_obj << 7;
break;
case 8:
oprnd_obj = oprnd_obj << 8;
break;
case 9:
oprnd_obj = oprnd_obj << 9;
break;
case 0x0a:
oprnd_obj = oprnd_obj << 0x0a;
break;
case 0x0b:
oprnd_obj = oprnd_obj << 0x0b;
break;
case 0x0c:
oprnd_obj = oprnd_obj << 0x0c;
break;
case 0x0d:
oprnd_obj = oprnd_obj << 0x0d;
break;
case 0x0e:
oprnd_obj = oprnd_obj << 0x0e;
break;
case 0x0f:
oprnd_obj = oprnd_obj << 0x0f;
break;
default:
break;
}
// 将移位完的操作数返回
return(oprnd_obj);
}
/*------------------------------------------------------
名称 : set_trm_std_dataframe_can0
功能 : 设置CAN0标准数据帧的发送
入口 : in_slot: 信箱号
*in_trm_data:发送数据帧的地址
出口 : 无
调用 : uint16 left_shift(uint16 oprnd_obj, uchar8 left_bit)
寄存器 : c0mctl,c0icr,c0idr,c0slot
------------------------------------------------------*/
void set_trm_std_dataframe_can0(uchar8 in_slot, can_std_data_def *in_trm_data)
{
uchar8 LoopCounter;
uint16 temp;
// 确认可以发送
while(c0mctl[in_slot].transmit.trmactive == 1)
{
}
// 清零CAN0消息控制寄存器
while(c0mctl[in_slot].byte != 0x00)
{
c0mctl[in_slot].byte = 0x00;
}
// 对应信箱,CAN0中断控制寄存器禁止
temp = c0icr_addr.word + 0U;
temp &= (~(left_shift((uint16)0x0001, in_slot)));
c0icr_addr.word = (int16)temp;
// 对应信箱,CAN0采用标准ID
temp = c0idr_addr.word + 0U;
temp &= ~(left_shift((uint16)0x0001, in_slot));
c0idr_addr.word = (int16)temp;
c0slot[in_slot].ba.sidh = (uchar8)(((in_trm_data->id)>> 6U) & 0x1FU); // 设置SID10-6
c0slot[in_slot].ba.sidl = (uchar8)((in_trm_data->id) & 0x3FU); // 设置SID5-0
c0slot[in_slot].ba.dlc = in_trm_data->dlc; // 设置DLC
// 将发送数据放入CAN0发送信箱
for(LoopCounter=0; (LoopCounter<(in_trm_data->dlc))&&(LoopCounter<8); ++LoopCounter)
{
c0slot[in_slot].ba.data[LoopCounter] = in_trm_data->data[LoopCounter];
}
// 启动标准数据帧的发送
c0mctl[in_slot].byte = 0x80;
}
/*------------------------------------------------------
名称 : can0_receive
功能 : CAN0接收
入口 : 无
出口 : 无
调用 : void set_rcv_std_dataframe_can0(uchar8 in_slot, uint16 in_sid)
寄存器 : 无
------------------------------------------------------*/
void can0_receive(void)
{
// 调用CAN0标准数据帧的接收设置
set_rcv_std_dataframe_can0(re_slot, ReceiveData.id);
}
/*------------------------------------------------------
名称 : set_rcv_std_dataframe_can0
功能 : 设置CAN0标准数据帧的接收
入口 : in_slot: 信箱号
in_sid: 接收SID
出口 : 无
调用 : uint16 left_shift(uint16 oprnd_obj, uchar8 left_bit)
寄存器 : c0mctl,c0icr,c0idr,c0slot
------------------------------------------------------*/
void set_rcv_std_dataframe_can0(uchar8 in_slot, uint16 in_sid)
{
uint16 temp;
// 清零CAN0消息控制寄存器
while(c0mctl[in_slot].byte != 0x00)
{
c0mctl[in_slot].byte = 0x00;
}
// 对应信箱,CAN0中断控制寄存器允许
temp = c0icr_addr.word + 0U;
temp |= left_shift((uint16)0x0001, in_slot);
c0icr_addr.word = (int16)temp;
// 对应信箱,CAN0采用标准ID
temp = c0idr_addr.word + 0U;
temp &= ~(left_shift((uint16)0x0001, in_slot));
c0idr_addr.word = (int16)temp;
c0slot[in_slot].ba.sidh = (uchar8)((in_sid>> 6U) & 0x1FU); // 设置 SID10-6
c0slot[in_slot].ba.sidl = (uchar8)(in_sid & 0x3FU); // 设置 SID5-0
// 启动CAN0标准数据帧的接收
c0mctl[in_slot].byte = 0x40;
}
/*------------------------------------------------------
名称 : can0_transmit
功能 : CAN0发送
入口 : 无
出口 : 无
调用 : void set_trm_std_dataframe_can0(uchar8 in_slot, can_std_data_def * in_trm_data)
寄存器 : 无
------------------------------------------------------*/
void can0_transmit(void)
{
set_trm_std_dataframe_can0(tr_slot, &TransmitData);
}
/*------------------------------------------------------
名称 : int_can0_receive
功能 : 中断处理函数:CAN0接收
入口 : 无
出口 : 无
调用 : 无
寄存器 : c0mctl,c0slot
------------------------------------------------------*/
#pragma INTERRUPT int_can0_receive
void int_can0_receive(void)
{
uchar8 lp_dlc;
// 当发生中断时,将CAN0接收事件触发标志置为YES
ucFlag_CAN0_RE = YES;
// 确认新的数据来到
while(c0mctl [re_slot].receive.newdata != 1)
{
}
// 等待直到消息有效
while(c0mctl[re_slot].receive.invaldata == 1)
{
}
// 清零
c0mctl[re_slot].receive.newdata = 0;
// 检查过载错误
if(c0mctl[re_slot].receive.msglost == 1)
{
c0mctl[re_slot].receive.msglost = 0;
// 当发生过载错误时的用户处理程序(略)
}
else
{
}
// 读出消息
ReceiveData.id = ((uint16)c0slot[re_slot].ba.sidh << 6) + c0slot[re_slot].ba.sidl;
ReceiveData.dlc = c0slot[re_slot].ba.dlc;
for(lp_dlc=0; lp_dlc<c0slot[re_slot].ba.dlc; ++lp_dlc)
{
ReceiveData.data[lp_dlc] = c0slot[re_slot].ba.data[lp_dlc];
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -