历史上的今天
返回首页

历史上的今天

今天是:2024年10月08日(星期二)

正在发生

2019年10月08日 | STM32F4的CAN通信讲解

2019-10-08 来源:eefocus

#include "CAN.h"

#define CAN_Tx_Port  GPIOH

#define CAN_Tx_Pin    GPIO_Pin_13

#define CAN_Rx_Port  GPIOI

#define CAN_Rx_Pin    GPIO_Pin_9

CanTxMsg CAN_Tx_Msg;

CanRxMsg CAN_Rx_Msg;

u8 msg_box;

u8 std;

/*

CAN 总线GPIO配置

*/

void CAN_GPIO_Config(void)

{

GPIO_InitTypeDef GPIO_init;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH|RCC_AHB1Periph_GPIOI,ENABLE);

GPIO_PinAFConfig(CAN_Tx_Port,GPIO_PinSource13,GPIO_AF_CAN1);

GPIO_PinAFConfig(CAN_Rx_Port,GPIO_PinSource9,GPIO_AF_CAN1);

GPIO_init.GPIO_Mode = GPIO_Mode_AF;

GPIO_init.GPIO_OType  = GPIO_OType_PP;

GPIO_init.GPIO_PuPd  = GPIO_PuPd_UP;

GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_init.GPIO_Pin = CAN_Tx_Pin;

GPIO_Init(CAN_Tx_Port,&GPIO_init);

GPIO_init.GPIO_Pin = CAN_Rx_Pin;

GPIO_Init(CAN_Rx_Port,&GPIO_init);

 

}

void CAN_Config(void)

{

CAN_InitTypeDef CAN_init;

CAN_FilterInitTypeDef CAN_Filter_init;

CAN_DeInit(CAN1);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);

//工作模式的设置

CAN_init.CAN_Mode  = CAN_Mode_Normal;

       //工作模式的配置:可配置为正常模式,静默模式,回环模式,静默回环模式;

//发送FIFO使能

CAN_init.CAN_TXFP  = DISABLE;

//自动重发功能使能

CAN_init.CAN_NART = DISABLE;//不使能

//FIFO锁定功能

/*

FIFO锁定功能主要用于管理接收邮箱

如果不使能FIFO锁定功能,当FIFO使能时,则在FIFO邮箱已满之后,后续的信息将会覆盖最后接收的信息

如果使能FIFO锁定功能,则在FIFO邮箱已满之后,将丢弃最新的消息,保留最原始的三则消息

*/

CAN_init.CAN_RFLM = DISABLE;

//总线自动恢复功能

/*

当 TEC 大于 255 时,达到总线关闭状态,该状态由 CAN_ESR 寄存器的 BOFF 位指示。在总线关闭状态下, bxCAN 不能再发送和接收消息。

        bxCAN 可以自动或者应软件请求而从总线关闭状态中恢复(恢复错误主动状态),具体取决于 CAN_MCR 寄存器的 ABOM 位。但在两种情况下, bxCAN 都必须至少等待 CAN 标准中指定的恢复序列完成(在 CANRX 上监测到 128 次 11 个连续隐性位)。

如果 ABOM 位置 1, bxCAN 将在进入总线关闭状态后自动启动恢复序列。

如果 ABOM 位清零,则软件必须请求 bxCAN 先进入再退出初始化模式,从而启动恢复序列。

注意: 在初始化模式下, bxCAN 不会监视 CANRX 信号,因此无法完成恢复序列。 要进行恢复,bxCAN 必须处于正常模式。

*/

CAN_init.CAN_ABOM  = DISABLE;

//---------------

CAN_init.CAN_AWUM = DISABLE;

CAN_init.CAN_TTCM = DISABLE;

//--------------------------

//关于CAN总线比特率计算

