IIC设备驱动程序
51单片机的I2C底层驱动程序(IO口模拟)

51单片机的I2C底层驱动程序(IO口模拟)/*Title:I2C for 80C51Author:yuyouliang51单片机(本人使用STC89C52单片机,12T模式)的I2C驱动程序,使用逻辑分析仪对该协议进行分析,发现波形比较美观,SCL 的频率在70KHz左右(11.0592M晶振),低于标准的100K,可以适应大多数的I2C器件。
如果感觉速度过快或过慢,可以自行修改延时。
希望可以给读者一个参考,给读者一些帮助!*//*i2c.h文件 */#ifndef __I2C_H_#define __I2C_H_sbit SCL = P2^1;sbit SDA = P2^0;void start_i2c(); //启动I2C总线:SCL高电平期间,SDA由高变低void stop_i2c(); //停止I2C总线:SCL高电平期间,SDA由低变高void send_i2c(unsigned char c); //主机发送一个字节,先发送最高位unsigned char receive_i2c(); //主机接收一个字节,先接收最高位void master_ack(bit ack); //主机非应答信号(填参数0)或应答信号(填参数1)void slave_ack(); //等待从机应答信号#endif/* i2c.c文件 */#include#include#include#define nop() _nop_()void start_i2c() //启动I2C总线:SCL高电平期间,SDA由高变低{SDA=1;SCL=1;nop();nop();nop();nop();SDA=0;SCL=0;}void stop_i2c() //停止I2C总线,SCL高电平期间,SDA由低变高{SDA=0;SCL=1;nop();nop();nop();nop();SDA=1;}void slave_ack() //等待从机应答信号,如果从机迟迟没有应答,则结束总线。
Linux下I2C驱动介绍

1、I2C概述I2C是philips公司提供的外设总线,I2C有两条数据线,一条是串行数据线SDA、一条是时钟线SCL,使用SDA和SCL实现了数据的交换,便于布线。
I2C总线方便用在EEPROM、实时钟、小型LCD等与CPU外部的接口上。
2、Linux下的驱动思路Linux系统下编写I2c驱动主要有两种方法:一种是把I2C当做普通字符设备来使用;另一种利用Linux下驱动的体系结构来实现。
第一种方法:优点:思路比较直接,不用花费大量时间去了解Linux系统下I2C体系结构缺点:不仅对I2C设备操作要了解,还有了解I2C的适配器操作不仅对I2C设备器和设备操作需要了解,编写的驱动移植性差,内核提供的I2C设备器都没有用上。
第二种方法:第一种的优点就是第二种的缺点,第一种的缺点就是第二种的优点。
3、I2C框架概述Linux的I2C体系结构分为3部分:1)I2C核心I2C核心提供了I2C总线驱动和设备驱动的注册和注销的方法,I2C 通信方法(algorithm)上层,与具体适配器无关的代码,检测设备上层的代码等。
2)I2C总线驱动I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可以直接受CPU来控制。
3)I2C设备驱动I2C设备驱动是对I2C硬件体系结构中设备端的实现,设备端挂在受CPU控制的适配器上,通过I2C适配器与CPU交换数据。
Linux下的I2C体系结构:1)Linux下的I2C体系结构4、I2C设备驱动编写方法首先让我们明白适配器驱动的作用是让我们能够通过它发出标准的I2C时序,在linux内核源代码中driver/I2C/buss包含一些适配器的驱动,例如s3c2410的驱动I2C-s3c2410.c,适配器被加载到内核中,接下的任务就是实现设备驱动的编写。
编写设备驱动的方法主要分为两种方法:第一种:利用设备提供的I2C-dev.c来实现I2C适配器设备文件,然后通过上层应用程序来操作I2C设备器来控制I2C设备。
基于ARMLinux下IIC设备驱动程序设计与实现

具有免费 、 开放源代 、 强大的 网络功 能等特点 , 在嵌入式产 品中 正在得 到广泛 的应 用。本文主要研 究 A MLnx系 统 I R i u I 备 C设 驱动程序 的设计方法 。
多个从 机 , 每个从机都有一个 唯一 的地址 。 主机负 责 I I C总线 的初始化 、 数据传 输 、 产生 时钟信 号等工 作 。I I c总线传 输 的时序 是 : S A T( 从 T R 开始 位 ) 开始 传输 , SO ( T P 结束位 ) 结束传输。传送 到 S A上 的每一个字 节必须是 D 8位 , 每次传送 的字节数不限 , 一个字节后面 必须 跟一个应答 每 位 。如果在传输过程 中, 从设备不能一次接收完一个 字节 , 此时 它就会使时钟置为低 电平 , 迫使主设备等待 ; 当从设备能接收下
包 括 oe ( 、 a( 、re ) i t ) r es( 等 等 。 pn ) r d ) wi ( 、 c ( 和 e ae ) e t ol l O e ( 函数 的 主 要 功 能是 提 供 给 驱 动 程 序 初 始化 能 力 , pn ) 为
个数据字节后 , 将释 放 S L线 , C 继续 后面 的数据 传输 。数 据
£0 )0口 [ l 0口 厂 = Ⅺ l
kv b o
…
…
传输的时序如图 1 所示 。
s ^ 。
.
维普资讯
第2 5卷第 3期
20 0 8年 3月
计 算机 应 用与软件
C mp tr A p iai n n ot a e o u e p l t sa d S f r c o w
V 12 . o . 5 No 3
Ma . 0 8 r2 0
24Cxx I2C EEPROM字节读写驱动程序

_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); //Thd:STA
SCL=0; //START
write_8bit(0xa0 | page); //写页地址和操作方式,对于24C32-24C256,page不起作用
ACK(ห้องสมุดไป่ตู้;
if(eepromtype>IIC24C16) //如果是24C01-24C16,地址为一字节;24C32-24C256,地址为二字节
调用方式:void WriteIIC_24CXX(enum EEPROMTYPE eepromtype,unsigned int address,unsigned char ddata) ﹫2001/09/18
函数说明:对于IIC芯片24CXX,在指定地址address写入一个字节ddata
SDA=0;
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); //Thd:STA
SCL=0; //START
write_8bit( (address<<1) | 0x01); //写页地址和操作方式
ACK();
while (i--)
{
SDA=1;
#include "reg51.h"
#include "intrins.h"
sbit SCL= P2^7;
sbit SDA= P2^6;
enum EEPROMTYPE {IIC24C01,IIC24C01A,IIC24C02,IIC24C04,IIC24C08,IIC24C16,IIC24C32,IIC24C64,IIC24C128,IIC24C256};
I2C总线8位远程IO扩展口芯片PCF8574的驱动程序

//......................................//名称: PCF8574(A).c I2C扩展8位I/O芯片的接口程序//编程: 不详//日期: 20111025////发现问题请指点,谢谢!//......................................//CPU: 89C55 11.0592MHz//环境:KeilC51 V8.01//引脚定义://CPU_P2.0--- P CF8574X_SC L 时钟// CP U_P2.1 ---PCF8574X_SDA 数据//CPU_P2.2 --- PC F8574X_INT中断//......................................#incl ude <Publi c.h>#incl ude <Intri ns.h>#inc lude"dela y_s.h"#in clude "pcf8574.h"//PCF8574(A)芯片指令的定义#defi ne PC F8574_WRIT E 0x40 //器件地址= 0111 A2 A1 A0r/w#defin e PCF8574_READ0x41//器件地址= 0111 A2 A1A0 r/w#de finePCF8574A_W RITE0x70//器件地址= 0111 A2 A1A0 r/w#de finePCF8574A_R EAD 0x71 //器件地址= 0111 A2 A1 A0 r/w#de fineP CF8574X_R EGIST ER_AD DR_MA X 7 //器件内部寄存器地址的最大值//内部函数s tatic void i2c_star t_con d(voi d);s tatic void i2c_stop_cond(void);st aticuchar i2c_read_byte(void);sta tic u chari2c_r ead_b yte_n ack(v oid);stat ic vo id i2c_wr ite_b yte(u charda);//============================================================== ===============//接口调用函数部分//*******************************************************//序号:// HD_PC F8574X_S01//功能://读出芯片的复位状态// is_pcf8574a=1 是A芯片// ad d_of_part器件的子地址 0~3//输出://端口的数据//********************************************************uch ar PC F8574X_rea d_io(uchar is_p cf8574a, u charadd_o f_par t){uchar i;i2c_s tart_cond();i f(is_pcf8574a !=0){i2c_wr ite_b yte(P CF8574A_RE AD |((add_of_pa rt <<1) &0x0E));//器件地址=0111 A2 A1 A0 r/w}else{i2c_write_byte(PCF8574_R EAD |((add_of_p art <<1) &0x0E));//器件地址=0100 A2 A1A0 r/w}i =i2c_re ad_by te_na ck();//顺序读的方式读出一个字节i2c_st op_co nd();ret urn(i);}//*******************************************************//序号:// H D_PCF8574X_S02//功能://写数据到I/O端口//输入://is_pcf8574a =1 是A芯片//add_of_p art:器件的子地址 0~7//dat:写入的字节//输出: // 无//********************************************************voidPCF8574X_w rite_io(uc har i s_pcf8574a, uch ar ad d_of_part, ucha r dat){i2c_s tart_cond();i f(is_pcf8574a !=0){i2c_wr ite_b yte(P CF8574A_WR ITE |((add_of_p art <<1) &0x0E)); //器件地址=0111A2 A1 A0 r/wel se{i2c_wri te_by te(PC F8574_WRIT E |((add_o f_par t <<1) &0x0E));//器件地址=0100 A2 A1 A0 r/w}i2c_write_byte(dat);i2c_st op_co nd();}//==============//内部调用函数部分//==============//----------------------------------------------//I2C发启始条件:时钟线为高时数据线发生下降沿跳变//----------------------------------------------sta tic v oid i2c_st art_c ond(v oid){CO DE_SC L_LOW;_D ELAY_NOP3;COD E_SDA_HIGH;_D ELAY_NOP3;COD E_SCL_HIGH;_D ELAY_NOP3;COD E_SDA_LOW;_DE LAY_N OP3;}//----------------------------------------//I2C 发结束条件:时钟线为高时数据线发生上升沿跳变//----------------------------------------st aticvoidi2c_s top_c ond(v oid){CO DE_SC L_LOW;_D ELAY_NOP3;COD E_SDA_LOW;_DE LAY_N OP3;CODE_SCL_HIGH;_DE LAY_N OP3;CODE_SDA_HIGH;_DE LAY_N OP3;}//----------------------------------------// I2C 读取一个中间字节的数据//----------------------------------------/*stat ic uc har i2c_re ad_by te(vo id){uch ar i;uch ar da=0;for(i =0;i<8;i++){da <<=1; //传输的数据高位在前C ODE_S CL_LO W;_DELA Y_NOP3;CODE_SCL_H IGH;//时钟为高时读数据//N OP3;if(JUDG E_PCF8574X_SDA) da++;}CODE_SCL_LOW;_DEL AY_NO P3;CODE_SDA_L OW; //发送应答位_DELA Y_NOP3;C ODE_S CL_HI GH;_DELA Y_NOP3;C ODE_S CL_LO W;_DELAY_NOP3;CO DE_SD A_HIG H;r eturn(da);}*///----------------------------------------// I2C读取一个结尾字节的数据//----------------------------------------stat ic uc har i2c_re ad_by te_na ck(vo id){uch ar i;uch ar da =0;for(i =0; i<8; i++){da<<=1;CO DE_SC L_LOW;_DELAY_NOP3;C ODE_S CL_HI GH;//NOP3;i f(JUD GE_PC F8574X_SDA) da++;}COD E_SCL_LOW;_DE LAY_N OP3;CODE_SDA_HIGH;_DE LAY_N OP3;CODE_SCL_HIGH;_DE LAY_N OP3;CODE_SCL_LOW;retu rn( d a );}//----------------------------------------// I2C 写入一个字节的数据//----------------------------------------stat ic vo id i2c_wri te_by te(uc har d a ){uch ar i;for(i =0; i<8; i++){COD E_SCL_LOW;if(da&0x80){COD E_SDA_HIGH;}el se{CODE_SDA_L OW;}CODE_SCL_H IGH;da<<=1;}CODE_SCL_L OW; //第8个SCL下降沿,写入8位数据_DELA Y_NOP3;C ODE_S DA_HI GH;_DELA Y_NOP3;C ODE_S CL_HI GH;}//============================================================== ===============//End O f Fil e。
TI-I2C驱动

TI-I2C驱动一、与I2C驱动相关的文件分成两部分:1)应用层接口部分:程序在svn中的路径如下:在https://dareglob-971006/svn/eocOS/branches/eocOS_v4/branches/bsp/user/i2c目录下,i2ctest.c文件,提供了lm75a_temp_read()方法,用来读取LM75A设备温度寄存器中的温度信息的功能。
2)内核驱动部分:内核位于svn中的路径如下:https://dareglob-971006/svn/eocOS/branches/eocOS_v4/branches/bsp/kernel(1)总线驱动:i2c-davinci.c:在内核目录中driver/i2c/busses目录下,适用于TI的I2C总线驱动程序。
I2C总线驱动是对I2C硬件体系结构中适配器端的实现。
(2)I2C驱动代码核心:i2c-core.c:在内核目录中driver/i2c/目录下,是I2C代码的核心,用于沟通虚拟文件系统与底层实现。
该文件提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。
(3)I2C设备驱动:lm75.c:在内核目录中driver/hwmon目录下,是针对LM75A以及其他能兼容的温度传感器的设备驱动。
I2C设备驱动是对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。
二、I2C简要工作流程1)在总线驱动初始化时候,当通过Linux内核源代码/driver/base/platform.c文件中定义platform_driver_register()函数注册platform_driver结构体时,其中probe指针指向的davinci_i2c_probe()函数将被调用,以初始化适配器硬件。
2)而davinci_i2c_remove()函数则完成与davinci_i2c_probe()相反的功能。
i2c_register_driver函数详解

