历史上的今天
返回首页

历史上的今天

今天是:2026年03月20日(星期五)

正在发生

2023年03月20日 | CAN总线学习笔记 | STM32CubeMX配置CAN环回测试

2023-03-20 来源:zhihu

CAN基础知识介绍文中介绍了CAN协议的基础知识,以及STM32F4芯片的CAN控制器相关知识,下面将通过实例,利用STM32CubeMX图形化配置工具,来实现CAN通讯的环回测试


一、STM32CubeMX配置

CAN是挂载在APB1总线上,设置PCLK1时钟频率到最大45MHz

激活CAN1,配置位时序参数,其他基本参数以及工作模式(此处设置为Loopback环回模式)


CAN波特率的计算公式:只需要知道BS1和BS2的设置,以及APB1的时钟频率,就可以方便的计算出波特率。比如设置TS1=8、TS2=6和BRP=6,在APB1频率为45Mhz的条件下,即可得到CAN通信的波特率=45000/6/(8+6+1)=500Kbps

激活USART1作为调试串口,配置相关LED对应的GPIO引脚作为指示灯


二、MDK-ARM编程

2.1 几个重要的结构体

CAN 初始化结构体:此结构体内容,可由STM32CubeMX工具进行配置

typedef struct

{

    uint32_t Prescaler;  /* 配置 CAN 外设的时钟分频,可设置为 1-1024*/

    uint32_t Mode;        /* 配置 CAN 的工作模式,回环或正常模式 */

    uint32_t SyncJumpWidth;  /* 配置 SJW 极限值 */

    uint32_t TimeSeg1;    /* 配置 BS1 段长度 */

    uint32_t TimeSeg2;    /* 配置 BS2 段长度 */

    FunctionalState TimeTriggeredMode;    /* 是否使能 TTCM 时间触发功能 */

    FunctionalState AutoBusOff;      /* 是否使能 ABOM 自动离线管理功能 */

    FunctionalState AutoWakeUp;    /* 是否使能 AWUM 自动唤醒功能 */

    FunctionalState AutoRetransmission;  /* 是否使能 NART 自动重传功能 */

    FunctionalState ReceiveFifoLocked;    /* 是否使能 RFLM 锁定 FIFO 功能 */

    FunctionalState TransmitFifoPriority; /* 配置 TXFP 报文优先级的判定方法 */

} CAN_InitTypeDef;

发送及接收头结构体:主要用于构造发送报文,以及接收报文。收发发文时,需要自定义头结构体变量

typedef struct

{

    uint32_t StdId;    /* 存储报文的标准标识符 11 位,0-0x7FF. */

    uint32_t ExtId;    /* 存储报文的扩展标识符 29 位,0-0x1FFFFFFF. */

    uint32_t IDE;      /* 存储 IDE 扩展标志 */

    uint32_t RTR;    /* 存储 RTR 远程帧标志 */

    uint32_t DLC;    /* 存储报文数据段的长度,0-8 */

    FunctionalState TransmitGlobalTime; 

} CAN_TxHeaderTypeDef;


typedef struct

{

    uint32_t StdId;    /* 存储报文的标准标识符 11 位,0-0x7FF. */

    uint32_t ExtId;    /* 存储报文的扩展标识符 29 位,0-0x1FFFFFFF. */

    uint32_t IDE;      /* 存储 IDE 扩展标志 */

    uint32_t RTR;      /* 存储 RTR 远程帧标志 */

    uint32_t DLC;      /* 存储报文数据段的长度,0-8 */

    uint32_t Timestamp; 

    uint32_t FilterMatchIndex; 

} CAN_RxHeaderTypeDef;

过滤器结构体:STM32CubeMX不会初始化过滤器的相关内容,需要自己添加

typedef struct

{

    uint32_t FilterIdHigh;          /*CAN_FxR1 寄存器的高 16 位 */

    uint32_t FilterIdLow;          /*CAN_FxR1 寄存器的低 16 位 */

    uint32_t FilterMaskIdHigh;    /*CAN_FxR2 寄存器的高 16 位 */

    uint32_t FilterMaskIdLow;    /*CAN_FxR2 寄存器的低 16 位 */

    uint32_t FilterFIFOAssignment;  /* 设置经过筛选后数据存储到哪个接收 FIFO */

    uint32_t FilterBank;            /* 筛选器编号,范围 0-27,CAN1是0-13,CAN2是14-27 */

    uint32_t FilterMode;            /* 筛选器模式 */

    uint32_t FilterScale;            /* 设置筛选器的尺度 */

    uint32_t FilterActivation;      /* 是否使能本筛选器 */

    uint32_t SlaveStartFilterBank;  /* CAN2起始过滤器组 */

} CAN_FilterTypeDef;