/*

NominalBitTime = 1*Tq +tBS1 +  tBS2

tBS1 = tq x (TS1[3:0] + 1);

tBS2 = tq x (TS2[2:0] + 1),

Tq = (BRP[9:0] + 1) x TPCLK;

TPCLK = APB 时钟的时间周期;

BRP[9:0], TS1[3:0] 和 TS2[2:0] 在 CAN_BTR 寄存器中定义;

//-------------------------------------------------------------

CAN 波特率 = RCC_APB1Periph_CAN1 / Prescaler / (SJW + BS1 + BS2);

SJW = synchronisation_jump_width 

BS = bit_segment

本例中,设置CAN波特率为500Kbps

CAN 波特率 = 420000000 / 2 / (1 + 12 + 8) / = 1 MBps

*/

CAN_init.CAN_BS1 = CAN_BS1_12tq;

CAN_init.CAN_BS2 = CAN_BS2_8tq;

CAN_init.CAN_SJW = CAN_SJW_1tq;

CAN_init.CAN_Prescaler = 4;

CAN_Init(CAN1,&CAN_init);

//------------------------------------

CAN_Filter_init.CAN_FilterActivation = ENABLE;//过滤器使能

//选择使用哪个FIFO,可为CAN_FilterFIFO0,CAN_FilterFIFO1;

CAN_Filter_init.CAN_FilterFIFOAssignment = CAN_FilterFIFO0;

          

CAN_Filter_init.CAN_FilterMode = CAN_FilterMode_IdMask;//掩码模式,此处可配置为掩码模式和列表模式

CAN_Filter_init.CAN_FilterScale = CAN_FilterScale_16bit;//

CAN_Filter_init.CAN_FilterNumber = 0;

CAN_Filter_init.CAN_FilterIdHigh = 0x0000;

CAN_Filter_init.CAN_FilterMaskIdHigh = 0x0000;

CAN_Filter_init.CAN_FilterIdLow = 0x0000;

CAN_Filter_init.CAN_FilterMaskIdLow = 0x0000;

CAN_FilterInit(&CAN_Filter_init);

}

void CAN_NVIC_Config(void)

{

NVIC_InitTypeDef NVIC_init;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

NVIC_init.NVIC_IRQChannel = CAN1_RX0_IRQn;

NVIC_init.NVIC_IRQChannelCmd  =ENABLE;

NVIC_init.NVIC_IRQChannelPreemptionPriority  =0x00;

NVIC_init.NVIC_IRQChannelSubPriority = 0x00;

NVIC_Init(&NVIC_init);

CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);

}

u8 CAN_send_massage(u8 *data,u8 leng,u32 massage_id)

{

u8 tx_cnt;

u32 tx_time_out_cnt = 0;

/*

当数据帧的ID大于0x7FF时就认为是拓展帧,否则都为标准帧

*/

if(massage_id > 0x7FF)

{

CAN_Tx_Msg.IDE = CAN_ID_EXT  ;//发送帧的类型:CAN_Id_Standard   标准帧; CAN_Id_Extended  拓展帧

}

else

{

CAN_Tx_Msg.IDE = CAN_ID_STD  ;//发送帧的类型:CAN_Id_Standard   标准帧; CAN_Id_Extended  拓展帧

}

CAN_Tx_Msg.DLC = leng;//发送数据长度

CAN_Tx_Msg.RTR = CAN_RTR_DATA;//发送帧的类型:CAN_RTR_DATA  发送数据帧;CAN_RTR_REMOTE 远程帧,远程帧中没有数据;

CAN_Tx_Msg.StdId = massage_id;//标准帧的ID,11位

CAN_Tx_Msg.ExtId = massage_id;//拓展帧的ID,29位

for(tx_cnt = 0;tx_cnt < leng;tx_cnt++)

{

CAN_Tx_Msg.Data[tx_cnt] = data[tx_cnt];

}

do

{

tx_time_out_cnt++;

msg_box = CAN_Transmit(CAN1,&CAN_Tx_Msg);

}

while(((CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP0) !=RESET) ||

              (CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP1) !=RESET) ||

              (CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP2) !=RESET))&&(tx_time_out_cnt < 10000));

 