i2c_register_driver函数详解在嵌入式软件开发中,I2C(Inter-Integrated Circuit)总线是一种常用的串行通信接口,用于在微控制器和外部设备之间传输数据。
i2c_register_driver函数是Linux内核中一个重要的函数,用于注册I2C 驱动程序。
本文将详细解析i2c_register_driver函数的功能、参数和应用。
一、i2c_register_driver函数概述i2c_register_driver函数是在Linux内核中注册一个I2C驱动程序的函数。
它的作用是将驱动程序与对应的I2C适配器绑定,使得操作系统能够正确地识别和管理该驱动程序。
在驱动程序注册后,当相应的I2C设备连接到系统时,驱动程序将会自动加载并为该设备提供服务。
二、i2c_register_driver函数参数i2c_register_driver函数包含一个结构体参数,该结构体用于指定驱动程序的相关信息和功能。
1. struct i2c_driverstruct i2c_driver是一个定义I2C驱动程序的结构体,包含了以下重要的成员:- .driver:指向内核的struct device_driver结构体,用于描述驱动程序的信息,如名称、文件操作方法等。
- .probe:指向I2C设备探测函数的指针,用于在设备连接时进行初始化和配置。
- .remove:指向I2C设备移除函数的指针,用于在设备断开连接时进行清理和释放资源。
- .id_table:指向I2C设备ID表的指针,用于匹配设备和驱动程序。
2. I2C设备探测函数(probe函数)I2C设备探测函数是I2C驱动程序的核心功能之一,在I2C设备连接到系统时被调用。
该函数的作用是检测和初始化I2C设备,并将设备与驱动程序进行绑定。
在probe函数中,可以执行一系列必要的操作,如配置寄存器、分配内存、注册字符设备等。
有关于iic以及ds18b20驱动的解读

有关于iic以及ds18b20驱动的解读对于任何一个芯片的使用都离不开对芯片手册的解读,手册中的时序图以及协议必须完全的知晓,才能将芯片正确的使用起来:首先来了解一下使用iic协议的比较常见的AT24C02 这款芯片:通过手册我们可以知道:这款芯片有A0、A1、A2着三个地址管脚,将这三个管脚任意的接上VCC或者是GND都可以构成这款芯片的序列号、在实际的使用中就能够通过总线来进行寻址,然后发送地址,就能对应某一个芯片,并且由此可知,总线上最多可以连接8个这样的芯片,只要改变管脚的三个地址位,就能轻松实现对不同的芯片的控制。
芯片上除了这三个地址管脚之外还有一个WP,是用来写保护的,当这个管脚上是高电平的时候,是没有办法将我们所要的数据写进这款芯片中的,只有当它为低电平的时候才能对这款芯片进行操作。
正常情况下,在使用的时候都是通过硬件电路直接将这个管脚连在GND上。
还有就是Vcc跟Vss分别接上+5V和地,SDA和SCL分别是我们这款芯片的数据位和时钟位,也是我们操作这款芯片的重点。
根据手册的解读,我们可以了解到在时钟线为高电平的时候,数据线要保持不变,如果数据线在时钟线高电平期间,由高电平变为低电平,说明了iic总线协议的开始,如果由低电平变为高电平时,说明了总线协议的结束。
在时钟线为低电平的时候才允许数据线进行跳变并进行传输数据。
在解读时序图的时候底下着两张图很重要。
因为这两张图包含了在写时序图当中的一点细节。
如果这些细节没有处理好的话就会出现芯片不会正常工作的状况。
接下类介绍各个驱动的书写和处理:1、起始信号:由上面的时间表查出来的时间显示,起始信号建立的时间至少是4.7us。
因为时序图是完全按照现实的时间走向画出来的,所以从左向右可以想象成是一个时间轴。
然后看上面这张起始信号的图有可以知道,显示SCL由低电平变为高电平然后保持至少4us的时间。
SDA才开始由高电平变为低电平,在低电平的这段时间查表就可知,这个起始信号保持的时间至少是4us。
Arduino驱动IIC接口(I2C接口)LCD12864液晶模块

