9. 通信接口技术
9.1 串行通信
9.1.1 UART (通用异步收发传输器)
UART 是一种常用的串行通信接口,用于实现两个设备之间的异步数据传输。在 LPC1100 系列单片机中,UART 模块提供了多种配置选项,包括波特率设置、数据长度、停止位和校验位等。本节将详细介绍如何配置和使用 LPC1100 系列单片机的 UART 模块。
9.1.1.1 UART 模块配置
- 初始化 UART 模块:
- 首先需要配置 UART 的时钟源和波特率。
- 接着配置数据长度、停止位和校验位。
- 最后使能 UART 模块。
#include "LPC11xx.h"
void UART_Init(void) {
// 使能 UART 时钟
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 12); // 使能 UART 时钟
// 配置 UART 线
LPC_IOCON->P0_0 &= ~(0x07); // P0_0 为 UART_TX
LPC_IOCON->P0_0 |= (1 << 3); // 选择 UART 功能
LPC_IOCON->P0_1 &= ~(0x07); // P0_1 为 UART_RX
LPC_IOCON->P0_1 |= (1 << 3); // 选择 UART 功能
// 配置波特率
LPC_UART->LCR = 0x83; // 8 位数据,1 位停止位,无校验位,允许访问 DLL 和 DLM
LPC_UART->DLM = 0x00; // 波特率高字节
LPC_UART->DLL = 13; // 波特率低字节,9600 波特率
LPC_UART->LCR = 0x03; // 8 位数据,1 位停止位,无校验位
// 配置 FIFO
LPC_UART->FIFOCTL |= (0x01 << 6); // 使能 FIFO
LPC_UART->FIFOCTL |= (0x01 << 0); // 使能接收 FIFO
// 使能 UART
LPC_UART->UCR |= (1 << 0); // 使能接收
LPC_UART->UCR |= (1 << 1); // 使能发送
LPC_UART->UCR |= (1 << 2); // 使能 UART
}
- 发送数据:
- 使用
LPC_UART->THR
寄存器发送数据。
- 使用
void UART_SendChar(char ch) {
while (!(LPC_UART->LSR & (1 << 5))); // 等待发送缓冲区为空
LPC_UART->THR = ch; // 发送字符
}
void UART_SendString(char *str) {
while (*str) {
UART_SendChar(*str);
str++;
}
}
- 接收数据:
- 使用
LPC_UART->RBR
寄存器接收数据。
- 使用
char UART_ReceiveChar(void) {
while (!(LPC_UART->LSR & (1 << 0))); // 等待接收缓冲区非空
return LPC_UART->RBR; // 返回接收到的字符
}
void UART_ReceiveString(char *buffer, int length) {
int i;
for (i = 0; i < length; i++) {
buffer[i] = UART_ReceiveChar();
if (buffer[i] == '\0' || buffer[i] == '\n') {
break;
}
}
buffer[i] = '\0'; // 确保字符串以空字符结尾
}
9.1.2 SPI (串行外设接口)
SPI 是一种同步串行通信接口,通常用于在主设备和多个从设备之间进行高速数据传输。LPC1100 系列单片机支持多种 SPI 模式,包括主模式和从模式。本节将详细介绍如何配置和使用 LPC1100 系列单片机的 SPI 模块。
9.1.2.1 SPI 模块配置
- 初始化 SPI 模块:
- 使能 SPI 时钟。
- 配置 SPI 引脚。
- 设置 SPI 模式和波特率。
#include "LPC11xx.h"
void SPI_Init(void) {
// 使能 SPI 时钟
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 8); // 使能 SPI 时钟
// 配置 SPI 引脚
LPC_IOCON->P0_2 &= ~(0x07); // P0_2 为 SCK
LPC_IOCON->P0_2 |= (1 << 3); // 选择 SPI 功能
LPC_IOCON->P0_3 &= ~(0x07); // P0_3 为 MISO
LPC_IOCON->P0_3 |= (1 << 3); // 选择 SPI 功能
LPC_IOCON->P0_4 &= ~(0x07); // P0_4 为 MOSI
LPC_IOCON->P0_4 |= (1 << 3); // 选择 SPI 功能
LPC_IOCON->P0_5 &= ~(0x07); // P0_5 为 SS
LPC_IOCON->P0_5 |= (1 << 3); // 选择 SPI 功能
// 配置 SPI 模式
LPC_SPI->CR0 = (0 << 4) | (8 - 1); // 8 位数据长度,主模式
LPC_SPI->CR1 = (1 << 1) | (1 << 0); // 使能 SPI,主模式
// 设置波特率
LPC_SPI->DSSPBR = 128; // 设置波特率
}
- 发送和接收数据:
- 使用
LPC_SPI->DR
寄存器发送和接收数据。
- 使用
void SPI_SendChar(char ch) {
LPC_SPI->DR = ch; // 发送数据
while (!(LPC_SPI->SR & (1 << 1))); // 等待发送完成
}
char SPI_ReceiveChar(void) {
while (!(LPC_SPI->SR & (1 << 0))); // 等待接收完成
return LPC_SPI->DR; // 返回接收到的数据
}
void SPI_Transfer(char *txData, char *rxData, int length) {
int i;
for (i = 0; i < length; i++) {
SPI_SendChar(txData[i]);
rxData[i] = SPI_ReceiveChar();
}
}
9.1.3 I2C (两线式串行接口)
I2C 是一种半双工同步串行通信接口,通常用于低速通信,如与传感器或存储器通信。LPC1100 系列单片机支持 I2C 主模式和从模式。本节将详细介绍如何配置和使用 LPC1100 系列单片机的 I2C 模块。
9.1.3.1 I2C 模块配置
- 初始化 I2C 模块:
- 使能 I2C 时钟。
- 配置 I2C 引脚。
- 设置 I2C 模式和波特率。
#include "LPC11xx.h"
void I2C_Init(void) {
// 使能 I2C 时钟
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 19); // 使能 I2C 时钟
// 配置 I2C 引脚
LPC_IOCON->P0_10 &= ~(0x07); // P0_10 为 SDA
LPC_IOCON->P0_10 |= (1 << 3); // 选择 I2C 功能
LPC_IOCON->P0_11 &= ~(0x07); // P0_11 为 SCL
LPC_IOCON->P0_11 |= (1 << 3); // 选择 I2C 功能
// 配置 I2C 模式
LPC_I2C->CONSET = (1 << 2); // 使能 I2C
LPC_I2C->CONSET |= (1 << 7); // 使能主模式
// 设置波特率
LPC_I2C->CLKT = 10; // 设置 SCL 高电平时间
LPC_I2C->CLKH = 20; // 设置 SCL 低电平时间
}
- 发送和接收数据:
- 使用
LPC_I2C->DAT
寄存器发送和接收数据。
- 使用
void I2C_Start(void) {
LPC_I2C->CONSET = (1 << 0); // 产生 I2C 起始条件
while (LPC_I2C->STAT != 0x08); // 等待起始条件完成
}
void I2C_Stop(void) {
LPC_I2C->CONCLR = (1 << 4); // 产生 I2C 停止条件
}
void I2C_SendAddress(char address, char rw) {
LPC_I2C->DAT = (address << 1) | rw; // 发送地址和读写位
while (LPC_I2C->STAT != 0x18 && LPC_I2C->STAT != 0x20); // 等待地址发送完成
}
void I2C_SendByte(char data) {
LPC_I2C->DAT = data; // 发送数据
while (LPC_I2C->STAT != 0x28); // 等待数据发送完成
}
char I2C_ReceiveByte(void) {
while (LPC_I2C->STAT != 0x50); // 等待数据接收完成
return LPC_I2C->DAT; // 返回接收到的数据
}
void I2C_Write(char slaveAddress, char *data, int length) {
I2C_Start();
I2C_SendAddress(slaveAddress, 0); // 发送写地址
int i;
for (i = 0; i < length; i++) {
I2C_SendByte(data[i]);
}
I2C_Stop();
}
void I2C_Read(char slaveAddress, char *data, int length) {
I2C_Start();
I2C_SendAddress(slaveAddress, 1); // 发送读地址
int i;
for (i = 0; i < length; i++) {
data[i] = I2C_ReceiveByte();
}
I2C_Stop();
}
9.2 USB (通用串行总线)
USB 是一种通用的高速串行通信接口,广泛用于连接各种外设。LPC1100 系列单片机支持 USB 设备模式。本节将详细介绍如何配置和使用 LPC1100 系列单片机的 USB 模块。
9.2.1 USB 模块配置
- 初始化 USB 模块:
- 使能 USB 时钟。
- 配置 USB 引脚。
- 初始化 USB 设备。
#include "LPC11xx.h"
#include "lpc_usb.h"
void USB_Init(void) {
// 使能 USB 时钟
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 17); // 使能 USB 时钟
// 配置 USB 引脚
LPC_IOCON->P0_29 &= ~(0x07); // P0_29 为 USB_DM
LPC_IOCON->P0_29 |= (1 << 3); // 选择 USB 功能
LPC_IOCON->P0_30 &= ~(0x07); // P0_30 为 USB_DP
LPC_IOCON->P0_30 |= (1 << 3); // 选择 USB 功能
// 初始化 USB 设备
USB_DeviceInit();
USB_DeviceConnect();
}
- USB 数据传输:
- 使用 USB 设备库函数进行数据传输。
void USB_SendData(uint8_t *data, uint32_t length) {
USB_WriteEP(0, data, length); // 通过端点 0 发送数据
}
void USB_ReceiveData(uint8_t *data, uint32_t length) {
USB_ReadEP(0, data, length); // 通过端点 0 接收数据
}
9.2.2 USB 设备示例
- USB 设备初始化:
- 设置 USB 设备的描述符和端点。
USB_DEVICE_DESCRIPTOR deviceDesc = {
.bLength = sizeof(USB_DEVICE_DESCRIPTOR),
.bDescriptorType = USB_DESC_TYPE_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = 0xFF,
.bDeviceSubClass = 0xFF,
.bDeviceProtocol = 0xFF,
.bMaxPacketSize0 = 64,
.idVendor = 0x1FC9,
.idProduct = 0x0001,
.bcdDevice = 0x0001,
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.bNumConfigurations = 1
};
USB_CONFIGURATION_DESCRIPTOR configDesc = {
.bLength = sizeof(USB_CONFIGURATION_DESCRIPTOR),
.bDescriptorType = USB_DESC_TYPE_CONFIGURATION,
.wTotalLength = 9 + 9 + 7,
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = 0x80,
.bMaxPower = 50
};
USB_INTERFACE_DESCRIPTOR interfaceDesc = {
.bLength = sizeof(USB_INTERFACE_DESCRIPTOR),
.bDescriptorType = USB_DESC_TYPE_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 1,
.bInterfaceClass = 0xFF,
.bInterfaceSubClass = 0xFF,
.bInterfaceProtocol = 0xFF,
.iInterface = 0
};
USB_ENDPOINT_DESCRIPTOR endpointDesc = {
.bLength = sizeof(USB_ENDPOINT_DESCRIPTOR),
.bDescriptorType = USB_DESC_TYPE_ENDPOINT,
.bEndpointAddress = 0x81,
.bmAttributes = 0x03, // 中断端点
.wMaxPacketSize = 64,
.bInterval = 1
};
void USB_Setup(void) {
USB_SetDeviceDescriptor(&deviceDesc);
USB_SetConfigurationDescriptor(&configDesc);
USB_SetInterfaceDescriptor(&interfaceDesc);
USB_SetEndpointDescriptor(0, &endpointDesc);
}
- USB 数据处理:
- 处理 USB 数据的回调函数。
void USB_Endpoint0_Handler(uint8_t ep, USB_TRANS_TYPE transType, uint32_t length) {
switch (transType) {
case USB_TRANS_IN:
// 处理 IN 传输
break;
case USB_TRANS_OUT:
// 处理 OUT 传输
break;
case USB_TRANS_SETUP:
// 处理 SETUP 传输
break;
default:
break;
}
}
void USB_Data_Handler(uint8_t ep, USB_TRANS_TYPE transType, uint32_t length) {
switch (ep) {
case 0:
USB_Endpoint0_Handler(ep, transType, length);
break;
default:
break;
}
}
9.3 CAN (控制器局域网)
CAN 是一种用于汽车和工业应用的多主设备通信协议。LPC1100 系列单片机支持 CAN 通信。本节将详细介绍如何配置和使用 LPC1100 系列单片机的 CAN 模块。
9.3.1 CAN 模块配置
- 初始化 CAN 模块:
- 使能 CAN 时钟。
- 配置 CAN 引脚。
- 设置 CAN 模式和波特率。
#include "LPC11xx.h"
#include "lpc_can.h"
void CAN_Init(void) {
// 使能 CAN 时钟
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 20); // 使能 CAN 时钟
// 配置 CAN 引脚
LPC_IOCON->P0_31 &= ~(0x07); // P0_31 为 CAN_TX
LPC_IOCON->P0_31 |= (1 << 3); // 选择 CAN 功能
LPC_IOCON->P1_5 &= ~(0x07); // P1_5 为 CAN_RX
LPC_IOCON->P1_5 |= (1 << 3); // 选择 CAN 功能
// 配置 CAN 模块
CAN_InitModule(0); // 初始化 CAN 模块 0
CAN_SetBitRate(0, 500000); // 设置波特率为 500 kbps
CAN_EnableModule(0); // 使能 CAN 模块
}
- 发送 CAN 消息:
- 使用 CAN 库函数发送消息。
void CAN_SendMessage(CAN_MSG_T *msg) {
CAN_SendMsg(0, msg); // 通过 CAN 模块 0 发送消息
}
- 接收 CAN 消息:
- 使用 CAN 库函数接收消息。
void CAN_ReceiveMessage(CAN_MSG_T *msg) {
CAN_ReadMsg(0, msg); // 通过 CAN 模块 0 接收消息
}
9.3.2 CAN 消息处理
- CAN 消息结构:
- 定义 CAN 消息结构体,以便于发送和接收消息。
typedef struct {
uint32_t ID; // 消息标识符
uint8_t Len; // 数据长度
uint8_t Data[8]; // 数据
} CAN_MSG_T;
- CAN 发送示例:
- 发送一个 CAN 消息的示例代码。
void CAN_SendExample(void) {
CAN_MSG_T msg;
msg.ID = 0x123; // 消息标识符
msg.Len = 4; // 数据长度
msg.Data[0] = 0xAA; // 数据
msg.Data[1] = 0xBB;
msg.Data[2] = 0xCC;
msg.Data[3] = 0xDD;
CAN_SendMessage(&msg); // 发送消息
}
- CAN 接收示例:
- 接收一个 CAN 消息的示例代码。
void CAN_ReceiveExample(void) {
CAN_MSG_T msg;
if (CAN_MsgAvailable(0)) { // 检查是否有消息可用
CAN_ReceiveMessage(&msg); // 接收消息
// 处理接收到的消息
if (msg.ID == 0x123) {
for (int i = 0; i < msg.Len; i++) {
// 处理数据
printf("Data[%d]: 0x%02X\n", i, msg.Data[i]);
}
}
}
}
- CAN 中断处理:
- 配置 CAN 中断以处理消息接收和发送完成事件。
void CAN_IRQHandler(void) {
uint32_t status = CAN_GetStatus(0); // 获取 CAN 状态
if (status & CAN_STATUS_RI) { // 接收中断
CAN_MSG_T msg;
CAN_ReceiveMessage(&msg); // 接收消息
// 处理接收到的消息
if (msg.ID == 0x123) {
for (int i = 0; i < msg.Len; i++) {
printf("Data[%d]: 0x%02X\n", i, msg.Data[i]);
}
}
}
if (status & CAN_STATUS_TI) { // 发送中断
// 处理发送完成事件
printf("Message sent successfully\n");
}
CAN_ClearInt(0, status); // 清除中断状态
}
9.3.3 CAN 模块配置详细步骤
- 使能 CAN 时钟:
- 通过设置
LPC_SYSCON->SYSAHBCLKCTRL
寄存器来使能 CAN 模块的时钟。
- 通过设置
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 20); // 使能 CAN 时钟
- 配置 CAN 引脚:
- 通过设置
LPC_IOCON
寄存器来配置 CAN 引脚。
- 通过设置
LPC_IOCON->P0_31 &= ~(0x07); // P0_31 为 CAN_TX
LPC_IOCON->P0_31 |= (1 << 3); // 选择 CAN 功能
LPC_IOCON->P1_5 &= ~(0x07); // P1_5 为 CAN_RX
LPC_IOCON->P1_5 |= (1 << 3); // 选择 CAN 功能
- 设置 CAN 模式和波特率:
- 初始化 CAN 模块并设置波特率。
CAN_InitModule(0); // 初始化 CAN 模块 0
CAN_SetBitRate(0, 500000); // 设置波特率为 500 kbps
CAN_EnableModule(0); // 使能 CAN 模块
9.3.4 CAN 模块使用注意事项
-
波特率设置:
- 确保波特率设置正确,以匹配通信双方的要求。LPC1100 系列单片机支持多种波特率设置,包括 500 kbps、250 kbps 等。
-
消息过滤:
- CAN 模块支持消息过滤功能,可以通过配置消息接受过滤器来接收特定标识符的消息。
-
中断配置:
- 为了及时处理 CAN 事件,建议配置 CAN 中断。通过设置
LPC_CAN->CTRL
寄存器中的相应位来使能中断。
- 为了及时处理 CAN 事件,建议配置 CAN 中断。通过设置
-
错误处理:
- CAN 通信中可能会出现错误,可以通过检查
LPC_CAN->STATUS
寄存器来获取错误状态,并进行相应的处理。
- CAN 通信中可能会出现错误,可以通过检查
9.3.5 CAN 模块示例应用
- 汽车传感器数据传输:
- 使用 CAN 模块在汽车中的多个传感器之间传输数据。
void CarSensorDataTransmission(void) {
CAN_MSG_T sensorData;
uint32_t sensorID = 0x100; // 传感器标识符
uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; // 传感器数据
sensorData.ID = sensorID;
sensorData.Len = 4;
memcpy(sensorData.Data, data, 4);
CAN_SendMessage(&sensorData); // 发送传感器数据
// 接收其他传感器的数据
CAN_ReceiveExample();
}
- 工业控制设备通信:
- 使用 CAN 模块在工业控制设备之间进行通信。
void IndustrialDeviceCommunication(void) {
CAN_MSG_T controlData;
uint32_t deviceID = 0x200; // 控制设备标识符
uint8_t commandData[4] = {0x01, 0x02, 0x03, 0x04}; // 控制命令数据
controlData.ID = deviceID;
controlData.Len = 4;
memcpy(controlData.Data, commandData, 4);
CAN_SendMessage(&controlData); // 发送控制命令
// 接收设备的响应数据
CAN_ReceiveExample();
}
9.4 总结
本章详细介绍了 LPC1100 系列单片机的串行通信接口技术,包括 UART、SPI、I2C 和 USB 模块的配置和使用方法。通过这些接口,可以实现单片机与各种外设之间的数据传输。每种通信接口都有其特点和适用场景,选择合适的通信接口可以提高系统的性能和可靠性。
- UART:适用于简单的异步串行通信,如与串行终端或传感器通信。
- SPI:适用于高速同步通信,如与外设存储器或传感器通信。
- I2C:适用于低速同步通信,如与传感器或存储器通信。
- USB:适用于高速通用通信,广泛用于连接各种外设。
在实际应用中,根据具体需求选择合适的通信接口,并进行相应的配置和编程。希望本章的内容对读者在使用 LPC1100 系列单片机进行串行通信时有所帮助。