前言
最近也是秋招收到 offer 了,嵌软方向,本地企业,于是闲的没事干在学校开摆,顺便提升下代码水平。
于是首当其冲的就是指针和面向对象思维,emmmm 怎么说呢,这方面蛮薄弱的,于是刚学了一点结构体指针的皮毛,结合之前比赛因为用了许多 I2C 设备而多次反复的初始化 GPIO 口的麻烦,尝试了下把 I2C 面向对象化,顺便复习下 I2C。
1. 面向对象核心思想和 C 语言的实现
众所周知,向对象编程(Object-Oriented Programming,OOP)是一种通过抽象和封装来提高代码复用性和可维护性的编程范式,但是 C 语言他原生是面向过程语言,并未向 Python 和 Java 那样原生支持面向对象的特性。
C 语言的精髓和核心是指针,通过指针直接操作内存,可以实现很多骚操作;加上 C 语言的 struct 结构体,以及 typedef 自定义类型,从而实现模拟类和对象;又因结构体支持结构体的嵌套,因此可以实现基于嵌套意义的类和方法继承;进而实现面向对象的思想和全部功能。
1-1. 面向对象的核心思想
面向对象编程的核心包括以下几方面:
1-2. 在 C 语言中模拟面向对象的方法
虽然 C 语言本身不支持类和对象,但可以通过结构体和函数指针模拟这些特性:
但由于 C 是为面向过程设计的,本质上仍然是面向过程的语言,因此类方法必须严格按照面向过程的顺序。
结构体实现封装
结构体(struct
)是 C 语言中组织数据的核心工具。可以在结构体中包含数据和函数指针,从而将操作封装为模块化的对象。
函数指针实现多态
通过在结构体中嵌入函数指针,可以动态绑定不同对象的行为。例如,不同设备可以通过函数指针调用各自的初始化和操作方法。
嵌套结构体模拟继承
使用嵌套的方式,使一个结构体拥有另一个结构体的成员,达到继承属性和方法的效果。
2. I2C——Inter-Integrated Circuit 集成电路总线
2.1. I2C 总线特性
I2C 是一种广泛应用于嵌入式系统的串行通信协议,采用主从结构,通过两线完成数据传输。
2.2. I2C 通讯基本过程
- 启动条件(Start):主机拉低 SDA 并拉高 SCL。
- 地址传输:主机发送从设备地址,等待应答。
- 数据读写:按字节传输数据,每字节后需要应答信号。
- 停止条件(Stop):主机拉低 SCL 后拉高 SDA。
3. 代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #ifndef __I2C_H__ #define __I2C_H__
#include "stm32f10x.h"
typedef struct SoftI2C_t{ GPIO_TypeDef *SCL_Port; uint16_t SCL_Pin; GPIO_TypeDef *SDA_Port; uint16_t SDA_Pin; uint32_t Delay;
void(*Start)(struct SoftI2C_t *self); void(*Stop)(struct SoftI2C_t *self); uint8_t(*WriteByte)(struct SoftI2C_t *self, uint8_t byte); uint8_t(*ReadByte)(struct SoftI2C_t *self, uint8_t ack);
} SoftI2C_t;
void SoftI2C_Init(SoftI2C_t *self);
#endif
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
| #include "I2C.h"
#define SCL_HIGH(self) GPIO_SetBits((self)->SCL_Port, (self)->SCL_Pin) #define SCL_LOW(self) GPIO_ResetBits((self)->SCL_Port, (self)->SCL_Pin) #define SDA_HIGH(self) GPIO_SetBits((self)->SDA_Port, (self)->SDA_Pin) #define SDA_LOW(self) GPIO_ResetBits((self)->SDA_Port, (self)->SDA_Pin) #define SDA_READ(self) GPIO_ReadInputDataBit((self)->SDA_Port, (self)->SDA_Pin)
static void _SoftI2C_Delay(SoftI2C_t *self) { if (!self->Delay){ return ; } SysTick->LOAD = 72 * (self->Delay); SysTick->VAL = 0x00; SysTick->CTRL = 0x00000005; while(!(SysTick->CTRL & 0x00010000)); SysTick->CTRL = 0x00000004; }
static void _SoftI2C_GPIO_Init(SoftI2C_t *self) {
if (self->SCL_Port == GPIOB || self->SDA_Port == GPIOB) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); } if (self->SCL_Port == GPIOA || self->SDA_Port == GPIOA) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); }
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = self->SCL_Pin; GPIO_Init(self->SCL_Port, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = self->SDA_Pin; GPIO_Init(self->SDA_Port, &GPIO_InitStructure);
SDA_HIGH(self); SCL_HIGH(self); } static void SoftI2C_Start(SoftI2C_t *self) { SDA_HIGH(self); SCL_HIGH(self); _SoftI2C_Delay(self); SDA_LOW(self); _SoftI2C_Delay(self); SCL_LOW(self); }
static void SoftI2C_Stop(SoftI2C_t *self) { SCL_LOW(self); SDA_LOW(self); _SoftI2C_Delay(self); SCL_HIGH(self); SDA_HIGH(self); _SoftI2C_Delay(self); }
static uint8_t SoftI2C_WriteByte(SoftI2C_t *self, uint8_t byte) { uint8_t ack = 0; for (uint8_t i = 0; i < 8; i++) { if (byte & 0x80) { SDA_HIGH(self); } else { SDA_LOW(self); } byte <<= 1; SCL_HIGH(self); _SoftI2C_Delay(self); SCL_LOW(self); _SoftI2C_Delay(self); }
SDA_HIGH(self); SCL_HIGH(self); _SoftI2C_Delay(self); ack = !SDA_READ(self); _SoftI2C_Delay(self); SCL_LOW(self);
return ack; }
static uint8_t SoftI2C_ReadByte(SoftI2C_t *self, uint8_t ack) { uint8_t byte = 0; SDA_HIGH(self); for (uint8_t i = 0; i < 8; i++){ byte <<= 1; SCL_HIGH(self); _SoftI2C_Delay(self); if (SDA_READ(self)){ byte |= 0x01; } SCL_LOW(self); _SoftI2C_Delay(self); } if (ack){ SDA_LOW(self); }else{ SDA_HIGH(self); } SCL_HIGH(self); _SoftI2C_Delay(self); SCL_LOW(self); SDA_HIGH(self); return byte; }
void SoftI2C_Init(SoftI2C_t *self) { _SoftI2C_GPIO_Init(self);
self->Start = SoftI2C_Start; self->Stop = SoftI2C_Stop; self->WriteByte = SoftI2C_WriteByte; self->ReadByte = SoftI2C_ReadByte; }
|