Arduino驱动IIC接口(I2C接口)LCD12864液晶模块关键词:Arduino显示,12864液晶模块,中文显示,IIC 接口,I2C接口,12864驱动程序液晶显示模块目前在中国发展已经有30多个年头了,市场上应用最广泛的要属于128*64点阵的显示屏,从类型上分COB,COG及OLED, 稳定性和经济性最好要属于COB工艺的液晶显示模块。
在百度一搜索就可以找到COB简介及工艺COB Chip-on-Board 也称为芯片直接贴装技术,是指将裸芯片直接粘贴在印刷电路板上,然后进行引线键合,再用有机胶将芯片和引线包封保护的工……12864点阵的液晶屏主控芯片一般是ST7920及KS0107+KS0108及KS0086等IC,今天介绍一款我最新发现的一款COB液晶带(RSCG12864B) 拥有I2C接口,内建中文字库(GB2312),ASCII有5*7点阵,6*12点阵,8*16点阵三种之多,可谓目前市场最全,这款液晶屏最出色的要属于可以存储多达2000张图片,可以一般界面只需在电脑上做好BIN格式图片,配合相应的下载工具,就可以存储到液晶模块上。
引脚接线图:序号符号I/O功能描述1<td width="80" valign="top"style="width:59.7pt;border-top:none;border-left:none; border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">GND<td width="72" valign="top"style="width:53.8pt;border-top:none;border-left:none; border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">P<td width="337" valign="top"style="width:252.5pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solid black .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">电源地2<td width="80" valign="top"style="width:59.7pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.15pt;mso-height-rule:exactly">VDD<td width="72" valign="top"style="width:53.8pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.15pt;mso-height-rule:exactly">P<td width="337" valign="top"style="width:252.5pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solid black .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm 5.4pt;height:14.15pt;mso-height-rule:exactly">电源3<td width="80" valign="top"style="width:59.7pt;border-top:none;border-left:none; border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">RST<td width="72" valign="top"style="width:53.8pt;border-top:none;border-left:none; border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">I<td width="337" valign="top"style="width:252.5pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solid black .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">复位信号,低电平有效4<td width="80" valign="top"style="width:59.7pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.15pt;mso-height-rule:exactly">SCL<td width="72" valign="top"style="width:53.8pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.15pt;mso-height-rule:exactly">I<td width="337" valign="top"style="width:252.5pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solid black .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.15pt;mso-height-rule:exactly">I2C 时钟信号5<td width="80" valign="top"style="width:59.7pt;border-top:none;border-left:none; border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">SDA<td width="72" valign="top"style="width:53.8pt;border-top:none;border-left:none; border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">I<td width="337" valign="top"style="width:252.5pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solid black .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">I2C 数据信号6<td width="80" valign="top"style="width:59.7pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">BUSY<td width="72" valign="top"style="width:53.8pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">O<td width="337" valign="top"style="width:252.5pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solid black .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">忙信号,高为忙,低为闲。
Linux I2C设备驱动编写

Linux I2C设备驱动编写(一)在Linux驱动中I2C系统中主要包含以下几个成员:如果一个I2C适配器不支持I2C通道,那么就将master_xfer成员设为NULL。
如果适配器支持SMBUS 协议,那么需要去实现smbus_xfer,如果smbus_xfer指针被设为NULL,那么当使用SMBUS协议的时候将会通过I2C通道进行仿真。
master_xfer指向的函数的返回值应该是已经成功处理的消息数,或者返回负数表示出错了。
functionality指针很简单,告诉询问着这个I2C主控器都支持什么功能。
在内核的drivers/i2c/i2c-stub.c中实现了一个i2c adapter的例子,其中实现的是更为复杂的SMBUS。
SMBus 与I2C的区别通常情况下,I2C和SMBus是兼容的,但是还是有些微妙的区别的。
时钟速度对比:在电气特性上他们也有所不同,SMBus要求的电压范围更低。
I2C driver具体的I2C设备驱动,如相机、传感器、触摸屏、背光控制器常见硬件设备大多都有或都是通过I2C 协议与主机进行数据传输、控制。
结构体如下:如同普通设备的驱动能够驱动多个设备一样,一个I2C driver也可以对应多个I2C client。
以重力传感器AXLL34X为例,其实现的I2C驱动为:这里要说明一下module_i2c_driver宏定义(i2c.h):module_driver():理解上述宏定义后,将module_i2c_driver(adxl34x_driver)展开就可以得到:这一句宏就解决了模块module安装卸载的复杂代码。
这样驱动开发者在实现I2C驱动时只要将i2c_driver结构体填充进来就可以了,无需关心设备的注册与反注册过程。
I2C client即I2C设备。
I2C设备的注册一般在板级代码中,在解析实例前还是先熟悉几个定义:下面还是以adxl34x为例:这样ADXL34X的i2c设备就被注册到了系统中,当名字与i2c_driver中的id_table中的成员匹配时就能够出发probe匹配函数了。
voodooi2c启动参数

voodooi2c启动参数VoodooI2C是一款用于在Windows系统上提供I2C总线控制器支持的开源驱动程序。
在安装和配置VoodooI2C驱动程序时,我们需要指定一些启动参数来确保其正常运行。
以下是一些常见的VoodooI2C启动参数及其作用:1. `voodooi2c.kext`- 这是VoodooI2C的内核扩展文件,用于加载VoodooI2C驱动程序。
确保正确安装此文件以启用VoodooI2C功能。
2. `VoodooI2C.kext`- 这是VoodooI2C的内核扩展文件,用于加载VoodooI2C驱动程序。
与`voodooi2c.kext`不同的是,此文件可能会在一些系统上使用。
3. `I2C-xxx.aml`- 这是VoodooI2C的ACPI机制定义文件,用于描述I2C总线的配置和设备信息。
根据具体的硬件配置,可能需要不同的`I2C-xxx.aml`文件来正确识别和配置I2C设备。
4. `I2C0.aml`- 在一些设备上,I2C总线可能被标识为I2C0。
使用正确的`I2C0.aml`文件可以确保VoodooI2C正确识别和初始化I2C0总线。
5. `VoodooI2CController.kext`- 这是VoodooI2C的控制器内核扩展文件,用于实现I2C总线控制器的功能。
确保正确加载此文件以确保I2C总线的正常通信。
6. `I2CController.kext`- 与`VoodooI2CController.kext`类似,这是另一个可能使用的I2C控制器内核扩展文件。
在一些系统上,可能会使用`I2CController.kext`来实现I2C控制器的功能。
7. `I2CControllerName`- 在一些系统上,I2C控制器可能具有特定的名称,如`I2C1`或`I2C2`等。
确保在启动参数中正确指定I2C控制器的名称以便VoodooI2C正确识别。
以上是一些常见的VoodooI2C启动参数及其作用,根据具体的硬件配置和系统要求,可能还会有其他参数需要配置。
LinuxI2C驱动整理(以RK3399Pro+Kernel4.4为例)

LinuxI2C驱动整理(以RK3399Pro+Kernel4.4为例)⼀. Linux I2C驱动架构Linux内核⾥,I2C驱动框架可以分为两层,adapter驱动和deivce驱动。
Adapter驱动也可以理解为I2C总线驱动,指的是SOC⾥的I2C控制器驱动。
⼀个SOC可能包含多个I2C控制器,⽽每个控制器的使⽤⽅式是相同的(寄存器参数、收发数据的⽅法等),因此多个控制器可以共⽤⼀套adapter驱动;Deivce驱动,对应的是SOC外围的I2C设备,不同类型I2C设备需要开发不同的设备驱动,同⼀类型的I2C设备可以使⽤⼀种驱动,但是每⼀个I2C设备都由⼀个唯⼀的client来描述。
⼆. Adapter配置DTSI⽂件(kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi)描述了RK3399Pro所有的I2C控制器信息:i2c0: i2c@ff3c0000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff3c00000x00x1000>;clocks = <&pmucru SCLK_I2C0_PMU>, <&pmucru PCLK_I2C0_PMU>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c0_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c1: i2c@ff110000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1100000x00x1000>;clocks = <&cru SCLK_I2C1>, <&cru PCLK_I2C1>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c1_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c2: i2c@ff120000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1200000x00x1000>;clocks = <&cru SCLK_I2C2>, <&cru PCLK_I2C2>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c2_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c3: i2c@ff130000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1300000x00x1000>;clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c3_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c5: i2c@ff140000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1400000x00x1000>;clocks = <&cru SCLK_I2C5>, <&cru PCLK_I2C5>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c5_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c6: i2c@ff150000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1500000x00x1000>;clocks = <&cru SCLK_I2C6>, <&cru PCLK_I2C6>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c6_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c7: i2c@ff160000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1600000x00x1000>;clocks = <&cru SCLK_I2C7>, <&cru PCLK_I2C7>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c7_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c4: i2c@ff3d0000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff3d00000x00x1000>;clocks = <&pmucru SCLK_I2C4_PMU>, <&pmucru PCLK_I2C4_PMU>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c4_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c8: i2c@ff3e0000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff3e00000x00x1000>;clocks = <&pmucru SCLK_I2C8_PMU>, <&pmucru PCLK_I2C8_PMU>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c8_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};可以看出,该SOC共有9个I2C控制器,分别为I2C0~I2C8, 每个控制器对应了不同的寄存器基地址(例如I2C0对应0xff3c0000),它们的compatible匹配属性都是"rockchip,rk3399-i2c",也就是对应了同⼀个adapter驱动。
AN0003+RT-Thread应用笔记之I2C设备应用指南

