关注公众号,回复“入门资料”获取单片机入门到高级开挂教程
开发板带你入门,我们带你飞
文 | 无际(微信:2777492857)
全文约10109字,阅读大约需要 20 分钟
雷猴啊,我是无际。
你有没有经历过,传输数据时,速度就像便秘一样,我在做OTA升级功能的时候碰到过。
领导天天追问进度,我只能原地急的团团转,心想"大佬,这不是我的错"。
今天,来普及下,STM32最常用,最快的几种通讯方式,今天内容有亿点点长,全文9000字以上。
不过别担心,我不是来念经的!看完这篇文章,你将:
•彻底搞懂 STM32 与上位机通信的各种姿势(串口、USB、CAN、以太网)。
•掌握 如何选择最适合你项目的通信方式,告别“选错协议,加班到哭”的惨剧。
•学会 各种通信方式的优化技巧,让你的数据传输速度提升 N 倍!
•获得 大量实战案例和代码示例(基于标准库),拒绝纸上谈兵。
•避开 那些隐藏的“坑”,少走弯路,早点下班!
•学会 简单的硬件选型,避免踩坑!
废话不多说,直接上干货!我们来逐一分析各种通信方式。
1. 串口 (UART),最简单粗暴
•原理:串口是最基础的通信方式,就像你和邻居扯着嗓子喊话,简单直接。
•优点:易于上手,成本低廉,硬件要求不高。
•缺点:速度慢,容易受到干扰,数据安全性较差。
•速率范围:通常支持 300 bps 到 4 Mbps 甚至更高,具体取决于 STM32 型号和硬件设计。常用的波特率包括 9600 bps, 115200 bps, 230400 bps, 460800 bps 等。
1.1 硬件选型建议:
•STM32型号:STM32F103C8T6(俗称“小蓝板”)是入门首选,成本低廉,资源丰富。STM32F407/F429 则提供更强大的性能和更多 UART 接口。
•USB转串口模块:CH340G 是常用且廉价的选择。CP2102 则提供更好的稳定性和兼容性。
•杜邦线:用于连接模块和开发板。
1.2 配置步骤(基于标准库):
步骤 1:使能时钟
使能 UART 和 GPIO 的时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // 使能 USART1 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能 GPIOA 时钟
步骤 2:配置 GPIO
配置 UART 的 TX 和 RX 引脚。
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // TX 引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // RX 引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
步骤 3:配置 UART
配置 UART 的波特率、数据位、停止位、校验位等。
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200; // 波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 数据位
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 停止位
USART_InitStructure.USART_Parity = USART_Parity_No; // 校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 发送和接收模式
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE); // 使能 USART1
1.3 代码示例:
// 初始化 USART1
void USART1_Init(uint32_t baudrate)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
// 开启接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
// 发送数据
void USART1_Send(char *data)
{
while (*data)
{
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // 等待发送缓冲区为空
USART_SendData(USART1, *data++);
}
}
// 接收中断处理函数
volatile char recv_char = 0; // 使用 volatile 避免编译器优化
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
recv_char = USART_ReceiveData(USART1);
// 在这里处理接收到的数据,例如:
printf("Received: %c\n", recv_char);
// 清除中断标志
}
}
int main(void)
{
USART1_Init(115200);
char send_str[] = "Hello from STM32!\r\n";
while (1)
{
USART1_Send(send_str);
// printf("Received: %c\n", recv_char); // 注释掉,在中断中处理
Delay_ms(1000); // 使用你自己的延时函数
}
}
1.4 优化技巧:
•提高波特率:这是最简单粗暴的方式,但要注意硬件和上位机是否支持。
•使用 DMA:DMA (Direct Memory Access) 可以让 UART 在后台传输数据,不占用 CPU 资源,提高效率。
•使用中断:通过中断方式处理接收到的数据,避免轮询,提高响应速度。
•减少数据量:采用压缩算法,减少传输的数据量。
•协议优化:减少不必要的协议头和校验位。
// 串口 DMA 发送 (需要配置 DMA 通道和中断)
// DMA 配置示例 (仅供参考,需要根据具体情况修改):
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; // UART 数据寄存器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)data; // 数据缓冲区地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // 外设为目标
DMA_InitStructure.DMA_BufferSize = strlen(data); // 数据长度
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 数据大小
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 数据大小
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 正常模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; // 优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 内存到内存传输
DMA_Init(DMA1_Channel4, &DMA_InitStructure); // 初始化 DMA 通道
DMA_Cmd(DMA1_Channel4, ENABLE); // 使能 DMA 通道
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); // 使能 UART DMA 发送请求
1.5 常见问题及解决方法:
•乱码:检查波特率、数据位、停止位和校验位是否一致。
•数据丢失:检查缓冲区大小是否足够,是否开启了硬件流控制。
•接收中断异常:检查中断优先级是否正确,中断处理函数是否正确。
以下是优化排版后的内容,使其更加清晰、有条理:
1.6 适用场景
UART 虽然简单,但在很多场景下仍然非常实用。以下是一些具体示例:
1.6.1 调试信息输出(必备技能)
•项目:几乎所有 STM32 项目都需要调试信息。
•功能:使用 printf() 函数将程序的运行状态、变量值等信息通过 UART 发送到上位机(例如,串口调试助手)。
•原因:这是最常用的调试手段,可以帮助开发者快速定位问题。
•举例:在一个电机控制项目中,可以通过 UART 输出电机转速、电流、PID 参数等信息,以便观察电机的运行状态。
1.6.2 GPS 数据解析与显示(定位导航)
•项目:GPS 定位模块与 STM32 连接。
•功能:GPS 模块通过 UART 输出 NMEA 0183 格式的数据,STM32 解析这些数据,提取经纬度、速度、时间等信息,并在 LCD 屏幕上显示。
•原因:UART 是 GPS 模块常用的通信接口,NMEA 0183 格式简单易懂。
•举例:制作一个简单的 GPS 定位器,可以显示当前的经纬度信息。
1.6.3 蓝牙模块通信(无线控制)
•项目:使用蓝牙模块(例如 HC-05)实现 STM32 与手机 App 的无线通信。
•功能:手机 App 通过蓝牙发送控制指令,STM32 接收指令并控制外设(例如,LED 灯、电机等)。
•原因:HC-05 蓝牙模块通常使用 UART 进行通信,简单易用。
•举例:开发一个智能小车,可以使用手机 App 通过蓝牙控制小车的运动。
1.6.4 RFID 读卡器数据读取(身份识别)
•项目:使用 RFID 读卡器读取 RFID 卡片的信息。
•功能:RFID 读卡器通过 UART 将读取到的卡片 ID 发送给 STM32,STM32 根据卡片 ID 进行身份验证或权限控制。
•原因:RFID 读卡器通常使用 UART 进行通信,数据传输量不大。
•举例:制作一个门禁系统,只有刷了授权卡片才能开门。
1.6.5 传感器数据采集(环境监测)
•项目:使用温湿度传感器、光照传感器等采集环境数据。
•功能:传感器通过 UART 将采集到的数据发送给 STM32,STM32 对数据进行处理,并发送到上位机或存储到 SD 卡中。
•原因:某些传感器模块(例如,Modbus RTU 传感器)使用 UART 进行通信。
•举例:开发一个环境监测系统,可以实时显示温湿度、光照强度等信息。
1.6.6 Modbus RTU 通信(工业控制)
•项目:使用 Modbus RTU 协议与工业设备进行通信。
•功能:STM32 作为 Modbus 客户端,读取或者写入 Modbus 从机的数据。
•原因:Modbus RTU 是一种常用的工业通信协议,基于串口通信,简单可靠。
•举例:使用 STM32 控制变频器,读取电机的运行状态和设置运行参数。
1.6.7 WiFi 模块控制(无线网络连接)
•项目:使用 WiFi 模块(例如 ESP8266, ESP32)将 STM32 连接到 WiFi 网络。
•功能:STM32 通过 UART 向 WiFi 模块发送 AT 指令,配置 WiFi 连接参数(例如,SSID、密码)。连接成功后,STM32 可以通过 WiFi 模块与服务器进行 TCP/UDP 通信。
•原因:ESP8266/ESP32 等 WiFi 模块通常使用 UART 接口进行通信,成本低廉,易于集成。
•举例:开发一个智能插座,可以通过 WiFi 连接到云平台,实现远程控制和数据监测。
1.6.8 4G 模块控制(移动网络连接)
•项目:使用 4G 模块(例如 SIM800C, SIM7600)实现 STM32 通过移动网络进行通信。
•功能:STM32 通过 UART 向 4G 模块发送 AT 指令,拨号连接到移动网络。连接成功后,STM32 可以通过 4G 模块与服务器进行 TCP/UDP 通信,或者发送短信。
•原因:SIM800C/SIM7600 等 4G 模块通常使用 UART 接口进行通信,可以实现远程数据传输。
•举例:开发一个远程监控设备,可以通过 4G 网络将采集到的数据发送到云平台。
比如我们无际单片机特训营项目6,就有WiFi模块和4G模块,实现设备远程监控,OTA等功能,就是对UART的一种深度应用。
2. USB:速度与便捷的结合!
•原理:USB 是一种高速串行通信协议,就像高速公路,数据可以飞速传输。
•优点:速度快,即插即用,兼容性好。
•缺点:硬件和软件复杂度较高,开发难度较大,需要 USB 驱动。
•速率范围:USB 2.0 (Full Speed) 速率为 12 Mbps,USB 2.0 (High Speed) 速率为 480 Mbps,USB 3.0 速率高达 5 Gbps。STM32 支持的 USB 速率取决于型号。
2.1 硬件选型建议:
•STM32型号:STM32F103C8T6 虽然可以使用 USB,但资源有限。建议选择 STM32F407/F429/F405 系列,它们自带 USB OTG 功能,并且性能更强。
•USB接口类型:常见的有 Type-A、Type-B、Mini-USB、Micro-USB 和 Type-C。根据你的需求选择合适的接口。Type-C 逐渐成为主流,正反插都方便。
•晶振:确保使用正确频率的晶振,以保证 USB 的正常工作。通常需要 12 MHz 或 25 MHz 的晶振。
2.2 实现方法:
•CDC (Virtual COM Port):将 USB 设备模拟成串口,上位机使用串口工具进行通信,易于实现。
•HID (Human Interface Device):用于模拟键盘、鼠标等设备,不需要驱动程序,但数据传输格式有限制。
•自定义协议:可以自定义 USB 通信协议,灵活性高,但开发难度大。
2.3 代码示例(CDC,基于标准库,需要完整的 USB 库支持):
标准库下实现 USB CDC 比较复杂,需要移植完整的 USB 协议栈,例如 VCP (Virtual COM Port) 驱动。这里提供一个简要的思路:
•配置 USB 时钟、中断、端点等:使用标准库的函数配置相应的寄存器。
•实现 USB 中断处理函数:例如 USB_LP_CAN1_RX0_IRQHandler。
•实现 USB CDC 驱动:包括初始化、发送、接收等函数。
•在主循环中处理 USB 事件:检测 USB 连接状态,发送和接收数据。
由于代码量较大,这里无法提供完整的示例代码。建议参考 STM32 官方的 USB CDC 例程,或者第三方 USB 协议栈(例如,STM32_USB-FS-Device_Lib)。
我给大家整理STM32实现USB、CAN、以太网的参考源码,正在用的可以找我拿。
2.4 优化技巧:
•Bulk 传输:使用 Bulk 传输模式,可以提高数据传输速度。
•优化 USB 描述符:合理配置 USB 描述符,减少不必要的开销。
•使用 DMA:通过 DMA 方式进行 USB 数据传输,减少 CPU 占用。
2.5 常见问题及解决方法:
•驱动问题:确保上位机安装了正确的 USB 驱动。
•枚举失败:检查 USB 供电是否正常,USB 配置是否正确。
•数据传输错误:检查数据包大小是否符合 USB 协议,是否开启了校验。
2.6 适用场景:
大容量数据传输、需要高速通信的设备、需要即插即用的设备。
以下是优化排版后的内容,使其更加清晰、有条理:
2.6.1 固件升级 (Bootloader)
•项目:为 STM32 设备提供便捷的固件升级方式。
•功能:通过 USB CDC 或自定义协议,将新的固件文件从上位机传输到 STM32,并写入 Flash 存储器中。
•原因:USB 传输速度快,无需额外的编程器,用户操作方便。
•举例:智能手环、无人机等设备通常使用 USB 进行固件升级。
2.6.2 2. 数据采集与存储 (高速数据记录仪)
•项目:构建一个高速数据记录仪,例如示波器、逻辑分析仪。
•功能:STM32 通过 ADC 采集模拟信号,或者通过 GPIO 采集数字信号,然后将数据通过 USB 传输到上位机进行存储和分析。
•原因:USB 的高速传输能力可以满足实时数据采集的需求。
•举例:用于记录传感器数据、音频信号、视频信号等。
2.6.3 虚拟串口 (USB CDC 应用)
•项目:需要与上位机进行频繁的数据交互,但又不想使用传统的串口。
•功能:将 STM32 设备模拟成一个虚拟串口,上位机可以使用串口调试助手或其他串口工具与 STM32 进行通信。
•原因:USB CDC 驱动通用,无需额外安装驱动程序,使用方便。
•举例:开发一个 USB 示波器,将采集到的数据通过虚拟串口发送到上位机进行显示。
2.6.4 4. 人机接口设备 (USB HID 应用)
•项目:需要将 STM32 设备模拟成键盘、鼠标、游戏手柄等。
•功能:STM32 采集按键、摇杆等输入信号,并将这些信号通过 USB HID 协议发送到上位机。
•原因:USB HID 设备无需安装驱动程序,即插即用。
•举例:自制一个 USB 游戏手柄或 MIDI 键盘。
2.6.5 音频设备 (USB Audio Class)
•项目:开发 USB 声卡或者音频播放器。
•功能:通过 USB 接口接收或者发送音频数据,进行播放或者录制。
•原因:USB Audio Class 是一种标准的音频设备协议,兼容性好。
•举例:使用 STM32 制作一个 USB 声卡,连接耳机和麦克风,实现语音通话功能。
2.6.6 摄像头设备 (USB Video Class)
•项目:开发 USB 摄像头。
•功能:通过 USB 接口将图像数据传输到上位机。
•原因:UVC 是一种标准的视频设备协议,兼容性好,无需额外驱动。
•举例:使用 STM32 控制摄像头模组,制作一个 USB 摄像头,用于视频会议或者图像采集。
2.6.7 高速数据传输
•项目:需要在 STM32 和上位机之间进行高速数据传输的应用,如图像处理、科学实验数据采集等。
•功能:利用 USB 的高速传输能力,实现大量数据的快速交换。
•原因:相比串口,USB 具有更高的带宽,可以满足高速数据传输的需求。
•举例:开发一个高速数据采集卡,用于采集传感器数据,并通过 USB 传输到上位机进行分析。
3. CAN 总线:工业领域的“老司机”!
•原理:CAN 总线是一种多主通信协议,就像一个“聊天室”,所有设备都可以发言,但只有优先级最高的设备才能发送数据。
•优点:可靠性高,抗干扰能力强,适用于工业环境。
•缺点:速度相对较慢,协议复杂,需要 CAN 收发器。
•速率范围:标准 CAN 支持的速率为 1 Mbps,CAN FD (Flexible Data-Rate) 支持的速率更高,可达 8 Mbps 甚至更高。
3.1 硬件选型建议:
•STM32型号:STM32F103C8T6 具备 CAN 功能,入门够用。STM32F105/F107 系列则拥有更高级的 CAN 控制器。
•CAN 收发器:TJA1050 是常用的 CAN 收发器,体积小巧,性能稳定。也可以选择更高级的带隔离功能的收发器,例如 ISO1050。
•终端电阻:CAN 总线两端需要连接 120 欧姆的终端电阻,以匹配阻抗,减少信号反射。
•CAN 分析仪:用于调试 CAN 总线,查看总线上的数据和错误信息。
3.2 配置步骤(基于标准库):
步骤 1:使能时钟
使能 CAN 和 GPIO 的时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); // 使能 CAN1 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 使能 GPIOB 时钟
步骤 2:配置 GPIO
配置 CAN 的 TX 和 RX 引脚。
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // TX 引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; // RX 引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
步骤 3:配置 CAN
配置 CAN 的工作模式、波特率、滤波器等。
CAN_InitTypeDef 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_RFLM = DISABLE; // FIFO 锁定模式
CAN_InitStructure.CAN_TXFP = DISABLE; // 发送 FIFO 优先级
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; // 正常模式
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; // 同步跳转宽度
CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq; // 时间段 1
CAN_InitStructure.CAN_BS2 = CAN_BS2_5tq; // 时间段 2
CAN_InitStructure.CAN_Prescaler = 3; // 分频系数 (根据时钟频率计算) - 需要根据实际时钟频率调整
CAN_Init(CAN1, &CAN_InitStructure);
步骤 4:配置 CAN 滤波器
配置 CAN 滤波器,过滤不需要的消息。
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CAN_FilterInitStructure.CAN_FilterNumber = 0; // 滤波器编号
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; // 标识符掩码模式
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; // 32 位滤波器
CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000; // 滤波器 ID 高位
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000; // 滤波器 ID 低位
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000; // 滤波器掩码 ID 高位
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000; // 滤波器掩码 ID 低位
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0; // 滤波器 FIFO
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; // 使能滤波器
CAN_FilterInit(&CAN_FilterInitStructure);
CAN_Cmd(CAN1, ENABLE); // 使能 CAN1
3.3 代码示例:
// 初始化 CAN1
void CAN1_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
CAN_InitTypeDef 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_RFLM = DISABLE;
CAN_InitStructure.CAN_TXFP = DISABLE;
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_5tq;
CAN_InitStructure.CAN_Prescaler = 3; // For 72MHz Clock and 1Mbps (Adjust for your clock)
CAN_Init(CAN1, &CAN_InitStructure);
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CAN_FilterInitStructure.CAN_FilterNumber = 0;
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
CAN_Cmd(CAN1, ENABLE);
// 开启接收中断 (可选)
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; // CAN1 RX0 中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
// 发送 CAN 消息
void CAN1_Send(uint32_t id, uint8_t *data, uint8_t len)
{
CanTxMsg TxMessage;
TxMessage.StdId = id;
TxMessage.RTR = CAN_RTR_DATA;
TxMessage.IDE = CAN_ID_STD;
TxMessage.DLC = len;
for (int i = 0; i < len; i++)
{
TxMessage.Data[i] = data[i];
}
CAN_Transmit(CAN1, &TxMessage);
}
// 接收 CAN 消息 (中断方式)
CanRxMsg RxMessage;
void USB_LP_CAN1_RX0_IRQHandler(void)
{ // CAN1 RX0 中断处理函数
if (CAN_GetITStatus(CAN1, CAN_IT_FMP0) != RESET)
{
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
// 处理接收到的消息
printf("Received CAN ID: 0x%X\n", RxMessage.StdId);
for (int i = 0; i < RxMessage.DLC; i++)
{
printf("Data[%d]: 0x%X\n", i, RxMessage.Data[i]);
}
CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0); // 清除中断标志
}
}
int main(void)
{
CAN1_Init();
uint8_t send_data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
while (1)
{
CAN1_Send(0x123, send_data, sizeof(send_data));
Delay_ms(100); // 降低发送频率,防止总线堵塞
}
}
3.4 优化技巧:
•选择合适的波特率:根据实际需求选择合适的波特率,避免浪费带宽。
•优化 CAN ID:合理分配 CAN ID,避免冲突,提高效率。
•使用滤波器:通过滤波器过滤不感兴趣的消息,减少 CPU 负担。
•减少数据量:尽量减少 CAN 消息的数据长度。
3.5 常见问题及解决方法:
•总线错误:检查 CAN 收发器是否正常,总线电平是否正确,终端电阻是否匹配。
•消息冲突:检查 CAN ID 是否冲突,优先级分配是否合理。
•数据丢失:检查接收缓冲区是否足够,是否开启了中断。
3.6 适用场景:
汽车电子、工业控制、机器人等需要高可靠性和抗干扰能力的应用。
3.6.1 汽车电子 (车身控制、动力系统)
•项目:汽车的车身控制系统、动力系统、安全系统等。
•功能:各个 ECU (电子控制单元) 通过 CAN 总线进行通信,例如发动机 ECU、ABS ECU、安全气囊 ECU、车身控制 ECU 等。
•原因:CAN 总线可以保证各个 ECU 之间可靠、实时的通信,实现车辆的各种功能。
•举例:
○发动机 ECU 将发动机转速、扭矩等信息发送给仪表盘 ECU 进行显示。
○ABS ECU 检测到车轮抱死,通过 CAN 总线通知发动机 ECU 降低发动机输出。
○安全气囊 ECU 检测到碰撞,通过 CAN 总线触发安全气囊弹出。
3.6.2 工业自动化 (机器人、PLC、传感器网络)
•项目:工业机器人、PLC (可编程逻辑控制器)、传感器网络等。
•功能:机器人中的各个关节控制器、PLC 中的各个模块、传感器网络中的各个节点通过 CAN 总线进行通信,实现协同工作。
•原因:CAN 总线可以保证各个设备之间可靠、实时的通信,适用于工业环境。
•举例:
○机器人控制器通过 CAN 总线控制各个关节电机的运动。
○PLC 通过 CAN 总线读取传感器数据,并根据数据控制执行机构。
○传感器网络中的各个节点通过 CAN 总线将采集到的数据发送到中央控制器。
3.6.3 医疗设备 (CT、MRI、监护仪)
•项目:CT (计算机断层扫描)、MRI (磁共振成像)、监护仪等医疗设备。
•功能:各个模块(例如,数据采集模块、控制模块、显示模块)通过 CAN 总线进行通信,实现设备的各种功能。
•原因:CAN 总线具有高可靠性和抗干扰能力,适用于对安全性要求较高的医疗设备。
3.6.4 电力系统 (智能电网、变电站自动化)
•项目:智能电网、变电站自动化系统。
•功能:各个设备(例如,保护继电器、测量装置、控制单元)通过 CAN 总线进行通信,实现电力系统的监控和控制。
•原因:CAN 总线具有高可靠性和实时性,适用于电力系统对通信要求较高的应用。
3.6.5 轨道交通 (列车控制系统、信号系统)
•项目:列车控制系统、信号系统等。
•功能:列车上的各个设备(例如,牵引控制单元、制动控制单元、车门控制单元)通过 CAN 总线进行通信,实现列车的控制和管理。
•原因:CAN 总线具有高可靠性和实时性,适用于对安全性要求极高的轨道交通系统。
3.6.6 工程机械 (挖掘机、起重机、装载机)
•项目:挖掘机、起重机、装载机等工程机械的控制系统。
•功能:各个传感器(例如,压力传感器、位移传感器、角度传感器)和执行机构(例如,液压阀、电机)通过 CAN 总线进行通信,实现工程机械的精确控制。
•原因:工程机械工作环境恶劣,CAN 总线的抗干扰能力强,能够保证系统的可靠运行。
3.6.7 船舶系统 (发动机监控、导航系统)
•项目:船舶的发动机监控系统、导航系统、自动化控制系统。
•功能:各个传感器(例如,温度传感器、压力传感器、流量传感器)和控制单元通过 CAN 总线进行通信,实现船舶设备的监控和管理。
•原因:CAN 总线具有高可靠性和抗干扰能力,适用于船舶的恶劣环境。
3.6.8 航空航天 (飞行控制、数据采集)
•项目:航空航天领域的飞行控制系统、数据采集系统。
•功能:各个传感器(例如,陀螺仪、加速度计、压力传感器)和控制单元通过 CAN 总线进行通信,实现飞行器的姿态控制和数据采集。
•原因:航空航天领域对可靠性和实时性要求极高,CAN 总线能够满足这些要求。
4. 以太网 (Ethernet):走向物联网的“高速公路”!
•原理:以太网是一种高速局域网通信协议,就像四通八达的高速公路,数据可以快速传输到任何地方。
•优点:速度快,传输距离远,支持 TCP/IP 协议栈,易于接入互联网。
•缺点:硬件和软件复杂度高,开发难度大,需要以太网 PHY 芯片。
•速率范围:以太网支持 10 Mbps, 100 Mbps (Fast Ethernet), 1 Gbps (Gigabit Ethernet) 甚至更高的速率。
4.1 硬件选型建议:
•STM32型号:建议选择带有内置以太网 MAC 的 STM32F407/F429/F7 系列。
•以太网 PHY 芯片:LAN8720A 是常用的 10/100M 以太网 PHY 芯片,体积小巧,易于使用。
•RJ45 接口:用于连接网线。部分 RJ45 接口集成了变压器,可以简化电路设计。
•晶振:PHY 芯片需要提供时钟信号,通常使用 25 MHz 晶振。
•网线:选择 Cat5e 或 Cat6 网线,以保证数据传输的稳定性和速度。
4.2 实现方法:
•TCP/IP 协议栈:使用 TCP/IP 协议栈进行网络通信,需要移植和配置 TCP/IP 协议栈,例如 LWIP。
•Socket 编程:使用 Socket 编程接口进行网络通信,需要了解 TCP/IP 协议的基本原理。
•Web 服务器:将 STM32 变成一个 Web 服务器,可以通过浏览器访问和控制。
标准库下实现以太网通信需要移植 LWIP 等 TCP/IP 协议栈,并配置相关的硬件资源。由于代码量巨大,这里无法提供完整的示例。建议参考 STM32 官方的以太网例程和 LWIP 的文档。
4.3 优化技巧:
•优化 TCP/IP 协议栈:根据实际需求裁剪和优化 TCP/IP 协议栈,减少资源占用。
•使用 DMA:通过 DMA 方式进行以太网数据传输,减少 CPU 占用。
•减少网络延迟:优化网络配置,减少网络延迟。
•数据压缩:采用压缩算法,减少网络传输的数据量。
4.4 常见问题及解决方法:
•IP 地址冲突:检查 IP 地址是否冲突,是否正确配置了网络参数。
•网络连接失败:检查网线是否连接正常,网络配置是否正确,防火墙是否阻止了连接。
•数据传输错误:检查数据包是否完整,是否开启了校验。
4.5 适用场景:
以太网凭借其高速率、远距离传输和易于接入互联网的优势,在以下场景中应用广泛:
4.6 物联网 (IoT) 设备
•项目:智能家居、智能城市、工业物联网等各种 IoT 设备。
•功能:设备通过以太网连接到互联网,实现远程监控、数据采集、设备控制等功能。
•原因:以太网能够提供稳定的网络连接和足够的数据带宽,满足 IoT 设备对通信的需求。
•举例:
○智能摄像头通过以太网将视频数据传输到云平台。
○智能电表通过以太网将用电数据上传到电力公司服务器。
○工业传感器通过以太网将生产数据发送到工厂管理系统。
4.6.1 2. 工业自动化
•项目:工业机器人、PLC (可编程逻辑控制器)、SCADA (监控与数据采集) 系统等。
•功能:设备通过以太网进行高速数据交换和实时控制,提高生产效率和自动化水平。
•原因:以太网能够提供高速、可靠的网络连接,满足工业自动化对实时性和稳定性的需求。
•举例:
○工业机器人通过以太网与视觉系统进行数据交换,实现精确的定位和抓取。
○PLC 通过以太网与上位机进行通信,实现生产过程的监控和管理。
○SCADA 系统通过以太网采集各个生产环节的数据,并进行分析和优化。
4.6.2 楼宇自动化
•项目:智能照明系统、HVAC (暖通空调) 系统、安防监控系统等。
•功能:设备通过以太网连接到中央控制系统,实现远程控制、节能管理和安全监控。
•原因:以太网能够提供高速、稳定的网络连接,方便楼宇设备的集中管理。
•举例:
○智能照明系统通过以太网根据光照强度和人员活动自动调节灯光亮度。
○HVAC 系统通过以太网根据室内外温度自动调节空调温度和风量。
○安防监控系统通过以太网将视频监控画面传输到监控中心。
4.6.3 医疗设备
•项目:远程医疗系统、医疗影像传输系统、医疗设备监控系统等。
•功能:设备通过以太网进行高速数据传输和远程控制,提高医疗效率和质量。
•原因:以太网能够提供高速、稳定的网络连接,满足医疗设备对数据传输的需求。
4.6.4 视频监控
•项目:网络摄像头 (IP Camera)、视频服务器、监控中心等。
•功能:网络摄像头通过以太网将视频数据传输到视频服务器,用户可以通过网络远程观看和管理监控画面。
•原因:以太网能够提供足够的数据带宽,满足视频数据传输的需求。
•举例:家庭安防、商铺监控、交通监控等。
4.6.5 音频传输 (网络音频)
•项目:网络广播系统、IP 音箱、音频工作站等。
•功能:音频设备通过以太网传输音频数据,实现远程播放和控制。
•原因:以太网能够提供高速、稳定的网络连接,满足音频数据传输的需求。
4.6.6 远程控制与管理
•项目:服务器管理、远程设备维护、远程实验室等。
•功能:通过以太网远程访问和控制设备,实现远程管理和维护。
•原因:以太网能够提供高速、稳定的网络连接,方便远程操作。
4.6.7 高速数据传输和存储
•项目:网络存储服务器 (NAS)、高速数据备份系统等。
•功能:通过以太网实现高速数据传输和存储,方便用户进行数据备份和共享。
•原因:以太网能够提供高速率的数据传输能力,满足大数据应用的需求。
4.6.8 Web 服务器
•项目:将 STM32 设备作为 Web 服务器使用。
•功能:通过以太网向用户提供 Web 页面,用户可以通过浏览器访问和控制设备。
•原因:以太网方便接入网络,用户界面友好,易于操作。
•举例:制作一个智能家居网关,用户可以通过 Web 页面控制家电。
最后,希望这篇文章对你有帮助!早日摆脱“龟速”通信的困扰!
end
下面是更多无际原创的个人成长经历、行业经验、技术干货。
1.电子工程师是怎样的成长之路?10年5000字总结
2.如何快速看懂别人的代码和思维
3.单片机开发项目全局变量太多怎么管理?
4.C语言开发单片机为什么大多数都采用全局变量的形式?
5.单片机怎么实现模块化编程?实用程度让人发指!
6.c语言回调函数的使用及实际作用详解
7.手把手教你c语言队列实现代码,通俗易懂超详细!
8.c语言指针用法详解,通俗易懂超详细!