打印
[STM32L5]

怎样用STM32CAN总线接口发送和接收数据

[复制链接]
手机看帖
扫描二维码
随时随地手机跟帖
61
花间一壶酒sd|  楼主 | 2021-10-26 22:07 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
通过配置位时序寄存器CAN_BTR的TS1[3:0]及TS2[2:0]寄存器位设定BS1及BS2段的长度后,就可以确定每个CAN数据位的时间:

使用特权

评论回复
62
花间一壶酒sd|  楼主 | 2021-10-26 22:08 | 只看该作者
BS1段时间:
T S1 =Tq x (TS1[3:0] + 1),
BS2段时间:
T S2 = Tq x (TS2[2:0] + 1),

使用特权

评论回复
63
花间一壶酒sd|  楼主 | 2021-10-26 22:15 | 只看该作者
一个数据位的时间:
T 1bit =1Tq+T S1 +T S2 =1+ (TS1[3:0] + 1)+ (TS2[2:0] + 1)= N Tq

使用特权

评论回复
64
花间一壶酒sd|  楼主 | 2021-10-26 22:15 | 只看该作者
其中单个时间片的长度Tq与CAN外设的所挂载的时钟总线及分频器配置有关,CAN1和CAN2外设都是挂载在APB1总线上的,而位时序寄存器CAN_BTR中的BRP[9:0]寄存器位可以设置CAN外设时钟的分频值 ,所以:
Tq = (BRP[9:0]+1) x T PCLK

使用特权

评论回复
65
花间一壶酒sd|  楼主 | 2021-10-26 22:18 | 只看该作者
其中的PCLK指APB1时钟,默认值为36MHz。最终可以计算出CAN通讯的波特率:
BaudRate = 1/N Tq

使用特权

评论回复
66
花间一壶酒sd|  楼主 | 2021-10-26 22:18 | 只看该作者
程序设计要点中强调的三个重要参数,其实是can总线物理层中所要求的位时序。共三个阶段,分别为SJW,BS1和BS2阶段,这三个阶段的时间长度都是以长度为tq的时间单元为单位的。这样可以逐步计算出CAN总线的波特率。因此要点提示中所要求的参数,实际上将CAN的波特率设置为450kdps。

使用特权

评论回复
67
花间一壶酒sd|  楼主 | 2021-10-26 22:19 | 只看该作者
过滤器的设置

can总线没有所谓地址的概念。总线上的每个报文都可以被各个节点接收。这是一种典型的广播式网络。在实际应用中。某个节点往往只希望接收到特定类型的数据, 这就要借助过滤器来实现。顾名思义,过滤器的作用就是把节点不希望接收到的数据过滤掉。只将希望接收到的数据给予通行。stm32的CAN控制器,提供14个过滤器。可以设置为屏蔽模式和列表模式对can总线上的报文进行过滤。当节点希望接收到一种报文时。可以用屏蔽位模式对can总线上的报文进行过滤。反之,当节点希望接受到单一类型报文时。则应该配置为列表模式。本机程序中使用了32位的屏蔽位模式。下面仅对这种模式进行解析。can控制器的每个过滤器都具备一个寄存器。称为屏蔽寄存器。其中标识符寄存器的每一位都有屏蔽寄存器的每一位所对应。事实上,这也对应着can数据。事实上,这也对应着看标准数据帧中的标识符段。如下图所示。

使用特权

评论回复
68
花间一壶酒sd|  楼主 | 2021-10-26 22:20 | 只看该作者

使用特权

评论回复
69
花间一壶酒sd|  楼主 | 2021-10-26 22:20 | 只看该作者
此处重点在于屏蔽寄存器的作用。通过查阅stm32微控制器参考文档可以知道。当过滤器工作在屏蔽模式下时。屏蔽寄存器被置为1的每一位都要求can接收到的数据帧标识符段必须和对应的接收缓冲区标识位相同。否则予以滤除。以本程序为例。要点中要求将节点接收缓冲标识符配置为0x00AA0000。过滤器屏蔽标识符为0x00FF0000。

使用特权

评论回复
70
花间一壶酒sd|  楼主 | 2021-10-26 22:21 | 只看该作者
该节点接收到的数据帧的标识符段的位[23:16],必须和接收缓冲区标识符中的[23:16]匹配。否则予以滤除。但若满足了这一条件而即便如下的位不匹配。则该数据帧仍不会被滤除。正如本程序而言。即can接口仅仅接收标识符段的位[23:16]为0xAA的数据帧.

使用特权

评论回复
71
花间一壶酒sd|  楼主 | 2021-10-26 22:22 | 只看该作者
根据can总线物理层的要求。can总线的波特率和传输距离成反比关系。传输距离变化时,要根据位时序来调整can总线的波特率。

使用特权

评论回复
72
花间一壶酒sd|  楼主 | 2021-10-26 22:24 | 只看该作者

使用特权

评论回复
73
花间一壶酒sd|  楼主 | 2021-10-26 22:27 | 只看该作者

使用特权