图4.2.1-1 发送数据函数调用关系
drv_mpu6050.c 中的 mpu6050_write_reg() 函数是MCU向mpu6050寄存器写数据。此函数的实现共有2种,分别 调用了I2C设备驱动接口 rt_i2c_transfer() 和 rt_i2c_master_send() 实现。
图3.2-2 修改MCU 图3.2-3 修改调试选项
5. 编译工程后下载程序至开发板运行。在终端PuTTY(打开对应端口,波特率配置为115200)输入 list_device 命令可以看到名为i2c2的设备,设备类型是I2C Bus,说明I2C设备驱动添加成功了。如图所示:
图3.2-4使用list_device命令查看i2c总线
1. 用户可以在msh shell输入 list_device 命令查看已有的I2C设备,确定I2C设备名称。 2. 查找设备使用 rt_i2c_bus_device_find() 或者 rt_device_find() ,传入I2C设备名称获取i2c总线设备句
柄。 3. 使用 rt_i2c_transfer() 即可以发送数据也可以接收数据,如果主机只发送数据可以使用
3.3 运行示例代码
将I2C示例代码里的 main.c 拷贝到\rt-thread\bsp\stm32f4xx-HAL\applications目录,替换原有的 main.c 。 drv_mpu6050.c、drv_mpu6050.h 拷贝到\rt-thread\bsp\stm32f4xx-HAL\drivers目录,并将它们添加到工程中对应 分组。如图所示:
i2c_register_driver函数详解

i2c_register_driver函数详解一、概述i2c_register_driver函数是Linux内核中用于注册I2C设备驱动的函数之一。
它用于将设备驱动程序注册到内核,以便其他模块可以使用该驱动程序来与I2C设备进行通信。
二、函数原型int i2c_register_driver(struct i2c_driver *driver);三、函数参数说明* driver:指向i2c_driver结构体的指针,该结构体包含了设备驱动的相关信息,如设备名称、设备ID等。
四、函数返回值如果函数成功注册驱动程序,则返回0;否则返回-E...等错误代码。
五、函数功能详解i2c_register_driver函数将指定的i2c_driver结构体注册到内核中,使其成为可用的I2C设备驱动。
在注册驱动程序之前,需要确保驱动程序已经正确编译并包含在内核中。
在注册驱动程序时,i2c_register_driver函数会执行以下操作:1. 检查驱动程序是否符合内核的要求,如设备ID、设备名称等是否正确。
2. 将驱动程序的信息添加到内核的设备列表中,以便其他模块可以找到并使用该驱动程序。
3. 注册成功后,内核会为该驱动程序分配相应的资源,如内存、端口等,并建立与I2C总线的连接。
六、使用示例```c#include <linux/module.h>#include <linux/i2c.h>struct i2c_driver my_driver;int main(){int ret;ret = i2c_register_driver(&my_driver);if (ret) {printk(KERN_ERR "Failed to register driver: %d\n", ret);return ret;}// 其他操作...return 0;}```在上述示例中,首先定义了一个i2c_driver结构体变量my_driver,用于存储驱动程序的相关信息。
0.96寸OLED显示屏STM32F103C8T6IIC驱动程序

