📄 can1.c
字号:
OSCXCN = 0x77; // start external oscillator; 22.1184 MHz Crystal
// system clock is 22.1 MHz / 2(二分频) = 11.0592 MHz
// 0111 0111 书150页
for (n=0;n<255;n++); // delay about 1ms
while ((OSCXCN & 0x80) == 0); // wait for oscillator to stabilize
CLKSEL |= 0x01; // switch to external oscillator 系统时钟采用外部时钟
}
void config_IO (void)
{
SFRPAGE = CONFIG_PAGE; //Port SFR's on Configuration page
XBR3 = 0x80; // Configure CAN TX pin (CTX) as push-pull digital output
// BIT7=1: CTX配为推挽模式
P1MDOUT |= 0x40; // Configure P1.6 as push-pull to drive LED
// 1:相应口设为推挽输出模式
XBR2 = 0x40; // Enable Crossbar/low ports
//bit6=1,Crossbar开启,交叉配置时将XBARE清0,配置结束后将其置1,使交叉开关生效
}
////////////////////////////////////////////////////////////////////////////////
//CAN Functions
////////////////////////////////////////////////////////////////////////////////
//Clear Message Objects
void clear_msg_objects (void) //将所有消息清0
{
SFRPAGE = CAN0_PAGE;
CAN0ADR = IF1CMDMSK; // Point to IF1 Command Mask Register 1
CAN0DATL = 0xFF; // Set direction to WRITE all IF registers to Msg Obj
for (i=1;i<33;i++) // i 为1到32
{
CAN0ADR = IF1CMDRQST; // Write blank (reset) IF registers to each msg obj
CAN0DATL = i;
}
}
//Initialize Message Object for RX
void init_msg_object_RX (char MsgNum) //初始化消息对象接收消息号为0x01
{
SFRPAGE = CAN0_PAGE;
CAN0ADR = IF1CMDMSK; // Point to Command Mask 1
CAN0DAT = 0x00B8; // Set to WRITE, and alter all Msg Obj except ID MASK
//0000 0000 1011 1000 // and data bits
CAN0ADR = IF1ARB1; // Point to arbitration1 register
CAN0DAT = 0x0000; // Set arbitration1 ID to "0"
CAN0DAT = 0x8004; // Arb2 high byte:Set MsgVal bit, no extended ID,
//1000 0000 0000 0100 // Dir = RECEIVE
CAN0DAT = 0x0480; // Msg Cntrl: set RXIE, remote frame function disabled(因为RmtEn=0)
//0000 0100 1000 0000
CAN0ADR = IF1CMDRQST; // Point to Command Request reg.
CAN0DATL = MsgNum; // Select Msg Obj passed into function parameter list
// --initiates write to Msg Obj
// MsgNum为消息号,即1~~32
// 3-6 CAN clock cycles to move IF register contents to the Msg Obj in CAN RAM
}
//Initialize Message Object for TX
void init_msg_object_TX (char MsgNum)
{
SFRPAGE = CAN0_PAGE; //切换到CAN寄存器页
CAN0ADR = IF1CMDMSK; // (指向)Point to Command Mask 1 寄存器
CAN0DAT = 0x00B2; // Set to WRITE, & alter all Msg Obj except ID MASK bits
// 设定读写方向(写),改变所有信息目标但MASK位不变
CAN0ADR = IF1ARB1; // Point to arbitration1 register
CAN0DAT = 0x0000; // Set arbitration1 ID to highest priority
// 写仲裁寄存器,设定信息ID(标志码)
//CAN0ADR = IF1ARB2 // CAN0ADR会自动加0,所以这一行要不要都可以
CAN0DAT = 0xA000; // Autoincrement to Arb2 high byte:
// Set MsgVal bit, no extended ID即不扩展ID, Dir = WRITE 即报文传输方向为发送
// 设定信息目标有效位并设为标准帧,读写方向为WRITE
//CAN0ADR = IF1MSGC // IF1 Message Control Register CAN0ADR会自动加0,所以这一行要不要都可以
CAN0DAT = 0x0081; // Msg Cntrl: DLC = 1, remote frame function not enabled(远程帧功能未启用)
// EoB=1 当消息对象只是应用与单数据帧场合,则此位须置1,书213页
// 数据帧的数据长度为1个字节(DLC = 1)
CAN0ADR = IF1CMDRQST; // Point to Command Request reg.
CAN0DAT = MsgNum; // 选择信息目标号 Select Msg Obj passed into function parameter list
// --initiates write to Msg Obj
// MsgNum 为1到32消息号
// 3-6 CAN clock cycles to move IF reg contents to the Msg Obj in CAN RAM.
}
//Start CAN
void start_CAN (void)
{
/* Calculation of the CAN bit timing :
System clock f_sys = 22.1184 MHz/2 = 11.0592 MHz.
System clock period t_sys = 1/f_sys = 90.422454 ns.
CAN time quantum tq = t_sys (at BRP = 0)
Desired bit rate is 1 MBit/s, desired bit time is 1000 ns.
Actual bit time = 11 tq = 996.65ns ~ 1000 ns
Actual bit rate is 1.005381818 MBit/s = Desired bit rate+0.5381%
CAN bus length = 10 m, with 5 ns/m signal delay time.
Propagation delay time : 2*(transceiver loop delay + bus line delay) = 400 ns
(maximum loop delay between CAN nodes)
Prop_Seg = 5 tq = 452 ns ( >= 400 ns).
Sync_Seg = 1 tq
Phase_seg1 + Phase_Seg2 = (11-6) tq = 5 tq
Phase_seg1 <= Phase_Seg2, => Phase_seg1 = 2 tq and Phase_Seg2 = 3 tq
SJW = (min(Phase_Seg1, 4) tq = 2 tq
TSEG1 = (Prop_Seg + Phase_Seg1 - 1) = 6
TSEG2 = (Phase_Seg2 - 1) = 2
SJW_p = (SJW - 1) = 1
Bit Timing Register = BRP + SJW_p*0x0040 = TSEG1*0x0100 + TSEG2*0x1000 = 2640
Clock tolerance df :
A: df < min(Phase_Seg1, Phase_Seg2) / (2 * (13*bit_time - Phase_Seg2))
B: df < SJW / (20 * bit_time)
A: df < 2/(2*(13*11-3)) = 1/(141-3) = 1/138 = 0.7246%
B: df < 2/(20*11) = 1/110 = 0.9091%
Actual clock tolerance is 0.7246% - 0.5381% = 0.1865% (no problem for quartz)
*/
SFRPAGE = CAN0_PAGE;
CAN0CN |= 0x41; // 将 CCE and INIT 位置1,开始初始化
// 0100 0001 CCE=1,若CPU要对CAN波特率重新配置,该位必须为1,且Init位也必须为1
// Init=1,CAN正常操作挂起,CPU要对CAN控制器初始化配置时应将此位先置1
CAN0ADR = BITREG; // 指向定时寄存器进行配置 Point to Bit Timing register
CAN0DAT = 0x2640; // see above 配置波特率
// 0010 0110 0100 0000
// TSeg2=bit14~bit12=010,采样点之前的位时间片断
// TSeg1=bit11~bit8=0110,采样点之后的位时间片断
// SJW=bit7~bit6=01,同步跳转宽度,可设置为0x0~0x3,即0~3
// BRP=bit5~bit0,时间份额设置
CAN0ADR = IF1CMDMSK; // Point to Command Mask 1
CAN0DAT = 0x0087; // Config for TX : WRITE to CAN RAM, write data bytes,
// set TXrqst/NewDat, clr IntPnd
// RX-IF2 operation may interrupt TX-IF1 operation
CAN0ADR = IF2CMDMSK; // Point to Command Mask 2
CAN0DATL = 0x1F; // Config for RX : READ CAN RAM, read data bytes,
// clr NewDat and IntPnd
CAN0CN |= 0x06; // 允许全局中断 Global Int. Enable IE and SIE
CAN0CN &= ~0x41; // Clear CCE and INIT bits, starts CAN state machine
}
//Transmit CAN frame to turn other node's LED ON
void transmit_turn_LED_ON (char MsgNum)
{
SFRPAGE = CAN0_PAGE; // IF1 already set up for TX
CAN0ADR = IF1CMDMSK; // Point to Command Mask 1
CAN0DAT = 0x0087; // Config to WRITE to CAN RAM, write data bytes,
// set TXrqst/NewDat, Clr IntPnd
CAN0ADR = IF1DATA1; // 指向数据场的第一个字节 Point to 1st byte of Data Field
CAN0DATL = 0x11; // Ones signals to turn LED's light ON in data A1 field
CAN0ADR = IF1CMDRQST; // Point to Command Request Reg.
CAN0DATL = MsgNum; // 将报文对象编号写入,则数据发送到对应的报文对象中
// Move new data for TX to Msg Obj "MsgNum"
}
//Transmit CAN Frame to turn other node's LED OFF
void transmit_turn_LED_OFF (char MsgNum)
{
SFRPAGE = CAN0_PAGE; // IF1 already set up for TX
CAN0ADR = IF1DATA1; // Point to 1st byte of Data Field
CAN0DATL = 0x00; // Zero signals to turn LED's light ON in Data A1 field
CAN0ADR = IF1CMDRQST; // Point to Command Request Reg.
CAN0DATL = MsgNum; // Move new data for TX to Msg Obj "MsgNum"
}
// Receive Data from the IF2 buffer
void receive_data (char MsgNum)
{
char virtual_button;
SFRPAGE = CAN0_PAGE; // IF1 already set up for RX
CAN0ADR = IF2CMDRQST;// Point to Command Request Reg.
CAN0DATL = MsgNum; // Move new data for RX from Msg Obj "MsgNum"
// Move new data to a
CAN0ADR = IF2DATA1; // Point to 1st byte of Data Field
virtual_button = CAN0DATL;
if (virtual_button == 0x11) //Ones is signal from other node to turn LED ON
LED = 1; //sbit LED = P1^6;
else LED = 0; //Otherwise turn LED OFF (message was one's)
}
////////////////////////////////////////////////////////////////////////////////
//Interrupt Service Routine
////////////////////////////////////////////////////////////////////////////////
void ISRname (void) interrupt 19
{
status = CAN0STA;
//CAN控制寄存器(CAN0CN)、CAN状态寄存器(CAN0STA)、CAN测试寄存器(CANTST)
if ((status&0x10) != 0)
{ // RxOk is set, interrupt caused by reception
CAN0STA = (CAN0STA&0xEF)|0x07; // Reset RxOk, set LEC to NoChange
/* read message number from CAN INTREG */
receive_data (0x01); // Up to now, we have only one RX message
}
if ((status&0x08) != 0)
{ // TxOk is set, interrupt caused by transmision
CAN0STA = (CAN0STA&0xF7)|0x07; // Reset TxOk, set LEC to NoChange
}
if (((status&0x07) != 0)&&((status&0x07) != 7))
{ // Error interrupt, LEC changed
/* error handling ? */
CAN0STA = CAN0STA|0x07; // Set LEC to NoChange
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -