STM32F103ZET6 KEIL5工程:CAN控制器内部回环测试例程(免硬件收发器)

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:这个KEIL5工程专为STM32F103ZET6芯片设计,实现CAN控制器纯软件回环通信验证——不依赖外部CAN收发器或第二块板子,直接在芯片内部完成发送与接收闭环。工程采用标准外设库结构,SYSTEM目录负责系统初始化和毫秒级延时,HARDWARE目录下封装了CAN初始化、发送、接收及状态查询函数,同时集成USART串口打印用于实时观察帧收发结果,LCD和KEY模块保留接口便于后续功能扩展。代码包含main.c主流程调度、can.c核心驱动逻辑、delay.c高精度延时、sys.c系统配置,以及标准启动文件startup_stm32f10x_hd.s和链接脚本。配套readme.txt说明编译步骤与调试要点,Objects和Listings目录自动生成编译中间文件,.uvprojx和.uvguix.admin支持KEIL5一键打开即用。所有源码已通过完整编译,输出可执行的.axf、.hex和.htm调试信息文件,还提供stm32_simulator.py脚本辅助仿真验证。适合嵌入式初学者快速掌握CAN寄存器配置、中断处理流程和回环模式调试方法,也适用于MCU外设功能自检与实时通信基础验证。

1. 项目概述:为什么CAN回环测试是嵌入式工程师的“必修课”

刚接触STM32 CAN外设的朋友,十有八九会在第一步卡住:接好硬件,烧进程序,串口却始终没打印出“接收成功”——到底是线没接对?收发器坏了?还是CAN波特率算错了?我带过不少应届生做毕业设计,他们花三天排查物理层问题,最后发现只是把CAN_RX和CAN_TX引脚焊反了。这种低级错误背后,其实是缺乏一个“隔离变量”的调试起点。而CAN控制器内部回环(Loopback Mode)就是这个起点:它把发送出去的数据帧,不经过物理总线、不经过收发器芯片、不依赖任何外部硬件,直接在CAN控制器内部打个弯,原封不动送回接收FIFO。你看到的“收到一帧”,不是从另一块板子发来的,而是自己刚发出去的“影子”。这就像给CAN外设装了个单向玻璃——你能清楚看见它内部每个寄存器怎么被写入、状态位如何翻转、中断何时触发,而完全不用操心外部线路是否可靠。

这个工程专为STM32F103ZET6打造,核心价值就四个字:免硬件验证。关键词里反复出现的“STM32 CAN回环”“KEIL5工程”“CAN驱动例程”,说的正是这件事——它不是一个炫技的完整通信系统,而是一把精准的手术刀,专门用来解剖CAN控制器的工作机理。你不需要买TJA1050收发器,不需要准备两块开发板,甚至不需要焊接一根杜邦线。只要一块带SWD接口的STM32F103ZET6最小系统板(比如正点原子或野火的战舰/指南者),用ST-Link连上KEIL5,点一下编译下载,就能立刻看到串口输出“TX OK → RX OK → ID:0x123, Data:01 02 03 04…”这样的实时日志。它把抽象的CAN协议栈,压缩成可触摸、可打断点、可逐行观察的C代码。SYSTEM目录下的delay.c提供微秒级延时,这是配置CAN波特率时计算BS1/BS2分频系数的基础;HARDWARE/can.c里每一行寄存器操作,都对应着参考手册第22章CAN控制器的状态机图;而USART串口打印,则是你与芯片之间的翻译官,把二进制的CAN帧ID、DLC、数据域,转化成人类能读懂的十六进制字符串。这不是一个拿来即用的产品级工程,而是一个“可拆解的教具”——所有模块边界清晰,所有函数职责单一,所有配置项都有注释说明计算依据。哪怕你是第一次听说“同步段”“传播段”这些术语,也能通过修改can.c里的CAN_BTR寄存器值,亲眼看到波特率变化如何影响接收成功率。它解决的不是“怎么让两台设备通信”,而是“怎么确认我的CAN外设真的活了”。

2. 整体架构与设计思路:为什么选择标准外设库而非HAL

拿到这个工程,第一眼看到的是熟悉的目录结构:SYSTEM、HARDWARE、CORE、USER。这种组织方式不是为了好看,而是源于十多年嵌入式开发中踩出的一条血路。很多新手一上来就奔着HAL库去,觉得“高级封装=省事”,结果调试时一头雾水——某个CAN接收中断没触发,翻遍HAL_CAN_Receive_IT()源码,发现它底层调用了__HAL_CAN_ENABLE_IT(),而这个宏又展开成一堆位操作,中间还夹着__HAL_CAN_GET_FLAG()的状态轮询。当问题出现在硬件初始化阶段时,你根本不知道该在HAL_CAN_Init()里打断点,还是在HAL_CAN_MspInit()里查GPIO配置。而标准外设库(SPL)不同,它像一本摊开的说明书:CAN_DeInit()就是把CAN寄存器全清零,CAN_Init()就是按顺序往CAN_BTR、CAN_MCR等寄存器里填数值,CAN_Transmit()就是往发送邮箱写数据再置位请求位。没有中间商赚差价,没有抽象层遮蔽细节。这个工程坚持用SPL,核心考量就三点:可追溯性、可教学性、可移植性。

先说可追溯性。当你在KEIL5里按F12跳转到CAN_Init()函数,看到的是实实在在的寄存器地址操作:

CAN->MCR &= ~CAN_MCR_SLEEP;   // 退出睡眠模式
CAN->MCR |= CAN_MCR_INRQ;     // 请求初始化
while((CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK); // 等待初始化确认
CAN->BTR = (uint32_t)(CAN_BTR_SJW | CAN_BTR_TS2 | CAN_BTR_TS1 | CAN_BTR_BRP);

每一行都能在《STM32F103xx参考手册》第22.5节找到对应描述。而HAL库里类似的逻辑被封装在几十层函数调用之下,初学者容易迷失在API海洋里。再说可教学性。这个工程的can.c文件只有不到300行,但涵盖了CAN控制器初始化、发送、接收、状态查询四大核心功能。其中初始化部分,重点处理了三个关键寄存器:MCR(主控制寄存器)、BTR(位定时寄存器)、IER(中断使能寄存器)。MCR的CAN_MCR_LOOPBACK位必须置1才能开启回环模式,这是整个工程的基石;BTR的配置则直接决定波特率精度,我们采用经典的8MHz晶振+500kbps方案,计算过程如下:目标波特率500kbps,CAN时钟频率为APB1总线频率(通常为36MHz),时间量子数TQ = 1 / (波特率 × TQ) = 1 / (500000 × 20ns) = 100。根据公式TQ = (TS1 + 1) + (TS2 + 1) + 1,取TS1=5、TS2=2,则BS1=5、BS2=2,剩余分频系数BRP = (36MHz / 500kbps) / 100 - 1 = 7。最终BTR值为0x001C0007。这些计算细节全部写在can.c的注释里,而不是藏在HAL库的magic number里。最后是可移植性。SPL的寄存器定义与芯片手册严格对齐,当你需要把这套回环测试迁移到STM32F4系列时,只需替换启动文件和链接脚本,CAN初始化逻辑几乎不用改——因为F4的CAN控制器寄存器布局与F1高度兼容。而HAL库的移植往往意味着重写整个外设初始化流程。所以,这个工程没选HAL,不是因为它落后,而是因为它更“透明”。它强迫你直面硬件本质,而这恰恰是嵌入式工程师的核心竞争力。

3. 核心细节解析:回环模式下的寄存器配置与状态机流转

CAN控制器的内部回环模式,本质上是对硬件状态机的一次精准操控。它不像普通通信那样经历“发送→总线传输→接收”的物理路径,而是将发送邮箱(TxMailbox)与接收FIFO(RxMailbox)在逻辑上短接。要理解这个过程,必须拆解三个关键寄存器的操作序列:MCR、MSR和TSR。很多人以为只要设置CAN_MCR_LOOPBACK=1就万事大吉,结果发现接收中断死活不触发——问题往往出在状态机没有进入正确的运行阶段。

首先看MCR(主控制寄存器)。它的bit0(INRQ)是初始化请求位,bit1(SLEEP)是睡眠模式位,bit7(LOOPBACK)是回环使能位。正确配置顺序必须是:先清SLEEP位退出睡眠,再置INRQ位请求初始化,等待MSR寄存器的INAK位(初始化确认位)变为1,此时CAN控制器才真正进入初始化模式;接着配置BTR寄存器设定波特率;最后清除INRQ位并置LOOPBACK位,同时确保CAN_MCR_ABOM(自动离线管理)和CAN_MCR_AWUM(自动唤醒)为0,避免意外状态切换。这个顺序不能颠倒,否则MSR会一直卡在CAN_MSR_INAK=0,导致后续配置无效。我在调试初期就栽在这里:把LOOPBACK位和INRQ位同时置1,结果CAN控制器永远停在初始化模式,接收FIFO永远空。

然后是MSR(主状态寄存器)。它像一面镜子,实时反映CAN控制器的健康状况。回环测试中最关键的两个位是CAN_MSR_INAK(初始化确认)和CAN_MSR_SLAK(睡眠确认)。前者为1表示已进入初始化模式,后者为1表示处于睡眠模式。正常回环运行时,CAN_MSR_INAK必须为0(非初始化),CAN_MSR_SLAK必须为0(非睡眠),且CAN_MSR_RX(接收状态)应周期性闪烁。如果串口始终打印“RX FIFO Empty”,首先要检查MSR——很可能CAN_MSR_INAK还是1,说明初始化流程没走完。

最后是TSR(发送状态寄存器)。它揭示了发送动作的微观过程。当调用CAN_Transmit()后,TSR的bit23(TME0)会从1变为0,表示邮箱0已被占用;bit22(LOW0)变为1,表示邮箱0处于低优先级;bit19(TXOK0)在发送完成后变为1,表示发送成功。但在回环模式下,“发送完成”和“接收成功”几乎是同时发生的。我们通过轮询TSR的TXOK0位来确认发送结束,紧接着立即读取RF0R(接收FIFO0寄存器)的FMP0位(FIFO消息挂起数)。FMP0的值范围是0~3,当它从0变为1时,就证明回环数据已进入接收FIFO。这个“发送-确认-接收”的三步闭环,就是整个测试的灵魂。工程中在main.c里实现了严格的时序控制:

// 发送一帧标准帧
TxMessage.StdId = 0x123;
TxMessage.ExtId = 0x00;
TxMessage.RTR = CAN_RTR_DATA;
TxMessage.IDE = CAN_ID_STD;
TxMessage.DLC = 4;
TxMessage.Data[0] = 0x01; TxMessage.Data[1] = 0x02;
TxMessage.Data[2] = 0x03; TxMessage.Data[3] = 0x04;
TxMailbox = CAN_Transmit(&CAN_InitStructure, &TxMessage);

// 等待发送完成(超时保护)
timeout = 0;
while((CAN_TransmitStatus(&CAN_InitStructure, TxMailbox) == CAN_TxStatus_Failed) && timeout++ < 0xFFFF) {
    delay_us(1);
}
if(timeout >= 0xFFFF) printf("TX Timeout!\r\n");

// 立即检查接收FIFO
if(CAN_MessagePending(&CAN_InitStructure, CAN_FIFO0) > 0) {
    CAN_Receive(&CAN_InitStructure, CAN_FIFO0, &RxMessage);
    printf("RX OK! ID:0x%03X, Data:%02X %02X %02X %02X\r\n", 
           RxMessage.StdId, RxMessage.Data[0], RxMessage.Data[1], 
           RxMessage.Data[2], RxMessage.Data[3]);
} else {
    printf("RX FIFO Empty!\r\n");
}

这段代码看似简单,实则暗含玄机。CAN_TransmitStatus()返回CAN_TxStatus_Failed时,可能是因为邮箱被抢占,也可能是因为控制器未就绪;而CAN_MessagePending()的返回值大于0,才是接收成功的铁证。很多初学者习惯用CAN_GetITStatus()配合中断,但在纯轮询模式下,必须依赖这些状态寄存器的原始值。这就是为什么工程坚持用SPL——它让你亲手触摸每一个比特的变化,而不是依赖HAL库里封装好的“黑盒”函数。

4. 实操过程与核心环节实现:从KEIL5工程打开到串口日志验证

拿到这个工程压缩包,解压后你会看到典型的KEIL5项目结构。双击.uvprojx文件,KEIL5会自动加载所有源文件、头文件路径、宏定义和链接脚本。但别急着编译,先做三件关键的事:确认芯片型号、检查时钟配置、验证串口引脚映射。这是所有后续步骤的基石,跳过它们等于在流沙上盖楼。

第一步:确认Target配置。点击Project → Options for Target,在Device选项卡里,确保选择的是“STM32F103ZE”——注意是“ZE”后缀,不是“CB”或“C8”。ZET6芯片拥有512KB Flash和64KB RAM,其CAN控制器位于APB1总线上,时钟源来自APB1预分频器。如果误选成F103C8,KEIL会加载错误的启动文件,导致CAN时钟频率计算偏差,波特率必然不准。在Clock选项卡里,检查System Clock设置是否为72MHz(这是F103ZET6的典型主频),并确认APB1 Prescaler为2,这样APB1总线频率就是36MHz,与can.c里BTR寄存器的计算基准完全匹配。

第二步:检查头文件包含路径。在C/C++选项卡的Include Paths里,应该有四条关键路径:

.\SYSTEM\sys
.\SYSTEM\delay
.\SYSTEM\usart
.\HARDWARE\can

这些路径指向对应的.h文件。特别注意stm32f10x_conf.h这个配置文件,它决定了哪些外设驱动会被编译进工程。打开它,确认#define USE_STDPERIPH_DRIVER已启用,且#define STM32F10X_HD被取消注释(HD代表High Density,对应ZET6的大容量Flash)。如果这里配置错误,编译时会出现undefined reference to 'CAN_Init'之类的链接错误。

第三步:验证USART1引脚映射。这个工程默认使用USART1,TX引脚为PA9,RX引脚为PA10。打开usart.c,检查GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE)是否被调用。对于F103ZET6,USART1的默认引脚确实是PA9/PA10,无需重映射。但如果开发板把PA9复用给了其他功能(比如USB的DP),就必须在sys.c的Sys_Init()函数里禁用相关外设时钟,避免资源冲突。

做完这三项检查,就可以点击Build按钮编译了。正常情况下,Output窗口会显示“0 Error(s), 0 Warning(s)”,生成templete.axf(调试文件)、templete.hex(烧录文件)和templete.htm(符号表)。此时用ST-Link Utility或KEIL自带的Flash Downloader,将hex文件烧录到芯片。烧录完成后,打开串口调试助手(如XCOM或SSCOM),设置波特率为115200,8N1,你应该立即看到类似这样的输出:

CAN Loopback Test Start...
TX OK!
RX OK! ID:0x123, Data:01 02 03 04
TX OK!
RX OK! ID:0x123, Data:05 06 07 08
...

如果串口一片空白,不要慌,按以下顺序排查:
1. 检查ST-Link连接:设备管理器里是否有“STMicroelectronics ST-LINK USB Device”?没有的话重插ST-Link或更新驱动。
2. 确认串口线连接:PA9(TX)必须接到USB转串口模块的RX引脚,PA10(RX)接到TX引脚,GND共地。接反会导致无法发送。
3. 测量PA9电平:用万用表测PA9对地电压,空闲时应为3.3V(高电平),发送数据时应有脉冲波动。如果一直是0V,说明USART1时钟没开启或GPIO配置错误。
4. 检查CAN引脚:虽然回环模式不依赖物理总线,但CAN_RX(PA11)和CAN_TX(PA12)仍需正确配置为复用推挽输出。打开can.c的CAN_GPIO_Config()函数,确认GPIO_Mode_AF_PP和GPIO_Speed_50MHz设置无误。

一旦串口开始稳定输出,恭喜你,已经跨过了最硬的门槛。接下来可以深入验证更多场景:比如修改can.c里的CAN_BTR值,把0x001C0007改成0x001C000F(BRP=15),观察波特率降到250kbps后,接收成功率是否下降;或者在main.c的循环里加入CAN_ITConfig(CAN_IT_TME, ENABLE)开启发送中断,把轮询改成中断驱动,体验不同的编程范式。这个工程的价值,正在于它提供了这样一个安全、可控、可逆的实验场——所有改动都在软件层面,不会烧毁任何硬件,也不会引发总线冲突。

5. 常见问题与排查技巧实录:那些官方文档不会告诉你的坑

在实际教学和项目支持中,我整理了一份高频问题清单,这些问题大多不会出现在ST官方参考手册里,却是新手在KEIL5环境下跑通CAN回环时最常踩的“隐形地雷”。它们有些源于开发环境的细微差异,有些来自芯片手册的模糊表述,更多的是多年调试经验沉淀下来的直觉判断。

5.1 问题:串口输出“TX OK!”但始终不打印“RX OK!”,接收FIFO一直为空

现象描述:发送函数返回成功,TSR寄存器显示TXOK0=1,但CAN_MessagePending()始终返回0,RF0R的FMP0位恒为0。
根本原因:CAN控制器未真正退出初始化模式。MSR寄存器的CAN_MSR_INAK位仍为1,导致接收FIFO被锁定。
排查步骤:
1. 在KEIL5调试模式下,打开Peripherals → CAN → CAN1,观察MSR寄存器值。如果INAK=1,说明初始化流程卡住了。
2. 检查can.c中的CAN_Init()函数,确认在配置完BTR后,是否执行了CAN->MCR &= ~CAN_MCR_INRQ;(清除INRQ位)。常见错误是漏掉这行,或者把它写在了配置BTR之前。
3. 添加临时调试代码:在CAN_Init()末尾插入while(CAN->MSR & CAN_MSR_INAK);,强制等待初始化完成。如果程序卡在这里,证明前面的配置有误。

5.2 问题:串口输出乱码,或只显示部分字符(如“CAN Loopba…”后截断)

现象描述:预期输出“CAN Loopback Test Start…”,实际只看到前几个字符,后续内容缺失或变成乱码。
根本原因:USART时钟配置错误,导致波特率严重偏离115200。F103ZET6的USART1时钟源是APB2总线,而APB2频率由RCC_CFGR寄存器的PPRE2位决定。如果误将PPRE2设为2分频,APB2频率会变成72MHz/2=36MHz,此时USARTDIV计算值错误,实际波特率可能只有57600。
解决方案:
1. 打开sys.c,检查RCC_Configuration()函数中RCC_PCLK2Config(RCC_HCLK_Div1)是否被调用(即APB2不分频)。
2. 在usart.c的USART_Init()调用前,用示波器测PA9引脚,发送一个固定字符(如’U’),测量起始位到下一个起始位的时间间隔。115200bps对应周期≈8.68μs,如果实测为17.36μs,基本确定是APB2被2分频了。

5.3 问题:工程在KEIL5 v5.38上编译报错“undefined symbol CAN_Init”,但在v5.23上正常

现象描述:同样的源码,在不同版本KEIL5中编译结果迥异。
根本原因:KEIL5从v5.30开始,默认启用了ARM Compiler 6(AC6),而标准外设库是为ARM Compiler 5(AC5)编写的。AC6的链接器对符号解析更严格,会拒绝链接未声明的函数。
解决方案:
1. Project → Options for Target → Target选项卡,将ARM Compiler版本改为“Use default compiler version 5”。
2. 或者,在C/C++选项卡的Define框中,添加__USE_STDPERIPH_DRIVER宏定义,确保stm32f10x_conf.h正确包含CAN驱动头文件。

5.4 问题:使用stm32_simulator.py脚本仿真时,CAN接收中断不触发

现象描述:Python脚本能模拟发送,但KEIL5的调试窗口看不到中断服务函数(CAN1_RX0_IRQHandler)被执行。
根本原因:仿真脚本与真实硬件的中断触发机制不同。真实芯片中,回环数据写入接收FIFO会自动置位RF0R的FULL位,并触发中断;而仿真脚本只是修改内存中的RF0R值,并未模拟NVIC中断控制器的行为。
绕过方法:
1. 在can.c中,将接收逻辑从中断模式改为轮询模式(即注释掉CAN_ITConfig(CAN_IT_FMP0, ENABLE),改用while(CAN_MessagePending() > 0)循环检测)。
2. 这样仿真脚本只需保证RF0R的FMP0位被正确修改,就能被主循环捕获。