0.96⼨OLED显⽰屏STM32F103C8T6IIC驱动程序0.96⼨OLED显⽰屏的IIC驱动程序有很多现成的⽰例,但⼤部分编程风格实在是让程序阅读起来很困难,所以本伽椰⼦重新梳理了⼀下驱动程序,使得其更⽅便阅读,具体代码内容如下:1、滴答时钟DRIVE_SYSTICK.h1 #ifndef _DRIVE_SYSTICK_H_2#define _DRIVE_SYSTICK_H_3 #include "stm32f10x.h"45void LibDriveSystickInit(void);6void LibDriveSystickDelay_us(uint32_t Dus);7void LibDriveSystickDelay_ms(uint32_t Dms);8#endifDRIVE_SYSTICK.c1 #include "DRIVE_SYSTICK.h"234/*************************************************5函数名称 : LibDriveSystickInit6功能描述 : 滴答时钟初始化7被调⽤清单 : ⽆8调⽤清单 :9输⼊参数 : ⽆10输出参数 : ⽆11返回参数 : ⽆12其他 : ⽆13*************************************************/14void LibDriveSystickInit(void)15 {16 SysTick->LOAD = 1000;17 SysTick->VAL = 0;18 SysTick->CTRL = 0;19 }2021/*************************************************22函数名称 : LibDriveSystickDelay_us23功能描述 : 滴答时钟微妙级延时24被调⽤清单 : ⽆25调⽤清单 :26输⼊参数 : dus待延时微妙数27输出参数 : ⽆28返回参数 : ⽆29其他 : ⽆30*************************************************/31void LibDriveSystickDelay_us(uint32_t Dus)32 {33if((Dus == 0) || (Dus > 700000))34 {35return;36 }37 SysTick->LOAD = Dus*22-1;38 SysTick->VAL = 0;39 SysTick->CTRL |= 1;4041while((SysTick->CTRL & (1<<16)) == 0);42 SysTick->CTRL = 0;43 }4445/*************************************************46函数名称 : LibDriveSystickDelay_ms47功能描述 :滴答时钟毫秒级延时48被调⽤清单 : ⽆49调⽤清单 :50输⼊参数 : dms待延时毫秒数51输出参数 : ⽆52返回参数 : ⽆53其他 : ⽆54*************************************************/55void LibDriveSystickDelay_ms(uint32_t Dms)56 {57while(Dms >= 700)58 {59 LibDriveSystickDelay_us(700000);60 Dms -= 700;61 }62if(Dms < 700)63 {64 LibDriveSystickDelay_us(Dms*1000);65 }66 }APP_SYSTICK.h1 #ifndef _APP_SYSTICK_H_2#define _APP_SYSTICK_H_3 #include "DRIVE_SYSTICK.h"45void FunAppSystickInit(void);67#endifAPP_SYSTICK.c1 #include "APP_SYSTICK.h"23/*************************************************4函数名称 : FunAppOledDisplayTurn5功能描述 : 屏幕旋转180°6被调⽤清单 : ⽆7调⽤清单 :8输⼊参数 : Mode == 0正常显⽰ Mode == 1反转显⽰9输出参数 : ⽆10返回参数 : ⽆11其他 : ⽆12*************************************************/13void FunAppSystickInit(void)14 {15 LibDriveSystickInit();16 }2、IIC通讯驱动程序DRIVE_I2C2.h1 #ifndef _DRIVE_I2C2_H_2#define _DRIVE_I2C2_H_3 #include "stm32f10x.h"4 #include "DRIVE_SYSTICK.h"56#define SDA_H GPIO_SetBits(GPIOB, GPIO_Pin_11)7#define SDA_L GPIO_ResetBits(GPIOB, GPIO_Pin_11)8#define SCL_H GPIO_SetBits(GPIOB, GPIO_Pin_10)9#define SCL_L GPIO_ResetBits(GPIOB, GPIO_Pin_10)10#define SDA_IN GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)1112void LibDriveI2c2Init(void);13void LibDriveI2c2Start(void);14void LibDriveI2c2Stop(void);15void LibDriveI2c2SendAck(uint8_t Ack);16void LibDriveI2c2WriteByte(uint8_t Data);17 uint8_t LibDriveI2c2Read(void);18 uint8_t LibDriveI2c2CheckAck(void);1920#endifDRIVE_I2C2.c1 #include "DRIVE_I2C2.h"23/*************************************************4函数名称 : LibDriveI2c2Init5功能描述 : I2C2初始化6被调⽤清单 : ⽆7调⽤清单 :8输⼊参数 : ⽆9输出参数 : ⽆10返回参数 : ⽆11其他 : ⽆12*************************************************/13void LibDriveI2c2Init(void)14 {15 GPIO_InitTypeDef GPIO_InitStruct;16 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); 1718 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;19 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;20 GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;21 GPIO_Init(GPIOB, &GPIO_InitStruct);22 }2324/*************************************************25函数名称 : LibDriveI2c2Start26功能描述 : I2C2开始信号27被调⽤清单 : ⽆28调⽤清单 :29输⼊参数 : ⽆30输出参数 : ⽆31返回参数 : ⽆32其他 : ⽆33*************************************************/34void LibDriveI2c2Start(void)35 {36 SCL_L;37 SDA_H;3839 SCL_H;40 LibDriveSystickDelay_us(5);41 SDA_L;42 LibDriveSystickDelay_us(5);43 SCL_L;44 }4546/*************************************************47函数名称 : LibDriveI2c2Stop48功能描述 : I2C2停⽌信号49被调⽤清单 : ⽆50调⽤清单 :51输⼊参数 : ⽆52输出参数 : ⽆53返回参数 : ⽆54其他 : ⽆55*************************************************/56void LibDriveI2c2Stop(void)57 {58 SCL_L;59 SDA_L;6061 SCL_H;62 LibDriveSystickDelay_us(5);63 SDA_H;64 LibDriveSystickDelay_us(5);65 }6667/*************************************************68函数名称 : LibDriveI2c2SendAck69功能描述 : I2C2发送回复70被调⽤清单 : ⽆71调⽤清单 :72输⼊参数 : Ack 回复状态73输出参数 : ⽆74返回参数 : ⽆75其他 : ⽆76*************************************************/77void LibDriveI2c2SendAck(uint8_t Ack)78 {79if (Ack) //不应答80 {81 SCL_L;82 LibDriveSystickDelay_us(5);83 SDA_H;84 LibDriveSystickDelay_us(1);85 SCL_H;86 LibDriveSystickDelay_us(5);87 }88else if (Ack == 0) //应答89 {90 SCL_L;91 LibDriveSystickDelay_us(5);92 SDA_L;93 LibDriveSystickDelay_us(1);94 SCL_H;95 LibDriveSystickDelay_us(5);96 }97 SCL_L;98 }99100/*************************************************101函数名称 : LibDriveI2c2WriteByte102功能描述 : I2C2写⼀个字节103被调⽤清单 : ⽆104调⽤清单 :105输⼊参数 : Data 待发送数据106输出参数 : ⽆107返回参数 : ⽆108其他 : ⽆109*************************************************/110void LibDriveI2c2WriteByte(uint8_t Data)111 {112 uint8_t localIte = 0;113for (localIte = 0; localIte < 8; localIte++)114 {115 SCL_L; //可以改变数据线116 LibDriveSystickDelay_us(5);117if (Data & 0x80)118 {119 SDA_H;120 }121else122 {123 SDA_L;124 }125 LibDriveSystickDelay_us(1);126 SCL_H; //从机时钟线拉⾼从机才可以读此位数据127 LibDriveSystickDelay_us(5);128 Data = Data << 1;129 }130 SCL_L; //安全131 }132133/*************************************************134函数名称 : LibDriveI2c2Read135功能描述 : I2C2读取数据136被调⽤清单 : ⽆137调⽤清单 :138输⼊参数 : ⽆139输出参数 : ⽆140返回参数 : 所读取到的数据(⼀个字节)141其他 : ⽆142*************************************************/143 uint8_t LibDriveI2c2Read(void)144 {145 uint8_t localData = 0;146 uint8_t localIte = 0;147148/*把数线的模式改为输⼊模式*/149 SCL_L; //可以改变数据线150 SDA_H; //输⼊模式151152/*接收⼋位数据*/153for (localIte = 0; localIte < 8; localIte++)154 {155 SCL_L; //拉低时钟线,从机发送⼀个位数据156 LibDriveSystickDelay_us(5);157 SCL_H; //主机读158 LibDriveSystickDelay_us(5);159 localData = localData << 1;160if (SDA_IN)161 {162 localData = localData | 0x01;163 }164 }165 SCL_L; //安全166return localData;167 }168169/*************************************************170函数名称 : LibDriveI2c2CheckAck171功能描述 : I2C2检查回复状态172被调⽤清单 : ⽆173调⽤清单 :174输⼊参数 : ⽆175输出参数 : ⽆176返回参数 : 应答返回1 ⽆应答放回0177其他 : ⽆178*************************************************/179 uint8_t LibDriveI2c2CheckAck(void)180 {181 uint8_t Ack = 0;182/*将数据线的模式改变为输⼊模式*/183 SCL_L;184 SDA_H;185/*检测应答位信号*/186 SCL_L; //从机可以发送应答信号/不应答信号187 LibDriveSystickDelay_us(5);188189 SCL_H; //主机可以读应答信号190 LibDriveSystickDelay_us(5);191if (SDA_IN) //应答192 {193 Ack = 1;194 }195 SCL_L; //安全196return Ack;197 }3、OLED驱动程序APP_OLED.h1 #ifndef _APP_OLED_H_2#define _APP_OLED_H_3 #include "DRIVE_I2C2.h"4 #include <stdlib.h>56#define OLED_CMD 0//写命令7#define OLED_DATA 1//写数据89void FunAppOledInit(void);10void FunAppOledWriteByte(uint8_t Data, uint8_t Mode);11void FunAppOledDisPlayOn(void);12void FunAppOledDisPlayOff(void);13void FunAppOledClear(void);14void FunAppOledRefresh(void);15void FunAppOledDrawPoint(uint8_t X, uint8_t Y);16void FunAppOledClearPoint(uint8_t X, uint8_t Y);17void FunAppOledDrawLine(uint8_t X1, uint8_t Y1, uint8_t X2, uint8_t Y2);18void FunAppOledDrawCircle(uint8_t X, uint8_t Y, uint8_t R);19void FunAppOledShowChar(uint8_t X, uint8_t Y, uint8_t Chr, uint8_t Size); 20void FunAppOledShowString(uint8_t X, uint8_t Y, uint8_t * Chr, uint8_t Size);21void FunAppOledShowNum(uint8_t X, uint8_t Y, uint32_t Num, uint8_t Len, uint8_t Size);22void FunAppOledShowChinese(uint8_t X, uint8_t Y, uint8_t Num, uint8_t Size);23void FunAppOledScrollDisplay(uint8_t Num, uint8_t Space);24void FunAppOledWriteBP(uint8_t X, uint8_t Y);25void FunAppOledShowPicture(uint8_t X1, uint8_t Y1, uint8_t X2, uint8_t Y2, uint8_t *Bmp);26void FunAppOledColorTurn(uint8_t Mode);27void FunAppOledDisplayTurn(uint8_t Mode);28 uint32_t FunAppOledPow(uint8_t Num, uint8_t Index);29#endifAPP_OLED.c1 #include "APP_OLED.h"2 #include "OLED_FONT.h"34static uint8_t OLED_GRAM[144][8];56/*************************************************7函数名称 : FunAppOledInit8功能描述 : OLED初始化9被调⽤清单 : ⽆10调⽤清单 :11输⼊参数 : ⽆12输出参数 : ⽆13返回参数 : ⽆14其他 : ⽆15*************************************************/16void FunAppOledInit(void)17 {18 LibDriveI2c2Init();19 LibDriveSystickDelay_ms(100);20 FunAppOledWriteByte(0xAE,OLED_CMD);//--turn off oled panel21 FunAppOledWriteByte(0x00,OLED_CMD);//---set low column address22 FunAppOledWriteByte(0x10,OLED_CMD);//---set high column address23 FunAppOledWriteByte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)24 FunAppOledWriteByte(0x81,OLED_CMD);//--set contrast control register25 FunAppOledWriteByte(0xCF,OLED_CMD);// Set SEG Output Current Brightness26 FunAppOledWriteByte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常27 FunAppOledWriteByte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常28 FunAppOledWriteByte(0xA6,OLED_CMD);//--set normal display29 FunAppOledWriteByte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)30 FunAppOledWriteByte(0x3f,OLED_CMD);//--1/64 duty31 FunAppOledWriteByte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)32 FunAppOledWriteByte(0x00,OLED_CMD);//-not offset33 FunAppOledWriteByte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency34 FunAppOledWriteByte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec35 FunAppOledWriteByte(0xD9,OLED_CMD);//--set pre-charge period36 FunAppOledWriteByte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock37 FunAppOledWriteByte(0xDA,OLED_CMD);//--set com pins hardware configuration38 FunAppOledWriteByte(0x12,OLED_CMD);39 FunAppOledWriteByte(0xDB,OLED_CMD);//--set vcomh40 FunAppOledWriteByte(0x40,OLED_CMD);//Set VCOM Deselect Level41 FunAppOledWriteByte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)42 FunAppOledWriteByte(0x02,OLED_CMD);//43 FunAppOledWriteByte(0x8D,OLED_CMD);//--set Charge Pump enable/disable44 FunAppOledWriteByte(0x14,OLED_CMD);//--set(0x10) disable45 FunAppOledWriteByte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)46 FunAppOledWriteByte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)47 FunAppOledWriteByte(0xAF,OLED_CMD);48 FunAppOledClear();49 }5051/*************************************************52函数名称 : FunAppOledWriteByte53功能描述 : OLED写⼊⼀字节54被调⽤清单 : ⽆55调⽤清单 :56输⼊参数 : Data待写⼊数据,Mode数据写⼊模式,为0为写指令为1为写数据57输出参数 : ⽆58返回参数 : ⽆59其他 : ⽆60*************************************************/61void FunAppOledWriteByte(uint8_t Data, uint8_t Mode)62 {63 uint8_t localAck = 0;64 LibDriveI2c2Start();65 LibDriveI2c2WriteByte(0x78);66 localAck = LibDriveI2c2CheckAck();67if(localAck)68 {69 LibDriveI2c2Stop();70 }71if(Mode)72 {73 LibDriveI2c2WriteByte(0x40);74 }75else76 {77 LibDriveI2c2WriteByte(0x00);78 }7980 localAck = LibDriveI2c2CheckAck();81if(localAck)82 {83 LibDriveI2c2Stop();84 }85 LibDriveI2c2WriteByte(Data);8687 localAck = LibDriveI2c2CheckAck();88if(localAck)89 {90 LibDriveI2c2Stop();91 }92 LibDriveI2c2Stop();93 }9495/*************************************************96函数名称 : FunAppOledDisPlayOn97功能描述 : 开启OLED显⽰98被调⽤清单 : ⽆99调⽤清单 :100输⼊参数 : ⽆101输出参数 : ⽆102返回参数 : ⽆103其他 : ⽆104*************************************************/105void FunAppOledDisPlayOn(void)106 {107 FunAppOledWriteByte(0x8D, OLED_CMD);//电荷泵使能108 FunAppOledWriteByte(0x14, OLED_CMD);//开启电荷泵109 FunAppOledWriteByte(0xAE, OLED_CMD);//点亮屏幕110 }111112/*************************************************113函数名称 : FunAppOledDisPlayOn114功能描述 : 关闭OLED显⽰115被调⽤清单 : ⽆116调⽤清单 :117输⼊参数 : ⽆118输出参数 : ⽆119返回参数 : ⽆120其他 : ⽆121*************************************************/122void FunAppOledDisPlayOff(void)123 {124 FunAppOledWriteByte(0x8D, OLED_CMD);//电荷泵使能125 FunAppOledWriteByte(0x10, OLED_CMD);//关闭电荷泵126 FunAppOledWriteByte(0xAF, OLED_CMD);//关闭屏幕127 }128129/*************************************************130函数名称 : FunAppOledRefresh131功能描述 : 更新显⽰132被调⽤清单 : ⽆133调⽤清单 :134输⼊参数 : ⽆135输出参数 : ⽆136返回参数 : ⽆137其他 : ⽆138*************************************************/139void FunAppOledRefresh(void)140 {141 uint8_t localIte = 0;142 uint8_t localNum = 0;143144for (localIte = 0; localIte < 8; localIte++)145 {146 FunAppOledWriteByte(0xB0 + localIte, OLED_CMD);147 FunAppOledWriteByte(0x00 , OLED_CMD);148 FunAppOledWriteByte(0x10 , OLED_CMD);149for (localNum = 0; localNum < 128; localNum++)150 {151 FunAppOledWriteByte(OLED_GRAM[localNum][localIte], OLED_DATA); 152 }153 }154 }155156/*************************************************157函数名称 : FunAppOledClear158功能描述 : 清屏159被调⽤清单 : ⽆160调⽤清单 :161输⼊参数 : ⽆162输出参数 : ⽆163返回参数 : ⽆164其他 : ⽆165*************************************************/166void FunAppOledClear(void)167 {168 uint8_t localIte = 0;169 uint8_t localNum = 0;170171for (localIte = 0; localIte < 8; localIte++)172 {173for (localNum = 0; localNum < 128; localNum++)174 {175 OLED_GRAM[localNum][localIte] = 0;176 }177 }178 FunAppOledRefresh();179 }180181/*************************************************182函数名称 : FunAppOledDrawPoint183功能描述 : 画点184被调⽤清单 : ⽆185调⽤清单 :186输⼊参数 : X(0 ~ 127) , Y(0 ~ 63)187输出参数 : ⽆188返回参数 : ⽆189其他 : ⽆190*************************************************/191void FunAppOledDrawPoint(uint8_t X, uint8_t Y)192 {193 uint8_t localI = 0;194 uint8_t localM = 0;195 uint8_t localN = 0;196197 localI = Y / 8;198 localM = Y % 8;199 localN = 1 << localM;200 OLED_GRAM[X][localI] |= localN;201 }202203/*************************************************204函数名称 : FunAppOledClearPoint205功能描述 : 清除⼀个点206被调⽤清单 : ⽆207调⽤清单 :208输⼊参数 : X(0 ~ 127) , Y(0 ~ 63)209输出参数 : ⽆210返回参数 : ⽆211其他 : ⽆212*************************************************/213void FunAppOledClearPoint(uint8_t X, uint8_t Y)214 {215 uint8_t localI = 0;216 uint8_t localM = 0;217 uint8_t localN = 0;218219 localI = Y / 8;220 localM = Y % 8;221 localN = 1 << localM;222223 OLED_GRAM[X][localI] = ~OLED_GRAM[X][localI];224 OLED_GRAM[X][localI] |= localN;225 OLED_GRAM[X][localI] = ~OLED_GRAM[X][localI];226 }227228/*************************************************229函数名称 : FunAppOledDrawLine230功能描述 : 画线231被调⽤清单 : ⽆232调⽤清单 :233输⼊参数 : X(0 ~ 127) , Y(0 ~ 63) (X1 , Y1)第⼀个点坐标(X2 , Y2)第⼆个点坐标234输出参数 : ⽆235返回参数 : ⽆236其他 : ⽆237*************************************************/238void FunAppOledDrawLine(uint8_t X1, uint8_t Y1, uint8_t X2, uint8_t Y2)239 {240 uint8_t localIte = 0;241 uint8_t localK0 = 0;242 uint8_t localK1 = 0;243 uint8_t localK2 = 0;244245if ((X2 > 128)|| (Y2 > 64) || (X1 > X2) || (Y1 > Y2))246 {247return ;248 }249250if (X1 == X2) //竖线251 {252for (localIte = 0; localIte < (Y2 - Y1); localIte++)253 {254 FunAppOledDrawPoint(X1, (Y1 + localIte));255 }256 }257else if (Y1 == Y2)//横线258 {259for (localIte = 0; localIte < (X2 - X1); localIte++)260 {261 FunAppOledDrawPoint((X1 + localIte), Y1);262 }263 }264else//斜线265 {266 localK0 = Y2 - Y1;267 localK1 = X2 - X1;268 localK2 = (localK0 * 10) / localK1;269for (localIte = 0; localIte < (X2 - X1); localIte++)270 {271 FunAppOledDrawPoint((X1 + localIte), (Y1 + ((localIte * localK2) / 10)));272 }273 }274 }275276/*************************************************277函数名称 : FunAppOledDrawCircle278功能描述 : 画圆279被调⽤清单 : ⽆280调⽤清单 :281输⼊参数 : X(0 ~ 127) , Y(0 ~ 63) (X , Y)圆⼼坐标 R半径282输出参数 : ⽆283返回参数 : ⽆284其他 : ⽆285*************************************************/286void FunAppOledDrawCircle(uint8_t X, uint8_t Y, uint8_t R)287 {288int localA = 0;289int localB = 0;290int localN = 0;291292 localB = R;293while((2 * localB * localB) >= (R * R))294 {295 FunAppOledDrawPoint(X + localA, Y - localB);296 FunAppOledDrawPoint(X - localA, Y - localB);297 FunAppOledDrawPoint(X - localA, Y + localB);298 FunAppOledDrawPoint(X + localA, Y + localB);299300 FunAppOledDrawPoint(X + localB, Y - localA);301 FunAppOledDrawPoint(X - localB, Y - localA);302 FunAppOledDrawPoint(X - localB, Y + localA);303 FunAppOledDrawPoint(X + localB, Y + localA);304305 localA++;306 localN = ((localA * localA) + (localB * localB)) - (R * R);//计算画的点离圆⼼的距离307if (localN > 0 )308 {309 localA--;310 localB--;311 }312 }313 }314315/*************************************************316函数名称 : FunAppOledShowChar317功能描述 : 显⽰⼀个字符318被调⽤清单 : ⽆319调⽤清单 :320输⼊参数 : X(0 ~ 127) , Y(0 ~ 63) (X , Y)起点坐标 Chr待显⽰字符 Size字体⼤⼩321输出参数 : ⽆322返回参数 : ⽆323其他 : ⽆324*************************************************/325void FunAppOledShowChar(uint8_t X, uint8_t Y, uint8_t Chr, uint8_t Size)326 {327 uint8_t localIte = 0;328 uint8_t localIte1 = 0;329 uint8_t localTemp = 0;330 uint8_t localSize = 0;331 uint8_t localChr = 0;332 uint8_t localY = 0;333334 localY = Y;335 localSize = ((Size / 8) + ((Size % 8) ? 1 : 0)) * (Size / 2);//得到字体⼀个字符对应点阵集所占字节数336 localChr = Chr - ''; //计算偏移后的值337for (localIte = 0; localIte < localSize; localIte++)338 {339if (Size == 12)340 {341 localTemp = asc2_1206[localChr][localIte];//调⽤1206字体342 }343else if (Size == 16)344 {345 localTemp = asc2_1608[localChr][localIte];//调⽤1608字体346 }347else if (Size == 24)348 {349 localTemp = asc2_2412[localChr][localIte];//调⽤2412字体350 }351else352 {353return ;354 }355356for (localIte1 = 0; localIte1 < 8; localIte1++)357 {358if (localTemp & 0x80)359 {360 FunAppOledDrawPoint(X, Y);361 }362else363 {364 FunAppOledClearPoint(X, Y);365 }366 localTemp <<= 1;367 Y++;368if ((Y - localY) == Size)369 {370 Y = localY;371 X++;372break;373 }374 }375 }376 }377378/*************************************************379函数名称 : FunAppOledShowString380功能描述 : 显⽰字符串381被调⽤清单 : ⽆382调⽤清单 :383输⼊参数 : X(0 ~ 127) , Y(0 ~ 63) (X , Y)起点坐标 Chr待显⽰字符串 Size字体⼤⼩384输出参数 : ⽆385返回参数 : ⽆386其他 : ⽆387*************************************************/388void FunAppOledShowString(uint8_t X, uint8_t Y, uint8_t * Chr, uint8_t Size)389 {390while((*Chr >= '') && (*Chr <= '~'))//判断是不是⾮法字符391 {392 FunAppOledShowChar(X, Y, *Chr, Size);393 X += Size / 2;394if (X > (128 - Size)) //换⾏395 {396 X = 0;397 Y += 2;398 }399 Chr++;400 }401 }402403/*************************************************404函数名称 : FunAppOledPow405功能描述 : 计算⼀个数据的次⽅406被调⽤清单 : ⽆407调⽤清单 :408输⼊参数 : Num底数,Index指数409输出参数 : ⽆410返回参数 : 计算后的值411其他 : ⽆412*************************************************/413 uint32_t FunAppOledPow(uint8_t Num, uint8_t Index)414 {415 uint32_t localRes = 1;416while(Index--)417 {418 localRes *= Num;419 }420return localRes;421 }422423/*************************************************424函数名称 : FunAppOledShowNum425功能描述 : 显⽰数字426被调⽤清单 : ⽆427调⽤清单 :428输⼊参数 : (X , Y)起点坐标 Len数字的位数 Size字体⼤⼩429输出参数 : ⽆430返回参数 : ⽆431其他 : ⽆432*************************************************/433void FunAppOledShowNum(uint8_t X, uint8_t Y, uint32_t Num, uint8_t Len, uint8_t Size) 434 {435 uint8_t localIte = 0;436 uint8_t localTemp = 0;437438for (localIte = 0; localIte < Len; localIte++)439 {440 localTemp = (Num / FunAppOledPow(10, Len - localIte - 1)) % 10;441if (localTemp == 0)442 {443 FunAppOledShowChar((X + (Size / 2) * localIte), Y, '0', Size);444 }445else446 {447 FunAppOledShowChar((X + (Size / 2) * localIte), Y, (localTemp + '0'), Size); 448 }449 }450 }451452/*************************************************453函数名称 : FunAppOledShowChinese454功能描述 : 显⽰汉字455被调⽤清单 : ⽆456调⽤清单 :457输⼊参数 : (X , Y)起点坐标 Num汉字对应序号 Size字体⼤⼩458输出参数 : ⽆459返回参数 : ⽆460其他 : ⽆461*************************************************/462void FunAppOledShowChinese(uint8_t X, uint8_t Y, uint8_t Num, uint8_t Size)463 {464 uint8_t localIte0 = 0;465 uint8_t localIte1 = 0;466 uint8_t localCount = 0;467 uint8_t localTemp = 0;468 uint8_t localChr = 0;469 uint8_t localX = 0;470 uint8_t localY = 0;471 uint8_t localSize = 0;472473 localX = X;474 localY = Y;475 localSize = Size / 8;476477while (localSize--)478 {479 localChr = (Num * Size / 8) + localCount;480 localCount++;481482for (localIte0 = 0; localIte0 < Size; localIte0++)483 {484if (Size == 16)485 {486 localTemp = Hzk0[localChr][localIte0]; //调⽤16*16字体487 }488else if (Size == 24)489 {490 localTemp = Hzk2[localChr][localIte0]; //调⽤24*24字体491 }492else if (Size == 32)493 {494 localTemp = Hzk3[localChr][localIte0]; //调⽤32*32字体495 }496else if (Size == 64)497 {498 localTemp = Hzk4[localChr][localIte0]; //调⽤64*64字体499 }500else501 {502return ;503 }504505for (localIte1 = 0; localIte1 < 8; localIte1++)506 {507if (localTemp & 0x01)508 {509 FunAppOledDrawPoint(X, Y);510 }511else512 {513 FunAppOledClearPoint(X, Y);514 }515 localTemp >>= 1;516 Y++;517 }518 X++;519if ((X - localX) == Size)520 {521 X = localX;522 localY = localY + 8;523 }524 Y = localY;525 }526 }527 }528529/*************************************************530函数名称 : FunAppOledScrollDisplay531功能描述 : 左移显⽰532被调⽤清单 : ⽆533调⽤清单 :534输⼊参数 : Num显⽰汉字的个数,Space每⼀遍显⽰的间隔535输出参数 : ⽆536返回参数 : ⽆537其他 : ⽆538*************************************************/539void FunAppOledScrollDisplay(uint8_t Num, uint8_t Space)540 {541 uint8_t localIte0 = 0;542 uint8_t localIte1 = 0;543 uint8_t localIte2 = 0;544 uint8_t localIte3 = 0;545 uint8_t localIte4 = 0;546 uint8_t localNum = 0;547 uint8_t localTemp = 0;548549while (1)550 {551if (localNum == 0)552 {553 FunAppOledShowChinese(128, 24, localTemp, 16);//写⼊⼀个汉字保存在OLED_GRAM中554 localTemp++;555 }556557if (localTemp == Num)558 {559for (localIte0 = 0; localIte0 < (16 * Space); localIte0++)//显⽰间隔560 {561for (localIte1 = 0; localIte1 < 144; localIte1++)562 {563for (localIte2 = 0; localIte2 < 8; localIte2++)564 {565 OLED_GRAM[localIte1 - 1][localIte2] = OLED_GRAM[localIte1][localIte2]; 566 }567 }568 FunAppOledRefresh();569 }570 localTemp = 0;571 }572 localNum++;573if (localNum == 16)574 {575 localNum = 0;576 }577for (localIte3 = 0; localIte3 < 144; localIte3++) //左移578 {579for (localIte4 = 0; localIte4 < 8; localIte4++)580 {581 OLED_GRAM[localIte3 - 1][localIte4] = OLED_GRAM[localIte3][localIte4];582 }583 }584 FunAppOledRefresh();585 }586 }587588/*************************************************589函数名称 : FunAppOledWriteBP590功能描述 : 配置写⼊数据的起始位置591被调⽤清单 : ⽆592调⽤清单 :593输⼊参数 : (X , Y)起始位置坐标594输出参数 : ⽆595返回参数 : ⽆596其他 : ⽆597*************************************************/598void FunAppOledWriteBP(uint8_t X, uint8_t Y)599 {600 FunAppOledWriteByte((0xB0 + Y), OLED_CMD);601 FunAppOledWriteByte(((X & 0xF0) >> 4) | 0x10, OLED_CMD);602 FunAppOledWriteByte((X & 0x0F) | 0x01, OLED_CMD);603 }604605/*************************************************606函数名称 : FunAppOledShowPicture607功能描述 : 显⽰图⽚608被调⽤清单 : ⽆609调⽤清单 :610输⼊参数 : (X1 , Y1)起始坐标 (X2 , Y2)终点坐标 Bmp要写⼊的图⽚数组611输出参数 : ⽆612返回参数 : ⽆613其他 : ⽆614*************************************************/615void FunAppOledShowPicture(uint8_t X1, uint8_t Y1, uint8_t X2, uint8_t Y2, uint8_t *Bmp) 616 {617 uint32_t localIte0 = 0;618 uint8_t localX = 0;619 uint8_t localY = 0;620621if ((localY % 8) == 0)622 {623 localY = 0;624 }625else626 {627 localY += 1;628 }629630for (localY = Y1; localY < Y2; localY++)631 {632 FunAppOledWriteBP(X1, localY);633for (localX = X1; localX < X2; localX++)634 {635 FunAppOledWriteByte(Bmp[localIte0], OLED_DATA);636 localIte0++;637 }638 }639 }640641/*************************************************642函数名称 : FunAppOledColorTurn643功能描述 : 反显函数644被调⽤清单 : ⽆645调⽤清单 :646输⼊参数 : Mode == 0正常显⽰, Mode == 1反⾊显⽰647输出参数 : ⽆648返回参数 : ⽆649其他 : ⽆650*************************************************/651void FunAppOledColorTurn(uint8_t Mode)652 {653if (Mode == 0)654 {655 FunAppOledWriteByte(0xA6, OLED_CMD);//正常显⽰656 }657658if (Mode == 1)659 {660 FunAppOledWriteByte(0xA7, OLED_CMD);//反⾊显⽰661 }662 }663664/*************************************************665函数名称 : FunAppOledDisplayTurn666功能描述 : 屏幕旋转180°667被调⽤清单 : ⽆668调⽤清单 :669输⼊参数 : Mode == 0正常显⽰ Mode == 1反转显⽰670输出参数 : ⽆671返回参数 : ⽆672其他 : ⽆673*************************************************/674void FunAppOledDisplayTurn(uint8_t Mode)675 {676if (Mode == 0)677 {678 FunAppOledWriteByte(0xC8, OLED_CMD);//正常显⽰679 FunAppOledWriteByte(0xA1, OLED_CMD);680 }681682if (Mode == 1)683 {684 FunAppOledWriteByte(0xC0, OLED_CMD);//反转显⽰685 FunAppOledWriteByte(0xA0, OLED_CMD);686 }687 }4、字体OLED_FONT.h1/************************************************************2 * Copyright (C) 2021 , 伽椰⼦真可爱3 * All right reserved.4 * ⽂件名称:OLED_FONT.h5 * 作者:⾼弟(GaoDi)6 * 原始版本:V1.07 * 创建⽇期:2022/1/108 * ⽂件描述:OLED字体9 * 函数列表:10 *11 * 历史:12 * <作者> <时间> <版本> <功能描述>13 *14 * **********************************************************/15 #ifndef _OLED_FONT_H_16#define _OLED_FONT_H_1718//常⽤ASCII表19//偏移量3220//ASCII字符集21//偏移量3222//⼤⼩:12*623/************************************6*8的点阵************************************/24//12*12 ASCII字符集点阵25const unsigned char asc2_1206[95][12]={26 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/27 {0x00,0x00,0x00,0x00,0x3F,0x40,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/28 {0x00,0x00,0x30,0x00,0x40,0x00,0x30,0x00,0x40,0x00,0x00,0x00},/*""",2*/29 {0x09,0x00,0x0B,0xC0,0x3D,0x00,0x0B,0xC0,0x3D,0x00,0x09,0x00},/*"#",3*/30 {0x18,0xC0,0x24,0x40,0x7F,0xE0,0x22,0x40,0x31,0x80,0x00,0x00},/*"$",4*/31 {0x18,0x00,0x24,0xC0,0x1B,0x00,0x0D,0x80,0x32,0x40,0x01,0x80},/*"%",5*/32 {0x03,0x80,0x1C,0x40,0x27,0x40,0x1C,0x80,0x07,0x40,0x00,0x40},/*"&",6*/33 {0x10,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/。
加个模块,实现IIC方式驱动LCD1602

