关于can的调试

can是总线性架构,有双绞线的存在,抗干扰性极强。有非破坏性仲裁,自带纠错。

can总线没有时钟线,异步通信,需要靠位同步来约束数据收发。让接收方的采样点,永远死死咬住发送方数据位的正中心,保证不读错数据。

数据帧

RTR 作为远程发送请求位,为0时是显性电平,代表数据帧(CAN_RTR_DATA)。

为1时是隐性电平,代表遥控帧(CAN_RTR_REMOTE)。

IDE 作为标识符拓展位,为0是显性电平,代表标准帧(CAN_ID_STD)

为1是隐性电平,代表拓展帧(CAN_ID_EXT)

DLC表示数据有多少个字节

r0,r1为保留位,目前没有具体定义的用途

接收节点发送一个显性电平表示应答,随后发送七个隐性电平表示结束

can活动内核

主要负责:

can的位选取

三个要点:

关于can的邮箱机制

3个独立的发送邮箱,发送邮箱本质上是影子寄存器。总共有三组影子寄存器,每组寄存器有4个32位寄存器。位于can外设的寄存器空间,不在SRAM里,所以不能用memset,memcpy操作,只能通过HAL API或直接读写寄存器来操作。

以邮箱0为例

在外设寄存器,跟fifo相比是一个深度为3,不按照先后顺序,每格带独立状态的发送缓冲区,它存在的首要目的不是存数据,而是为了让CPU不要等待总线。

多个邮箱都待发时,先按id优先级来发,id数值小的先发。id相同时,邮箱号小的先发。

can的内部回环测试

先定义一些变量

复制代码
CAN_TxHeaderTypeDef TxHeader;       // 发送帧头
CAN_RxHeaderTypeDef RxHeader;       // 接收帧头

uint8_t  TxData[8];                 // 发送数据
uint8_t  RxData[8];                 // 接收数据
uint8_t  SentData[8];               // 发送快照(比对用)

uint32_t TxMailbox;                 // 使用的邮箱号(0~2)

/* ---------- 统计 ---------- */
uint32_t FrameCnt = 0;              // 帧序号(改 32 位,防回绕)
uint32_t PassCnt  = 0;              // 通过数
uint32_t FailCnt  = 0;              // 失败数

/* ---------- 循环变量 ---------- */
uint32_t i;                         // 收发共用的临时下标

配置滤波器和启动

复制代码
/* ============ CAN 验收滤波器 + 启动 ============ */
CAN_FilterTypeDef sFilterConfig;   // 建议改成 = {0}:该结构体有 10 个字段,
                                   // HAL 会把它们全部读入寄存器,未赋值的字段是栈上垃圾值

/* ---- 第 1 组:用哪一组滤波器(F103CB 共有 14 组,编号 0~13)---- */
sFilterConfig.FilterBank = 0;                    // 只用组 0,其余 13 组保持未激活(不参与匹配)

/* ---- 第 2 组:匹配方式 ---- */
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 掩码模式:写 "ID + 掩码",掩码位=1必须相同,=0不关心
                                                 // 另一种是 IDLIST(列表模式),逐个精确匹配

/* ---- 第 3 组:位宽 ---- */
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 32 位宽:一组 = 1 个 ID + 1 个掩码
                                                  // 16 位宽则一组能放 2 个 ID + 2 个掩码,但只能筛标准帧

/* ---- 第 4 组:ID 和掩码,全 0 = 全通 ---- */
sFilterConfig.FilterIdHigh     = 0x0000;   // 期望 ID 的高 16 位(标准帧 ID 放在 bit[31:21])
sFilterConfig.FilterIdLow      = 0x0000;   // 期望 ID 的低 16 位
sFilterConfig.FilterMaskIdHigh = 0x0000;   // 掩码高 16 位:0x0000 = 这些位"全部不关心"
sFilterConfig.FilterMaskIdLow  = 0x0000;   // 掩码低 16 位
                                          // 判据:(收到的ID & 掩码) == (期望ID & 掩码)
                                          // 掩码为 0 → 0 == 0 → 恒成立 → 任何帧都放行

/* ---- 第 5 组:放行后送哪个 FIFO ---- */
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;  // 送 FIFO0(也可以选 FIFO1,两个独立队列)

/* ---- 第 6 组:是否启用这一组 ---- */
sFilterConfig.FilterActivation = ENABLE;   // 置 FA1R 的 bit0 = 1
                                          // ⚠️ 复位默认所有组都是"关闭"状态 = 任何帧都不收

/* ---- 写入硬件 ---- */
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
    printf("ConfigFilter error\r\n");       // ⚠️ 只报告不处理,失败后程序继续往下跑
}

/* ---- 启动 CAN(退出初始化模式,允许收发)---- */
if (HAL_CAN_Start(&hcan) != HAL_OK)
{
    printf("CAN START error\r\n");          // ⚠️ 同上,失败后接着发帧,会一直 mailboxes full
}

printf("CAN init OK, filter all-pass, mode=LOOPBACK\r\n");   // 检查点 1:能打出这行说明前面都过了

组建帧头部

