[研电赛技术支持] GD32F103C8T6入门教程-CAN外设回环测试

[复制链接]
2178|21
 楼主| kqh11a 发表于 2022-11-18 15:47 | 显示全部楼层 |阅读模式
基础知识

相关stm32CAN外设
外设特征:

3个发送邮箱
2个深度为3个邮箱的接收FIFO
自动重传
自动唤醒
发送、接收时间戳
最大速率1Mbps
3种工作模式

睡眠模式:可以检车总线状态自动唤醒
初始化工作模式:如果需要对 CAN 总线通信参数调整, CAN 必须进入初始化工作模式
正常工作模式:
4中通讯模式:

静默通讯模式
回环通讯模式:发送的数据又可以被自己接收,同时这些发送数据也送至 CAN 网络
静默回环模式:CAN 总线控制器既不从CAN 网络接收数据,也不向 CAN 网络发送数据
正常模式:

评论

———————————————— 版权声明:本文为CSDN博主「Car12」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/u010261063/article/details/124251643  发表于 2022-11-18 15:47
 楼主| kqh11a 发表于 2022-11-18 15:48 | 显示全部楼层
数据发送:

选择一个空闲邮箱
配置发送寄存器
使能发送
检测发送转态和错误标志
数据接收

查看FIFO中的帧数量

通过2个深度为3个个邮箱的FIFO接收数据,读取数据

释放邮箱
 楼主| kqh11a 发表于 2022-11-18 15:49 | 显示全部楼层
4个中断向量

发送中断{3个邮箱空闲中断}
fifo0中断{FIFO有数据,数据满,数据溢出}
FIFO1中断
错误和状态改变中断{错误,唤醒,进入睡眠}
CAN外设挂载在APB1 ,APB1 最大时钟54MHz
 楼主| kqh11a 发表于 2022-11-18 15:50 | 显示全部楼层
过滤器

掩码模式和列表模式
16位或32位
1850863773949da21f.png
 楼主| kqh11a 发表于 2022-11-18 15:51 | 显示全部楼层
例程:CAN回环模式下的数据发送接收测试

CAN设置必须使能过滤器,关闭过滤器接收数据失败
 楼主| kqh11a 发表于 2022-11-18 15:52 | 显示全部楼层
CAN外设的基本初始化
  1. /*
  2.         can 外设基本初始化
  3. */
  4. void can_loopback_init(void)
  5. {
  6.     can_parameter_struct        can_parameter;
  7.     can_filter_parameter_struct can_filter;
  8.     //使能外设时钟
  9.     rcu_periph_clock_enable(RCU_CAN0);
  10.     can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
  11.     can_struct_para_init(CAN_FILTER_STRUCT, &can_filter);

  12.     /* 复位CAN外设 */
  13.     can_deinit(CANX);

  14.     /* initialize CAN */
  15.     can_parameter.time_triggered = DISABLE;//时间触发
  16.     can_parameter.auto_bus_off_recovery = DISABLE;//自动离线
  17.     can_parameter.auto_wake_up = DISABLE;//自动唤醒
  18.     can_parameter.no_auto_retrans = DISABLE;//自动重发
  19.     can_parameter.rec_fifo_overwrite = DISABLE;//禁用FIFO满覆盖
  20.     can_parameter.trans_fifo_order = DISABLE;//标识符小的先发送,发送优先级
  21.     can_parameter.working_mode = CAN_LOOPBACK_MODE;//工作模式,回环模式
  22.     /* 配置波特率为 125kbps   CAN外设的时钟是在APB1=54MHz,125K = 54Mhz/48(分频)/(1+5+3)*/
  23.     can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;//固定一个TQ
  24.     can_parameter.time_segment_1 = CAN_BT_BS1_5TQ;//1-16个TQ
  25.     can_parameter.time_segment_2 = CAN_BT_BS2_3TQ;//可选1-8个TQ
  26.     can_parameter.prescaler = 48;
  27.     can_init(CANX, &can_parameter);

  28.     /* initialize filter */
  29.     #ifdef  CAN0_USED
  30.     /* CAN0 filter number */
  31.     can_filter.filter_number = 0;
  32.     #else
  33.     /* CAN1 filter number  过滤器数量*/
  34.     can_filter.filter_number = 15;
  35.     #endif
  36.     /* initialize filter */
  37.     can_filter.filter_mode = CAN_FILTERMODE_MASK;//掩码模式
  38.     can_filter.filter_bits = CAN_FILTERBITS_32BIT;
  39.     can_filter.filter_list_high = 0x0000;
  40.     can_filter.filter_list_low = 0x0000;
  41.     can_filter.filter_mask_high = 0x0000;
  42.     can_filter.filter_mask_low = 0x0000;
  43.     can_filter.filter_fifo_number = CAN_FIFO1;//过滤器关联的FIFO
  44.     can_filter.filter_enable = ENABLE;
  45.     can_filter_init(&can_filter);
  46. }

 楼主| kqh11a 发表于 2022-11-18 15:52 | 显示全部楼层