加个模块,实现IIC驱动LCD1602 PCF8574模块使实现IIC驱动LCD1602成为现实。
下图是PCF8574模块与1602的连接电路图:实物接法如下:想要使用PCF8574模块来实现IIC驱动LCD1602,首先非常必要弄清楚IIC的时序、PCF8574设备地址、四线控制LCD1602方法。
下面是两个重要的h文件。
通过修改这两个h文件中的部分代码(接线有所不同)即可移植到你的程序中去。
PCF8574.h程序:sbit scl=P1^6;sbit sda=P1^7;void delay()//{ ;; }void init()//IIC初始化{sda=1;delay();scl=1;delay();}void start() //IIC开始信号{sda=1;delay();sda=0;delay();}void stop() //IIC停止{sda=0;delay();scl=1;delay();sda=1;delay();}void respons() //IIC应答{uchar i;scl=1;delay();while((sda==1)&&(i<250))i++;}void write_byte(uchar date)//IIC写入数据{uchar i,temp;temp=date;for(i=0;i<8;i++){temp=temp<<1;scl=0;delay();sda=CY;delay();scl=1;delay();}scl=0;delay();sda=1;uchar read_byte()//IIC读取字节{uchar i,k;scl=0;delay();sda=1;delay();for(i=0;i<8;i++){scl=1;delay();k=(k<<1)|sda;scl=0;delay();}return k;}start();write_byte(0x7e); //8574设备地址(写)respons();write_byte(date1);respons();stop();}uchar read_add()//向IO读取数据{uchar date1;start();write_byte(0x71); //8574设备地址(读)respons();date1=read_byte();respons();stop();return date1;}PCF8574+LCD1602_4.h程序:uchar a,b;for(a=x;a>0;a--)for(b=200;b>0;b--);}void write_com(uchar com) //写命令函数{ uchar com1,com2;com1=com|0x0f;write_add(com1&0xfc);delay1(2);write_add(com1&0xf8);com2=com<<4;com2=com2|0x0f;write_add(com2&0xfc);delay1(2);write_add(com2&0xf8);}void write_date(uchar date) //写数据函数{date1=date|0x0f;write_add(date1&0xfd);delay1(2);write_add(date1&0xf9);date2=date<<4;date2=date2|0x0f;write_add(date2&0xfd);delay1(2);write_add(date2&0xf9);}void init_lcd() //初始化函数{write_com(0x33); //显示模式设置delayms(6);write_com(0x32); //显示模式设置delayms(6);write_com(0x28); //4位总线,双行显示,显示5×7的点阵字符delayms(6);write_com(0x01); //清屏write_com(0x06); //字符进入模式:屏幕不动,字符后移delayms(6);write_com(0x0c); //显示开,关光标//write_LCD_Command(0x0f); //显示开,开光标,光标闪烁delayms(6);}//显示字符串:第x行第y列显示什么内容void ShowString(unsigned char x,unsigned char y,unsigned char *str){//设置起始位置if(x == 1){write_com(0x80 | y-1);// |相当于加法}if(x == 2){write_com(0xc0 | y-1);}//输出字符串while(*str!='\0') {write_date(*str);str++;}}。
如何对AT24C02编写驱动程序——IIC总线协议