2.2 程序编写

生成工程后,打开can.c文件,可见STM32CubeMX已经对位时序参数、其他基本参数以及工作模式进行了初始化。但是并没有初始化过滤器的相关内容,因此需要我们自己添加,并在CAN初始化时调用

//下面的设置只使能了FIFO0,并不过滤任何消息

void CAN_Filter_Config(){

    CAN_FilterTypeDef sFilterConfig;

    sFilterConfig.FilterBank = 0; //筛选器编号, CAN1是0-13, CAN2是14-27

    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //采用掩码模式

    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //设置筛选器的尺度, 采用32位

    sFilterConfig.FilterIdHigh = 0X0000; //过滤器ID高16位,即CAN_FxR1寄存器的高16位

    sFilterConfig.FilterIdLow = 0X0000; //过滤器ID低16位,即CAN_FxR1寄存器的低16位

    sFilterConfig.FilterMaskIdHigh = 0X0000; //过滤器掩码高16位,即CAN_FxR2寄存器的高16位

    sFilterConfig.FilterMaskIdLow = 0X0000; //过滤器掩码低16位,即CAN_FxR2寄存器的低16位

    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //设置经过筛选后数据存储到哪个接收FIFO

    sFilterConfig.FilterActivation = ENABLE; //是否使能本筛选器

    sFilterConfig.SlaveStartFilterBank = 14; //指定为CAN1分配多少个滤波器组

    if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)

    {

Error_Handler();

    }

}

编写发送和接收数据函数:此处将格式固定为标准数据帧,ID为12

uint8_t CAN1_Send_Msg(uint8_t *msg, uint8_t len){

    uint16_t i = 0;

    uint32_t txMailBox;

    uint8_t send_buf[8];

    txHeader.StdId = 12;

    txHeader.ExtId = 12;

    txHeader.IDE = CAN_ID_STD;

    txHeader.RTR = CAN_RTR_DATA;

    txHeader.DLC = len;

    for(i = 0; i < len; i++)

send_buf[i] = msg[i];

    if(HAL_CAN_AddTxMessage(&hcan1, &txHeader, send_buf, &txMailBox) != HAL_OK)

return 1;

    return 0;

}


uint8_t CAN1_Recv_Msg(uint8_t *buf){

    uint16_t i = 0;

    HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &rxHeader, buf);

    if(rxHeader.IDE == CAN_ID_STD)

printf("StdId ID: %drn", rxHeader.StdId);

    else

printf("ExtId ID: %drn", rxHeader.ExtId);

    printf("CAN IDE: %drn", rxHeader.IDE);

    printf("CAN RTR: %drn", rxHeader.RTR);

    printf("CAN DLC: %drn", rxHeader.DLC);

    printf("Recv Data: ");

    for(i = 0; i < rxHeader.DLC; i++)

printf("%c",buf[i]);

    printf("n");

    return rxHeader.DLC;

}

默认Cubemx生成的代码并没有can start,没有调用HAL_CAN_Start(&hcan1) 来使能CAN,因此需要在CAN初始化代码中添加

void MX_CAN1_Init(void){

    ......

    /* USER CODE BEGIN CAN1_Init 2 */

    CAN_Filter_Config();

    HAL_CAN_Start(&hcan1);

    /* USER CODE END CAN1_Init 2 */

}

主函数main.c中,代码如下

int main(void){

    HAL_Init();

    SystemClock_Config();

    MX_GPIO_Init();

    MX_CAN1_Init();

    MX_USART1_UART_Init();

    /* USER CODE BEGIN 2 */

    uint8_t ret,i;

    printf("CAN Testing....!rn");

    uint8_t txdata[8] = {76, 79, 79, 80, 66, 65, 67, 75};

    uint8_t rxdata[8];

    /* USER CODE END 2 */

    /* Infinite loop */

    /* USER CODE BEGIN WHILE */

    while (1)

    {

HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_1);

HAL_Delay(1000);

printf("Start Send data...rn");

ret = CAN1_Send_Msg(txdata, 8);

if(ret == 0)

    printf("CAN Send success!rn");

else 

    printf("CAN Send failed!rn");

CAN1_Recv_Msg(rxdata);

printf("+++++++++++++++++++++++++++++++rn");

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

    }

    /* USER CODE END 3 */

}


三、下载测试

编译无误后下载到开发板,可以看到系统运行时D1指示灯不断闪烁,串口不断的打印CAN环回测试的数据

推荐阅读

史海拾趣

Dowosemi公司的发展小趣事