轮训模式下的数据发送接收测试函数

  1. /*
  2.         轮训模式下CAN数据发送和接收测试,使用CAN的回环模式
  3. */
  4. ErrStatus can_loopback(void)
  5. {
  6.     can_trasnmit_message_struct transmit_message;
  7.     can_receive_message_struct  receive_message;
  8.     uint32_t timeout = 0xFFFF;
  9.     uint8_t transmit_mailbox = 0;
  10.     /* 初始化 CAN */
  11.     can_loopback_init();

  12.     /* initialize transmit message 初始化发送消息结构 */
  13.     can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &transmit_message);
  14.     transmit_message.tx_sfid = 0x11;//标准帧ID
  15.     transmit_message.tx_ft = CAN_FT_DATA;//数据帧
  16.     transmit_message.tx_ff = CAN_FF_STANDARD;//标准帧
  17.     transmit_message.tx_dlen = 2;//数据长度
  18.     transmit_message.tx_data[0] = 0xAB;//数据adcd
  19.     transmit_message.tx_data[1] = 0xCD;

  20.     /* initialize receive message初始化发送消息结构 */
  21.     can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &receive_message);

  22.     /* transmit message 发送消息 返回邮箱编号*/
  23.     transmit_mailbox = can_message_transmit(CANX, &transmit_message);

  24.     /* waiting for transmit completed 等待消息发送完成*/
  25.     while((CAN_TRANSMIT_OK != can_transmit_states(CANX, transmit_mailbox)) && (0 != timeout))
  26.     {
  27.         timeout--;
  28.     }

  29.     timeout = 0xFFFF;

  30.     /* waiting for receive completed 等待接收完成*/
  31.     while((can_receive_message_length_get(CANX, CAN_FIFO1) < 1) && (0 != timeout))
  32.     {
  33.         timeout--;
  34.     }

  35.     /* initialize receive message 初始化接收结构体*/
  36.     receive_message.rx_sfid = 0x00;
  37.     receive_message.rx_ff = 0;
  38.     receive_message.rx_dlen = 0;
  39.     receive_message.rx_data[0] = 0x00;
  40.     receive_message.rx_data[1] = 0x00;
  41.     //接收数据
  42.     can_message_receive(CANX, CAN_FIFO1, &receive_message);
  43.     printf("recv:%02x %02x", (int)receive_message.rx_data[0], (int)receive_message.rx_data[1]);

  44.     /* check the receive message */
  45.     if((0x11 == receive_message.rx_sfid) && (CAN_FF_STANDARD == receive_message.rx_ff)
  46.             && (2 == receive_message.rx_dlen) && (0xCDAB == (receive_message.rx_data[1] << 8 | receive_message.rx_data[0])))
  47.     {

  48.         printf("data send recv ok\r\n");
  49.         return SUCCESS;
  50.     }
  51.     else
  52.     {
  53.         printf("data send recv error\r\n");
  54.         return ERROR;
  55.     }
  56. }
 楼主| kqh11a 发表于 2022-11-18 15:53 | 显示全部楼层
中断模式下的数据接收测试
  1. //中断模式下接收数据
  2. ErrStatus can_loopback_interrupt(void)
  3. {
  4.     can_trasnmit_message_struct transmit_message;
  5.     uint32_t timeout = 0x0000FFFF;

  6.     /* initialize CAN and filter 初始化CAN外设和CAN过滤器 */

  7.     can_loopback_init();

  8.     /* enable CAN receive FIFO1 not empty interrupt  打开CAN中断*/
  9.     nvic_irq_enable(CAN0_RX1_IRQn, 0, 0);
  10.     can_interrupt_enable(CANX, CAN_INT_RFNE1);

  11.     /* initialize transmit message */
  12.     transmit_message.tx_sfid = 0;
  13.     transmit_message.tx_efid = 0x1234; //扩展ID
  14.     transmit_message.tx_ff = CAN_FF_EXTENDED;//扩展帧
  15.     transmit_message.tx_ft = CAN_FT_DATA;//数据帧
  16.     transmit_message.tx_dlen = 2;//数据长度
  17.     transmit_message.tx_data[0] = 0xDE;//数据ABCD
  18.     transmit_message.tx_data[1] = 0xCA;
  19.     /* 发送数据*/
  20.     can_message_transmit(CANX, &transmit_message);

  21.     /* 等待中断*/
  22.     while((SUCCESS != test_flag_interrupt) && (0 != timeout))
  23.     {
  24.         timeout--;
  25.     }

  26.     if(0 == timeout)
  27.     {
  28.         test_flag_interrupt = ERROR;
  29.     }

  30.     /* disable CAN receive FIFO1 not empty interrupt 关闭CAN设备的FIFO1接收非空中断  */
  31.     can_interrupt_disable(CANX, CAN_INTEN_RFNEIE1);

  32.     return test_flag_interrupt;
  33. }


 楼主| kqh11a 发表于 2022-11-18 16:36 | 显示全部楼层
