在线时间104 小时
UID3338547
注册时间2017-1-28
NXP金币14
TA的每日心情 | 无聊 2021-12-29 19:06 |
---|
签到天数: 47 天 连续签到: 1 天 [LV.5]常住居民I
金牌会员
 
- 积分
- 1392
- 最后登录
- 2025-3-4
|
本帖最后由 day_day 于 2019-3-10 14:15 编辑
老实说这是挺久之前弄的了,这个星期为找工作的事情焦头烂额,现在抽空来天下坑,有些地方记得不太清楚了……
(一)IIC初始化配置
主要寄存器:
主要有三步:使能电源、时钟,配置引脚复用,配置IIC,如果需要中断还要配置中断- void I2cInit(void)
- {
- //1、使能电源、时钟(略,默认配置)
- LPC_SYSCTL->PCONP |= 0x00000080;
- //2、配置引脚复用
- LPC_IOCON->PINSEL[1] |= 0x01400000;
- //3、配置IIC
- //3.1-清除标志位
- LPC_I2C0->CONCLR = I2CONSET_AA | I2CONSET_SI | I2CONSET_STA | I2CONSET_I2EN;
- //3.2-配置高低电平占空比
- LPC_I2C0->SCLL = 0x80;
- LPC_I2C0->SCLH = 0x80;
- //3.3-使能
- LPC_I2C0->CONSET = I2CONSET_I2EN;
- LPC_I2C0->CONSET = I2CONSET_STO;
- }
复制代码
(二)IIC发送
根绝数据手册,主发送模式:
1、
必须置位I2EN来使能I2C功能。如果AA位为 0,而另一个器件成为总线的主控制器时,I2C接口不会对任何地址产生应答,也就是说它无法进入从模式。
首先我们需要置位EN来使能IIC,但由于其默认值为1,已经使能,所以可以不配置。
但AA位必须配置为0才能防止进入从模式!
2、
通过软件置位 STA,将进入 I2C 主发送模式。I2C 逻辑在总线空闲后立即发送一个起始条件。当发送完起始条件后,SI 会置位。此时 I2STAT 中的状态代码为 0x08。该状态代码用于中断服务程序的处理。该中断程序把从地址和写操作位装入 I2DAT(数据寄存器),然后清零 SI位。向 I2CONCLR 寄存器中的 SIC 位写入 1 可清零 SI。
可以看到,主发送模式下I2C的起始条件是:置位STA!
但同时还要注意到,SI在发送完成会置位,为了区分发送完成和发送未完成,必须事先清除SI!
3、
LPC1768的IIC设计艺术是将之分为三个部分的:
开头起始部分、中间发送部分、末尾结束部分
4、开头起始部分
通过软件置位 STA,将进入 I 2 C 主发送模式。I 2 C 逻辑在总线空闲后立即发送一个起始条件。当发送完起始条件后,SI 会置位。此时 I2STAT 中的状态代码为 0x08。该状态代码用于中断服务程序的处理。
即置位STA产生其实条件后,SI会置位,我们通过阻塞实现:
- LPC_I2C0->CONCLR = I2CONSET_AA | I2CONSET_SI | I2CONSET_STA | I2CONSET_STO;
- LPC_I2C0->CONSET = I2CONSET_STA | I2CONSET_I2EN;
- while (!(LPC_I2C0->CONSET & I2CONSET_SI)); // Wait for START
复制代码
5、末尾结束部分
在主模式中,当 STO 为 1 时,会使 I 2 C 接口发送一个停止条件或在从模式中从错误状态中恢复。当主模式中 STO=1 时,向 I 2 C 总线发送停止条件。当总线检测到停止条件时,STO 自动清零。
通过置位STO控制位,产生结束条件。然后阻塞访问知道STO又变成0
- LPC_I2C0->CONSET = I2CONSET_STO;
- LPC_I2C0->CONCLR = I2CONSET_SI;
- while (LPC_I2C0->CONSET & I2CONSET_STO);
复制代码
6、中间发送部分
把从地址和写操作位装入 I2DAT(数据寄存器),然后清零 SI位。向 I2CONCLR 寄存器中的 SIC 位写入 1 可清零 SI。
数据手册里面建议在中断里面装载DAT,我们先阻塞装载:
-
- LPC_I2C0->DAT = hwaddr;
- LPC_I2C0->CONCLR = I2CONSET_SI | I2CONSET_STA;
- while (!(LPC_I2C0->CONSET & I2CONSET_SI)); // Wait for ADDRESS send
-
- LPC_I2C0->DAT = command;
- LPC_I2C0->CONCLR = I2CONSET_SI;
- while (!(LPC_I2C0->CONSET & I2CONSET_SI)); // Wait for DATA send
-
- LPC_I2C0->DAT = data;
- LPC_I2C0->CONCLR = I2CONSET_SI;
- while (!(LPC_I2C0->CONSET & I2CONSET_SI)); // Wait for DATA send
-
复制代码 这是常见的三段式IIC通讯。
(三)IIC接收
接收会稍微麻烦些,数据手册写得很暧昧不清,让人无法捉摸发送和接收之间如何切换。实际上它这里提到这么一句:
- 发送完重复的起始条件之后,I 2 C 可以切换到主发送模式。
复制代码 那么也就是说,重复起始条件同样也能从主发送切换到主接收?
当 STA=1 并且 I 2 C 接口还没进入主模式时,I 2 C 接口进入主模式,检测总线并在总线空闲时产生一个起始条件。如果总线忙,则等待一个停止条件(释放总线)并在延迟半个内部时钟发生器周期后发送一个起始条件。当 I 2 C 接口已经处于主模式中并发送或接收了数据时,I 2 C 接口会发送一个重复的起始条件。STA 可在任何时候置位,当 I 2 C 接口处于可寻址的从模式时,STA 也可以置位。
那么就是说STA已经为1的时候再往STA里面写1就能进入重复发送条件?
- unsigned char IICReadChar(unsigned char hwaddr, unsigned char command)
- {
- unsigned char rec;
-
- LPC_I2C0->CONCLR = I2CONSET_AA | I2CONSET_SI | I2CONSET_STA | I2CONSET_STO;
- LPC_I2C0->CONSET = I2CONSET_STA | I2CONSET_I2EN;
- while (!(LPC_I2C0->CONSET & I2CONSET_SI)); // Wait for START
-
- LPC_I2C0->DAT = hwaddr;
- LPC_I2C0->CONCLR = I2CONSET_SI | I2CONSET_STA;
- while (!(LPC_I2C0->CONSET & I2CONSET_SI)); // Wait for ADDRESS(write) send
-
- LPC_I2C0->DAT = command;
- LPC_I2C0->CONCLR = I2CONSET_SI;
- while (!(LPC_I2C0->CONSET & I2CONSET_SI)); // Wait for DATA(ass_addr) send
-
- LPC_I2C0->CONCLR = I2CONSET_AA | I2CONSET_SI | I2CONSET_STA | I2CONSET_STO;
- LPC_I2C0->CONSET = I2CONSET_STA | I2CONSET_I2EN;
- while (!(LPC_I2C0->CONSET & I2CONSET_SI)); //restart
-
- LPC_I2C0->DAT = hwaddr+0x01;
- LPC_I2C0->CONCLR = I2CONSET_SI | I2CONSET_STA;
- while (!(LPC_I2C0->CONSET & I2CONSET_SI)); // Wait for ADDRESS(read) send
-
- //LPC_I2C0->I2DAT = data;
- LPC_I2C0->CONCLR = I2CONSET_SI;
- while (!(LPC_I2C0->CONSET & I2CONSET_SI)); // Wait for DATA send
- rec = LPC_I2C0->DAT;
-
- LPC_I2C0->CONSET = I2CONSET_STO;
- LPC_I2C0->CONCLR = I2CONSET_SI;
- while (LPC_I2C0->CONSET & I2CONSET_STO); //end
-
- return rec;
- }
复制代码 测试了一下,果然如此
(四)IIC实战
板子左下角的四个led就是由一个IIC设备控制,其IIC地址为0xC0,其0x06地址里面每两位控制一个led灯,00为低电平,01为高电平,LED另一端接3.3V,即低电平亮!
IICSendChar(0xC0, 0x06, 0x54);
灯就亮起来了!
|
|