固件开发项目实例1000例实例(5)
来源:新闻资讯 /
时间: 2024-11-23
目录
“固件开发项目1000例”专栏中,“串行通信协议(UART, SPI, I2C)”是中级项目部分的重要一节。这一章节旨在帮助读者了解如何使用微控制器实现不同类型的串行通信协议,包括UART、SPI和I2C。以下是这一章节的详细介绍:
串行通信协议
1. 串行通信基础知识
串行通信是一种数据传输方式,数据一位一位地传输。常见的串行通信协议包括:
- UART(Universal Asynchronous Receiver-Transmitter):通用异步收发传输器。
- SPI(Serial Peripheral Interface):串行外设接口。
- I2C(Inter-Integrated Circuit):集成电路间总线。
2. UART(通用异步收发传输器)
2.1 UART基础知识
UART是一种异步通信协议,适用于点对点通信。其主要特点包括:
- 异步:不需要同步时钟信号。
- 波特率:传输速率,单位为bps(比特每秒)。
- 数据格式:通常包括起始位、数据位、校验位和停止位。
2.2 UART硬件连接
假设我们使用STM32F4 Discovery板,硬件连接如下:
- TX(发送):连接到目标设备的RX引脚。
- RX(接收):连接到目标设备的TX引脚。
2.3 UART软件实现
c
深色版本
#include "stm32f4xx_hal.h"
UART_HandleTypeDef huart1;
// 初始化UART
void UART1_Init(void) {
__HAL_RCC_USART1_CLK_ENABLE(); // 使能USART1时钟
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler();
}
}
// 发送数据
void UART_SendData(const char *data) {
HAL_UART_Transmit(&huart1, (uint8_t *)data, strlen(data), HAL_MAX_DELAY);
}
// 接收数据
void UART_ReceiveData(char *buffer, uint16_t size) {
HAL_UART_Receive(&huart1, (uint8_t *)buffer, size, HAL_MAX_DELAY);
}
int main(void) {
HAL_Init(); // 初始化HAL库
UART1_Init(); // 初始化UART
char send_data[] = "Hello, World!";
char receive_buffer[100];
while (1) {
UART_SendData(send_data); // 发送数据
HAL_Delay(1000); // 延时1秒
UART_ReceiveData(receive_buffer, sizeof(receive_buffer)); // 接收数据
HAL_Delay(1000); // 延时1秒
}
}
3. SPI(串行外设接口)
3.1 SPI基础知识
SPI是一种同步通信协议,适用于主从设备之间的通信。其主要特点包括:
- 同步:需要同步时钟信号。
- 全双工:可以同时发送和接收数据。
- 四线制:包括MOSI(主输出从输入)、MISO(主输入从输出)、SCLK(时钟)、SS(片选)。
3.2 SPI硬件连接
假设我们使用STM32F4 Discovery板,硬件连接如下:
- MOSI:连接到从设备的MOSI引脚。
- MISO:连接到从设备的MISO引脚。
- SCLK:连接到从设备的SCLK引脚。
- NSS:连接到从设备的NSS引脚。
3.3 SPI软件实现
c
深色版本
#include "stm32f4xx_hal.h"
SPI_HandleTypeDef hspi1;
// 初始化SPI
void SPI1_Init(void) {
__HAL_RCC_SPI1_CLK_ENABLE(); // 使能SPI1时钟
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER; // 主模式
hspi1.Init.Direction = SPI_DIRECTION_2LINES; // 全双工
hspi1.Init.DataSize = SPI_DATASIZE_8BIT; // 8位数据
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // 时钟极性低
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // 时钟相位第一个边沿
hspi1.Init.NSS = SPI_NSS_SOFT; // 软件管理NSS
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; // 波特率预分频
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; // MSB在前
hspi1.Init.TIMode = SPI_TIMODE_DISABLE; // 禁用TI模式
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // 禁用CRC校验
hspi1.Init.CRCPolynomial = 7; // CRC多项式
if (HAL_SPI_Init(&hspi1) != HAL_OK) {
Error_Handler();
}
}
// 发送数据
void SPI_SendData(const char *data, uint16_t size) {
HAL_SPI_Transmit(&hspi1, (uint8_t *)data, size, HAL_MAX_DELAY);
}
// 接收数据
void SPI_ReceiveData(char *buffer, uint16_t size) {
HAL_SPI_Receive(&hspi1, (uint8_t *)buffer, size, HAL_MAX_DELAY);
}
int main(void) {
HAL_Init(); // 初始化HAL库
SPI1_Init(); // 初始化SPI
char send_data[] = "Hello, World!";
char receive_buffer[100];
while (1) {
SPI_SendData(send_data, strlen(send_data)); // 发送数据
HAL_Delay(1000); // 延时1秒
SPI_ReceiveData(receive_buffer, sizeof(receive_buffer)); // 接收数据
HAL_Delay(1000); // 延时1秒
}
}
4. I2C(集成电路间总线)
4.1 I2C基础知识
I2C是一种同步通信协议,适用于主从设备之间的通信。其主要特点包括:
- 同步:需要同步时钟信号。
- 半双工:在同一时间内只能发送或接收数据。
- 二线制:包括SDA(数据线)和SCL(时钟线)。
4.2 I2C硬件连接
假设我们使用STM32F4 Discovery板,硬件连接如下:
- SDA:连接到从设备的SDA引脚。
- SCL:连接到从设备的SCL引脚。
4.3 I2C软件实现
c
深色版本
#include "stm32f4xx_hal.h"
I2C_HandleTypeDef hi2c1;
// 初始化I2C
void I2C1_Init(void) {
__HAL_RCC_I2C1_CLK_ENABLE(); // 使能I2C1时钟
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000; // 100kHz
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; // 50%占空比
hi2c1.Init.OwnAddress1 = 0x00; // 主设备地址
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; // 7位地址模式
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; // 禁用双地址模式
hi2c1.Init.OwnAddress2 = 0x00; // 第二个地址
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; // 禁用一般呼叫模式
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // 禁用无拉伸模式
if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
Error_Handler();
}
}
// 发送数据
void I2C_SendData(uint8_t slave_address, const char *data, uint16_t size) {
HAL_I2C_Master_Transmit(&hi2c1, slave_address << 1, (uint8_t *)data, size, HAL_MAX_DELAY);
}
// 接收数据
void I2C_ReceiveData(uint8_t slave_address, char *buffer, uint16_t size) {
HAL_I2C_Master_Receive(&hi2c1, slave_address << 1, (uint8_t *)buffer, size, HAL_MAX_DELAY);
}
int main(void) {
HAL_Init(); // 初始化HAL库
I2C1_Init(); // 初始化I2C
uint8_t slave_address = 0x50; // 从设备地址
char send_data[] = "Hello, World!";
char receive_buffer[100];
while (1) {
I2C_SendData(slave_address, send_data, strlen(send_data)); // 发送数据
HAL_Delay(1000); // 延时1秒
I2C_ReceiveData(slave_address, receive_buffer, sizeof(receive_buffer)); // 接收数据
HAL_Delay(1000); // 延时1秒
}
}
5. 实践案例
为了帮助读者更好地理解和应用所学知识,本章节将提供一些具体的实践案例,包括但不限于:
- 多协议混合使用:在一个系统中同时使用多种串行通信协议。
- 数据传输优化:提高数据传输的效率和可靠性。
- 错误处理:处理通信过程中的错误和异常情况。
5.1 多协议混合使用
假设我们需要在一个系统中同时使用UART、SPI和I2C通信协议。
c
深色版本
#include "stm32f4xx_hal.h"
UART_HandleTypeDef huart1;
SPI_HandleTypeDef hspi1;
I2C_HandleTypeDef hi2c1;
// 初始化UART
void UART1_Init(void) {
__HAL_RCC_USART1_CLK_ENABLE(); // 使能USART1时钟
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler();
}
}
// 初始化SPI
void SPI1_Init(void) {
__HAL_RCC_SPI1_CLK_ENABLE(); // 使能SPI1时钟
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER; // 主模式
hspi1.Init.Direction = SPI_DIRECTION_2LINES; // 全双工
hspi1.Init.DataSize = SPI_DATASIZE_8BIT; // 8位数据
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // 时钟极性低
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // 时钟相位第一个边沿
hspi1.Init.NSS = SPI_NSS_SOFT; // 软件管理NSS
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; // 波特率预分频
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; // MSB在前
hspi1.Init.TIMode = SPI_TIMODE_DISABLE; // 禁用TI模式
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // 禁用CRC校验
hspi1.Init.CRCPolynomial = 7; // CRC多项式
if (HAL_SPI_Init(&hspi1) != HAL_OK) {
Error_Handler();
}
}
// 初始化I2C
void I2C1_Init(void) {
__HAL_RCC_I2C1_CLK_ENABLE(); // 使能I2C1时钟
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000; // 100kHz
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; // 50%占空比
hi2c1.Init.OwnAddress1 = 0x00; // 主设备地址
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; // 7位地址模式
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; // 禁用双地址模式
hi2c1.Init.OwnAddress2 = 0x00; // 第二个地址
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; // 禁用一般呼叫模式
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // 禁用无拉伸模式
if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
Error_Handler();
}
}
// 发送数据(UART)
void UART_SendData(const char *data) {
HAL_UART_Transmit(&huart1, (uint8_t *)data, strlen(data), HAL_MAX_DELAY);
}
// 发送数据(SPI)
void SPI_SendData(const char *data, uint16_t size) {
HAL_SPI_Transmit(&hspi1, (uint8_t *)data, size, HAL_MAX_DELAY);
}
// 发送数据(I2C)
void I2C_SendData(uint8_t slave_address, const char *data, uint16_t size) {
HAL_I2C_Master_Transmit(&hi2c1, slave_address << 1, (uint8_t *)data, size, HAL_MAX_DELAY);
}
int main(void) {
HAL_Init(); // 初始化HAL库
UART1_Init(); // 初始化UART
SPI1_Init(); // 初始化SPI
I2C1_Init(); // 初始化I2C
char send_data[] = "Hello, World!";
uint8_t slave_address = 0x50; // 从设备地址
while (1) {
UART_SendData(send_data); // 发送数据(UART)
HAL_Delay(1000); // 延时1秒
SPI_SendData(send_data, strlen(send_data)); // 发送数据(SPI)
HAL_Delay(1000); // 延时1秒
I2C_SendData(slave_address, send_data, strlen(send_data)); // 发送数据(I2C)
HAL_Delay(1000); // 延时1秒
}
}
小结
通过这一章节的学习,读者将对如何使用微控制器实现不同类型的串行通信协议有一个全面的了解。掌握这些基本技能后,读者可以进一步探索更多复杂的嵌入式系统开发项目。
上一篇: 设备基于 TCP 的 MQTT 接入
下一篇: 常见物联网通信协议简介.pptx