tx_time_out_cnt++;

if(tx_time_out_cnt > 10000)

{

return 0;

}

else

{

return 1;

}

}

void CAN1_RX0_IRQHandler(void)

{

if(CAN_GetITStatus(CAN1,CAN_IT_FMP0) == SET)

{

CAN_Receive(CAN1,CAN_FIFO0,&CAN_Rx_Msg);

CAN_send_massage(&CAN_Rx_Msg.Data[0],CAN_Rx_Msg.DLC,CAN_Rx_Msg.ExtId);

// CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);

}

}

以上是关于CAN的基本配置,主要是波特率相关配置



今天在对STM32F4的CAN总线进行学习,更加深刻的理解了SMT32的CAN总线模块功能。具体描述如下所示:


主要是关于CAN总线滤波器的设置的问题,STM32的CAN总线接收滤波器可以设置为掩码模式和标识符列表模式,两种模式都容易理解,关键是在参数设置时需要注意,在实验过程中采用的16位标识符列表模式那么一个滤波器可以设置4个标识符,27个滤波器就可以设置27*4=108个标识符,足够今后的应用;


注意上图所对应的标识符和参数设置的问题,


假如我现在只需要接收ID为0x0321的标准数据帧,那么对应上图参数设置就应该为


CAN_Filter_init.CAN_FilterIdHigh      = 0x321<<5;为何要将数据右移5位??


解释如下所述:在上面的截图中可以看出这16位数据中不仅仅包括数据ID还有远程帧和数据帧选择位(RTR)及其


标准帧和扩展帧选择位(IDE),今天 今天白天的测试一直不通过问题就在这儿,当时仅仅将该设置参数理解为数据ID的,导致一直无法成功。


 最后的测试程序如下所示:(程序是16位列表模式)


#include "CAN.h"

#define CAN_Tx_Port  GPIOH

#define CAN_Tx_Pin    GPIO_Pin_13

#define CAN_Rx_Port  GPIOI

#define CAN_Rx_Pin    GPIO_Pin_9

CanTxMsg CAN_Tx_Msg;

CanRxMsg CAN_Rx_Msg;

u8 msg_box;

u8 std;

void CAN_GPIO_Config(void)

{

GPIO_InitTypeDef GPIO_init;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH|RCC_AHB1Periph_GPIOI,ENABLE);

GPIO_PinAFConfig(CAN_Tx_Port,GPIO_PinSource13,GPIO_AF_CAN1);

GPIO_PinAFConfig(CAN_Rx_Port,GPIO_PinSource9,GPIO_AF_CAN1);

GPIO_init.GPIO_Mode = GPIO_Mode_AF;

GPIO_init.GPIO_OType  = GPIO_OType_PP;

GPIO_init.GPIO_PuPd  = GPIO_PuPd_UP;

GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_init.GPIO_Pin = CAN_Tx_Pin;

GPIO_Init(CAN_Tx_Port,&GPIO_init);

GPIO_init.GPIO_Pin = CAN_Rx_Pin;

GPIO_Init(CAN_Rx_Port,&GPIO_init);

 

}

void CAN_Config(void)

{

CAN_InitTypeDef CAN_init;

CAN_FilterInitTypeDef CAN_Filter_init;

CAN_DeInit(CAN1);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);

//工作模式的设置

CAN_init.CAN_Mode  = CAN_Mode_Normal;//工作模式的配置:可配置为正常模式,静默模式,回环模式,静默回环模式;

//发送FIFO使能

CAN_init.CAN_TXFP  = DISABLE;

//自动重发功能使能

CAN_init.CAN_NART = DISABLE;//不使能

//FIFO锁定功能

/*

FIFO锁定功能主要用于管理接收邮箱

如果不使能FIFO锁定功能,当FIFO使能时,则在FIFO邮箱已满之后,后续的信息将会覆盖最后接收的信息

如果使能FIFO锁定功能,则在FIFO邮箱已满之后,将丢弃最新的消息,保留最原始的三则消息

*/