复制代码
 TxHeader.StdId = 0x123;
   TxHeader.ExtId = 0;
   TxHeader.IDE = CAN_ID_STD;
   TxHeader.RTR = CAN_RTR_DATA;
   TxHeader.DLC = 8;
   TxHeader.TransmitGlobalTime = DISABLE;

把数据发到邮箱

复制代码
	  for(i=0;i<8;i++)                              // 填满 8 字节数据域
	  {
		  TxData[i]=(uint8_t)(FrameCnt+i);          // 第 i 字节 = 帧号低 8 位 + i → 递增图案
	  }
	  memcpy(SentData,TxData,8);                    // 发前留快照,收回来后拿它比对

	  if(HAL_CAN_GetTxMailboxesFreeLevel(&hcan)>0)  // 先查 3 个发送邮箱有没有空的
	  {                                             // (0 = 全满,再发也是失败)
		  if(HAL_CAN_AddTxMessage(&hcan,&TxHeader,TxData,&TxMailbox)==HAL_OK)
		  {                                         // 入队成功:数据已复制进硬件寄存器
			  FrameCnt++;                           // 只有真正入队才计数
			  printf("TX: %-3u  ",FrameCnt);        // 打印帧号,十进制,左对齐
			  for(i=0;i<8;i++)
			  {
				  printf("%02x",TxData[i]);         // 8 字节十六进制,补齐两位
			  }
			  printf("\r\n");
		  }
	  }
	  else                                          // ← 这个 else 对应的是外层 if
	  {
		  printf("TX mailboxes full\r\n");          // 三个邮箱全满:总线忙 / 收不到 ACK
	  }

把数据从FIFO中取出

复制代码
	uint32_t start = HAL_GetTick();                     // 记下等待起点(ms 时间戳)
	while(HAL_CAN_GetRxFifoFillLevel(&hcan,CAN_RX_FIFO0) == 0)   // FIFO0 里 0 帧就继续轮询
	{
		if (HAL_GetTick() - start > 20) break;          // 超过 20ms 放弃,防止卡死
	}

	if (HAL_CAN_GetRxFifoFillLevel(&hcan, CAN_RX_FIFO0) > 0)     // 再确认一次:真有帧才往下走
    {
        HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxHeader, RxData);  // 出队,FMP 自动 −1

        if (RxHeader.StdId == 0x123 &&                  // ① ID 对不对
            RxHeader.DLC   == 8     &&                  // ② 长度对不对(防 memcmp 越界)
            memcmp(SentData, RxData, 8) == 0)           // ③ 8 字节逐字节相同
        {
            PassCnt++;                                  // 通过计数
            printf("RX     ID=0x%03X DLC=%d ", RxHeader.StdId, RxHeader.DLC);
            for (i = 0; i < 8; i++) printf("%02X ", RxData[i]);   // 8 字节,大写,带空格
            printf("PASS\r\n");
        }
        else                                            // 收到帧,但 ID/长度/内容有一项不符
        {
            FailCnt++;                                  // 失败计数
            printf("RX     ID=0x%03X DLC=%d ", RxHeader.StdId, RxHeader.DLC);
            for (i = 0; i < 8; i++) printf("%02X ", RxData[i]);
            printf("FAIL\r\n");
        }
    }

数据先发到邮箱,硬件等待总线空闲,由can内核进行组帧同时回环给接收端,CRC校验,经由滤波器检查对照id,发到fifo中,等待数据被取走

遇到一个问题

程序烧录进去串口助手收不到信息,之前的程序可以

通过debug找到原因,断点卡在main入口处。芯片里存在一个硬件断点,位置在main的第一条指令,CPU一进入main就停住,根本没有运行。

解决办法,断电清除断点,下一次运行不要勾选run to main,这个选项会给main入口处打上断点

相关推荐
2501_9226395840 分钟前
率能半导体 SS6812T双通道H桥驱动芯片:32V/1.0A,覆盖POS打印机、安防相机、办公自动化、游戏机、机器人五大应用场景
单片机·嵌入式硬件·硬件工程
女神下凡1 小时前
芯参谋(77):裸机(无 OS)存储驱动开发指南
arm开发·单片机·嵌入式硬件·设计规范·1024程序员节
weixin_464078071 小时前
反激原副边之间的Y电容
单片机·嵌入式硬件
超级架构师1 小时前
让 COBOL 长出 AI 大脑:原生 Agent 核心框架 praxo-core 深度剖析
c语言·开发语言·c++·人工智能·python·架构·ai编程
·present·1 小时前
CSAPP(lecture 10)
c语言·c++
Zw-awa2 小时前
串口:一条调试信息是怎么从芯片出来的
stm32
女神下凡2 小时前
芯参谋(76):电源监控复位芯片电路设计指南
arm开发·单片机·嵌入式硬件·fpga开发·设计规范
Tel199253080042 小时前
旋转变压器型编码器转多种绝对值协议 旋变转SSI/BISS-C/ENDAT2.2 RS422RTU协议+增量 转换器
单片机·自动化·工业自动化·仪器仪表·工控设备
国科安芯2 小时前
LEO卫星里的IO脉冲事件通信,毛刺误触发解析及处理方案
单片机·嵌入式硬件·fpga开发·低轨卫星·商业航天·抗辐射