网站建设目标定位,中信建设有限责任公司经济性质,前端优化,枣庄手机网站建设公司一.IIC传输数据的格式 1.写操作 2.读操作 3.IIC信号 二. IIC底层驱动 1.重新初始化配置延时单元
//软件延时
void I2C_Delay(uint32_t t)
{volatile uint32_t tmp t;while(tmp--);
}void I2C_GPIO_ReInit(void)
{/* 1. 使用结构体定义硬件GPIO对象 */GPIO_InitTypeDef GPIO…
一.IIC传输数据的格式 1.写操作 2.读操作 3.IIC信号 二. IIC底层驱动 1.重新初始化配置延时单元
//软件延时
void I2C_Delay(uint32_t t)
{volatile uint32_t tmp t;while(tmp--);
}void I2C_GPIO_ReInit(void)
{/* 1. 使用结构体定义硬件GPIO对象 */GPIO_InitTypeDef GPIO_InitStruct {0};/* 2. 将SCL和SDA的GPIO寄存器的值恢复为复位上电值 */HAL_GPIO_DeInit(SCL_PORT, SCL_PIN);HAL_GPIO_DeInit(SDA_PORT, SDA_PIN);/* 3. 使能SCL和SDA的GPIO的时钟因为他们都是GPIOF组的所以这里只使能GPIOF的时钟 */__HAL_RCC_GPIOF_CLK_ENABLE();/* 4. 设置GPIO的模式为开漏输出模式响应速度设置为快速响应 */GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pin SCL_PIN; HAL_GPIO_Init(SCL_PORT, GPIO_InitStruct);GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pin SDA_PIN;HAL_GPIO_Init(SDA_PORT, GPIO_InitStruct);
} 2.配置开始和结束信号 void I2C_Start(void)
{SCL_H;SDA_H;I2C_Delay(100);SDA_L;I2C_Delay(100);
}void I2C_Stop(void)
{SDA_L;SCL_H;I2C_Delay(100);SDA_H;I2C_Delay(100);
}
3.从机接收应答位成功得到响应返回0否则返回-1
接收应答前要先将SDA拉高 int I2C_GetAck(void)
{int i 0;SCL_L;SDA_H;//释放控制权I2C_Delay(100);SCL_H;while(SDA_IN ! 0){i;if(i 100)//防止超时{SCL_L;return -1;}I2C_Delay(10);}SCL_L;return 0;
}
4.主机发送应答和非应答 void I2C_ACK(void)
{SCL_L;SDA_L;I2C_Delay(100);SCL_H;I2C_Delay(100);
}
void I2C_NACK(void)
{SCL_L;SDA_H;I2C_Delay(100);SCL_H;I2C_Delay(100);
}
5.发送字节 void I2C_WriteByte(uint8_t data)
{uint8_t i 0;for(i0; i8; i){SCL_L;I2C_Delay(100);if(data 0x80){SDA_H;}else{SDA_L;}data 1; // 发出1bit数据后要更新数据将data的次高位移位到最高位SCL_H;I2C_Delay(100);}I2C_GetAck();
}
6.接收字节 uint8_t I2C_ReadByte(uint8_t ack)
{uint8_t i 0;uint8_t data 0;SDA_H;for(i0; i8; i){SCL_L;I2C_Delay(100);SCL_H;I2C_Delay(100);data 1; // 更新数据前要将上一次数据左移1位用来保存接下来的这一位数据if(SDA_IN 1) { data;}else{data data;}}// 根据ack决定是否发出应答if(ack 0){I2C_ACK();}else if(ack 1){I2C_NACK();}return data;
}
三.IIC所有代码
#define SCL_PIN GPIO_PIN_6
#define SDA_PIN GPIO_PIN_7#define SCL_PORT GPIOB
#define SDA_PORT GPIOB/********************** 函数宏定义
**********************/
#define SCL_H HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, 1)
#define SCL_L HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, 0)#define SDA_H HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, 1)
#define SDA_L HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, 0)
#define SDA_IN HAL_GPIO_ReadPin(SDA_PORT, SDA_PIN)/** 函数名I2C_GPIO_ReInit* 功能描述将模拟I2C的SCL和SDA引脚进行重新初始化* 输入参数无* 输出参数无* 返回值无
*/
extern void I2C_GPIO_ReInit(void);/** 函数名I2C_Start* 功能描述模拟发出I2C的开始信号--在SCL的高电平下SDA的电平由高到低变化* 输入参数无* 输出参数无* 返回值无
*/
extern void I2C_Start(void);/** 函数名I2C_Stop* 功能描述模拟发出I2C的停止信号--在SCL的高电平下SDA的电平由低到高变化* 输入参数无* 输出参数无* 返回值无
*/
extern void I2C_Stop(void);/** 函数名I2C_GetAck* 功能描述模拟I2C获取从设备的响应信号--在SCL的高电平下从设备将SDA拉低* 输入参数无* 输出参数无* 返回值成功得到响应返回0否则返回-1
*/
extern int I2C_GetAck(void);/** 函数名I2C_ACK* 功能描述模拟I2C发出一个应答信号在第九个时钟将SDA拉低* 输入参数无* 输出参数无* 返回值无
*/
extern void I2C_ACK(void);/** 函数名I2C_NACK* 功能描述模拟I2C发出一个非应答信号在第九个时钟将SDA拉高* 输入参数无* 输出参数无* 返回值无
*/
extern void I2C_NACK(void);/** 函数名I2C_WriteByte* 功能描述模拟I2C发出一个字节的数据* 输入参数data--要发送出去的数据范围0~255* 输出参数无* 返回值无
*/
extern void I2C_WriteByte(uint8_t data);/** 函数名I2C_ReadByte* 返回值返回读取到的数据* 输入参数ack--根据此参数判断在读到一个字节之后是否发出应答信号* 输出参数无
*/
extern uint8_t I2C_ReadByte(uint8_t ack);#endif /* __DRIVER_I2C_H */
void I2C_Delay(uint32_t t)
{volatile uint32_t tmp t;while(tmp--);
}/** 函数名I2C_GPIO_ReInit* 功能描述将模拟I2C的SCL和SDA引脚进行重新初始化* 输入参数无* 输出参数无* 返回值无
*/
void I2C_GPIO_ReInit(void)
{/* 1. 使用结构体定义硬件GPIO对象 */GPIO_InitTypeDef GPIO_InitStruct {0};/* 2. 将SCL和SDA的GPIO寄存器的值恢复为复位上电值 */HAL_GPIO_DeInit(SCL_PORT, SCL_PIN);HAL_GPIO_DeInit(SDA_PORT, SDA_PIN);/* 3. 使能SCL和SDA的GPIO的时钟因为他们都是GPIOF组的所以这里只使能GPIOF的时钟 */__HAL_RCC_GPIOF_CLK_ENABLE();/* 4. 设置GPIO的模式为开漏输出模式响应速度设置为快速响应 */GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH;/* 5. 选择要设置的GPIO引脚 */GPIO_InitStruct.Pin SCL_PIN;/* 6. 调用init函数初始化GPIO */HAL_GPIO_Init(SCL_PORT, GPIO_InitStruct);GPIO_InitStruct.Pin SDA_PIN;HAL_GPIO_Init(SDA_PORT, GPIO_InitStruct);
}/** 函数名I2C_Start* 功能描述模拟发出I2C的开始信号--在SCL的高电平下SDA的电平由高到低变化* 输入参数无* 输出参数无* 返回值无
*/
void I2C_Start(void)
{SCL_H;SDA_H;I2C_Delay(100);SDA_L;I2C_Delay(100);
}/** 函数名I2C_Stop* 功能描述模拟发出I2C的停止信号--在SCL的高电平下SDA的电平由低到高变化* 输入参数无* 输出参数无* 返回值无
*/
void I2C_Stop(void)
{SDA_L;SCL_H;I2C_Delay(100);SDA_H;I2C_Delay(100);
}/** 函数名I2C_GetAck* 功能描述模拟I2C获取从设备的响应信号--在SCL的高电平下从设备将SDA拉低* 输入参数无* 输出参数无* 返回值成功得到响应返回0否则返回-1
*/
int I2C_GetAck(void)
{int i 0;SCL_L;SDA_H;I2C_Delay(100);SCL_H;while(SDA_IN ! 0){i;if(i 100){SCL_L;return -1;}I2C_Delay(10);}SCL_L;return 0;
}/** 函数名I2C_ACK* 功能描述模拟I2C发出一个应答信号在第九个时钟将SDA拉低* 输入参数无* 输出参数无* 返回值无
*/
void I2C_ACK(void)
{SCL_L;SDA_L;I2C_Delay(100);SCL_H;I2C_Delay(100);
}/** 函数名I2C_NACK* 功能描述模拟I2C发出一个非应答信号在第九个时钟将SDA拉高* 输入参数无* 输出参数无* 返回值无
*/
void I2C_NACK(void)
{SCL_L;SDA_H;I2C_Delay(100);SCL_H;I2C_Delay(100);
}/** 函数名I2C_WriteByte* 功能描述模拟I2C发出一个字节的数据* 输入参数data--要发送出去的数据范围0~255* 输出参数无* 返回值无
*/
void I2C_WriteByte(uint8_t data)
{uint8_t i 0;for(i0; i8; i){SCL_L;I2C_Delay(100);if(data 0x80){SDA_H;}else{SDA_L;}data 1; // 发出1bit数据后要更新数据将data的次高位移位到最高位SCL_H;I2C_Delay(100);}I2C_GetAck();
}/** 函数名I2C_ReadByte* 返回值返回读取到的数据* 输入参数ack--根据此参数判断在读到一个字节之后是否发出应答信号* 输出参数无
*/
uint8_t I2C_ReadByte(uint8_t ack)
{uint8_t i 0;uint8_t data 0;SDA_H;for(i0; i8; i){SCL_L;I2C_Delay(100);SCL_H;I2C_Delay(100);data 1; // 更新数据前要将上一次数据左移1位用来保存接下来的这一位数据if(SDA_IN 1) { data;}else{data data;}}// 根据ack决定是否发出应答if(ack 0){I2C_ACK();}else if(ack 1){I2C_NACK();}return data;
}
四.SSD1306
1.特点 2.SSD1306设备地址 R/W#1, it is in read mode. R/W#0, it is in write mode. 0111 1000 0x78 写数据时的设备地址 0111 1000 0x79 读数据时的设备地址 // 第一种分别定义读写设备地址
#define OLED_WRITE_ADDR 0x78
#define OLED_READ_ADDR 0x79// 第二种定义基础地址通过改变读写位来改变地址
#define OLED_ADDR 0x78
#define OLED_WRITE 0x00
#define OLED_READ 0x01 3.SSD1306总线格式 3.1发送命令
void OLED_WriteCmd(uint8_t cmd)
{I2C_Start();I2C_WriteByte(OLED_WRITE_ADDR);//发送设备地址// I2C_WriteByte(OLED_ADDR | OLED_WRITE);I2C_WriteByte(0x00);//发送控制字节0x00I2C_WriteByte(cmd);//发送命令I2C_Stop();//停止
}
3.2发送数据
void OLED_WriteData(uint8_t data)
{I2C_Start();I2C_WriteByte(OLED_WRITE_ADDR);//发送设备地址// I2C_WriteByte(OLED_ADDR | OLED_WRITE);I2C_WriteByte(0x40);I2C_WriteByte(data);I2C_Stop();
}
3.3发送一组数据
void OLED_WriteNBytes(uint8_t *buf, uint16_t length)
{uint16_t i 0;if(buf NULL) return;I2C_Start();I2C_WriteByte(OLED_WRITE_ADDR);I2C_WriteByte(0x40);for(i0; ilength; i){I2C_WriteByte(buf[i]);}I2C_Stop();
}
4.显示到屏幕原理 内部显存GDDRAM,被分成8个页从PAGE0-PAGE7,每一个PAGE有128列可以保存128X64的数据数据会保存到从每一页的顶行到末行读到某个位为0时是不会显示亮度的。 5.显存数据
页地址模式(Page) 在页地址模式下当往显存里面写入数据后列地址指针会自动递增1。设置好起始页和起始列之后 就可以连续发送数据而不用 每发送一个数据就去指定一个 页和列的地址了如果列地址指针递增到了设置的结束列地址那么列地址指针就会复位回到设置的起始列地址而页地址指针是不会有变化的。为了访问下一页显存中的内容用户必须设置新的页和列的起始地址。 static MEM_MODE mem_mode PAGE_ADDR_MODE; // 静态局部变量保存OLED的地址模式的//发送命令0xB0-0xB7设置图像显示位置的起始页地址
void OLED_SetPageAddr_PAGE(uint8_t addr)
{if(mem_mode ! PAGE_ADDR_MODE) return;if(addr 7) return;OLED_WriteCmd(0xB0 addr);
}//发送命令0x00-0x0F设置图像显示位置的起始地址的低四位
//发送命令0x10-0x1F设置图像显示位置的起始地址的高四位
void OLED_SetColAddr_PAGE(uint8_t addr)
{if(mem_mode ! PAGE_ADDR_MODE) return;if(addr 0x7F) return;OLED_WriteCmd(0x00 (addr 0x0F));OLED_WriteCmd(0x10 (addr4));
}//封装成一个函数
void OLED_SetPosition(uint8_t page, uint8_t col)
{OLED_SetPageAddr_PAGE(page);OLED_SetColAddr_PAGE(col);
} 6.基础命令函数 1.Set Contrast Control(设置对比度)
要发送两个命令先发送0x81后面又要发送A[7:0]这个字节是个带参的函数对于带参函数要进行合法性检测。这里定义的都是uint8_t类型可以不检测。
void OLED_SetContrastValue(uint8_t Value)
{OLED_WriteCmd(0x81);OLED_WriteCmd(Value);
} 2.Entire Display ON (全屏显示) 设置命令0xA5全屏点亮设置命令0xA4熄灭
#define ENTIRE_DISP_ON() OLED_WriteCmd(0xA5)
#define ENTIRE_DISP_OFF() OLED_WriteCmd(0xA4) 3.Set Normal/Inverse Display(设置正常/反向显示)
对于数据是逻辑1发光显示还是逻辑0发光显示。 //阴码显示或者阳码显示
#define DISP_NORMAL() OLED_WriteCmd(0xA6)
#define DISP_INVERSE() OLED_WriteCmd(0xA7) 4.Set Display ON/OFF(设置显示打开/关闭) //打开显示或者关闭显示
#define DISP_ON() OLED_WriteCmd(0xAF)
#define DISP_OFF() OLED_WriteCmd(0xAE) 7.滚动命令功能函数
1.Continuous Horizontal Scroll Setup(水平方向左/右滚动) typedef enum
{H_RIGHT 0x26,H_LEFT 0x27,
}H_SCROLL_DIR; // 水平滚动方向void OLED_H_Scroll(H_SCROLL_DIR dir,uint8_t start, uint8_t fr_time, uint8_t end)
{//合法性检测,数量不一定满足0-7个if((dir!H_RIGHT)(dir!H_LEFT)) return;if(start0x07||fr_time0x07||end0x07) return;OLED_WriteCmd(dir);OLED_WriteCmd(0x00);OLED_WriteCmd(start);OLED_WriteCmd(fr_time);OLED_WriteCmd(end);OLED_WriteCmd(0x00);OLED_WriteCmd(0xFF);
} 2.Continuous Vertical and Horizontal Scroll Setup(垂直方向左右滚动设置) typedef enum
{HV_RIGHT 0x29,HV_LEFT 0x2A,
}HV_SCROLL_DIR; // 水平和垂直滚动的方向void OLED_HV_Scroll(HV_SCROLL_DIR dir, uint8_t start, uint8_t fr_time, uint8_t end, uint8_t offset)
{if((dir!HV_RIGHT)(dir!HV_LEFT)) return;if(start0x07||fr_time0x07||end0x07||offset0x3F) return; OLED_WriteCmd(dir);OLED_WriteCmd(0x00);OLED_WriteCmd(start);OLED_WriteCmd(fr_time);OLED_WriteCmd(end);OLED_WriteCmd(offset);
} 3.开始/结束滚动 //开始或者停止滚动
#define SCROLL_ON() OLED_WriteCmd(0x2F)
#define SCROLL_OFF() OLED_WriteCmd(0x2E) 4.Set Vertical Scroll Area(设置垂直滚动区域) void OLED_SetVScrollArea(uint8_t area, uint8_t row_num)
{if((area0x3F) || (row_num0x7F))return;OLED_WriteCmd(0xA3);OLED_WriteCmd(area);OLED_WriteCmd(row_num);
} 8.寻址设置命令表 typedef enum
{H_ADDR_MODE 0, // 水平地址模式V_ADDR_MODE 1, // 垂直地址模式PAGE_ADDR_MODE 2, // 页地址模式
}MEM_MODE; // 内存地址模式static MEM_MODE mem_mode PAGE_ADDR_MODE; // 静态局部变量保存OLED的地址模式的
1.设置OLED在页地址模式下的显示起始column地址 void OLED_SetColAddr_PAGE(uint8_t addr)
{//先要判断当前的地址是否是页地址模式if(mem_mode ! PAGE_ADDR_MODE) return;if(addr 0x7F) return;OLED_WriteCmd(0x00 (addr 0x0F));OLED_WriteCmd(0x10 (addr4));
} 2.Set Memory Addressing Mode(设置内存寻址模式) void OLED_SetMemAddrMode(MEM_MODE mode)
{if((mode ! H_ADDR_MODE) (mode ! V_ADDR_MODE) (mode ! PAGE_ADDR_MODE)) return;OLED_WriteCmd(0x20);OLED_WriteCmd(mode);mem_mode mode;
}3.Set Column Address(在水平和垂直模式下的起始column地址和终止column地址) void OLED_SetColAddr_HV(uint8_t start, uint8_t end)
{if(mem_mode PAGE_ADDR_MODE) return;if((start 127) || (end 127)) return;OLED_WriteCmd(0x21);OLED_WriteCmd(start);OLED_WriteCmd(end);
}
4.分别在水平垂直模式和页地址模式的起始页地址和结束页地址 //函数名OLED_SetPageAddr_HV
//功能描述设置OLED在水平地址模式或垂直地址模式下像素显示的起始页地址和结束页地址
void OLED_SetPageAddr_HV(uint8_t start, uint8_t end)
{if(mem_mode PAGE_ADDR_MODE) return;if((start 7) || (end 7)) return; OLED_WriteCmd(0x22);OLED_WriteCmd(start);OLED_WriteCmd(end);
}// 函数名OLED_SetPageAddr_PAGE
//功能描述设置OLED在页地址模式下的显示起始页地址
void OLED_SetPageAddr_PAGE(uint8_t addr)
{if(mem_mode ! PAGE_ADDR_MODE) return;if(addr 7) return;OLED_WriteCmd(0xB0 addr);
} 9.硬件配置功能函数