在电子保护器件领域,Dowosemi公司以其创新的TVS二极管技术崭露头角。该公司研发团队经过数年的努力,成功开发出具有PS级响应速度、大瞬态功率和低漏电流的TVS二极管。这一技术突破大大提高了产品的性能,满足了市场对高效能过电压保护元件的需求。Dowosemi公司凭借这一优势,迅速在市场上确立了领先地位。

HEIMANN公司的发展小趣事

Dowosemi公司深知不同行业对电路保护的需求各异,因此他们致力于提供定制化的解决方案。无论是汽车电子、通讯设备还是智能电表等领域,Dowosemi公司都能根据客户的具体需求,提供量身定做的电路保护产品。这种贴心的服务赢得了客户的广泛赞誉,也为公司带来了源源不断的订单。

Broadband公司的发展小趣事

在电子保护器件领域,Dowosemi公司以其创新的TVS二极管技术崭露头角。该公司研发团队经过数年的努力,成功开发出具有PS级响应速度、大瞬态功率和低漏电流的TVS二极管。这一技术突破大大提高了产品的性能,满足了市场对高效能过电压保护元件的需求。Dowosemi公司凭借这一优势,迅速在市场上确立了领先地位。

昆泰(CHRONTEL)公司的发展小趣事

1994年4月,昆泰在美国成功上市,募集资金3550万美金。这笔资金为昆泰的后续发展提供了强有力的支持。上市后,昆泰加速了其业务扩张和技术创新的步伐,进一步巩固了其在全球CRO行业的领先地位。

全智景(Allvision)公司的发展小趣事

为了进一步提升公司的竞争力,全智景公司开始实施全球化战略。公司积极拓展海外市场,与多个国家和地区的企业建立了合作关系。通过引进国外先进的技术和管理经验,全智景公司不断提升自身的综合实力。同时,公司还积极参与国际展览和交流活动,提升了品牌知名度和影响力。这一全球化战略为全智景公司带来了更广阔的发展空间和市场机遇。

Cyrix Corp公司的发展小趣事

1999年,Cyrix再次被威盛电子(VIA)收购。这次收购后,Cyrix所生产的CPU产品上开始出现了两个商标:VIA和Cyrix。这种双标现象反映了Cyrix在被收购后的地位变化。随着时间的推移,Cyrix的商标逐渐淡出市场,最终被彻底放弃。

问答坊 | AI 解惑

PROTEUS的应用

这是一本关于PROTEUS应用的教材…

查看全部问答>

关于AVR-M8使用串口中断的一些疑问。

最近在做M8的串口通讯实验,准备2个MCU之间串口通讯,使用发送和接受中断的思想来做,请问在一个多任务系统下,如何确保通讯以及别的程序不被出错。。。。谢谢!…

查看全部问答>

射频知识专题讲座

PPT格式的,射频的定义和概念,图文并茂,感觉比较详细。 …

查看全部问答>

win ce 界面控件透明

  我做的对话框有张背景,所以添上的控件需透明才好看,比如CStatic控件。   哪位有什么方法介绍?   对话框添背景图(BMP格式)哪位有什么更好的方法,我觉得我采用的不好   thanks.…

查看全部问答>

我在关闭udp 的socket时,有时会导致多个任务挂起是怎么回事?

同一个socket描述符,在两个任务里同时使用,一个负责接收,一个复杂发送. 当发送次数超时而关闭socket时,有时候会导致多个任务挂起,都处于ready状态.而关闭socket的这个任务处于ready+I状态.这种现象只是偶尔会出现,不知道为什么?各位给个答案,谢了…

查看全部问答>

调试求救!

调试遇到这个,是个什么错误啊? first-chance exceptiont in xxxx.exe 0xc0000005:access violation. 一调试运行就显示这个。…

查看全部问答>

U盘的问题!

我的STM32的开发板连到PC之后,发现新硬件,但是出现一个病毒,可能是我在单位电脑上传播到开发板的病毒,想把他格式化,但是开发板上的好像是只读的,无法格式化,大家告诉我应该怎么解决呢?…

查看全部问答>

求助这个光耦控制电路的原理

在一个电源板上见到的,请问这个电路是怎样工作的?十分感谢…

查看全部问答>

一个怪现象:flash无法采用块写模式循环写入超过256+56字节?

芯片:F449 现象:通过RAM采用块写模式向主Flash存储区0xEA00(远离代码区)写入128*8字节的数据。采用一个循环,使地址递增,但只能写入两个128B字节,写第三个的时间地址自动跳回第1个地址(0xEA00),陷入死循环。 已经注意了连续写入之间的时 ...…

查看全部问答>

tftp配置、下载和运行

一、tftp的配置:      1、用网线将开发板和电脑连接起来;      2、板子接电源启动 u-boot,三秒内按任意键进入命令行,可设置板子ip,           服务器 ip,网关等, ...…

查看全部问答>