CAN外设的中断服务函数
  1. //can0 外设中断服务函数
  2. void CAN0_RX1_IRQHandler(void)
  3. {
  4.     can_receive_message_struct receive_message;
  5.     /* 初始化消息结构体 */
  6.     receive_message.rx_sfid = 0x00;
  7.     receive_message.rx_efid = 0x00;
  8.     receive_message.rx_ff = 0;
  9.     receive_message.rx_dlen = 0;
  10.     receive_message.rx_fi = 0;
  11.     receive_message.rx_data[0] = 0x00;
  12.     receive_message.rx_data[1] = 0x00;

  13.     /* 从FIFO1接收消息 */
  14.     can_message_receive(CAN0, CAN_FIFO1, &receive_message);

  15.     //判断消息是否和发送一致
  16.     if((0x1234 == receive_message.rx_efid) && (CAN_FF_EXTENDED == receive_message.rx_ff)
  17.             && (2 == receive_message.rx_dlen) && (0xCADE == (receive_message.rx_data[1] << 8 | receive_message.rx_data[0])))
  18.     {
  19.         test_flag_interrupt = SUCCESS;
  20.     }
  21.     else
  22.     {
  23.         test_flag_interrupt = ERROR;
  24.     }
  25. }
 楼主| kqh11a 发表于 2022-11-18 16:38 | 显示全部楼层
例程测试函数
  1. /*
  2. CAN外设测试函数
  3. */
  4. void can_test(void)
  5. {
  6.     //回环模式下的轮训方式接收数据
  7.     test_flag = can_loopback();

  8.     if(SUCCESS == test_flag)
  9.     {

  10.         printf("ok\r\n");
  11.     }
  12.     else
  13.     {

  14.         printf("fail\r\n");
  15.     }

  16.     //中断模式下接收数据
  17.     test_flag_interrupt = can_loopback_interrupt();

  18.     if(SUCCESS == test_flag_interrupt)
  19.     {
  20.         printf("ok\r\n");
  21.     }
  22.     else
  23.     {
  24.         printf("fail\r\n");
  25.     }

  26.     while (1);
  27. }


 楼主| kqh11a 发表于 2022-11-18 16:48 | 显示全部楼层
测试截图

68487637746e317989.png
chenqianqian 发表于 2022-11-19 10:45 来自手机 | 显示全部楼层
CAN的回环测试还是很有用的
daichaodai 发表于 2022-11-19 17:44 来自手机 | 显示全部楼层
回环测试,在自检时比较实用。
tpgf 发表于 2022-12-7 16:05 | 显示全部楼层
CAN外设回环测试成功了 为什么连接另一端就不成功了呢
heimaojingzhang 发表于 2022-12-7 16:27 | 显示全部楼层
在can外设回环测试模式下 如何验证我的过滤参数设置是否正确呢
keaibukelian 发表于 2022-12-7 16:36 | 显示全部楼层
回环模式没有问题 但是正常模式不成功 一般都是什么原因导致的呢
weifeng90 发表于 2022-12-7 17:46 来自手机 | 显示全部楼层
CAN回环模式可以用作系统上电自检。
paotangsan 发表于 2022-12-8 08:58 | 显示全部楼层
keaibukelian 发表于 2022-12-7 16:36
回环模式没有问题 但是正常模式不成功 一般都是什么原因导致的呢

首先肯定需要检查寄存器配置  另外外部硬件连接看看有没有接错
renzheshengui 发表于 2022-12-8 09:32 | 显示全部楼层
检查一下线路上的波形是否良好  先确保外部的条件都完全满足
wakayi 发表于 2022-12-8 10:48 | 显示全部楼层
请问3个邮箱的接收FIFO的使用顺序是如何定义的呢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

554

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部