5.5 问题:修改波特率后,接收成功率大幅下降,偶尔出现“RX OK!”但数据错乱

现象描述:将BTR从0x001C0007(500kbps)改为0x001C0003(1Mbps)后,约30%的帧接收失败或数据校验错误。
根本原因:波特率过高时,采样点偏移超出容限。CAN协议要求采样点落在TQ的87.5%位置附近,而F103的CAN控制器在1Mbps下,TS1+TS2的组合难以精确满足。
优化方案:
1. 重新计算BTR:保持BRP=3,取TS1=3、TS2=1,则TQ=3+1+1=5,采样点位置=(TS1+1)/TQ=4/5=80%,接近理想值87.5%。BTR值为0x000C0003。
2. 在can.c中增加CAN->MCR |= CAN_MCR_NART;(禁止自动重传),避免因采样错误导致的无限重发,掩盖真实问题。

提示:所有这些问题的根源,都指向同一个原则——CAN通信的本质是时序艺术,而非逻辑编程。每一个寄存器位的设置,都是在跟纳秒级的时间赛跑。这个工程的价值,不在于它能跑通,而在于它逼你直面这些微妙的时序关系,直到你能在脑中画出完整的位定时波形图。

6. 工程扩展与进阶实践:从回环测试到真实总线通信

当CAN回环测试稳定运行后,下一步自然是从“自说自话”走向“真实对话”。这个工程预留了极佳的扩展接口,所有硬件抽象都已做好,你只需替换几个关键模块,就能无缝接入物理总线。但切记:扩展不是简单地拔掉回环开关,而是要系统性地补全通信链路的每一个环节。

6.1 物理层接入:从回环到真实CAN总线

回环模式关闭只需一行代码:CAN->MCR &= ~CAN_MCR_LOOPBACK;。但这只是万里长征第一步。真实通信必须解决三个物理层问题:终端电阻、共模电压、收发器选型。
- 终端电阻:CAN总线两端必须各接一个120Ω电阻。很多新手只在开发板上接一个,结果通信不稳定。记住口诀:“两头有阻,中间无阻”。
- 共模电压:CAN_H和CAN_L的电压差必须在±2V内,否则收发器无法识别。用万用表测开发板CAN接口的CAN_H-CAN_L电压,正常应在2.5V左右。如果低于1.5V,检查收发器供电是否正常(TJA1050需5V,SN65HVD230需3.3V)。
- 收发器选型:工程中HARDWARE目录下的can.c已预留了CAN_GPIO_Config()函数,它配置PA11/PA12为复用推挽。但不同收发器对引脚驱动能力要求不同:TJA1050需要强驱动,应设置GPIO_Speed_50MHz;而SN65HVD230对驱动要求较低,GPIO_Speed_2MHz即可。

6.2 协议栈升级:从裸机驱动到CANopen基础

回环测试验证的是物理层和数据链路层,而真实应用需要更高层的协议。这个工程的模块化设计,让它成为绝佳的CANopen入门跳板。
- 对象字典雏形:在HARDWARE/can.c中,CAN_Receive()函数已解析出StdId、DLC、Data[]。你可以在此基础上,定义一个简单的对象字典结构体:

typedef struct {
    uint16_t index;      // 如0x1001(错误寄存器)
    uint8_t subindex;    // 如0x00(子索引0)
    uint8_t data[8];     // 数据内容
} CO_OBJ_DICT;
  • NMT状态机:在main.c的主循环中,加入NMT(网络管理)状态机,监听0x0000标准帧,根据第二个字节(命令字)切换节点状态(Pre-operational/Operational)。
  • PDO映射:利用CAN控制器的过滤器(Filter),在CAN_FilterInit()中配置接受列表,只接收特定ID的PDO帧,避免CPU被无关帧打断。

6.3 调试工具链整合:从串口打印到CAN分析仪

工程自带的串口打印是初级调试手段,进阶需要专业工具。
- CANalyzer/CANoe对接:将开发板的CAN接口接入PC的USB-CAN适配器,在CANalyzer中新建数据库(.dbc文件),导入工程中定义的帧ID(如0x123为心跳帧,0x201为温度数据帧)。这样,串口打印的“ID:0x123”就变成了图形化的信号曲线。
- 逻辑分析仪抓波形:用Saleae Logic或DSLogic,同时采集CAN_H、CAN_L和PA9(USART TX),对比物理层波形与协议层解析结果。你会发现,当波特率误差超过±1%时,逻辑分析仪显示的位宽开始抖动,而CAN控制器仍能正确接收——这正是CAN协议鲁棒性的直观体现。

