[TOC]
1. IIC总线
1.0 概述
IIC总线全称:Inter-Integrated Circuit,是由飞利浦公司开发出来的一种串行总线协议,它是一种多主机的总线,当发生主机竞争时,有总线仲裁机制。
IIC总线只有两根信号线:
当总线空闲时,这两根数据线均处于高电平的状态,数据传输时由设备拉低总线。
IIC的通信原理可以通过数据手册了解,想要写底层代码的时候对比着写就好,在蓝桥杯中提供了底层代码,因此我们只需要了解官方代码如何使用就好。
蓝桥杯提供的驱动函数:
1 2 3 4 5 6 7 8 9 10 11
| #ifndef _IIC_H #define _IIC_H
void IIC_Start(void); //起始信号 void IIC_Stop(void); //停止信号 bit IIC_WaitAck(void); //等待应答 void IIC_SendAck(bit ackbit); //产生应答 void IIC_SendByte(unsigned char byt); //发生数据 unsigned char IIC_RecByte(void); //接受数据
#endif
|
1.1 IIC数据传输过程
在没有硬件IIC外设的微处理器中,需要根据总线时序设计IIC接口的驱动程序。包括:起始信号、停止信号、产生应答、等待应答、发送数据和接收数据6个函数,如上.h文件当中的函数,那如何利用这些函数实现数据的传输
与接受?
流程
|开始信号 |写入地址 |等待响应 | 得到响应 |发送数据 |等待响应|停止信号|
| — | — | — | — | — |— |— |
| S | 从机地址 |0 |A | 数据 |A/非A|P|
ps:当接受信号时,数据后面为非应答信号。
每发送或接受一个数据都需要经过这样的流程,那么利用官方函数代码就可以这样写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| // ***********发送数据**************** IIC_Start(); //IIC总线起始信号 IIC_SendByte(0xxx); //设备地址 IIC_WaitAck(); //等待从机应答 IIC_SendByte(0xxx); //写入数据 IIC_WaitAck(); //等待从机应答 IIC_Stop(); //IIC总线停止信号 //**************接受数据************** IIC_Start(); //IIC总线起始信号 IIC_SendByte(0xxx); //读设备地址 IIC_WaitAck(); //等待从机应答 dat = IIC_RecByte(); //读取数据 IIC_Ack(0); //产生非应答信号 IIC_Stop(); //IIC总线停止信号 ————————————————
|
2.PCF8591
2.1概述
PCF8591是具有IIC接口的8位A/D和D/A转换芯片,具有4路模拟输入、一路DAC输出和一个IIC总线接口。
原理图:

2.2设备地址
PCF8591设备地址包括固定部分和可编程的部分,如图:

2.3控制
PCF8591内部控制寄存器,当确定地址后,向该地址发送数据来控制器件的功能。

7 |
6 |
5 和4 |
3 |
2 |
1 和0 |
固定值 |
模拟输出控制 |
模拟量输入方式选择 |
固定值 |
自动增量控制 |
A/D通道选择 |
2.4A/D转换流程
- 1–发送写设备地址,选择IIC总线上的PCF8591器件。
- 2–发送控制字节,选择模拟量输入模式和通道。
- 3–发送读设备地址,选择IIC总线上的PCF8591器件。
- 4–读取PCF8591中目标通道的数据。
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 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
| #include "reg52.h" #include "iic.h" unsigned char Num[10] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; unsigned char dat = 0; void delay(unsigned char T){ while(T--); }
void select_74HC138(unsigned char num){ switch(num){ case 4: P2 = (P2 & 0x1f) |0x80; //led break; case 5: P2 = (P2 & 0x1f) |0xa0; //蜂鸣器 break; case 6: P2 = (P2 & 0x1f) |0xc0; //位置 break; case 7: P2 = (P2 & 0x1f) |0xe0; //数据 break; case 0: P2 = P2 & 0x1f ; break; } } // ******************关闭蜂鸣器和led************* void system_Init(){ select_74HC138(4); P0 = 0xff; select_74HC138(5); P0 = 0x00; select_74HC138(0); } //**************************************************
//************************数码管显示**************** void Desplay(unsigned char dat , unsigned pos){ P0 = 0xff; select_74HC138(6); P0 = 0x01 << pos; select_74HC138(7); P0 = dat; } void display_smg(){ Desplay(Num[dat/100],5); delay(100); Desplay(Num[(dat%100)/10],6); delay(100); Desplay(Num[(dat%100)%10],7); delay(100); }
void read_rb2(){ IIC_Start(); IIC_SendByte(0x90); IIC_WaitAck(); IIC_SendByte(0x03); IIC_WaitAck(); IIC_Stop(); display_smg();
IIC_Start(); IIC_SendByte(0x91); IIC_WaitAck(); dat = IIC_RecByte(); IIC_SendAck(0); IIC_Stop(); display_smg(); }
|