评论回复
74
花间一壶酒sd|  楼主 | 2021-10-26 23:05 | 只看该作者
程序代码如下:
void RCC_Config(void)
{
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE)

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE)

}
void GPIO_for_can_and_uart_Config(void)
{               
                /*定义一个GPIO_InitTypeDef类型的结构体*/
                GPIO_InitTypeDef GPIO_InitStructure;

               
                /*设置can的RX--pa.11引脚*/
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;       
               
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   
               
                GPIO_Init(GPIOA, &GPIO_InitStructure);       
               
                /*设置can的TX--pa.12引脚*/
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
                GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
                GPIO_Init(GPIOA, &GPIO_InitStructure);
                /*设置usart1 的RX 脚 -PA.10为父浮空输入脚*/
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;       
               
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   
               
                GPIO_Init(GPIOA, &GPIO_InitStructure);

               
               
               
}

void Can_Config(void)
{
        CAN_InitTypeDef          CAN_InitStructure;
        CAN_FilterInitTypeDef         CAN_FilterInitStructure;

        CAN_DeInit(CAN1);

        CAN_StructInit(&CAN_InitStructure);
        CAN_InitStructure.CAN_TTCM=DISABLE;
        CAN_InitStructure.CAN_ABOM=DISABLE;
        CAN_InitStructure.CAN_AWUM=DISABLE;
        CAN_InitStructure.CAN_NART=DISABLE;
        CAN_InitStructure.CAN_RFIM=DISABLE;
        CAN_InitStructure.CAN_TXFP=DISABLE;

        CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack;
        CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
        CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;
        CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;

        CAN_InitStructure.CAN_Prescaler=5;
        CAN_Init(CAN1,&CAN_InitStructure);

        CAN_FilterInitStructure.CAN_FilterNumber=0;
        CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
        CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
        CAN_FilterInitStructure.CAN_FilterIdHigh=0x00AA<<3;
        CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
        CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x00FF<<3;
        CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
        CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0;
        CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
        CAN_FilterInit(&CAN_FilterInitStructure);

}

void main(void)
{
        u8 TransmitMailbox=0;
        CanTxMsg   TxMessage;
        CanRxMsg   RxMessage;
        RCC_Config();
        GPIO_for_can_and_uart_Config();
        USART_Config();
        Can_Config();

        TxMessage.ExtId=0x00aa0000;
        TxMessage.RTR=CAN_RTR_Data;
        TxMessage.IDE=CAN_ID_EXT;
        TxMessage.DLC=8;
        TxMessage.Data[0]=0x00;
        TxMessage.Data[1]=0x12;
        TxMessage.Data[2]=0x34;
        TxMessage.Data[3]=0x56;
        TxMessage.Data[4]=0x78;
        TxMessage.Data[5]=0xab;
        TxMessage.Data[6]=0xcd;
        TxMessage.Data[7]=0xef;

        TransmitMailbox=CAN_Transmit(CAN1,&TxMessage);
        while((CAN_TransmitStatus(CAN1,TransmitMailbox))!=CANTXOK);
        printf("\r\nThe CAN has send data :0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,\r\n",
                TxMessage.Data[0],TxMessage.Data[1],TxMessage.Data[2],TxMessage.Data[3],
                TxMessage.Data[4],TxMessage.Data[5],TxMessage.Data[6],TxMessage.Data[7],);

        while((CAN_MessagePending(CAN1,CAN_FIFO0)==0));
       
        RxMessage.StdId=0x00;
        RxMessage.IDE=CAN_ID_EXT;
        RxMessage.DLC=0;
        RxMessage.Data[0]=0x00;
        RxMessage.Data[1]=0x12;
        RxMessage.Data[2]=0x34;
        RxMessage.Data[3]=0x56;
        RxMessage.Data[4]=0x78;
        RxMessage.Data[5]=0xab;
        RxMessage.Data[6]=0xcd;
        RxMessage.Data[7]=0xef;

        CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);
        printf("\r\nThe CAN has received data :0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,\r\n",
                RxMessage.Data[0],RxMessage.Data[1],RxMessage.Data[2],RxMessage.Data[3],
                RxMessage.Data[4],RxMessage.Data[5],RxMessage.Data[6],RxMessage.Data[7],);
        while(1);


}

使用特权

评论回复
75
wiba| | 2021-11-8 13:12 | 只看该作者
我都是外挂一片can芯片

使用特权

评论回复
76
zljiu| | 2021-11-8 14:30 | 只看该作者
出现总线错误会报错 吗

使用特权

评论回复
77
tfqi| | 2021-11-8 14:44 | 只看该作者
节点数增加 功率就需要增加吧

使用特权

评论回复
78
qcliu| | 2021-11-8 15:02 | 只看该作者
主要就是调试的过程很坎坷

使用特权

评论回复
79
nawu| | 2021-11-8 15:05 | 只看该作者
替代远程请求位的作用是什么呢

使用特权

评论回复
80
dongnanxibei| | 2022-6-27 13:15 | 只看该作者
当CAN节点需要发送数据时,控制器把要发送的二进制编码通过CAN_Tx线发送到收发器,然后由收发器把这个普通的逻辑电平信号转化成差分信号,通过差分线CAN_High和CAN_Low线输出到CAN总线网络。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则