如何对AT24C02编写驱动程序——IIC总线协议AT24C02是一种2Kbit(256字节)的串行EEPROM芯片,采用I2C总线协议进行通信。
编写AT24C02的驱动程序需要了解I2C总线协议的工作原理以及AT24C02的读写操作。
以下是编写AT24C02驱动程序的步骤:1. 硬件配置:首先,需要在单片机上配置I2C总线的硬件连接。
I2C 总线需要两根信号线,即SDA(Serial Data Line)和SCL(Serial Clock Line)。
将SDA和SCL引脚连接到AT24C02的对应引脚,并通过上拉电阻将其拉高。
2.初始化I2C总线:在驱动程序中,需要初始化I2C总线的相关寄存器和配置参数。
这包括设置I2C总线的通信速率、使能I2C模块、使能中断等。
3.开始信号和设备地址:发送开始信号START,然后发送AT24C02的设备地址,设备地址由3位固定的值和一个读/写位组成。
读写位为0代表写操作,为1代表读操作。
4.发送数据:如果是写操作,发送要写入的数据到AT24C02的指定地址。
数据写入时,需要注意AT24C02的内存地址范围,以及页写操作的限制。
如果是读操作,发送读取的目标地址。
5.停止信号:传输完成后,发送停止信号STOP,结束通信。
6.延时和轮询:在I2C总线通信中,需要一定的延时等待数据传输完成。
在写入大量数据或读取数据时,还需要轮询等待操作完成。
7.错误处理:在驱动程序中,需要考虑到可能发生的错误和异常情况。
例如,设备地址未响应、通信超时、数据传输错误等,都需要进行相应的错误处理。
8.封装函数接口:为了方便上层应用调用,可以将上述操作封装成函数接口。
例如,提供读写函数、擦除函数和查询设备ID的函数等。
除了以上的驱动程序,还可以根据实际需求进行功能扩展。
例如,可以实现批量写入数据、随机读取数据、擦除操作等。
总之,编写AT24C02的驱动程序主要包括硬件配置、初始化I2C总线、发送开始信号和设备地址、发送数据、发送停止信号、延时和轮询、错误处理等步骤。
I2C驱动E2PROM

