CAN驱动代码

这是一个CAN驱动程序的实现,包括初始化、发送和接收报文的功能。代码详细定义了CAN的初始化函数`CAN_Mode_Init()`,该函数设置波特率、模式等参数。`Can_Tx_Msg()`函数用于发送CAN报文,而`Can_Rx_Msg()`用于接收报文。此外,还有中断服务函数`USB_LP_CAN1_RX0_IRQHandler()`处理接收中断。示例还展示了如何发送和接收固定格式的数据。
摘要由CSDN通过智能技术生成

#include "can.h"
#include "led.h"
#include "delay.h"
#include "usart.h"
// 
//CAN驱动代码       
// 
//CAN初始化
//tsjw:重新同步跳跃时间单元.范围:1~3;
//tbs2:时间段2的时间单元.范围:1~8;
//tbs1:时间段1的时间单元.范围:1~16;
//brp :波特率分频器.范围:1~1024;(实际要加1,也就是1~1024) tq=(brp)*tpclk1
//注意以上参数任何一个都不能设为0,否则会乱.
//波特率=Fpclk1/((tbs1+tbs2+1)*brp);
//mode:0,普通模式;1,回环模式;
//Fpclk1的时钟在初始化的时候设置为36M,如果设置CAN_Normal_Init(1,8,7,5,1);
//则波特率为:36M/((8+7+1)*5)=450Kbps
//返回值:0,初始化OK;
//    其他,初始化失败;
u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{
 u16 i=0;
  if(tsjw==0||tbs2==0||tbs1==0||brp==0)return 1;
 tsjw-=1;//先减去1.再用于设置
 tbs2-=1;
 tbs1-=1;
 brp-=1;

 RCC->APB2ENR|=1<<2;    //使能PORTA时钟 
 GPIOA->CRH&=0XFFF00FFF;
 GPIOA->CRH|=0X000B8000;//PA11 RX,PA12 TX推挽输出    
    GPIOA->ODR|=3<<11;
        
 RCC->APB1ENR|=1<<25;//使能CAN时钟 CAN使用的是APB1的时钟(max:36M)
 CAN->MCR=0x0000; //退出睡眠模式(同时设置所有位为0)
 CAN->MCR|=1<<0;  //请求CAN进入初始化模式
 while((CAN->MSR&1<<0)==0)
 {
  i++;
  if(i>100)return 2;//进入初始化模式失败
 }
 CAN->MCR|=0<<7;  //非时间触发通信模式
 CAN->MCR|=0<<6;  //软件自动离线管理
 CAN->MCR|=0<<5;  //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
 CAN->MCR|=1<<4;  //禁止报文自动传送
 CAN->MCR|=0<<3;  //报文不锁定,新的覆盖旧的
 CAN->MCR|=0<<2;  //优先级由报文标识符决定
 CAN->BTR=0x00000000;//清除原来的设置.
 CAN->BTR|=mode<<30; //模式设置 0,普通模式;1,回环模式;

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: S32K116芯片的CAN驱动代码如下: #include "S32K116.h"// 初始化CAN模块 void CAN_Init(void) { // 开启CAN时钟 SIM->SCGC6 |= SIM_SCGC6_FLEXCAN0_MASK; // 配置FlexCAN0模块 CAN0->MCR |= CAN_MCR_MDIS_MASK; // 关闭CAN CAN0->MCR &= ~CAN_MCR_MAXMB_MASK; // 最大MB为15 CAN0->CTRL1 &= ~CAN_CTRL1_CLKSRC_MASK; // 时钟源为外部晶振 CAN0->MCR &= ~CAN_MCR_HALT_MASK; // 启动CAN CAN0->MCR &= ~CAN_MCR_FRZ_MASK; // 取消冻结 CAN0->MCR &= ~CAN_MCR_SRXDIS_MASK; // 接收使能 CAN0->MCR |= CAN_MCR_IRMQ_MASK; // 配置中断类型为消息队列 // 配置标准CAN CAN0->CTRL1 |= CAN_CTRL1_PRESDIV(3) | CAN_CTRL1_RJW(2) | CAN_CTRL1_PSEG1(8) | CAN_CTRL1_PSEG2(7); // 配置扩展CAN CAN0->CTRL2 |= CAN_CTRL2_EACEN_MASK | CAN_CTRL2_EAFEN_MASK | CAN_CTRL2_EASP_MASK; CAN0->RXIMR[0] |= CAN_RXIMR_MI(0xFFFFFFFF); // 设置接收屏蔽寄存器 // 配置MB for (int i = 0; i <= 15; i++) { CAN0->MB[i].CS = CAN_CS_CODE(0b1000); // 设置MB状态为空闲 CAN0->MB[i].ID = 0x00; // 设置MB ID } }// 接收消息 uint8_t CAN_Receive(uint32_t *id, uint8_t *data, uint8_t *dlc, uint32_t length) { uint8_t mb_index; mb_index = CAN0->IFLAG1 & 0x000F; // 获取MB编号 if (CAN0->MB[mb_index].CS & CAN_CS_CODE_MASK) { // 读取ID *id = CAN0->MB[mb_index].ID; // 读取数据 if (length > 8) length = 8; for (int i = 0; i < length; i++) data[i] = CAN0->MB[mb_index].BYTE[i]; // 读取数据长度 *dlc = CAN0->MB[mb_index].DL; // 清除中断标志 CAN0->IFLAG1 = CAN_IFLAG1_BUF0I_MASK << mb_index; // 置MB状态为空闲 CAN0->MB[mb_index].CS = CAN_CS_CODE(0b1000); return 1; } else return 0; }// 发送消息 uint8_t CAN_Send(uint32_t id, uint8_t *data, uint8_t dlc, uint32_t length) { uint8_t mb_index; // 获取空闲MB编号 mb_index = CAN0->IFLAG1 & 0x000F; // 如果MB状态为空闲,则发送消息 if (CAN0->MB[mb_index].CS & CAN_CS_CODE_MASK) { // 写入ID CAN0->MB[mb_index].ID = id; // 写入数据 if (length > 8) length = 8; for (int i = 0; i < length; i++) CAN0->MB[mb_index].BYTE[i] = data[i]; // 写入数据长度 CAN0->MB[mb_index].DL = dlc; // 置MB状态为发送 CAN0->MB[mb_index].CS = CAN_CS_CODE(0b0100); return 1; } else return 0; } ### 回答2: S32K116芯片是一款集成了CAN控制器的微控制器。要实现标准CAN和扩展CAN的收发功能,我们可以编写以下代码。 首先,我们需要初始化CAN控制器,设置CAN模式、波特率等参数。 ```c void CAN_Init(void) { // 初始化CAN时钟 CAN_INIT_CLOCK(); // 选择CAN时钟源 CAN_SELECT_CLOCK_SOURCE(); // 设置波特率 CAN_SET_BITRATE(); // 设置CAN工作模式 CAN_SET_MODE(); // 使能CAN模块 CAN_ENABLE(); } ``` 接下来,我们编写发送数据的函数。 ```c void CAN_Send(uint32_t id, uint8_t *data, uint8_t length, uint8_t ext) { // 等待发送缓冲区为空 while (!(CAN_CONTROLLER->IFLAG1 & CAN_IFLAG1_BUF1I_MASK)) { } // 设置帧ID和扩展标志位 CAN_CONTROLLER->BUF[1].CS = (CAN_CONTROLLER->BUF[1].CS & ~CAN_CS_ID_MASK) | id; if (ext) { CAN_CONTROLLER->BUF[1].CS |= CAN_CS_EXTENDED_MASK; } else { CAN_CONTROLLER->BUF[1].CS &= ~CAN_CS_EXTENDED_MASK; } // 设置数据长度 CAN_CONTROLLER->BUF[1].CS = (CAN_CONTROLLER->BUF[1].CS & ~CAN_CS_DLC_MASK) | (length << CAN_CS_DLC_SHIFT); // 设置数据 memcpy((void *)&CAN_CONTROLLER->BUF[1].DATA.B0, data, length); // 发送帧 CAN_CONTROLLER->BUF[1].CS |= CAN_CS_TX_MASK; } ``` 最后,我们编写接收数据的函数。 ```c void CAN_Receive(uint32_t *id, uint8_t *data, uint8_t *length, uint8_t *ext) { // 等待接收缓冲区非空 while (!(CAN_CONTROLLER->IFLAG1 & CAN_IFLAG1_BUF0I_MASK)) { } // 获取帧ID和扩展标志位 *id = CAN_CONTROLLER->BUF[0].CS & CAN_CS_ID_MASK; *ext = CAN_CONTROLLER->BUF[0].CS & CAN_CS_EXTENDED_MASK; // 获取数据长度 *length = (CAN_CONTROLLER->BUF[0].CS & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT; // 获取数据 memcpy(data, (const void *)&CAN_CONTROLLER->BUF[0].DATA.B0, *length); // 清除接收中断标志位 CAN_CONTROLLER->IFLAG1 |= CAN_IFLAG1_BUF0I_MASK; } ``` 以上就是一个简单的S32K116芯片的CAN驱动代码,可以实现标准CAN和扩展CAN的数据收发功能。当收到数据时,可以调用CAN_Receive函数获取数据和帧信息;当要发送数据时,可以调用CAN_Send函数发送数据。根据具体应用需求,我们可以在代码中添加错误处理和其他功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值