CAN_init.CAN_RFLM = DISABLE;

//总线自动恢复功能

/*

当 TEC 大于 255 时,达到总线关闭状态,该状态由 CAN_ESR 寄存器的 BOFF 位指示。在总线关闭状态下, bxCAN 不能再发送和接收消息。

        bxCAN 可以自动或者应软件请求而从总线关闭状态中恢复(恢复错误主动状态),具体取决于 CAN_MCR 寄存器的 ABOM 位。但在两种情况下, bxCAN 都必须至少等待 CAN 标准中指定的恢复序列完成(在 CANRX 上监测到 128 次 11 个连续隐性位)。

如果 ABOM 位置 1, bxCAN 将在进入总线关闭状态后自动启动恢复序列。

如果 ABOM 位清零,则软件必须请求 bxCAN 先进入再退出初始化模式,从而启动恢复序列。

注意: 在初始化模式下, bxCAN 不会监视 CANRX 信号,因此无法完成恢复序列。 要进行恢复,bxCAN 必须处于正常模式。

*/

CAN_init.CAN_ABOM  = DISABLE;

//---------------

CAN_init.CAN_AWUM = DISABLE;

CAN_init.CAN_TTCM = DISABLE;

//--------------------------

//关于CAN总线比特率计算

/*

NominalBitTime = 1*Tq +tBS1 +  tBS2

tBS1 = tq x (TS1[3:0] + 1);

tBS2 = tq x (TS2[2:0] + 1),

Tq = (BRP[9:0] + 1) x TPCLK;

TPCLK = APB 时钟的时间周期;

BRP[9:0], TS1[3:0] 和 TS2[2:0] 在 CAN_BTR 寄存器中定义;

//-------------------------------------------------------------

CAN 波特率 = RCC_APB1Periph_CAN1 / Prescaler / (SJW + BS1 + BS2);

SJW = synchronisation_jump_width 

BS = bit_segment

本例中,设置CAN波特率为500Kbps

CAN 波特率 = 420000000 / 4/ (1 + 12 + 8) / = 500kBps

*/

CAN_init.CAN_BS1 = CAN_BS1_12tq;

CAN_init.CAN_BS2 = CAN_BS2_8tq;

CAN_init.CAN_SJW = CAN_SJW_1tq;

CAN_init.CAN_Prescaler = 4;

CAN_Init(CAN1,&CAN_init);

//------------------------------------

CAN_Filter_init.CAN_FilterActivation = ENABLE;//过滤器使能

CAN_Filter_init.CAN_FilterFIFOAssignment = CAN_FilterFIFO0;//选择使用哪个FIFO,可为CAN_FilterFIFO0,CAN_FilterFIFO1;

CAN_Filter_init.CAN_FilterMode = CAN_FilterMode_IdList;//标识符列表模式

CAN_Filter_init.CAN_FilterScale = CAN_FilterScale_16bit;//

CAN_Filter_init.CAN_FilterNumber = 0;

        /*

            以下配置CAN总线可以接收数据帧,标准帧同时帧ID仅仅是0x321,0x322,0x7AE及其0x000才能接收。

*/

CAN_Filter_init.CAN_FilterIdHigh      = 0x321<<5;

CAN_Filter_init.CAN_FilterIdLow       = 0x0000;

CAN_Filter_init.CAN_FilterMaskIdHigh  = 0x0322<<5;

CAN_Filter_init.CAN_FilterMaskIdLow   = 0x07AE<<5;

CAN_FilterInit(&CAN_Filter_init);

}

void CAN_NVIC_Config(void)

{

NVIC_InitTypeDef NVIC_init;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

NVIC_init.NVIC_IRQChannel = CAN1_RX0_IRQn;

NVIC_init.NVIC_IRQChannelCmd  =ENABLE;

NVIC_init.NVIC_IRQChannelPreemptionPriority  =0x00;

NVIC_init.NVIC_IRQChannelSubPriority = 0x00;

NVIC_Init(&NVIC_init);

CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);

}