注意:所有扩展的前提,是彻底吃透当前回环工程的每一行代码。我见过太多人,急着加CANopen协议栈,结果连最基本的波特率计算都搞错,最后在协议层浪费大量时间。真正的进阶,永远始于对基础的敬畏。这个工程的价值,正在于它用最朴素的方式告诉你:嵌入式没有捷径,只有把寄存器每一位都摸透,才能在复杂系统中游刃有余。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:这个KEIL5工程专为STM32F103ZET6芯片设计,实现CAN控制器纯软件回环通信验证——不依赖外部CAN收发器或第二块板子,直接在芯片内部完成发送与接收闭环。工程采用标准外设库结构,SYSTEM目录负责系统初始化和毫秒级延时,HARDWARE目录下封装了CAN初始化、发送、接收及状态查询函数,同时集成USART串口打印用于实时观察帧收发结果,LCD和KEY模块保留接口便于后续功能扩展。代码包含main.c主流程调度、can.c核心驱动逻辑、delay.c高精度延时、sys.c系统配置,以及标准启动文件startup_stm32f10x_hd.s和链接脚本。配套readme.txt说明编译步骤与调试要点,Objects和Listings目录自动生成编译中间文件,.uvprojx和.uvguix.admin支持KEIL5一键打开即用。所有源码已通过完整编译,输出可执行的.axf、.hex和.htm调试信息文件,还提供stm32_simulator.py脚本辅助仿真验证。适合嵌入式初学者快速掌握CAN寄存器配置、中断处理流程和回环模式调试方法,也适用于MCU外设功能自检与实时通信基础验证。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

7_MDK-ARM(Keil5)创建STM32F103标准库工程模板 本文介绍了MDK-ARM(Keil5)IDE工具创建和配置STM32F103ZET6标准库工程模板的详细方法,包括工程文件和项目配置相关内容,适用于STM32单片机开发初学者和MCU开发工程师做技术参考。 阅读详情

相关推荐

从零构建:如何为STM32F103ZET6定制SPI Flash下载算法

本文详细讲解如何为STM32F103ZET6微控制器定制SPI Flash下载算法,实现在Keil MDK环境中对外部W25Q64 Flash进行编程。内容涵盖算法工程配置、核心接口函数实现、编译问题排查及实际验证方法,帮助开发者扩展嵌入式系统存储能力,高效管理大容量资源。

aa123的博客 898

【STM32】STM32F103ZET6 创建工程模版详解(HAL库)

HAL库,全称为Hardware Abstraction Layer(硬件抽象层)库,是STMicroelectronics(ST)为STM32微控制器提供的较新的固件库。HAL库的定义与特点定义:HAL库是一个中间件,为应用程序和硬件之间提供了一个接口,允许开发者在不知道底层硬件细节的情况下编写控制硬件的代码。特点跨平台支持:HAL库支持STM32全系列微控制器,使得开发者编写的代码可以在不同的STM32产品之间移植。结构统一:为所有外设提供统一的API和驱动结构,简化了开发过程。易于使用。

C/C++软件工程师、嵌入式软件工程师、物联网研发工程师、C/C++讲师、物联网讲师、嵌入式讲师、鸿蒙讲师---欢迎大家一起交流(私信添加博主微信) 4251

Keil5环境下STM32F103ZET6工程搭建全流程(含软件仿真调试技巧)

本文详细介绍了在Keil5开发环境下搭建STM32F103ZET6工程的完整流程,包括开发环境准备、工程创建、关键文件配置以及软件仿真调试技巧。通过模块化目录结构设计和优化编译选项,帮助开发者高效完成项目搭建。特别分享了软件仿真中的外设寄存器观察、断点设置等高级调试方法,提升开发效率。

weixin_29162439的博客 195

探索CAN协议的便捷之路:STM32F103ZET6开发板上的高效通信解决方案

探索CAN协议的便捷之路:STM32F103ZET6开发板上的高效通信解决方案 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 在现代嵌入式系统中,CAN(Controller Area Network)协议因其高可靠性和实时性,广泛应用于汽车、工业控制等领域。为了帮助开发者快速上手CAN协议的开发,我们推出了一个基于STM32F103ZET6微控制器的CAN协议基本通...

gitblog_09779的博客 826

STM32F103ZET6与OV7670摄像头交互设计

STM32F103ZET6是STMicroelectronics(意法半导体)生产的一款高性能微控制器,它属于Cortex-M3内核系列,具有丰富的外设接口,适用于多种嵌入式应用。这款微控制器拥有高达72 MHz的处理速度、256 KB闪存和64 KB的SRAM,使其成为工业控制、医疗设备以及高性能应用的理想选择。Keil是广泛应用于嵌入式系统开发的集成开发环境(IDE),尤其在使用ARM处理器的项目中更是如此。

weixin_42453228的博客 994

STM32F103ZET6微控制器与DHT11温湿度传感器项目实战

