C语言与硬件交互:从GPIO到中断的嵌入式编程实践
一、引言
C语言因其高效性、灵活性和接近硬件底层的能力,成为嵌入式系统开发的首选语言。在嵌入式开发中,程序员需要直接与硬件打交道,通过寄存器操作、中断处理和外设驱动等方式控制硬件设备。本文将从GPIO、定时器、中断等基础硬件交互入手,全面介绍C语言在嵌入式系统中的编程实践。
二、嵌入式C语言基础
2.1 硬件抽象层
在嵌入式开发中,硬件抽象层(HAL)是连接软件和硬件的桥梁。通过HAL,程序员可以使用统一的API操作不同的硬件设备。
```c
// 硬件抽象层示例
typedef struct {
void (*init)(void);
void (*write)(uint8_t data);
uint8_t (*read)(void);
void (*set_baud_rate)(uint32_t baud_rate);
} UART_Interface;
// 具体的UART实现
typedef struct {
volatile uint32_t* base_address;
uint32_t baud_rate;
} UART_Device;
void uart_init(void* device) {
UART_Device* uart = (UART_Device*)device;
// 初始化UART硬件
// 设置波特率、数据位、停止位等
}
void uart_write(void* device, uint8_t data) {
UART_Device* uart = (UART_Device*)device;
// 等待发送缓冲区空
while (!(UART_TX_READY(uart->base_address)));
// 发送数据
UART_TX_DATA(uart->base_address) = data;
}
uint8_t uart_read(void* device) {
UART_Device* uart = (UART_Device*)device;
// 等待接收缓冲区满
while (!(UART_RX_READY(uart->base_address)));
// 读取数据
return UART_RX_DATA(uart->base_address);
}
```
2.2 寄存器操作
嵌入式系统中的硬件设备通常通过寄存器进行控制。C语言通过指针可以直接访问这些寄存器。
```c
// 寄存器操作基础
#define REGISTER_BASE(addr) (*(volatile uint32_t*)(addr))
// GPIO寄存器定义示例(以STM32为例)
typedef struct {
volatile uint32_t MODER; // 模式寄存器
volatile uint32_t OTYPER; // 输出类型寄存器
volatile uint32_t OSPEEDR; // 输出速度寄存器
volatile uint32_t PUPDR; // 上拉下拉寄存器
volatile uint32_t IDR; // 输入数据寄存器
volatile uint32_t ODR; // 输出数据寄存器
volatile uint32_t BSRR; // 位设置/复位寄存器
volatile uint32_t LCKR; // 锁定寄存器
volatile uint32_t AFR2; // 复用功能寄存器
} GPIO_TypeDef;
// GPIO基地址定义
#define GPIOA_BASE 0x40020000
#define GPIOB_BASE 0x40020400
#define GPIOC_BASE 0x40020800
// GPIO实例定义
#define GPIOA ((GPIO_TypeDef*)GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef*)GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef*)GPIOC_BASE)
// 寄存器操作宏
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define MODIFY_REG(REG, MASK, VALUE) ((REG) = ((REG) & ~(MASK)) | ((VALUE) & (MASK)))
```
三、GPIO编程
3.1 GPIO基础操作
GPIO(通用输入输出)是嵌入式系统中最基础的外设,用于控制数字信号的输入和输出。
```c
// GPIO初始化
void GPIO_Init(GPIO_TypeDef* GPIOx, uint32_t pin, uint32_t mode) {
// 清除引脚配置
GPIOx->MODER &= ~(0x3 << (pin * 2));
// 设置引脚模式
GPIOx->MODER |= (mode << (pin * 2));
}
// GPIO输出设置
void GPIO_SetPin(GPIO_TypeDef* GPIOx, uint32_t pin) {
GPIOx->BSRR = (1 << pin); // 设置引脚高电平
}
void GPIO_ResetPin(GPIO_TypeDef* GPIOx, uint32_t pin) {
GPIOx->BSRR = (1 << (pin + 16)); // 设置引脚低电平
}
void GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint32_t pin) {
GPIOx->ODR ^= (1 << pin); // 翻转引脚状态
}
// GPIO输入读取
uint32_t GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint32_t pin) {
return (GPIOx->IDR >> pin) & 1;
}
// GPIO模式定义
#define GPIO_MODE_INPUT 0x00
#define GPIO_MODE_OUTPUT 0x01
#define GPIO_MODE_AF 0x02
#define GPIO_MODE_ANALOG 0x03