u8 CAN_send_massage(u8 *data,u8 leng,u32 massage_id)

{

u8 tx_cnt;

u32 tx_time_out_cnt = 0;

/*

当数据帧的ID大于0x7FF时就认为是拓展帧,否则都为标准帧

*/

if(massage_id > 0x7FF)

{

CAN_Tx_Msg.IDE = CAN_ID_EXT  ;//发送帧的类型:CAN_Id_Standard   标准帧; CAN_Id_Extended  拓展帧

}

else

{

CAN_Tx_Msg.IDE = CAN_ID_STD  ;//发送帧的类型:CAN_Id_Standard   标准帧; CAN_Id_Extended  拓展帧

}

CAN_Tx_Msg.DLC = leng;//发送数据长度

CAN_Tx_Msg.RTR = CAN_RTR_DATA;//发送帧的类型:CAN_RTR_DATA  发送数据帧;CAN_RTR_REMOTE 远程帧,远程帧中没有数据;

CAN_Tx_Msg.StdId = massage_id;//标准帧的ID,11位

CAN_Tx_Msg.ExtId = massage_id;//拓展帧的ID,29位

for(tx_cnt = 0;tx_cnt < leng;tx_cnt++)

{

CAN_Tx_Msg.Data[tx_cnt] = data[tx_cnt];

}

do

{

tx_time_out_cnt++;

msg_box = CAN_Transmit(CAN1,&CAN_Tx_Msg);

}

while(((CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP0) !=RESET) ||

              (CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP1) !=RESET) ||

推荐阅读

史海拾趣

Alpha 3 Manufacturing公司的发展小趣事

Alpha 3 Manufacturing公司成立于XXXX年,初期面临着资金短缺、市场竞争激烈以及技术瓶颈等多重挑战。然而,创始人凭借对电子行业的深刻理解和敏锐的市场洞察力,看到了电子产品制造领域的巨大潜力。他带领团队攻克技术难关,开发出了一款具有创新性的电子产品,迅速获得了市场的认可,为公司的起步奠定了坚实的基础。

安国国际(ALCOR)公司的发展小趣事

近年来,安国国际将发展重心放在U盘控制IC的开发上。随着USB技术的不断升级和SSD市场的蓬勃发展,安国积极抢占USB 3.0、USB 3.1及SSD控制IC的市场先机。公司的U盘控制IC不仅支持新一代3D NAND技术,还具备高性能、低功耗等优点,深受市场欢迎。通过持续的技术创新和市场拓展,安国在U盘控制IC领域取得了显著成绩。

Holtek(合泰)公司的发展小趣事

在全球化趋势的推动下,安国国际积极拓展海外市场,与全球多家知名企业和研究机构建立了紧密的合作关系。通过与国际伙伴的技术合作和市场共享,安国得以更快地了解市场需求和技术动态,加速产品研发和市场推广。同时,公司还加强了对全球供应链的管理和优化,确保产品质量和交货期的稳定性。这些举措为安国国际在全球市场的竞争提供了有力支持。

这五个故事展示了安国国际在电子行业中的发展历程和取得的成就。从创业初期的USB键盘集线器控制芯片研发到产品线拓展、组织架构调整、专注于U盘控制IC开发以及全球化布局与合作伙伴关系的建立,安国国际始终坚持以技术创新为驱动,以市场需求为导向,不断提升自身的核心竞争力和市场份额。

Hamlin ( Littelfuse )公司的发展小趣事

进入21世纪,安国继续深耕集线器控制芯片领域。2000年,公司发布了首款USB键盘集线器控制芯片——AU9432,这款芯片凭借其卓越的性能和稳定性,成功被Apple的iMAC键盘所采用。这一里程碑事件不仅证明了安国在集线器控制芯片领域的领先地位,也为其后续的产品研发和市场拓展奠定了坚实基础。

Crystalfontz America Inc公司的发展小趣事

Crystalfontz America Inc公司自成立以来,一直致力于LCD、OLED等显示模块的研发和生产。在早期的发展阶段,公司面临着技术上的诸多挑战。然而,通过持续的技术投入和研发团队的不懈努力,公司成功突破了多项关键技术,推出了一系列具有竞争力的显示模块产品。这些产品在市场上获得了广泛认可,为公司的快速发展奠定了坚实基础。

Faraday Technology公司的发展小趣事

在发展过程中,Crystalfontz America Inc公司不断完善和升级产品线。除了传统的LCD、OLED显示模块外,公司还推出了触摸屏、线缆、PC安装支架等一系列配套产品。这些产品的推出不仅丰富了公司的产品线,也满足了客户多样化的需求。同时,公司还关注行业动态和市场需求变化,及时调整产品策略,确保产品始终保持竞争力。

问答坊 | AI 解惑

示波器开发总结

这段时间一直比较忙,没有时间来整理资料,幸亏有汤汤的提醒,做一些简单的总结和资料的发布。 示波器的性能指标: 最高60M采样; 具有上升边沿或下降边沿的电平触发功能; 采用2.8寸TFT显示,人机界面友好; 采用STM32控制器作为主控芯片,波 ...…

查看全部问答>

终结嵌入式时代的方案(原创)

这样设想,有一个家庭,他们有很多家用电器,包括电视机,空调,微波炉,冰箱等等,他们都需要有一个控制程序。现在一般是用嵌入式在家电里面进行编程是吧?这样有很多问题,一个是开发成本,因为要给每个家电做个小程序,用来控制它,一个是这个嵌 ...…

查看全部问答>

LPC2478能跑WinCE吗?

得到一块LPC2478的开发板,里面的资源太少了,只有些Demo程序,如果自己在上面移植个操作系统,ARM7TDMI-S,没MMU也能跑Linux、winCE吗? 请了解的人给点建议。…

查看全部问答>

串口通信的问题,高手来帮帮忙!

我们单位要给新买的AN2512C支流低电阻测量仪编一个软件用串口读取测量数据,vc++。这台仪器支持串口通信(说明书里也提供了通信协议)。可是我编出来之后“不灵”(也就是说那台仪器“没有反应”),求教高手!谢谢。 我用串口精灵也调过,按照协 ...…

查看全部问答>

何时可以买到STM32L的样品?

多处寻找STM32L样品未果,请版主提供一下线索,还有多久。 如果等待太长只好再选其他M3…

查看全部问答>

ADI竞赛失败总结

由于个人原因,这次参赛只能以失败告终,实为遗憾! 开始选题目时,就是因为噪声问题苦恼了我很久(有人建议我用示波器测量噪声,我所说的噪声不是这个量级的,我需要知道微伏甚至微伏级以下的噪声),因为我现在做的跟仪器有关的东东,精度往往受 ...…

查看全部问答>

我的是8*8的点阵,为什么我的中断没有到来

我的是8*8点阵,为什么我的中断没用啊,我用m设置中断的啊,要怎么样写才对的啊,为什么m不是=50ms的啊,主要是下面这一块,主函数里的,帮我看下了,谢谢#include<reg51.h>#define uchar unsigned char#define uint unsigned intuchar code ta ...…

查看全部问答>

STM32F205 串口无法接收数据

现象如题. 发送中断是可以进去的。 想了很久没想到原因在哪,求帮助。 代码如下: void NVIC_Configuration() { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);          ...…

查看全部问答>

【芯航线FPGA学习】Quartus II 15.1软件开启代码自动补全功能

    部分用户反映QuartusII15.1安装后没有代码的自动补全功能了,我记得我在首次安装完以后也发现了这个问题。其实软件本身是支持自动补全的,只是默认被关闭了,打开方法如下: 依次点击菜单栏中【Tools】—>【Options】,在打开的对话 ...…

查看全部问答>