htmltable {th, td {th {pre {简介:本项目结合了DHT11数字温湿度传感器与STM32F103ZET6微控制器,利用STM32的ARM Cortex-M3内核特性,进行高效的数据采集和处理。DHT11传感器以其结构紧凑、低功耗及易用性特点,广泛用于智能家居和环境监控场景。项目代码已经过实际测试,适用于MDK5开发环境,并提供了完整的可运行代码。开发过程中,参与者将深入了解硬件接口、软件编程和调试技巧,从而提升嵌入式系统开发能力。

weixin_30789053的博客 706

EPD屏幕+STM32F103ZET6 _02

本项目使用的硬件如下:1. 开发板:百问网的 100ASK_STM32F103_Pro开发板 主控芯片是STM32F103ZET6。2. 屏幕:屏幕是百问网的 3.52寸SPI接口墨水屏。实现效果:​ 使用STM32F103ZET6芯片驱动墨水屏显示图片并画出任意坐标的点、线、圆,要求全局刷新和局部刷新结合。部分效果图。

qq_56140091的博客 2798

STM32F103ZET6传感器调试指导:SDS011与DHT22集成

STM32F103ZET6是一款基于ARM Cortex-M3内核的高性能微控制器,具有丰富的外设接口和较高的处理速度,适用于复杂的嵌入式应用系统。此微控制器以其卓越的性能和广泛的兼容性,在工业控制、医疗设备、智能仪器等领域占据重要地位。本章将对STM32F103ZET6的硬件特性、软件开发环境及开发工具进行概览,为后续章节的深入探讨打下基础。核心特性:STM32F103ZET6拥有高达72MHz的处理速度和丰富的存储资源,包括64K至512K字节的闪存和高达64K字节的SRAM。

weixin_32480007的博客 1026

Keil5-STM32F103ZET6-案列一1.LED点灯

本工程代码下载区: https://download.csdn.net/download/qq_25140013/11985712 代码见优快云链接为: 编译环境为Keil5, 烧写的bin文件,烧写的区域为STM32F103ZET6内部的ROM 内部的ROM地址为0x08000000 LED.bin Code 代表执行的代码,程序中所有的函数都位于此处。 RO-data 代表只读数据,程序...

qq_25140013的博客 3342

告别理论!用AXI-Stream实战摄像头数据流采集(附Verilog关键代码片段)

本文详细解析了如何通过AXI-Stream接口实现工业级可靠性的摄像头数据流采集系统,重点介绍了Verilog实战代码、AXI-Stream握手机制及数据反压处理方案。通过三级缓冲架构和带宽优化,有效解决了OV5640等摄像头在高速场景下的帧丢失问题,为FPGA图像处理项目提供了实用解决方案。

weixin_42563415的博客 157

如何用zemax导入solidworks装配体

在zemax使用中,常常需要导入各种零件。如果光机结构较为复杂,那么手工一个一个加载零件,还需要在zmx文件中调整object的位置,非常麻烦。如果能将solidworks的装配体模型直接导入,则可以大幅减小工作量。具体过程为(非序列模式下): 1、新建或打开一个zemax空文件 2、在元件编辑器中,找到一个空文件,双击或直接展开三角符,在类型中找到zemax里的solidworks装配体,如图。...

wojiaoyyy的博客 1万+

STM32F103ZET6 - USB_DFU 升级

STM32F103ZET6 - USB_DFU 升级 前言: 记录下碰到的坑!! 仿真时发现读按键状态函数HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin),无论是判断等于1还是0,仿真都能进入; 纠结很久,然后查看GPIOx_IDR寄存器, 发现没问题,按键按下时该位为0,不按为1; 经查找发现是IDE优化等级问题,STM32CubeMX生成的代码默认优化等级为...

mimo6086的博客 2088

别再手动填数据了!Vivado里用.coe文件给ROM IP核预装数据的保姆级教程

本文详细介绍了在Vivado中使用.coe文件为ROM IP核预装数据的全流程教程,包括文件格式规范、数据转换技巧和Vivado配置指南。通过自动化数据加载,开发者可以显著提升FPGA开发效率,避免手动输入错误,适用于查找表、波形存储等多种应用场景。

weixin_33377602的博客 337

ARM汇编基础之基于MDK创建纯汇编语言的STM32工程

本文基于MDK 5.26软件,在stm32f103上进行汇编语言的实验测试;

一名热爱技术的工程师的博客。分享技术干货,记录美好生活。永远相信美好的事情即将发生。 1万+

Go游戏服务器开发的一些思考(一):语言层面

Go是比C++更好用的高级语言使用Go作为服务器开发的主语言前,首先需要对Go语言做下定性。在接触Go前,可能给人的印象(至少是我),Go是一门脚本语言。看了 官方文档 ,才知道Go是一门高级语言。与C++相比,它有以下优势: 面向接口的编程没有C++复杂的面向对象语法,如类、继承、多态、虚函数等等。Go中只有结构与接口,从语言层面上,直接指导功能与功能间的解耦。直接且语法简单 提供语言反射机制提供

范安崇的博客 9558

射频仿真软件:ADS (Advanced Design System)_(29).ADS脚本编程与自动化

ADS脚本编程为射频设计提供了强大的自动化工具,可以帮助用户实现设计流程的优化、参数扫描和优化、结果分析和报告生成等任务。选择合适的脚本语言(Python、Tcl、AEL)并合理设置ADS环境,可以显著提高设计效率和准确性。通过实际项目中的应用案例,我们可以更好地理解如何利用脚本编程解决复杂的射频设计问题。希望本文对您的ADS脚本编程学习有所帮助。

kkchenjj的博客 2468

【亲测免费】 STM32F103ZET6 工程模板

STM32F103ZET6 工程模板 【下载地址】STM32F103ZET6工程模板 本仓库提供了一个基于STM32F103ZET6微控制器的工程模板,旨在帮助开发者快速搭建和启动STM32F103ZET6的开发环境。该模板包含了基本的工程结构和配置,开发者可以直接在此基础上进行功能扩展和开发 ...

gitblog_09764的博客 333

微信小程序开发:实现地图导航功能

其中,id用于调用地图组件,latitude和longitude表示地图的中心点坐标,markers表示地图中的标记点,covers表示地图中的覆盖物,polyline表示地图中的折线图,show-location表示是否显示当前定位点,bindregionchange表示移动地图时触发的事件。其中,id表示标记点的唯一标识,latitude和longitude表示标记点的坐标,title表示标记点的名称,iconPath表示标记点的图标路径,width和height表示标记点的宽度和高度。

吃不胖. 8917

keil5软件仿真STM32F103波形

近日,在使用 Keil5 MDK 对STM32进行仿真的时候,无法查看IO端口的信号波形。在网络上搜索了一番,才搞明白原因:一是没有选中【设置】选项中的【仿真器(simulator)】;二是【Debug】中的参数设置有问题。现将有关设置记录如下:第一步,在工程选项中,找到【debug】选项卡,左上方,一定要选中【use simulator】;第二步,在下方的参数设置中,一定要修改四个参数,即第2步...

zlkk00的博客 2万+

windows下宝塔安装教程

windows下宝塔安装教程 目录宝塔是什么?宝塔安装流程1.下载2.配置3.登录4.安装的环境套件小结 宝塔是什么? 宝塔是管理服务器的免费的软件,宝塔上面可以进行对你的服务器批量进行管理,对于运维人员来说还是必不可少的一个软件,值得使用。 宝塔安装流程 1.下载 链接: https://download.bt.cn/win/panel/BtSoft.zip 下载后安装买最好自定义目录,方便找 2.配置 下载完成后会出现这个页面,对着页面进行配置 点击默认密码复制进来,这里注意一点就是一定要查看

你在看屏幕的同时,屏幕也在注视着你 4421

vLLM 显存泄漏与 OOM 深度排查:从日志到火焰图

系统性地排查 vLLM 运行中的显存泄漏和 OOM 问题,包括 CUDA 内存快照、PyTorch 内存分析器、火焰图工具。

kaixin110a的博客 185

STM32 USART串口DMA 接收和发送的源码详解!

硬件平台:STM32F103ZET6;开发环境:KEIL 4;先说说应用通讯模式,串口终端的工作方式和迪文屏差不多,终端被动接受MCU发的指令,终端会偶尔主动发送一些数据给MCU(像迪文屏的触摸信息上传)。串口DMA发送:发送数据的流程:前台程序中有数据要发送,则需要做如下几件事1.在数据发送缓冲区内放好要发送的数据,说明:此数据缓冲区的首地址必须要在DMA初始化的时候写入到DMA配......

魏波 2万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

STM32F103ZET6 - USB_HID -2 (IAP升级)

*STM32F103ZET6 - USB_HID -2 (IAP升级) 示例详解: (参考 : https://blog.csdn.net/u014803614/article/details/100033217) 基于硬件平台: STM32F103ZET6正点原子的精英板, 使用stm32cubemx 工具自动产生的配置工程,使用KEIL5编译代码。 STM32CubeMX生成代码过程如下...

mimo6086的博客 3428

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

结合CAN总线的Keil5芯片包使用实战案例

通过实际项目讲解如何完成keil5芯片包下载并配置CAN总线功能,深入剖析开发过程中的关键步骤与常见问题,帮助开发者快速上手嵌入式系统设计。

weixin_29443363的博客 492

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

STM32-F103-ZET6上的CoreMark跑分测试

     其实已经有很多通过提供一个简单的数来尝试整体评估CPUCPUCPU的性能基准,比如主频(MHzMHzMHz), 每秒百万指令(Million Instructions per Second,MIPS), 每秒百万操作(Million Operations per Second,MOPS),每秒百万浮点操作(Million Floating Point Operations per Second,MFLOPS)。但是当我们在看CPU的整体的潜在性能的

caoleiwe的博客 4057

STM32入门开发: LWIP网络协议栈移植(网卡采用DM9000)

一、环境介绍 MCU: STM32F103ZET6 代码开发工具: Keil5 TCP/IP协议栈: LWIP 网卡: DM9000 本篇文章主要讲解如何在STM32F103工程里添加移植LWIP协议,最终完成TCP服务器、TCP客户端的通信测试。 网卡采用的是DM9000,工程代码中,采用STM32的FSMC接口来驱动DM900网卡,DM9000是并口网卡,引脚多,但是速度快,也可以采用其他网卡,SPI协议的、UART协议的等。 比如:W5500。 因为主要是讲LWIP协议栈的移植,所以网卡相关

1万+
上一篇: Windows一键运行的Qt5连连看游戏工程:含源码、可执行文件和全套依赖库
下一篇: MT7663 USB WiFi驱动源码包|已适配海思Hi3531(aarch64交叉编译可用)
水果削皮艺术家
博客等级 码龄3年 47粉丝 1437原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值