I2C驱动E2PROM*By Neil Chiao ( neilchiao at ) 1、I2C总线原理I2C是一种常用的串行总线,由串行数据线SDA 和串线时钟线SCL组成。
系统的I2C模块分为I2C总线控制器和I2C设备。
I2C总线控制器是CPU提供的控制I2C总线接口,它控制I2C总线的协议、仲裁、时序。
I2C设备是指通过I2C总线与CPU相连的设备,如EEPROM。
使用I2C通信时必须指定主从设备。
一般来说,.I2C总线控制器被配置成主设备,与总线相连的I2C设备如AT24C02作为从设备。
1.1、IIC读写EEPROM 原理IIC总线的开始/停止信号如图1所示。
开始信号为:时钟信号线SCL为高电平,数据线SDA从高变低。
停止信号为:时钟信号线SCL为高电平,数据线SDA从低变高。
图1 IIC Start-Stop Signal 1.1.1 IIC总线Byte WriteIIC总线写数据分几种格式,如字节写和页写。
字节写传送格式如图2所示。
开始信号之后,总线开始发数据,第一个Byte是IIC的设备地址,第二个Byte是设备内的地址(如EEPROM中具体的某个物理地址),然后就是要传送的真正的数据DATA。
NOTE:IIC总线在传送每个Byte后,都会从IIC总线上的接收设备得到一个ACK信号来确认接收到了数据。
其中,第一个Byte的设备地址中,前7位是地址码,第8位是方向位(“0”为发送,“1”为接收)。
IIC的中断信号有:ACK,Start,Stop。
图2 IIC Byte Write Write功能的实际实现原理如图3所示:(1)设置GPIO的相关引脚为IIC输出;(2)设置IIC(打开ACK,打开IIC中断,设置CLK等);(3)设备地址赋给IICDS ,并设置IICSTAT,启动IIC发送设备地址出去;从而找到相应的设备即IIC总线上的EEPROM。
(4)第一个Byte的设备地址发送后,从EEPROM得到ACK信号,此信号触发中断;(5)在中断处理函数中把第二个Byte(设备内地址)发送出去;发送之后,接收到ACK 又触发中断;(6)中断处理函数把第三个Byte(真正的数据)发送到EEPROM中;(7)发送之后同样接收到ACK并触发中断,中断处理函数判断,发现数据传送完毕。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
IIC总线在传输数据的过程中有3种类型的信号:开始信号、结束信号、和应答信号
>>开始信号(S): 当SCL为高电平时,SDA由高电平向低电平跳变,表示将要开始传输数据
>>结束信号(P):当SCL为高电平时,SDA由低电平向高电平跳
S公司开发的两线式串行总线,用于连接微处理器用与音频和视频设备,现在在各种电子设备中都广泛应用
IIC总线有两条总线线路,一条是串行数据线(SDA),一条是串行时钟线(SCL)。SDA负责数据传输,SCL负责数据传输的时钟同步。IIC设备通过这两条总线连接到处理器的IIC总线控制器上。一种典型的设备连接如图:
与其他总线相比,IIC总线有很多重要的特点。在选择一种设备来完成特定功能时,这些特点是选择IIC设备的重要依据。
主要特点:
1,每一个连接到总线的设备都可以通过唯一的设备地址单独访问
2,串行的8位双向数据传输,位速率在标准模式下可达到100kb/s;快速模式下可以达到400kb/s;告诉模式下可以达到3.4Mb/s
3,总线长度最长7.6m左右
4,片上滤波器可以增加抗干扰能力,保证数据的完成传输
5,连接到一条IIC总线上的设备数量只受到最大电容400pF的限制
6,它是一个多主机系统,在一条总线上可以同时有多个主机存在,通过冲突检测方式和延时等待防止数据不被破坏。同一时间只能有一个主机占用总线